在設(shè)計單片機程序的過程中,經(jīng)常需要利用ADC采集外界模擬信號。有一些信號我們比較關(guān)注它的直流與低頻分量,希望將高頻噪聲濾除,就需要借助低通濾波器。
低通濾波器常見的利用電子電路實現(xiàn)的方式是一階RC無源濾波器。簡單講就是這樣:
RC濾波器的各類計算略,有需要請谷歌。
RC濾波器用于單片機ADC輸入有許多缺點。如果R的取值較小,就要求C較大,同時輸入信號阻抗不能過大;如果R的取值較大,則ADC采樣瞬間釋放的電荷會使得端口電壓升高而無法在采樣時間內(nèi)釋放到穩(wěn)定水平。這會導(dǎo)致采樣精度問題。
而即便使用一個運放來緩沖RC濾波器的輸出,再接入ADC,也只解決了輸入阻抗問題,ADC電路受外界干擾仍然會在轉(zhuǎn)換結(jié)果中產(chǎn)生噪聲。因此,我們希望在單片機內(nèi)部利用程序來實現(xiàn)低通濾波,徹底擺脫高頻噪聲。
數(shù)字低通濾波器有兩種形式,IIR和FIR。
IIR是無限脈沖響應(yīng)濾波器,它的特點是輸出與無限久以前的輸入有關(guān)。這就如同上面RC濾波器的響應(yīng),隨著時間流逝,輸出電壓只會無限接近于輸入電壓,而不會等于。
用c語言實現(xiàn)IIR低通很簡單:
int last = 0;
//下面的函數(shù)以固定頻率運行,函數(shù)輸出就是IIR低通濾波器的輸出。
int lowpass(){
int this = ADC();
last = (this * 1 + last * 15) / 16; //新的last 是舊的last * 15 / 16 + this * 1 / 16
return last;
}
如果對函數(shù)返回值作圖,得到的波形就會和RC濾波器的波形一樣。要改變截止頻率,只需要改變函數(shù)第二句中新的last的組成(例如改成3/4和1/4,截止頻率會提高)。
值得注意的是,上述代碼使用了整數(shù)乘法和2的n次冪除法,因此編譯優(yōu)化后,在8位平臺上運行超快。如果你使用帶有浮點運算模塊的平臺,請直接使用浮點數(shù)。
IIR的特點是節(jié)省內(nèi)存,上面的濾波器只使用了兩個變量。
IIR的缺點是不穩(wěn)定。如果你把15改成17,顯然這個濾波器的輸出會在一段時間后溢出。你必須負(fù)責(zé)保證IIR濾波器穩(wěn)定。
FIR是有限脈沖響應(yīng)濾波器,它的特點是輸出與有限久以前(一段時間內(nèi))的輸入有關(guān)。由于數(shù)字系統(tǒng)中采樣是離散的,每一段時間內(nèi)的采樣數(shù)是固定的,所以FIR濾波器的每一個輸出值,可通過對之前的若干個數(shù)量固定的采樣值進行計算得到。特別是,因為對固定數(shù)量的采樣值的計算在FPGA電路中可以并行實現(xiàn),因此FIR濾波器常常被用于基于FPGA的數(shù)字信號處理系統(tǒng)。相對的,IIR濾波器不依賴之前的采樣,但依賴于之前的濾波器狀態(tài)(存在反饋),因此在大部分比一階低通濾波器復(fù)雜的應(yīng)用場合,IIR濾波器的各項特性沒有FIR穩(wěn)定(若要實現(xiàn)穩(wěn)定,對計算精度要求較高),而且計算起來比FIR要慢,設(shè)計上也沒有通用性。
下面我用c語言實現(xiàn)一個最簡單的FIR低通。我們將最近的8次采樣值加起來,求平均值,作為輸出。
int buf[8];int lowpass()
{
int k = 7;
while(k--)
buf[k] = buf[k-1]; //將buf[6] 移到buf[7], buf[5] 移到buf[6],等等,以空出buf[0]
}
buf[0] = ADC();
return (buf[0] + buf[1] +...+ buf[7]) / 8;
}
這個濾波器的時域圖像有點像這樣:
值得注意的是,上面這個函數(shù)可以被進一步簡化,以加速計算。上面這種濾波器有另一個名字:滑動平均濾波器,這個濾波器大部分股民應(yīng)該很熟悉。
雖然時域圖像很美觀,但是這個濾波器的頻域圖像一點也不美觀:
可見,隨著點數(shù)的增加,圖像看起來只是從右向左縮水,對高頻的抑制并不好。
所以如果想要獲得比較好的低通效果,不應(yīng)該增加點數(shù),而應(yīng)該將多個一樣的FIR濾波器串聯(lián)使用(一個的輸出作為下一個的輸入)。
注:pass是“遍”的意思,表示迭代次數(shù)。
上面是串聯(lián)使用的幅頻響應(yīng)。而時域圖像也很美觀:
結(jié)尾給出的是寫這篇文章時隨手找到的資料。大家一定要學(xué)會使用谷歌搜索英文關(guān)鍵詞,因為老外比我們對待知識的態(tài)度更嚴(yán)肅也更開放。
http://www.analog.com/media/en/technical-documentation/dsp-book/dsp_book_Ch15.pdf
剛才的滑動平均濾波器,時間復(fù)雜度是O(n)(設(shè)每次處理n個采樣)。
可以優(yōu)化為O(1)的形式:
int buf[8];int k=0;
int result=0;
int lowpass()
{
result -= buf[k];
buf[k] = ADC();
result += buf[k];
k = (k + 1) % 8;
return result;
}