Android 기기에서 가장 일반적인 진동 액추에이터는 선형 공진 액추에이터 (LRA)입니다. LRA는 반응이 없는 유리 표면에서 버튼을 클릭하는 느낌을 시뮬레이션합니다. 선명하고 깔끔한 클릭 피드백 신호는 일반적으로 10~20밀리초 동안 지속됩니다. 이러한 느낌을 통해 사용자 상호작용이 더 자연스럽게 느껴집니다. 가상 키보드의 경우 이 클릭 피드백을 통해 입력 속도를 높이고 오류를 줄일 수 있습니다.
일부 LRA의 공진 주파수는 200~300Hz 범위였으며, 이는 인간 피부가 진동에 가장 민감한 주파수와 일치합니다. 이 주파수 범위에서 진동의 느낌은 일반적으로 부드럽고 날카롭고 꿰뚫는 느낌으로 표현됩니다.
다른 LRA 모델은 공진 주파수가 약 150Hz로 더 낮습니다. 느낌은 질적으로 더 부드럽고 꽉 차 있습니다.
선형 공진 액추에이터 (LRA)의 구성요소
두 가지 다른 주파수에서 동일한 입력 전압을 가정할 때 진동 출력 진폭은 다를 수 있습니다. 주파수가 LRA의 공진 주파수에서 멀수록 진동 진폭이 낮아집니다.
특정 기기의 햅틱 효과는 진동 액추에이터와 해당 드라이버를 모두 사용합니다.
오버드라이브 및 능동 제동 기능이 포함된 햅틱 드라이버는 LRA의 상승 시간과 울림을 줄여 더 민감하고 선명한 진동을 제공할 수 있습니다.
진동기 출력 가속
주파수-출력 가속도 매핑 (FOAM)은 주어진 진동 주파수 (헤르츠)에서 달성할 수 있는 최대 출력 가속도 (피크 G)를 나타냅니다. Android 16 (API 수준 36)부터 플랫폼은 VibratorFrequencyProfile를 통해 이 매핑을 위한 기본 제공 지원을 제공합니다. 이 클래스를 기본 및 고급 엔벨롭 API와 함께 사용하여 햅틱 효과를 만들 수 있습니다.
대부분의 LRA 모터는 FOAM에 단일 피크를 갖고 있으며, 일반적으로 공진 주파수 근처에 있습니다. 가속은 일반적으로 주파수가 이 범위를 벗어나면 지수적으로 감소합니다. 곡선이 대칭적이지 않을 수 있으며 모터가 손상되지 않도록 공진 주파수 주변에 고원이 있을 수 있습니다.
인접한 그래프는 LRA 모터의 FOAM 예시를 보여줍니다.
LRA 모터의 FOAM 예시
인간 인식 감지 기준
인간 지각 감지 기준점은 사람이 안정적으로 감지할 수 있는 최소 진동 가속도를 나타냅니다. 이 수준은 진동 빈도에 따라 다릅니다.
지각 측정값인 인간의 진동 강도 지각은 물리적 매개변수인 진동 진폭과 선형적으로 증가하지 않습니다. 지각된 강도는 동일한 주파수에서 감지 임계값을 초과하는 dB 값으로 정의되는 감각 수준 (SL)으로 특성화됩니다.
이에 상응하는 진동 가속도 진폭 (G 피크 단위)은 다음과 같이 계산할 수 있습니다.
$$
Amplitude(G) = 10^{Amplitude(db)/20}
$$
여기서 진폭 dB는 특정 주파수에서 SL과 감지 기준점(인접한 그래프의 세로축 값)의 합입니다.
인접한 그래프는 시간 주파수 함수로서 10, 20, 30, 40, 50 dB SL의 진동 가속도 수준과 인간의 햅틱 감지 감지 기준점 (0 dB SL)을 보여줍니다. 데이터는 Verrillo, R.의 그림 8에서 추정되었습니다. T., et al.'s 1969 article, "Sensation magnitude of vibrotactile stimulus."
진동 가속도 수준
Android는 BasicEnvelopeBuilder에서 이 변환을 자동으로 처리합니다. BasicEnvelopeBuilder는 값을 감각 수준 공간 (dB SL)의 정규화된 강도로 취하고 이를 출력 가속도로 변환합니다. 반면 WaveformEnvelopeBuilder는 이 변환을 적용하지 않으며 대신 가속 공간 (Gs)에서 정규화된 출력 가속도 진폭으로 값을 취합니다. Envelope API는 디자이너나 개발자가 진동 강도의 변화를 고려할 때 지각된 강도가 개별 선형 엔벨롭을 따른다고 가정합니다.
다음 플롯은 이전 코드 스니펫에 해당하는 입력 웨이브폼과 출력 가속도를 보여줍니다. 패턴에서 진폭의 단계적 변화가 있을 때마다(즉, 0ms, 150ms, 200ms, 250ms, 700ms) 가속도가 갑자기 증가하는 것이 아니라 점진적으로 증가합니다. 또한 진폭의 각 단계 변화에서 오버슈트가 발생하며 입력 진폭이 갑자기 0으로 떨어질 때 50ms 이상 지속되는 링잉이 눈에 띄게 보입니다.
계단 함수 입력 파형의 그래프입니다.
실제 측정된 파형의 플롯으로, 수준 간의 더 자연스러운 전환을 보여줍니다.
개선된 햅틱 패턴
오버슈트를 방지하고 울림 시간을 줄이려면 진폭을 더 점진적으로 변경하세요. 다음은 수정된 버전의 파형 및 가속도 그래프를 보여줍니다.
Kotlin
valtimings:LongArray=longArrayOf(25,25,50,25,25,25,25,25,25,25,75,25,25,300,25,25,150,25,25,25)valamplitudes:IntArray=intArrayOf(38,77,79,84,92,99,121,143,180,217,255,170,85,0,85,170,255,170,85,0)valrepeatIndex=-1// Do not repeat.vibrator.vibrate(VibrationEffect.createWaveform(timings,amplitudes,repeatIndex))
자바
long[]timings=newlong[]{25,25,50,25,25,25,25,25,25,25,75,25,25,300,25,25,150,25,25,25};int[]amplitudes=newint[]{38,77,79,84,92,99,121,143,180,217,255,170,85,0,85,170,255,170,85,0};intrepeatIndex=-1;// Do not repeat.vibrator.vibrate(VibrationEffect.createWaveform(timings,amplitudes,repeatIndex));
추가 단계가 포함된 입력 파형의 그래프
더욱 원활한 전환을 보여주는 측정된 파형의 그래프
더 복잡한 햅틱 효과 만들기
만족스러운 클릭 응답의 다른 요소는 더 복잡하여 기기에 사용되는 LRA에 관한 지식이 필요합니다. 최상의 결과를 얻으려면 기기의 사전 제작된 웨이브폼과 플랫폼에서 제공하는 상수를 사용하세요. 이를 통해 다음 작업을 할 수 있습니다.
이러한 사전 정의된 햅틱 상수와 프리미티브를 사용하면 고품질 햅틱 효과를 만들면서 작업 속도를 크게 높일 수 있습니다.
이 페이지에 나와 있는 콘텐츠와 코드 샘플에는 콘텐츠 라이선스에서 설명하는 라이선스가 적용됩니다. 자바 및 OpenJDK는 Oracle 및 Oracle 계열사의 상표 또는 등록 상표입니다.
최종 업데이트: 2025-07-27(UTC)
[[["이해하기 쉬움","easyToUnderstand","thumb-up"],["문제가 해결됨","solvedMyProblem","thumb-up"],["기타","otherUp","thumb-up"]],[["필요한 정보가 없음","missingTheInformationINeed","thumb-down"],["너무 복잡함/단계 수가 너무 많음","tooComplicatedTooManySteps","thumb-down"],["오래됨","outOfDate","thumb-down"],["번역 문제","translationIssue","thumb-down"],["샘플/코드 문제","samplesCodeIssue","thumb-down"],["기타","otherDown","thumb-down"]],["최종 업데이트: 2025-07-27(UTC)"],[],[],null,["# Analyze vibration waveforms\n\nThe most common vibration actuators on Android devices are [linear resonant\nactuators (LRAs)](https://medium.com/@SomaticLabs/what-is-a-linear-resonant-actuator-81cc25f85779). LRAs simulate the feeling of a button click\non what is otherwise an unresponsive glass surface. A clear and crisp click\nfeedback signal typically lasts between 10 and 20 milliseconds in duration. This\nsensation makes user interactions feel more natural. For virtual keyboards, this\nclick feedback can increase typing speed and reduce errors.\n\nLRAs have a few common [resonant frequencies](https://en.wikipedia.org/wiki/Resonance#Examples):\n\n- 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.\n- Other models of LRAs have lower resonance frequencies, at around 150 Hz. The sensation is qualitatively softer and fuller (in dimension). \nComponents of a linear resonant actuator (LRA).\n\n\u003cbr /\u003e\n\nGiven the same input voltage at two different frequencies, the vibration output\namplitudes can be different. The further away the frequency is from the LRA's\nresonant frequency, the lower its vibration amplitude.\n\nA given device's haptic effects use both the vibration actuator and its driver.\nHaptic drivers that include overdrive and active braking features can reduce the\nrise time and ringing of LRAs, leading to a more responsive and clear vibration.\n\nVibrator output acceleration\n----------------------------\n\n\nThe frequency-to-output-acceleration mapping (FOAM) describes the maximum\nachievable output acceleration (in G peak) at a given vibration frequency (in\nHertz). Starting in Android 16 (API level 36), the platform provides built-in\nsupport for this mapping through the `VibratorFrequencyProfile`. You can use\nthis class, along with the [basic](/reference/android/os/VibrationEffect.BasicEnvelopeBuilder) and [advanced](/reference/android/os/VibrationEffect.WaveformEnvelopeBuilder) envelope APIs, to create\nhaptic effects.\n\nMost LRA motors have a single peak in their FOAM, typically near their resonant\nfrequency. Acceleration generally decreases exponentially as frequency deviates\nfrom this range. The curve may not be symmetrical and might feature a plateau\naround the resonant frequency to protect the motor from damage.\n\nThe adjacent plot shows an example FOAM for an LRA motor. \nExample FOAM for an LRA motor.\n\n\u003cbr /\u003e\n\n### Human perception detection threshold\n\n\nThe *human perception detection threshold* refers to the minimum acceleration of\na vibration that a person can reliably detect. This level varies based on the\nvibration frequency.\n\nThe adjacent plot shows the human haptic perception detection threshold, in\nacceleration, as a function of temporal frequency. The threshold data is\nconverted from displacement threshold in Figure 1 of Bolanowski Jr., S. J., et\nal.'s 1988 article,\n[\"Four channels mediate the mechanical aspects of touch.\"](https://pubmed.ncbi.nlm.nih.gov/3209773/).\n\nAndroid automatically handles this threshold in the `BasicEnvelopeBuilder`,\nwhich verifies that all effects use a frequency range that prodcues vibration\namplitudes that exceed the human perception detection threshold by at least\n10 dB. \nHuman haptic perception detection threshold.\n\n\u003cbr /\u003e\n\nAn online tutorial further explains the [conversion between acceleration\namplitude and displacement amplitude](https://www.tangerinex.com/tutorial-1).\n\n### Vibration acceleration levels\n\n\nHuman perception of vibration intensity, a *perception* measure, doesn't grow\nlinearly with vibration amplitude, a *physical* parameter. Perceived intensity\nis characterized by sensation level (SL), which is defined as a dB amount above\nthe detection threshold at the same frequency.\n\nThe corresponding vibration acceleration amplitude (in G peak) can be calculated\nas follows: \n$$ Amplitude(G) = 10\\^{Amplitude(db)/20} $$\n\n...where the amplitude dB is the sum of SL and detection threshold---the value\nalong the vertical axis in the adjacent plot---at a particular frequency.\n\nThe adjacent plot shows the vibration acceleration levels at 10, 20, 30, 40 and\n50 dB SL, along with the human haptic perception detection threshold (0 dB SL),\nas a function of temporal frequency. The data is estimated from Figure 8 in\nVerrillo, R. T., et al.'s 1969 article, [\"Sensation magnitude of vibrotactile\nstimuli.\"](https://link.springer.com/article/10.3758/BF03212793). \nVibration acceleration levels.\n\n\u003cbr /\u003e\n\nAndroid automatically handles this conversion in the `BasicEnvelopeBuilder`,\nwhich takes values as normalized intensities in the sensation level space (dB\nSL) and converts them to output acceleration. The `WaveformEnvelopeBuilder`, on\nthe other hand, doesn't apply this conversion and takes values as normalized\noutput acceleration amplitudes in the acceleration space (Gs) instead. The\nenvelope API assumes that, when a designer or developer thinks about changes in\nvibration strength, they expect the perceived intensity to follow a piecewise\nlinear envelope.\n\nDefault waveform smoothing on devices\n-------------------------------------\n\nFor illustration, consider how a custom waveform pattern behaves on a generic\ndevice: \n\n### Kotlin\n\n val timings: LongArray = longArrayOf(50, 50, 50, 50, 50, 100, 350, 250)\n val amplitudes: IntArray = intArrayOf(77, 79, 84, 99, 143, 255, 0, 255)\n val repeatIndex = -1 // Don't repeat.\n\n vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex))\n\n### Java\n\n long[] timings = new long[] { 50, 50, 50, 50, 50, 100, 350, 250 };\n int[] amplitudes = new int[] { 77, 79, 84, 99, 143, 255, 0, 255 };\n int repeatIndex = -1 // Don't repeat.\n\n vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex));\n\nThe following plots show the input waveform and output acceleration\ncorresponding to the preceding code snippets. Note that the acceleration\nincreases gradually, not suddenly, whenever there is a step change of amplitude\nin the pattern---that is, at 0ms, 150ms, 200ms, 250ms, and 700ms. There is also an\novershoot at each step change of amplitude, and there is visible ringing that\nlasts at least 50ms when the input amplitude suddenly drops to 0.\n\n\nPlot of step function input waveform. \nPlot of actual measured waveform, showing more organic transitions between levels.\n\n\u003cbr /\u003e\n\nImproved haptic pattern\n-----------------------\n\nTo avoid overshoot and reduce ringing time, change the amplitudes more\ngradually. The following shows the waveform and acceleration plots of the\nrevised version: \n\n### Kotlin\n\n val timings: LongArray = longArrayOf(\n 25, 25, 50, 25, 25, 25, 25, 25, 25, 25, 75, 25, 25,\n 300, 25, 25, 150, 25, 25, 25\n )\n val amplitudes: IntArray = intArrayOf(\n 38, 77, 79, 84, 92, 99, 121, 143, 180, 217, 255, 170, 85,\n 0, 85, 170, 255, 170, 85, 0\n )\n val repeatIndex = -1 // Do not repeat.\n\n vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex))\n\n### Java\n\n long[] timings = new long[] {\n 25, 25, 50, 25, 25, 25, 25, 25, 25, 25, 75, 25, 25,\n 300, 25, 25, 150, 25, 25, 25\n };\n int[] amplitudes = new int[] {\n 38, 77, 79, 84, 92, 99, 121, 143, 180, 217, 255, 170, 85,\n 0, 85, 170, 255, 170, 85, 0\n };\n int repeatIndex = -1; // Do not repeat.\n\n vibrator.vibrate(VibrationEffect.createWaveform(timings, amplitudes, repeatIndex));\n\n\nPlot of input waveform with additional steps. \nPlot of measured waveform, showing smoother transitions.\n\n\u003cbr /\u003e\n\nCreate more complex haptic effects\n----------------------------------\n\nOther elements in a satisfying click response are more intricate, requiring some\nknowledge of the LRA used in a device. For best results, use the device's\npre-fabricated waveforms and platform-provided constants, which let you do the\nfollowing:\n\n- Perform clear effects and [primitives](/develop/ui/views/haptics/custom-haptic-effects#primitives).\n- Concatenate them to compose new haptic effects.\n\nThese predefined haptic constants and primitives can greatly speed up your work\nwhile creating high-quality haptic effects."]]