實時零相位濾波的神話(1)
做控制的人大概都夢想做到輸出和輸入訊號保持完全同步,相移為0。如果能做到,那該多酷。
MATLAB有個神奇的函式filtfilt,可以對資料做離線的濾波,實現零相移。原理就是先做一個方向的濾波,比如先forward 濾波,然後把濾波後的序列逆序,再用同一個濾波器做backward濾波,濾波得到的序列最後再逆序,得到最終結果。嘗試了一下,濾波效果那真是賞心悅目。可惜,不能實現線上訊號的實時零相移濾波。怎麼做呢?焦慮之際,在百度上搜到這個文章:http://blog.csdn.net/shenziheng1/article/details/53415642,作者的手段讓我萬分佩服:既然相移導致的group delay不為0,那咱就設計個group delay與其完全相反的全通濾波器,二者級聯,groupdelay兩兩相消,不就搞定了嗎?多麼完美!!
感謝這位博主,在相關文章裡把程式碼給的相當完整,某些略去的地方其實比較容易補全。按照這個思路做下去,確實得到了相移接近0 的結果,圖片如下:
但是當我興沖沖地把low pass 和all pass級聯進行濾波,得到了讓人鬱悶的玩意:濾波結果是震盪的,資料越來越大。。。。痛苦地找了好久,某篇英文文章說,級聯allpass濾波器,只能增大相移,尤其是在將iir整成線性相位濾波器時的典型應用時,group delay在通帶內雖然可以保持恆定,但只能讓group delay變大,即輸出結果比輸入delay更多個samples。這個震盪,應該是all pass的零極點與單位圓的關係導致系統不穩定造成的。
iir+all pass常用來進行相位均衡,這個均衡並不是要做到零相位,而是使得通帶內的訊號保持固定的group delay。下面是從某個大學課件上搞來的iir+all pass的程式碼,講解了相位均衡的常規應用:
t = 0:0.001:1; w = pi*t; % normalized frequencies alpha = 0.5; % LPF parameter blp = (1-alpha)/2*[1 1]; % numerator coefficients alp = [1 -alpha]; % denominator coefficients hlp = freqz(blp,alp,w); % compute DTFT glp = grpdelay(blp,alp,w); % compute group delay N = 4; % all-pass filter order F = w(1:501)/pi; % normalized frequencies edges = [0 1/2]; % band-edge frequencies Gd = max(glp)-glp(1:501); % desired group-delays of APF (>0) [bap,aap] = iirgrpdelay(N,F,edges,Gd); % make all-pass filter hap = freqz(bap,aap,w); % compute DTFT gap = grpdelay(bap,aap,w); % compute group-delay b = conv(blp,bap); % product of numerators a = conv(alp,aap); % product of denominators h = freqz(b,a,w); % compute DTFT g = grpdelay(b,a,w); % compute group delay subplot(3,1,1) plot(w,abs(h)); ylabel('magnitude response'); subplot(3,1,2); plot(w,unwrap(angle(h))); ylabel('phase response (rad)'); subplot(3,1,3); plot(w,g); xlabel('normalized freq (rad/sample)'); ylabel('group delay (samples)');
已經確定了,all pass 級聯不能讓group delay 變成0,反而是更大。於是,我的第一次充滿勇氣的尋找零相位實時濾波器行動宣告破產。