我正在尝试编写一个程序来平滑一些传感器数据。
传感器提供0到100的阈值输入。它通常精确到2个单位左右,但是读数很快。
我每秒都会多次输入,并希望从这些数据创建动态平均值,而不是那么跳跃。
如何以一种能够获得平滑移动数字,更准确数字(与读数实时保持一致)的方式来平均最近的输入,以便在界面上显示?
感谢您的帮助。
答案 0 :(得分:3)
根据您的数据,您可以通过计算平均值来平衡测量值。
使用一定数量的先前结果
int values[BUFLEN];
value = // your new raw measured value
index = index++ % BUFLEN;
values[index] = value;
avg = 0;
for(int i=0; i<BUFLEN; i++) {
avg = avg + values[i] / BUFLEN; // evenly weighted
}
如果您愿意,也可以使用不均匀的重量。此外,如果您使用相同的权重,则可以优化此循环。
使用浮动平均值
avg = (avg * 0.9) + (value * 0.1) // slow response
avg = (avg * 0.5) + (value * 0.5) // fast response
float q = // new ratio
avg = (avg * (1.0 - q)) + (value * q) // general solution
浮动平均值(数学上)是所有元素的加权和,其中权重为q Ni 其中N
是总测量值,i
是运行元素的索引。所有元素都涉及平均值,而不仅仅是有限数量的元素。
您可以查看错误措施的频率,与平均值的距离是多少,您希望您的(计算)措施遵循实际流程的响应等等。
另外,如果你有离散值(整数),你必须小心使用舍入的东西。我建议以浮点进行所有计算,然后将结果舍入到最接近的整数。但是将计算出的平均值存储在下一轮的浮点数中。
<强>更新强>
同时反映您关于最新和准确的问题:
问题是我们不确定最新数据是显示趋势还是错误阅读的结果。我会告诉你一个例子:
SEQ1: 15 15 14 15 15 [10] 6 6 5 6 6
SEQ2: 15 15 14 15 15 [10] 20 15 14 15 15
那么,[10]
在每个序列中意味着什么:在第一个序列中,它代表一个严肃的运动,一个趋势。在第二个中,这只是一个误读。但是当你刚读完[10]
时,你不知道下一个是什么。因此,您必须延迟该读取的效果。因此,它不会最新。
同样,您使用的是平均值,即计算值。所以,它不会准确。
平衡情况。值越新,准确性越低(误读的次数越多)。数据越准确,延迟就越大。根据数据系列,您必须明智地选择它。
我使用第二种(浮动平均)算法为您计算了三种情景。 q
的值设置为 lazy , normal 或 eager 。
SEQ1: 15 15 14 15 15 10 6 6 5 6 6
// q=0.25, "lazy"
Avg 15.00 15.00 14.75 14.81 14.86 13.64 11.73 10.30 8.98 8.23 7.67
Rounded 15 15 15 15 15 14 12 10 9 8 7
// q=0.5, "normal"
Avg 15.00 15.00 14.50 14.75 14.88 12.44 9.22 7.61 6.30 6.15 6.08
Rounded 15 15 15 15 15 12 9 7 6 6 6
// q=0.75, "eager"
Avg 15.00 15.00 14.25 14.81 14.95 11.23 7.31 6.33 5.33 5.83 5.96
Rounded 15 15 14 15 15 11 7 6 5 5 6
您可以看到 lazy 计算在5次迭代后仍未达到6
,可能还需要3次。
正常几乎不容易出错,(14.5只是四舍五入),但几乎可以立即跟随趋势。
渴望热切地关注这些措施,只是略微缓解了曲线。它甚至无法检测出15-14-15错误的读数。
上述系列的最佳价值大约是0.4
- 0.45
我认为。有必要使用您的实际测量数据的样本来查看什么是参数值的行为。
实际上我最喜欢的是浮动平均值算法,它很容易实现并且效果很好(如果参数化得好)。
答案 1 :(得分:1)
免责声明:这将导致非常平稳的结果 - 即使在此期间价值上下波动,这可能只是显示一条直线。这将显示平均随时间的变化。如果不希望这样,这个答案可能不是你想要的。
假设我们对最后k
个输入值进行平均。
首先要注意的是:
Average at time i = (value[i] + value[i-1] + ... + value[i-k+1]) / k
= value[i]/k + value[i-1]/k + ... + value[i-k+1]/k
and
Average at time i-1 = value[i-1]/k + value[i-2]/k + ... + value[i-k+2]/k
thus, cancelling out common terms...
Average at time i = Average at time i-1 + value[i]/k - value[i-k+2]/k
并且,为了避免潜在的舍入问题,请将k
除以此值 - 只要在得到平均值时执行此操作(这样做不会使数学无效)。
所以,关于算法:
k
的圆形数组。将此数组中的所有值初始化为0。average = newValue - overriddenValue
k
,则增加计数。