简体   繁体   English

在Android中生成强度不等的振动模式的算法?

[英]Algorithm for generating vibration patterns ranging in intensity in Android?

I am attempting to programmatically generate Android vibration patterns with 'micro pulses' on and off to control how strong the vibration feels to the end user. 我试图以编程方式生成Android振动模式,打开和关闭“微脉冲”,以控制振动对最终用户的强度。 This is the solution I've seen recommended in a few similar topics, to the problem of the API not providing an interface for controlling the vibration strength (because of how the hardware functions, as I understand it). 这是我在一些类似主题中推荐的解决方案,即API没有提供控制振动强度的接口的问题(因为硬件的功能如我所知)。

The algorithm for generating these patterns, however, seems to only be hinted at, but no actual algorithm posted. 然而,用于生成这些模式的算法似乎只是暗示,但没有发布实际的算法。

What I would like to do is, given an input intensity between 0.0f and 1.0f, generate an array following a pattern something like this: 我想要做的是,如果输入强度介于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]

Any help with writing such an algorithm (or suggestions for a better strategy to meet the same goal)? 编写这样的算法的任何帮助(或建议更好的策略来实现相同的目标)?

Edit: I've added a bounty of 100 reputation to the mix :) 编辑:我已经添加了100个声望的赏金:)

After looking at the problem for a while, and not being not very mathematically talented, I came up with an overly simplified algorithm (compared to some of the PWM formulas I found after Dithermaster pointed me in that direction). 在看了一会儿这个问题,而不是在数学上不是很有天赋之后,我想出了一个过于简化的算法(与我在Dithermaster指向那个方向后发现的一些PWM公式相比)。 A couple of assumptions I made were first that the short pulse width is always 1, and the long pulse width is an integer between 1 and the vibration duration. 我做的几个假设首先是短脉冲宽度始终为1,而长脉冲宽度是1和振动持续时间之间的整数。 I also assumed the long pulse width is a linear function of the vibration strength. 我还假设长脉冲宽度是振动强度的线性函数。 In particular, the latter assumption is not accurate. 特别是,后一种假设并不准确。 I'm guessing the function should be something more like a decibel calculation ("strength" of vibration is akin to "loudness" of a sound). 我猜这个函数应该更像是分贝计算(振动的“强度”类似于声音的“响度”)。

Posting my simplified solution in case it is useful for anyone else who ends up here. 发布我的简化解决方案,以防其他任何人在这里结束。 This is close enough for the application I am using it for, but I would still like something better. 这对于我正在使用它的应用程序足够接近,但我仍然想要更好的东西。 If anyone posts an alternative answer, I'll test and accept it if it is better. 如果有人发布替代答案,我会测试并接受它,如果它更好。

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

Suppose the total duration is n , rather than 20. Your function does two things as intensity i changes: 假设总持续时间是n ,而不是20.你的函数做了两件事,因为强度i改变了:

  • First, k(i) , the number of cycles changes. 首先, k(i) ,周期数改变。 It starts off with k(0) = 1 , peaks at k(0.5) = n/2 , then drops to k(1) = 1 . 它以k(0) = 1 ,峰值在k(0.5) = n/2 ,然后下降到k(1) = 1
  • Second, the ratio r(i) of time on/time off in each pair changes. 其次,每对中的时间开/关时间的比率r(i)改变。 If we have a cycle [a, b] , with a being the time on and b the time off, then r(i)*a = b . 如果我们有一个周期[a, b] ,其中a是时间, b是时间,那么r(i)*a = b Going by your example, we have r(0) = 0 , r(0.5) = 1 , then an asymptote up to r(1) = infinity 按照你的例子,我们有r(0) = 0r(0.5) = 1 ,然后渐近r(1) = infinity的渐近线

There are a lot of functions that could match k(i) and r(i) , but let's stick with simple ones: 有很多函数可以匹配k(i)r(i) ,但让我们坚持使用简单的函数:

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

where |x| 其中|x| denotes the absolute value of x . 表示x的绝对值。 I've also substituted 1 for 1.000001 in r 's denominator so that we won't have to deal with divide-by-zero errors. 我还在r的分母中用1代替1.000001 ,这样我们就不必处​​理被零除错误。

Now if the cycles need to sum to n , then the length of any one cycle [a, b] is n/k(i) . 现在,如果周期需要求和为n ,则任何一个周期[a, b]的长度为n/k(i) Since we also have that r(i)*a = b , it follows that 既然我们也有r(i)*a = b ,那么就是这样

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

and to form the array for intensity i , we just have to repeat [a, b] k times. 并且为了形成强度i的数组,我们只需要重复[a, b] k次。 Here's an example of the output for n = 20 : 这是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

And here's the shoddy code: 这是伪劣的代码:

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

The best thing to do from here is mess with the function r(i) . 从这里做的最好的事情就是功能r(i) If you can though, first relax the first and last timings to be [n, 1] and [1, n] , which'll save you from having to bother with asymptotes. 如果可以的话,首先要放松第一个和最后一个时间为[n, 1][1, n] ,这样可以避免使用渐近线。

Three thoughts: 三个想法:

  1. This is a kind of PWM . 这是一种PWM As intensity rises, "off" gets smaller and "on" gets larger. 随着强度上升,“关闭”变小,“开”变大。

  2. This seems like a form of dithering, like an Ordered Dither . 这似乎是一种抖动,就像有序抖动一样 But instead of an 2D, it's just 1D. 但不是2D,而只是1D。

  3. This also seems something like a Digital Differential Analyzer or Bresenham's line algorithm . 这看起来像是数字差分分析仪或Bresenham的线算法

Some combination of these ideas should solve the problem. 这些想法的某些组合应该可以解决问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM