2013-10-16 48 views
1

我想寫一個程序,平滑了一些傳感器數據。用於減少信號數據噪聲的算法?

該傳感器提供了一個閾值輸入0到100.它通常在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是元素的運行索引。所有元素都涉及到平均數,而不僅僅是有限數量的元素。

您可以檢查什麼是錯誤的措施的頻率,什麼是平均值的距離,你希望你的(計算值)的措施,遵循真實進程等

什麼反應此外,如果你有離散值(整數),你必須小心使用四捨五入的東西。我建議以浮點進行所有計算,然後將結果四捨五入爲最接近的整數。但將計算出的平均值存儲在下一輪的浮點數中。

更新:

爲了反映關於是你的問題了最新準確在同一時間:

的問題是,我們不知道是否有最新的數據正在顯示出一種傾向或者是錯誤閱讀的結果。我會告訴你一個例子:

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 

你可以看到計算還沒有達到6 5迭代之後,也許3更是必要的。

正常幾乎沒有錯誤傾向,(14.5剛剛四捨五入),但幾乎可以立即跟上趨勢。

渴望熱切地遵循這些措施,只是略微緩解曲線。它甚至無法檢測到15-14-15的錯誤讀取。

對於以上系列的最佳值應該是0.4 - 0.45 - 我認爲。這是值得玩弄你的真實測量數據樣本看什麼是什麼參數值的行爲。

其實我最喜歡的是浮動平均值算法,它很容易實現並且給出了很好的結果(如果參數化的很好)。

+0

謝謝,這是一個很好的方向指針。 BUFLEN =緩衝區長度,還是我想要使用的歷史值的數量? – boom

+0

是的,我添加了定義。 – gaborsch

+0

我推薦的是玩弄一些樣本數據,看看你會得到什麼算法和什麼參數(BUFLEN,q)。 – gaborsch

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
  • 當獲得顯示平均值時,只需將其除以計數即可。