Analyze vibration waveforms

The most common vibration actuators on Android devices are linear resonant actuators (LRAs). LRAs simulate the feeling of a button click on what is otherwise an unresponsive glass surface. A clear and crisp click feedback signal typically lasts between 10 and 20 milliseconds in duration. This sensation makes user interactions feel more natural. For virtual keyboards, this click feedback can increase typing speed and reduce errors.

LRAs have a few common resonant frequencies:

  • Some LRAs had resonant frequencies in the 200 to 300 Hz range, which coincides with the frequency at which human skin is most sensitive to vibration. The sensation of vibrations at this frequency range are usually described as smooth, sharp, and penetrating.
  • Other models of LRAs have lower resonance frequencies, at around 150 Hz. The sensation is qualitatively softer and fuller (in dimension).
Components include, from top to bottom, a cover, plate, middle
       magnet, 2 side magnets, mass, 2 springs, coil, flexible circuit, base,
       and adhesive.
Components of a linear resonant actuator (LRA).

Given the same input voltage at two different frequencies, the vibration output amplitudes can be different. The further away the frequency is from the LRA's resonant frequency, the lower its vibration amplitude.

A given device's haptic effects use both the vibration actuator and its driver. Haptic drivers that include overdrive and active braking features can reduce the rise time and ringing of LRAs, leading to a more responsive and clear vibration.

Default waveform smoothing on devices

For illustration, consider how a custom waveform pattern behaves on a generic device:

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));

The following plots show the input waveform and output acceleration corresponding to the preceding code snippets. Note that the acceleration increases gradually, not suddenly, whenever there is a step change of amplitude in the pattern—that is, at 0ms, 150ms, 200ms, 250ms, and 700ms. There is also an overshoot at each step change of amplitude, and there is visible ringing that lasts at least 50ms when the input amplitude suddenly drops to 0.

Plot of step function input waveform.
Plot of actual measured waveform, showing more organic transitions between levels.

Improved haptic pattern

To avoid overshoot and reduce ringing time, change the amplitudes more gradually. The following shows the waveform and acceleration plots of the revised version:

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));

Plot of input waveform with additional steps.
Plot of measured waveform, showing smoother transitions.

Create more complex haptic effects

Other elements in a satisfying click response are more intricate, requiring some knowledge of the LRA used in a device. For best results, use the device's pre-fabricated waveforms and platform-provided constants, which let you do the following:

  • Perform clear effects and primitives.
  • Concatenate them to compose new haptic effects.

These predefined haptic constants and primitives can greatly speed up your work while creating high-quality haptic effects.