[英]C99 equivalent to MATLAB “filter”?
Why do the MATLAB and C versions produce different results? 为什么MATLAB和C版本会产生不同的结果?
MATLAB: MATLAB:
[B_coeffs, A_coeffs ] = butter(4, 100/(16000/2), 'high');
state = zeros( 4, 1 );
input = zeros( 64,1 );
for i=1:64
input(i)=i;
end
[filtered_output, state] = filter( B_coeffs, A_coeffs, input, state );
C: C:
int main(...)
{
for(int test=0; test<64;test++)
Xin[test]=test+1;
...
high_pass_filter_init(...)
high_pass_filter_do(...)
}
// Do the filtering
void high_pass_filter_do( t_high_pass_filter* hpf, float *Xin, float *Yout )
{
double Xi, Yi;
double z0 = hpf->state[0],
z1 = hpf->state[1],
z2 = hpf->state[2],
z3 = hpf->state[3];
unsigned int N = 64;
unsigned int i = 0;
for(i=0;i<N;i++)
{
Xi = Xin[i];
Yi = hpf->B_coeffs[0] * Xi + z0;
z0 = hpf->B_coeffs[1] * Xi + z1 - hpf->A_coeffs[1] * Yi;
z1 = hpf->B_coeffs[2] * Xi + z2 - hpf->A_coeffs[2] * Yi;
z2 = hpf->B_coeffs[3] * Xi + z3 - hpf->A_coeffs[3] * Yi;
z3 = hpf->B_coeffs[4] * Xi - hpf->A_coeffs[4] * Yi;
Yout[i] = (float) Yi;
}
hpf->state[0] = z0;
hpf->state[1] = z1;
hpf->state[2] = z2;
hpf->state[3] = z3;
return;
}
where 哪里
typedef struct
{
float A_coeffs[5];
float B_coeffs[5];
float state[4];
} t_high_pass_filter;
void high_pass_filter_init( t_high_pass_filter* hpf)
{
hpf->A_coeffs[0] = 1.0000;
hpf->A_coeffs[1] = -3.8974;
hpf->A_coeffs[2] = 5.6974;
hpf->A_coeffs[3] = -3.7025;
hpf->A_coeffs[4] = 0.9025;
hpf->B_coeffs[0] = 0.9500;
hpf->B_coeffs[1] = -3.7999;
hpf->B_coeffs[2] = 5.6999;
hpf->B_coeffs[3] = -3.7999;
hpf->B_coeffs[4] = 0.9500;
hpf->state[0] = 0.0;
hpf->state[1] = 0.0;
hpf->state[2] = 0.0;
hpf->state[3] = 0.0;
}
**The outputs are: ** **输出为:**
MATLAB: C:
----------------------------
0.9500 0.9500
1.8025 1.8026
2.5625 2.5631
3.2350 3.2369
3.8247 3.8292
4.3360 4.3460
4.7736 4.7930
5.1416 5.1767
5.4442 5.5035
5.6854 5.7807
5.8691 6.0156
5.9991 6.2162
6.0788 6.3909
6.1119 6.5487
6.1016 6.6989
6.0511 6.8514
5.9637 7.0167
5.8421 7.2057
5.6894 7.4298
5.5083 7.7009
5.3013 8.0314
5.0710 8.4342
4.8199 8.9225
4.5501 9.5101
4.2640 10.2110
3.9637 11.0399
3.6511 12.0115
3.3281 13.1412
2.9965 14.4443
2.6582 15.9368
2.3146 17.6347
1.9674 19.5543
1.6180 21.7122
1.2677 24.1250
0.9179 26.8095
0.5698 29.7829
0.2245 33.0621
-0.1169 36.6643
-0.4535 40.6067
-0.7842 44.9066
-1.1084 49.5812
-1.4251 54.6477
-1.7336 60.1232
-2.0333 66.0249
-2.3236 72.3697
-2.6039 79.1746
-2.8738 86.4562
-3.1327 94.2313
-3.3804 102.5161
-3.6164 111.3270
-3.8405 120.6801
-4.0524 130.5911
-4.2520 141.0756
-4.4390 152.1490
-4.6134 163.8264
-4.7750 176.1225
-4.9239 189.0520
-5.0600 202.6291
-5.1832 216.8677
-5.2938 231.7814
-5.3917 247.3837
-5.4771 263.6875
-5.5501 280.7055
-5.6108 298.4500
The first few values are the same (or similar), but then they diverge. 前几个值相同(或相似),但随后却有所不同。 Also, the filter state is totally different after first iteration.
同样,第一次迭代后,滤波器状态完全不同。
What am I doing wrong? 我究竟做错了什么?
After your second edit, it is becoming clear what your problem is: chaotic behavior . 第二次编辑后,您将清楚问题所在: 混乱行为 。
First time round, you seem to have just copied the coefficients from the MATLAB command window into your C function. 第一次,您似乎刚刚将系数从MATLAB命令窗口复制到了C函数中。 However, MATLAB's
format
appears to have been set to short
, as the coefficients in the C function are rounded to 4 decimal places. 但是,由于C函数中的系数四舍五入到小数点后四位,因此MATLAB的
format
似乎设置为short
。 This rounding (as well as using float
in the C function the first time around) is your problem. 这种舍入(以及第一次使用C函数中的
float
)是您的问题。
Here's what I did this time: 这是我这次所做的:
Conclusions: you're seeing a very high sensitivity to initial values. 结论:您看到对初始值的灵敏度非常高。
TL;DR : this code: TL; DR :此代码:
clc
[B_coeffs, A_coeffs] = butter(4, 100/(16000/2), 'high');
state = zeros(4, 1);
input = 1:64;
% MATLAB version
[filtered_output0, state0] = filter(B_coeffs, A_coeffs, input, state);
mex filter_test.c
% MEX, using built-in constants (of which only the first few digits are equal)
[filtered_output1, state1] = filter_test([],[], input, state, 0);
% MEX, using the exact same constants
[filtered_output2, state2] = filter_test(B_coeffs, A_coeffs, input, state, 1);
% Compare!
[filtered_output0.' filtered_output1.' filtered_output2.']
[state0 state1 state2]
Where filter_test.c
contains: 其中
filter_test.c
包含:
#include <stdio.h>
#include "mex.h"
#define N ( 64u)
#define C ( 5u)
#define S (C-1u)
/* helper struct for HPF */
typedef struct
{
double A_coeffs[C];
double B_coeffs[C];
double state[S];
} t_high_pass_filter;
/* "Default" values (note that these are ROUNDED to 4 digits only)
void
high_pass_filter_init(t_high_pass_filter* hpf)
{
hpf->A_coeffs[0] = 1.0000;
hpf->A_coeffs[1] = -3.8974;
hpf->A_coeffs[2] = 5.6974;
hpf->A_coeffs[3] = -3.7025;
hpf->A_coeffs[4] = 0.9025;
hpf->B_coeffs[0] = 0.9500;
hpf->B_coeffs[1] = -3.7999;
hpf->B_coeffs[2] = 5.6999;
hpf->B_coeffs[3] = -3.7999;
hpf->B_coeffs[4] = 0.9500;
hpf->state[0] = 0.0;
hpf->state[1] = 0.0;
hpf->state[2] = 0.0;
hpf->state[3] = 0.0;
}
/* the actual filter */
void
high_pass_filter_do(t_high_pass_filter* hpf,
const double *Xin,
double *Yout)
{
double Xi, Yi;
double z0 = hpf->state[0],
z1 = hpf->state[1],
z2 = hpf->state[2],
z3 = hpf->state[3];
unsigned int i = 0u;
for(i=0; i<N; ++i)
{
Xi = Xin[i];
Yi = hpf->B_coeffs[0] * Xi + z0;
z0 = hpf->B_coeffs[1] * Xi + z1 - hpf->A_coeffs[1] * Yi;
z1 = hpf->B_coeffs[2] * Xi + z2 - hpf->A_coeffs[2] * Yi;
z2 = hpf->B_coeffs[3] * Xi + z3 - hpf->A_coeffs[3] * Yi;
z3 = hpf->B_coeffs[4] * Xi - hpf->A_coeffs[4] * Yi;
Yout[i] = Yi;
}
hpf->state[0] = z0;
hpf->state[1] = z1;
hpf->state[2] = z2;
hpf->state[3] = z3;
}
/* Wrapper between MATLAB MEX and filter function */
void
filter(const double *B_coeffs,
const double *A_coeffs,
const double *input,
const double *state,
double *filtered_output,
double *state_output)
{
unsigned int i = 0u;
t_high_pass_filter hpf;
/* Use built-in defaults when coefficients
* have not been passed explicitly */
if (B_coeffs == NULL)
{
high_pass_filter_init(&hpf);
}
/* Otherwise, use the coefficients on the arguments */
else
{
for (i=0u; i<C; ++i) {
hpf.B_coeffs[i] = B_coeffs[i];
hpf.A_coeffs[i] = A_coeffs[i];
}
for (i=0u; i<S; ++i)
hpf.state[i] = state[i];
}
/* Apply filter function */
high_pass_filter_do(&hpf,
input,
filtered_output);
/* Assign output state explicitly */
for (i=0u; i<S; ++i)
state_output[i] = hpf.state[i];
}
/* MATLAB/MEX Gateway function */
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
unsigned int i = 0u;
double *B_coeffs = mxGetPr(prhs[0]),
*A_coeffs = mxGetPr(prhs[1]),
*input = mxGetPr(prhs[2]),
*state = mxGetPr(prhs[3]);
int flag = *mxGetPr(prhs[4]);
double *filtered_output,
*state_output;
/* filtered_output, state */
plhs[0] = mxCreateDoubleMatrix(1, N, mxREAL);
plhs[1] = mxCreateDoubleMatrix(S, 1, mxREAL);
filtered_output = mxGetPr(plhs[0]);
state_output = mxGetPr(plhs[1]);
if (flag == 0)
{
filter(NULL,
NULL,
input,
state,
filtered_output,
state_output);
}
else
{
filter(B_coeffs,
A_coeffs,
input,
state,
filtered_output,
state_output);
}
}
gives this output: 给出以下输出:
% MATLAB C with rounding C without rounding
%===============================================================================
filtered values:
9.499817826393004e-001 9.500000000000000e-001 9.499817826393004e-001
1.802482117980145e+000 1.802630000000000e+000 1.802482117980145e+000
2.562533610562189e+000 2.563140162000000e+000 2.562533610562189e+000
... (58 more values) ... ...
-5.477082906502112e+000 2.637900416547026e+002 -5.477082906502112e+000
-5.550054712403821e+000 2.808186934967214e+002 -5.550054712403821e+000
-5.610782439991141e+000 2.985749768301545e+002 -5.610782439991141e+000
states after filter run:
-6.740826417997180e+001 2.553210086702404e+002 -6.740826417997180e+001
2.006572641218511e+002 -7.151404729138806e+002 2.006572641218511e+002
-1.991114894348111e+002 6.686913808328562e+002 -1.991114894348111e+002
6.586237103693912e+001 -2.086639165892145e+002 6.586237103693912e+001
Next time, make sure you use format long e
before copy-pasting like that :) 下次,请确保在复制粘贴之前使用
format long e
:)
When I run your code, I get this: 当我运行您的代码时,我得到以下信息:
MATLAB C
================================
0.9500 0.950000
1.8026 1.802630
2.5631 2.563139
...
(58 more values)
...
263.7900 263.687500
280.8187 280.705475
298.5750 298.450012
But, when I change the C
code to use double
instead of float
, I get this: 但是,当我将
C
代码更改为使用double
而不是float
,我得到了:
MATLAB C
================================
0.9500 0.950000
1.8026 1.802630
2.5631 2.563140
...
(58 more values)
...
263.7900 263.790042
280.8187 280.818693
298.5750 298.574977
So, @Richard is correct: 因此,@ Richard是正确的:
double
instead of float
. double
而不是float
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.