1

我正在尝试编写一个程序来平滑一些传感器数据。

传感器提供 0 到 100 的阈值输入。它通常在 2 个单位左右的范围内准确,但读数之间存在跳跃性。

我每秒获得多次输入,并希望从这些数据中创建动态平均值,而不是那么跳跃。

如何以一种可以在界面上显示平滑移动数字、更准确的数字(与读数实时保持一致)的方式对最近的输入进行平均?

谢谢你的帮助。

4

2 回答 2

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 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我认为。值得尝试使用真实测量数据的样本来查看参数值的行为。

实际上我最喜欢的是浮动平均算法,它很容易实现并且给出了很好的结果(如果参数化得好)。

于 2013-10-16T13:22:17.220 回答
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。
  • 记录填充元素的数量(初始化为 0)。
  • 每当您插入此缓冲区时,按如下方式更新平均值:
    average = newValue - overriddenValue
    如果小于 ,则增加计数k
  • 在获取平均值以进行显示时,只需将其除以计数即可。
于 2013-10-16T13:43:04.657 回答