降低信号数据噪声的算法?

时间:2013-10-16 13:05:30

标签: algorithm average sensor

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

传感器提供0到100的阈值输入。它通常精确到2个单位左右,但是读数很快。

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

如何以一种能够获得平滑移动数字,更准确数字(与读数实时保持一致)的方式来平均最近的输入,以便在界面上显示?

感谢您的帮助。

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。
  • 保留已填充元素数量的计数(初始化为0)。
  • 每当您插入此缓冲区时,请按如下方式更新平均值:
    average = newValue - overriddenValue
    如果小于k,则增加计数。
  • 获取显示平均值时,只需将其除以计数。