我正在尝试编写一个程序来平滑一些传感器数据。
传感器提供 0 到 100 的阈值输入。它通常在 2 个单位左右的范围内准确,但读数之间存在跳跃性。
我每秒获得多次输入,并希望从这些数据中创建动态平均值,而不是那么跳跃。
如何以一种可以在界面上显示平滑移动数字、更准确的数字(与读数实时保持一致)的方式对最近的输入进行平均?
谢谢你的帮助。
根据您的数据,您可以通过计算平均值来调整测量值。
使用一定数量的先前结果
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 N-i其中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
设置为惰性、正常或急切。
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
可以看到,经过 5 次迭代,惰性计算仍然没有达到,可能还需要 3 次。6
正常值几乎不容易出错(14.5 刚刚四舍五入),但几乎可以立即跟随趋势。
急切的人急切地遵循这些措施,只是稍微缓和了曲线。它甚至无法检测到 15-14-15 错误读取。
上述系列的最佳价值将是0.4
-0.45
我认为。值得尝试使用真实测量数据的样本来查看参数值的行为。
实际上我最喜欢的是浮动平均算法,它很容易实现并且给出了很好的结果(如果参数化得好)。
免责声明:这将导致非常平滑的结果 - 即使值在此期间上升和下降很多,这可能只是显示一条直线。这将显示平均值随时间的变化。如果这不是我们想要的,那么这个答案可能不是您想要的。
假设我们对最后一个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
。