Why my own direct form II filter function performs different with the Matlab function 'filter'

53 次查看(过去 30 天)
I'm trying to write my own sequential filter function and here is my code
function [yn,w_buff] = Sequential_filter(b,a,xn,w_buff)
% Input:
% b : 1*(N+1) vector that contains the numerator coefficients for a N-order
% filter.
% a : 1*(N+1) vector that contains the denominator coefficients for the
% N-order filter, where a(1) is assumed to be 1.
% xn : The input data for the nth sample, which is supposed to be a scalar
% w_buff: (N+1)*1 vector that contains the buff data.
% Output:
% yn : The filtered data for the nth sample.
% w_buff: (N+1)*1 vector that returns the updated buff data.
% The transfer function of system is
% H[z] = \frac{ \sum_{k=0}^{N} b_{k} z^{-k} }{ \sum_{k=0}^{N} a_{k}z^{-k} }
% and it can be divided into two subsystems as
% H_{1}[z] = \sum_{k=0}^{N} b_{k} z^{-k}
% H_{2}[z] = \frac{ 1 }{ \sum_{k=0}^{N} a_{k} z^{-k} }
% Then the signal flow graph is
% x[n] --> H_{2} --> w[n] --> H_{1} --> y[n]
w_buff = circshift(w_buff,1,1);
wn = xn - a(1,2:end)*w_buff(2:end,1);
w_buff(1,1) = wn;
yn = b*w_buff;
end
Then I test my sequential filter function and compared it with the Matlab function filter as follows
[b,a] = sos2tf(SOS,G);
y_out1 = filter(b,a,x_in);
w_buff = zeros(N+1,1);
y_out2 = zeros(length(x_in),1);
for n = 1:length(x_in)
[y_out2(n,1),w_buff] = Sequential_filter(b,a,x_in(n,1),w_buff)
end
Err = y_out1 - y_out2;
But the performance is significant different with the Matlab function filter, especially for some filters which holds the very close together poles. Why this happened? Is there any logic bug in my program? Or Matlab has optimized filter function to reduce the cumulative error?
I sincerely look forward to your instruction and thank you very very much.

采纳的回答

Shivam Gothi
Shivam Gothi 2024-9-20,5:30
编辑:Shivam Gothi 2024-9-20,5:34
Hello @Wentong
The logic used by you is perfectly correct and works well.
Cause of issue:
I tried to use your function on a third order Butterworth filter (refer : https://www.mathworks.com/help/signal/ref/sos2tf.html#mw_001efa27-2134-4877-99e0-b15c426487c0)
whose 3db frequency is 0.25 Hz. The [b,a] coefficients of the filter were evaluated as shown in the below code:
I obtained the following outputs.
It is seen that your filter is becoming unstable.
SOLUTION:
Please note that in the transfer function of a Butterworth filter the coefficient ( a(1) ) is not equal to 1. However, the user-defined function "Sequential_filter" that you provided requires ( a(1) = 1 ) to comply with the "direct form 2" syntax. Therefore, it is necessary to normalize the coefficients ([b, a]) so that ( a(1) = 1 ), as demonstrated below:
This resolves the issue you are facing.
I am attaching the code below:
sos = [2 4 2 6 0 2;3 3 0 6 0 0];
[b,a] = sos2tf(sos,1)
b = 1×4
6 18 18 6
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
a = 1×4
36 0 12 0
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
x_in=sin(2*pi*0.25*(0:0.001:4));
N=3;
y_out1 = filter(b,a,x_in);
w_buff = zeros(N+1,1);
y_out2 = zeros(1,length(x_in));
for n = 1:length(x_in)
[y_out2(n),w_buff] = Sequential_filter(b,a,x_in(n),w_buff);
end
%%%%% PLOT THE ERROR BETWEEN TWO FUNCTIONS %%%%%%%%%%%%%%%%%%
plot(y_out2-y_out1);
function [yn,w_buff] = Sequential_filter(b,a,xn,w_buff)
% Input:
% b : 1*(N+1) vector that contains the numerator coefficients for a N-order
% filter.
% a : 1*(N+1) vector that contains the denominator coefficients for the
% N-order filter, where a(1) is assumed to be 1.
% xn : The input data for the nth sample, which is supposed to be a scalar
% w_buff: (N+1)*1 vector that contains the buff data.
% Output:
% yn : The filtered data for the nth sample.
% w_buff: (N+1)*1 vector that returns the updated buff data.
% The transfer function of system is
% H[z] = \frac{ \sum_{k=0}^{N} b_{k} z^{-k} }{ \sum_{k=0}^{N} a_{k}z^{-k} }
% and it can be divided into two subsystems as
% H_{1}[z] = \sum_{k=0}^{N} b_{k} z^{-k}
% H_{2}[z] = \frac{ 1 }{ \sum_{k=0}^{N} a_{k} z^{-k} }
% Then the signal flow graph is
% x[n] --> H_{2} --> w[n] --> H_{1} --> y[n]
b=b/a(1);
a=a/a(1);
w_buff = circshift(w_buff,1,1);
wn = xn - a(1,2:end)*w_buff(2:end,1);
w_buff(1,1) = wn;
yn = b*w_buff;
end
I hope this helps !
  3 个评论
Shivam Gothi
Shivam Gothi 2024-9-21,6:32
Hello @Wentong
According to my understanding, the code for the function "Sequence_filter" is correct.
I used the same file as attached by you in the above connemt, but instead of passing "x_in" input from "x_in.mat" file, I generated "x_in" by below code:
x_in = sin(2*pi*0.25*[0:0.01:12])
The output I got is shown below:
We can see that the code is working as per expectation and error is also negligible.
CASE 2: PASSING "x_in" FROM "x_in.mat" FILE.
I have plotted your "x_in" signal (attached in below image). We can see that it is unbounded and has a very large amplitude. Therefore, as per my understanding, the difference between "y_out2" and "y_out1" in this case might be due to "quantization error". I am suggesting one of the way to reduce this error.
Workaround and Possible solution:
It is possible to achieve the desired results by passing "x_in.mat" as an input to your "sequence_filter".
You can form an equivalent system consisting of two cascade blocks of second order system. This approach is demonstrated in below figure.
Now, use your "Sequence_filter" function on each of the blocks above. I have tried this approach and attaching the results obtained.
We can see that using this approach error is significantly low as compared to what it was earlier for same input "x_in.mat". I think this should validate the working of "sequential_filter" code.
I am also attaching the code for implementing the filter using above approach. You can manipulate it according to your need and also try it on different inputs.
Wentong
Wentong 2024-9-23,0:55
Forgive me for taking your answer a little late.
I appreciate your thoughtful response and hope the best for you!

请先登录,再进行评论。

更多回答(0 个)

类别

Help CenterFile Exchange 中查找有关 Filter Analysis 的更多信息

产品


版本

R2024a

Community Treasure Hunt

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

Start Hunting!

Translated by