分析振动波形

Android 设备上最常见的振动致动器是线性共振致动器 (LRA)。LRA 可模拟在无响应的玻璃表面上点击按钮的感觉。清晰、响亮的点击反馈信号通常持续 10 到 20 毫秒。这种感觉让用户互动感觉更自然。对于虚拟键盘,这种点击反馈可以提高打字速度并减少错误。

LRA 具有几个常见的共振频率

  • 某些 LRA 的共振频率在 200 到 300 Hz 之间,这与人体皮肤对振动最敏感的频率相符。在这个频率范围内,振动感觉通常被描述为平滑、尖锐且穿透性强。
  • 其他型号的 LRA 的共振频率较低,约为 150 Hz。从感官上来说,这种感觉更柔和、更饱满(在维度上)。
组件包括(从上到下)盖子、板、中间磁铁、2 个侧边磁铁、质量块、2 个弹簧、线圈、柔性电路板、底板和粘合剂。
线性共振致动器 (LRA) 的组件。

在两个不同频率下使用相同的输入电压时,振动输出幅度可能会有所不同。频率离 LRA 的共振频率越远,其振动幅度就越小。

给定设备的触感反馈效果同时使用振动致动器及其驱动程序。包含超速和主动制动功能的触感反馈驱动程序可以缩短 LRA 的上升时间和振铃时间,从而实现更灵敏、更清晰的振动。

振动器输出加速度

频率到输出加速度映射 (FOAM) 描述了在给定振动频率 (Hz) 下可实现的最大输出加速度 (G 峰值)。从 Android 16(API 级别 36)开始,该平台通过 VibratorFrequencyProfile 提供对此映射的内置支持。您可以将此类与基本高级封装容器 API 结合使用,以创建触感反馈效果。

大多数 LRA 电机的 FOAM 中只有一个峰值,通常位于其共振频率附近。随着频率偏离此范围,加速度通常会呈指数级下降。曲线可能不对称,并且可能会在共振频率附近出现平台,以保护电机免受损坏。

旁边的图表显示了 LRA 电机的 FOAM 示例。

随着频率增加到约 120 Hz,加速度会呈指数级增加。然后,加速度会在约 180 Hz 时保持稳定,之后会逐渐减弱。
LRA 电机的 FOAM 示例。

人体感知检测阈值

人体感知检测阈值是指人体能够可靠检测到的振动最小加速度。此级别因振动频率而异。

旁边的图表显示了人类触感感知检测阈值(以加速度为单位)随时间频率的变化情况。阈值数据是根据 Bolanowski Jr. 的图 1 中的位移阈值转换而来,韩J. 等人 1988 年发表的文章《Four channels mediate the mechanical aspects of touch》。

Android 会在 BasicEnvelopeBuilder 中自动处理此阈值,以验证所有效果使用的频率范围产生的振动幅度是否至少比人类感知检测阈值高出 10 dB。

随着频率增加到约 20 Hz,人体检测阈值以对数方式上升到约 -35 dB。在约 200 Hz 之前,阈值保持稳定,之后大致呈线性增加,直到 -20 dB。
人体触感感知检测阈值。

在线教程进一步说明了加速度幅值与位移幅值之间的转换

振动加速度级别

人类对振动强度的感知(一种感知测量)不会随着振幅(一种物理参数)线性增加。感知到的强度由感知级别 (SL) 来表征,该级别定义为在相同频率下高于检测阈值的 dB 量。

相应的振动加速度幅值(以峰值 G 为单位)可按如下公式计算:

$$ Amplitude(G) = 10^{Amplitude(db)/20} $$

...其中,幅度 dB 是特定频率下 SL 和检测阈值(相邻图表中沿垂直轴的值)的总和。

旁边的图表显示了 10、20、30、40 和 50 dB SL 的振动加速度级别,以及人类触觉感知检测阈值 (0 dB SL) 随时间频率的变化情况。这些数据是根据 Verrillo, R. 的图 8 估算得出的。T. 等人于 1969 年发表的文章《振动触觉刺激的感觉强度》

随着所需的感觉强度增加,所需的加速度(以分贝为单位)也会大致增加相同的量。例如,100 Hz 振动时的 10 dB 感知级别约为 -20 dB,而不是 -30 dB。
振动加速度级别。

Android 会在 BasicEnvelopeBuilder 中自动处理此转换,该值将作为感觉强度空间 (dB SL) 中的归一化强度,并将其转换为输出加速度。另一方面,WaveformEnvelopeBuilder 不会应用此转换,而是将值视为加速度空间 (Gs) 中的归一化输出加速度幅值。Envelope API 假定,当设计师或开发者考虑振动强度的变化时,他们希望感知到的强度遵循分段线性封套。

设备上的默认波形平滑

举例来说,请考虑自定义波形模式在通用设备上的行为方式:

Kotlin

val timings: LongArray = longArrayOf(50, 50, 50, 50, 50, 100, 350, 250)
val amplitudes: IntArray = intArrayOf(77, 79, 84, 99, 143, 255, 0, 255)
val repeatIndex = -1 // Don't repeat.

vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex))

Java

long[] timings = new long[] { 50, 50, 50, 50, 50, 100, 350, 250 };
int[] amplitudes = new int[] { 77, 79, 84, 99, 143, 255, 0, 255 };
int repeatIndex = -1 // Don't repeat.

vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex));

以下图表显示了与上述代码段对应的输入波形和输出加速度。请注意,每当模式中的振幅发生阶跃变化时(即 0 毫秒、150 毫秒、200 毫秒、250 毫秒和 700 毫秒),加速度都会逐渐增加,而不是突然增加。此外,振幅的每个步骤变化都会出现过冲,并且当输入振幅突然下降到 0 时,会出现明显的铃声,持续时间至少为 50 毫秒。

阶跃函数输入波形图。
实际测量波形的图表,显示了各个音量级别之间更自然的过渡。

改进了触感反馈模式

为避免过冲并缩短振铃时间,请更缓慢地更改振幅。以下是修订版的波形和加速度图:

Kotlin

val timings: LongArray = longArrayOf(
    25, 25, 50, 25, 25, 25, 25, 25, 25, 25, 75, 25, 25,
    300, 25, 25, 150, 25, 25, 25
)
val amplitudes: IntArray = intArrayOf(
    38, 77, 79, 84, 92, 99, 121, 143, 180, 217, 255, 170, 85,
    0, 85, 170, 255, 170, 85, 0
)
val repeatIndex = -1 // Do not repeat.

vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex))

Java

long[] timings = new long[] {
        25, 25, 50, 25, 25, 25, 25, 25, 25, 25, 75, 25, 25,
        300, 25, 25, 150, 25, 25, 25
    };
int[] amplitudes = new int[] {
        38, 77, 79, 84, 92, 99, 121, 143, 180, 217, 255, 170, 85,
        0, 85, 170, 255, 170, 85, 0
    };
int repeatIndex = -1; // Do not repeat.

vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex));

包含额外步骤的输入波形图。
测量波形的图表,显示更流畅的过渡。

创建更复杂的触感反馈效果

令人满意的点击响应中的其他元素更为复杂,需要对设备中使用的 LRA 有一定的了解。为了获得最佳效果,请使用设备的预构建波形和平台提供的常量,以便执行以下操作:

  • 执行清晰的效果和基元
  • 将它们串联起来,组合出新的触感反馈效果。

这些预定义的触感反馈常量和基元可以大大加快您的工作速度,同时创建高品质的触感反馈效果。