Алгоритм генерации вибрационных моделей, варьирующих по интенсивности в Android?

Я пытаюсь программно генерировать шаблоны вибрации Android с «микроимпульсами» вкл. И выкл., Чтобы контролировать, насколько сильна вибрация для конечного пользователя. Это решение, которое я видел в нескольких похожих темах, к проблеме API, не предоставляющей интерфейс для управления силой вибрации (из-за того, как аппаратные функции, насколько я понимаю).

Однако алгоритм генерации этих шаблонов, по-видимому, намекает, но фактический алгоритм не опубликован.

То, что я хотел бы сделать, с учетом интенсивности ввода между 0.0f и 1.0f, генерирует массив, следующий за шаблоном, примерно так:

(zero intensity) [20,0] [9,1,9,1] ... [3,1,3,1,3,1,3,1,3,1] [2,1,2,1,2,1,2,1,2,1,2,1,2] (half intensity) [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] [1,2,1,2,1,2,1,2,1,2,1,2,1,1] [1,3,1,3,1,3,1,3,1,3] ... [1,9,1,9] (full intensity) [0,20] 

Любая помощь в написании такого алгоритма (или предложения для лучшей стратегии для достижения той же цели)?

Изменить: я добавил в микс репутацию 100 репутации 🙂

Solutions Collecting From Web of "Алгоритм генерации вибрационных моделей, варьирующих по интенсивности в Android?"

Рассмотрев проблему на некоторое время и не будучи очень математически талантливым, я придумал слишком упрощенный алгоритм (по сравнению с некоторыми формулами PWM, которые я нашел после того, как Dithermaster указал мне в этом направлении). Несколько предположений, которые я сделал, были первыми, что короткая ширина импульса всегда равна 1, а длительная ширина импульса – целое число от 1 до продолжительности вибрации. Я также предположил, что длительная длительность импульса является линейной функцией силы вибрации. В частности, последнее предположение неточно. Я предполагаю, что функция должна быть чем-то более похожа на расчет децибел («сила» вибрации сродни «громкости» звука).

Публикация моего упрощенного решения в случае, если оно полезно для всех, кто попадает сюда. Это достаточно близко для приложения, для которого я его использую, но мне все равно хотелось бы что-то получше. Если кто-нибудь отправит альтернативный ответ, я буду проверять и принимать его, если это лучше.

 public long[] genVibratorPattern( float intensity, long duration ) { float dutyCycle = Math.abs( ( intensity * 2.0f ) - 1.0f ); long hWidth = (long) ( dutyCycle * ( duration - 1 ) ) + 1; long lWidth = dutyCycle == 1.0f ? 0 : 1; int pulseCount = (int) ( 2.0f * ( (float) duration / (float) ( hWidth + lWidth ) ) ); long[] pattern = new long[ pulseCount ]; for( int i = 0; i < pulseCount; i++ ) { pattern[i] = intensity < 0.5f ? ( i % 2 == 0 ? hWidth : lWidth ) : ( i % 2 == 0 ? lWidth : hWidth ); } return pattern; } 

Предположим, что общая длительность равна n , а не 20. Ваша функция выполняет две вещи по мере изменения интенсивности i :

  • Во-первых, k(i) , число циклов меняется. Он начинается с k(0) = 1 , пиков при k(0.5) = n/2 , затем падает до k(1) = 1 .
  • Во-вторых, изменяется отношение r(i) времени на / время в каждой паре. Если у нас есть цикл [a, b] , причем a время – время, а b – время, то r(i)*a = b . Следуя вашему примеру, имеем r(0) = 0 , r(0.5) = 1 , тогда асимптота до r(1) = infinity

Существует множество функций, которые могут соответствовать k(i) и r(i) , но давайте придерживаться простых:

 k(i) = (int) (n/2 - (n-2)*|i - 0.5|) r(i) = 1 / (1.000001 - i) - 1 

Где |x| Обозначает абсолютное значение x . Я также заменил 1 на 1.000001 в знаменателе r , чтобы нам не приходилось иметь дело с ошибками с делением на нуль.

Теперь, если циклы должны суммироваться с n , то длина любого одного цикла [a, b] равна n/k(i) . Так как мы также имеем, что r(i)*a = b , то

 a = n/(k*(1+r)) b = r*a 

И для формирования массива для интенсивности i , нам просто нужно повторить [a, b] k раз. Вот пример вывода для n = 20 :

 Intensity: 0.00, Timings: 20.0, 0.0 Intensity: 0.05, Timings: 9.5, 0.5, 9.5, 0.5 Intensity: 0.10, Timings: 6.0, 0.7, 6.0, 0.7, 6.0, 0.7 Intensity: 0.15, Timings: 4.3, 0.7, 4.3, 0.7, 4.3, 0.7, 4.3, 0.7 Intensity: 0.20, Timings: 3.2, 0.8, 3.2, 0.8, 3.2, 0.8, 3.2, 0.8, 3.2, 0.8 Intensity: 0.25, Timings: 2.5, 0.8, 2.5, 0.8, 2.5, 0.8, 2.5, 0.8, 2.5, 0.8, 2.5, 0.8 Intensity: 0.30, Timings: 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9 Intensity: 0.35, Timings: 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9 Intensity: 0.40, Timings: 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9 Intensity: 0.45, Timings: 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9 Intensity: 0.50, Timings: 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 Intensity: 0.55, Timings: 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1, 0.9, 1.1 Intensity: 0.60, Timings: 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3, 0.9, 1.3 Intensity: 0.65, Timings: 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6, 0.9, 1.6 Intensity: 0.70, Timings: 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0, 0.9, 2.0 Intensity: 0.75, Timings: 0.8, 2.5, 0.8, 2.5, 0.8, 2.5, 0.8, 2.5, 0.8, 2.5, 0.8, 2.5 Intensity: 0.80, Timings: 0.8, 3.2, 0.8, 3.2, 0.8, 3.2, 0.8, 3.2, 0.8, 3.2 Intensity: 0.85, Timings: 0.8, 4.2, 0.8, 4.2, 0.8, 4.2, 0.8, 4.2 Intensity: 0.90, Timings: 0.7, 6.0, 0.7, 6.0, 0.7, 6.0 Intensity: 0.95, Timings: 0.5, 9.5, 0.5, 9.5 Intensity: 1.00, Timings: 0.0, 20.0 

И вот сводный код:

  public void Test() { foreach (var intensity in Enumerable.Range(0, 20 + 1).Select(i => i/20f)) { var cycle = new List<float> {a(intensity), b(intensity)}; var timings = Enumerable.Repeat(cycle, k(intensity)).SelectMany(timing => timing).ToArray(); SDebug.WriteLine( String.Format("Intensity: {0,2:N2}, Timings: ", intensity) + String.Join(", ", timings.Select(timing => String.Format("{0,2:N1}", timing)))); } } private static float r(float i) { return 1f/(1.000001f - i) - 1f; } private static int k(float i) { return Mathf.CeilToInt(10 - 18*Mathf.Abs(i - 0.5f)); } private static float a(float i) { return 20/(k(i)*(1 + r(i))); } private static float b(float i) { return r(i)*a(i); } 

Лучшее, что можно сделать здесь, это беспорядок с функцией r(i) . Если вы можете хотя, сначала расслабьте первый и последний тайминги, чтобы быть [n, 1] и [1, n] , что избавит вас от необходимости беспокоиться об асимптотах.

Три мысли:

  1. Это своего рода PWM . По мере увеличения интенсивности «off» становится меньше, а «on» становится больше.

  2. Это похоже на форму сглаживания, как Упорядоченный Дитер . Но вместо 2D это всего лишь 1D.

  3. Это также похоже на цифровой дифференциальный анализатор или линейный алгоритм Брешенема .

Некоторая комбинация этих идей должна решить проблему.