指數滑動濾波器
- 作用
- 原理
- 特點
- 公式
- 代碼
- 優化升級
作用
首先這個濾波器能夠將一些突變的信號對系統的影響降低,能夠平滑輸入信號,濾除噪聲,減少測量數據的瞬間波動和干擾,就是實現輸入信號不能不變,數值不會突然變大,比如你根據編碼器的值控制呼吸燈的亮度,如果編碼器突然拉的值很大,呼吸燈不會立刻變得很亮,會慢慢亮。
原理
原理就是不完全采樣當前的輸入信號,而是將輸入信號的值和上一刻濾波后的輸入信號做一個權重劃分,然后得到最終濾波后的信號值,比如前一刻濾波后是10V,當前采樣的電壓是5V,假如設置前一刻的權重是90%,當前采樣的信號權重是10%,則將100.9+50.1 = 9.5V,這就是濾波后的結果,不會說因為10V掉到5V,我對應的輸出也立刻改變,而是先按照9.5V對應輸出,如果后面保持5V,那么根據權重劃分輸出信號也會慢慢降低的,只是響應沒那么快。
特點
特點就是響應沒那么快,但是輸出信號會平滑,所以這個權重的設定也非常的重要,如果歷史值(也就是上一刻的濾波結果)占的權重比較大,就會導致響應非常的緩慢,如果歷史值的權重比較小,就會導致信號平滑的效果不是那么好。
所以需要注意系統剛開始運行的時候,輸出信號也是要緩慢變化才能達到目標值,這是因為系統第一次濾波時上一刻的濾波結果為0,如果想要在系統剛開始運行時就達到目標值附近在開始濾波,可以在進行第一次濾波時給上一刻濾波結果賦當前輸入值,讓系統更快速達到目標值附件。
公式
y[n]=a×x[n]+(1?a)×y[n?1]y[n] = a \times x[n] + (1 - a) \times y[n-1]y[n]=a×x[n]+(1?a)×y[n?1]
- x[n] 是最新的測量值
- y[n] 是濾波后的輸出值
- a 是濾波器“記憶權重”,越小說明當前輸入影響越小,濾波越平滑(但響應慢)
代碼
下面給出一段Python的案例代碼:
import numpy as npdef exponential_filter(input_signal, a):"""單一輸入信號的指數滑動濾波:param input_signal: 輸入信號列表:param a: 濾波系數(本次輸入權重),0 < a < 1:return: 濾波后的輸出信號列表"""output_signal = [input_signal[0]] # 以第一個輸入作為初始濾波值for n in range(1, len(input_signal)):y_prev = output_signal[-1]x_curr = input_signal[n]y_curr = a * x_curr + (1 - a) * y_prevoutput_signal.append(y_curr)return output_signal# 模擬你的濾波系數
a_vdc = 1 / 16 # vdc權重# 示例輸入信號,替換成你的采樣數據
np.random.seed(0)
input_vdc = 17 + 2 * np.random.randn(100) # 模擬帶噪聲電壓信號filtered_vdc = exponential_filter(input_vdc, a_vdc)# 輸出前10個濾波值查看
for i in range(10):print(f"原始vdc: {input_vdc[i]:.3f}, 濾波vdc: {filtered_vdc[i]:.3f}")
結果如下:
原始vdc: 20.528, 濾波vdc: 20.528
原始vdc: 17.800, 濾波vdc: 20.358
原始vdc: 18.957, 濾波vdc: 20.270
原始vdc: 21.482, 濾波vdc: 20.346
原始vdc: 20.735, 濾波vdc: 20.370
原始vdc: 15.045, 濾波vdc: 20.037
原始vdc: 18.900, 濾波vdc: 19.966
原始vdc: 16.697, 濾波vdc: 19.762
原始vdc: 16.794, 濾波vdc: 19.576
原始vdc: 17.821, 濾波vdc: 19.467
這里可以看出濾波后的值并不會由于原始vdc的值的變化而發生比較大的突變,接下來給出在單片機中C語言的實現代碼:
u16 DataFilter(u16 dat) {static u16 s_u16LastDat; // 記錄歷史值float a = 0.9; // 歷史值權重u16 result;// 進行指數濾波計算result = a * s_u16LastDat + (1 - a) * dat;// 記錄當前濾波結果用于下次計算s_u16LastDat = result;return result;
}
優化升級
雖然這樣寫可以,但是可以考慮一下單片機的性能問題,對單片機來說浮點運算是非常耗時的,因為有些單片機沒有浮點單元(大部分都沒有把),所以接下來對這段代碼進行優化升級:
u16 DataFilter(u16 dat) {static u16 s_u16LastDat; // 記錄歷史值u16 result;// 進行指數濾波計算,歷史權重比為0.9375result = (dat >> 4) + ((s_u16LastDat * 15) >> 4);// 記錄當前濾波結果用于下次計算s_u16LastDat = result;return result;
}
通過右移的方式,把乘除運算變成位移能夠大幅提高運算速度,這里是如何設置權重的呢,>>4相當于?16,所以系數a = 1/16 = 0.0625,而*15>>4相當于?15在?16,系數a=15/16 = 0.9375;最終的權重和還是為1的,只是將權重剛好設置成2的倍數,就能夠通過位移完成計算。
最后需要提醒一下這個權重系數的設置關系整個系統的性能,需要根據實際情況選擇合適的權重比。