Proper way to call designfilt for filtfilt

9 ビュー (過去 30 日間)
Bruno Luong
Bruno Luong 2023 年 10 月 24 日
コメント済み: Paul 2023 年 11 月 12 日
The command designfit is used to design a filter with user high level specification of the response funtion. The result of designfilter can be applied on a signal by using filter function.
In my caseI want to apply with zero-phase filter filtfilt instead of filter. Howeever this one squares the amplitude response function the the high level specification is not right.
Is there a proper way of compensate for this squaring in a high level? or any existing filter design function suitable for filtfilt?
Right now I use freqz function and adjust manually the parameter until te response curve looks empirically "right". I could do some more precise numerical optimisation to.
Do you kwon a better way?
  5 件のコメント
Mathieu NOE
Mathieu NOE 2023 年 10 月 24 日
編集済み: Mathieu NOE 2023 年 10 月 24 日
hello
why not simply reduce the filter order by a factor 2 when you want to use filtfilt instead of filter ? of course that makes sense only if the filter command is used for even order filters
Bruno Luong
Bruno Luong 2023 年 10 月 25 日
@Star Strider I like the idea, it seems a priori more generic than Paul method, but actually it also applied for FIR and more complicated.

サインインしてコメントする。

採用された回答

Paul
Paul 2023 年 10 月 24 日
編集済み: Paul 2023 年 10 月 25 日
The example above is a low pass, linear phase FIR filter. Maybe a simple delay as is implemented in lowpass is acceptable?
CutoffFrequency = 1500;
facq = 2e5;
Vfilter = designfilt('lowpassfir', 'FilterOrder', ceil(facq/CutoffFrequency), ...
'CutoffFrequency', CutoffFrequency, 'SampleRate', facq);
filter a sine wave
f0 = 2e3;
n = 0:1000;
t = n/facq;
x = sin(2*pi*f0*t);
y1 = filter(Vfilter.Coefficients,1,x);
figure
plot(t,x,t,y1),grid
The amplitude and phase shift are apparent consistent with the frequency response of Vfilter.
Because the linear phase FIR filter has a constant delay, we can zero pad the end of the input by the number of delayed samples, then filter, then delete number of delayed samples from the front of the output.
ndelay = Vfilter.FilterOrder/2;
y2 = filter(Vfilter.Coefficients,1,[x zeros(1,ndelay)]);
y2(1:ndelay) = [];
figure
plot(t,x,t,y2),grid
Same steady "state amplitude" of the output, but no more steady state phase delay. Here "steady state" is referring to the "middle of the response" as the effect of the impulse response of the filter is evident on the first and last cycles of the output.
Use a frequency sweep to show the zero-phase over all frequencies.
x = sweeptone(6,2,facq,SweepFrequencyRange=[100 facq/2]).';
y3 = filter(Vfilter.Coefficients,1,[x zeros(1,ndelay)]);
y3(1:ndelay) = [];
[H,fvec] = tfestimate(x,y3,[],[],[],facq);
figure
subplot(211)
semilogx(1e-3*fvec,db(abs(H)),1e-3*fvec,db(abs(freqz(Vfilter,fvec,facq))));grid
xlim([0.1 100])
subplot(212);
semilogx(1e-3*fvec,180/pi*angle(H),1e-3*fvec,180/pi*angle(freqz(Vfilter,fvec,facq)));grid
xlim([0.1 100])
I'm pretty sure that the blue phase starts getting hairy because of rounding errors accumulating with 134-tap filter and then trying to take the angle of very small complex numbers.
  18 件のコメント
Paul
Paul 2023 年 11 月 11 日
編集済み: Paul 2023 年 11 月 11 日
In the current incarnation of the code (i.e., equivalent to phase_factor = 0), h is mathematically symmetric, so there's no need for the fliplr, i.e., just do h2 = conv(h,h). Also, there might be slight benefit in accuracy by enforicng that symmetry numerically with something like
% k = (numel(h)-1)/2; h = [h(1:k) h(k+1) fliplr(h(1:k))];
Or maybe both sides around the middle should be averaged.
But, more importantly, that definiton of h2 suggests that we should be able to compute h2 directly. Specifically, let V(w) be the DTFT of the impulse response of Vfilter. Then, I think that it should be true that H2(w) = abs(V(w)). Then, the FIR approximation of h2 should be found from the ifft of frequency domain samples of H2(w).
We currently have (with the above-mentioned modifications)
PassbandFrequency = 1000;
FilterOrder = 5;
StopbandAttenuation = 60;
facq = 2e5;
Vfilter = designfilt('lowpassiir', 'FilterOrder', FilterOrder, ...
'PassbandFrequency', PassbandFrequency, ...
'StopbandAttenuation', StopbandAttenuation, ...
'SampleRate', facq);
Vimp = impz(Vfilter);
NVimp = numel(Vimp);
N = 2*NVimp + 1;
wfreq = (0:N-1)/N*2*pi;
Vfreq = freqz(Vfilter,wfreq);
sqrtVimp = fftshift(ifft(sqrt(abs(Vfreq)),'symmetric'));
h = sqrtVimp(:).';
k = (numel(h)-1)/2;
h = [h(1:k) h(k+1) fliplr(h(1:k))];
h2 = conv(h,h); % no fliplr
k = (numel(h2)-1)/2;
h2 = [h2(1:k) h2(k+1) fliplr(h2(1:k))];
nh2 = -2*NVimp:2*NVimp;
The proposed approach would be
N = 4*NVimp + 1;
wfreq = (0:N-1)/N*2*pi;
Vfreq = freqz(Vfilter,wfreq);
h2new = fftshift(ifft((abs(Vfreq)),'symmetric')); % no sqrt
h2new = [h2new(1:k) h2new(k+1) fliplr(h2new(1:k))];
At first glance h2 and h2new look the same
figure
plot(nh2,h2,nh2,h2new)
But they are different enough to give some cause for concern
figure
plot(nh2,h2-h2new)
I don't know if that large of a difference is due to 1) an error in my math, 2) the effect of different assumptions in arriving at h2 vs. h2new, or 3) numerical errors that build up differently between the two methods.
My gut feeling is that (2) is the issue and h2new is the better approach because it starts from the fundamental definition of H2(w) and then makes the FIR approximation, whereas h2 starts from sqrt(H2(w)), makes the FIR approximation, and then exacerbates that approximation by conv(h,h). But that's just my feeling.
If one has a LOT of time on one's hands, I suppose both approaches could be implemented using Symbolic Math Toolbox and see if they really are the same and (3) is the issue. I'm not sure this is a serious suggestion.
I did verify that using h2new does yield very clean mag and phase plots of Y2./X.
Paul
Paul 2023 年 11 月 12 日
Just to tie this off (I hope). I wish I had thought about this problem some more before answering, but having gone through this process the whole situation is much more clear to me.
Let h[n] be a discrete-time signal and H(w) be its DTFT. If h[n] is real and even-symmetric then so will be H(w).
In the FIR example, the Vfilter is a Type-1 filter, which has an even order N, and so its impulse response, v[n], is symmetric around N/2. Let h[n] = v[n+N/2], i.e., h[n] is v[n] shifted to the left by N/2. Then we'll have abs(H(w)) = abs(V(w)) (because time shifts don't affect magnitude of the DTFT) and angle(H(w)) = 0 (due to even symmetry of h[n]). Therefore filtering with h[n] yields the desired zero-phase response, which is basically what we did by using filter with v[n] and shifting the output to the left by N/2 (and zero-padding the input sequence to filter to make sure we collected all of the non-zero filtered output). However, this approach won't work for Type 2-4 FIR filters, because of odd order and/or v[n] not having the desired symmetry. However, for Type 2-4 FIR filters, I'm pretty sure we could use the same approach as for the general IIR case to get a very reasonable result.
For the IIR example, as hopefully is clear from the answer above with h2new, which I'll now call h[n] for simplicity, we're doing the exact same thing. We are defining H(w) = abs(V(w)), and then "finding" the corresponding, real, even-symmetric h[n] for filtering. I say "finding" because we are assuming that h[n] can be adequately represented as a finite duration signal, even though it may actually be infinite duration.

サインインしてコメントする。

その他の回答 (0 件)

カテゴリ

Help Center および File ExchangeFilter Analysis についてさらに検索

製品


リリース

R2023b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by