循环的角度求均值

来源:互联网 发布:java edittext获取值 编辑:程序博客网 时间:2024/04/23 14:45

为什么会讨论到这么简单的问题?

举几个例子,角度范围为0~360度,0度和360度是重合的,不妨先算法下面角度的均值,

[10, 30] = 20 结果正确

[20, 100] = 60 结果正确

[160, 200]= 180 结果正确

[0, 360] = 180 因为360度和0度重合,这个结果貌似不是我们想要的,结果360度才合理

[20, 300] = 160 要能求得均值为340度就好了

不知看出什么问题没有——角度求均值不再是简单的算术均值!

修正的0~360度求均值方案

从上面的结果也可以知道,有些情况下角度均值就是算术平均值,那什么情况下不是求算术平均值呢?

1

如上图,当α<β时,当β-α > 180时,(α+β)/2不再是要求的结果;同理,α<β时,α-β > 180时不再是求算术平均值。

综合这两种情况,当|α-β|>180情况下不是求算术平均值。这种情况下期望的角度均值为(以α小于β为例):

同理,因为上面的表达式中的α与β对称,所以α大于β计算的结果也一样。因此可知,非算术平均值的情况只要在算术平均值的基础上加180就可以了,因此归纳如下:

上面仅是两个角度值的平均,通过两个角度的差值做判别条件确定是否是算术均值,然而,多个的呢?

多个的角度均值显得有些复杂,这需要用户对输入输出角度范围提供约束,这里不妨将命题变成:考虑到相邻角度在时间上的相关性,设相邻的两个输入角度值偏移值不会大于180度,在这种情况下,只要考虑0~360度的突变情况就可以了。

直接看matlab程序吧(参考资料2),

function [avg] = avg_degree(angles)% 计算角度平均值,注意0-360度情况last = angles(1);sum = angles(1);for i=2:length(angles)    diff = mod(angles(i)-angles(i-1)+180,360)-180;    last = last + diff;    sum = sum + last;endavg = mod(sum/length(angles), 360);end

给个自己使用的C程序也有,只不过求模用条件运算替换了,

#define ANGLE_DIFF(diff, x2, x1) \do {  \    diff = x2-x1+180; \    if (diff < 0) {  \        diff = diff + 360 - 180;  \    } else if (diff > 360) {  \        diff = diff - 360 - 180;  \    } else {  \        diff = diff - 180;  \    }  \} while(0)float angle_avg(float *angle, uint32_t n){    float diff = 0;    float last = angle[0];    float sum  = angle[0];    uint32_t i = 0;    for (i=1; i<n; i++) {        /* diff = mod(angle[i]-angle[i-1]+180,360)-180 */        ANGLE_DIFF(diff, angle[i], angle[i-1]);        last += diff;        sum  += last;    }     return sum/n;}

其中的DIFF宏定义用于计算两个角度差值。

文献综述

维基百科角度出现循环的变量为圆周量,如上面的角度值、一天的24小时等。

Wikipedia中计算平均角度的方法:

参考文献1中给出了关于圆周变量更细致的数学分析与描述,是一份难得的资料,参考文献2是StackOverflow上关于圆周角度的探讨,作为对该问题的理解很有帮助。

参考

  1. CodeProject: Circular Values Math and Statistics with C++11
  2. Stackoverflow: How do you calculate the average of a set of angles?
  3. Wikipedia
1 0
原创粉丝点击