二阶滤波器matlab代码,双二阶滤波器之MATLAB设计及C语言实现

本文中的例子和代码放在Github

First,什么是双二阶滤波器?wiki上是这么说的:二阶、递归、线性,含有两个极点和两个零点,“双二阶”的名字来源于它的传递函数是两个二次多项式的比值。

In signal processing, a digital biquad filter is a second order recursive linear filter, containing two poles and two zeros. "Biquad" is an abbreviation of "biquadratic", which refers to the fact that in the Z domain, its transfer function is the ratio of two quadratic functions: H(z)=(b₀+b₁z⁻¹+b₂z⁻²)/(a₀+a₁z⁻¹+a₂z⁻²) The coefficients are often normalized such that a₀ = 1: H(z)=(b₀+b₁z⁻¹+b₂z⁻²)/(1+a₁z⁻¹+a₂z⁻²) High-order IIR filters can be highly sensitive to quantization of their coefficients, and can easily become unstable.

归一化传递函数写成这样:

$$H(z)= \frac{b₀+b₁z⁻¹+b₂z⁻²}{1+a₁z⁻¹+a₂z⁻²}$$

用MATLAB的Filter Designer来设计一个:400Hz带通IIR,需要用4个Sections来实现,默认给出的滤波器结构是Direct-Form II。

9225753d15b7af08837137670bee340f.png 在菜单栏的Analysis中选择Filter Coeffients就能看到滤波器系数了:

568a24d7f6a06e83899b35c6d7142d9d.png Numerator,分子,也就是传递函数中的b项们,从上到下依次为$b_0$,$b_1$和$b_2$。 Denominator,分母,也就是传递函数中的a项,从上到下依次为$a_0$,$a_1$和$a_2$,其中$a_0$总是为1。 Gain,增益。

用数组来存放滤波器系数:

//8-order IIR filter with 4 sections

const int sections = 4;

//nominator

const float b[4][3] = {

{ 1, -1.984454421, 1 },

{ 1, -1.999405318, 1 },

{ 1, -1.993167556, 1 },

{ 1, -1.998644244, 1 }

};

//denominator

const float a[4][3] = {

{ 1, -1.984532740, 0.9884094716 },

{ 1, -1.988571923, 0.9909378613 },

{ 1, -1.991214225, 0.9962624248 },

{ 1, -1.995917854, 0.9977478940 }

};

const float gain[4] = { 0.583805364, 0.583805364, 0.170388576, 0.170388576 };

以Direct-Form II为例来写个实现代码,计算过程是: $$y[n]=b_{0}w[n]+b_{1}w[n-1]+b_{2}w[n-2]$$ 其中$$w[n]=x[n]-a_{1}w[n-1]-a_{2}w[n-2]$$ 代码如下: 用一个数组来存放滤波器的中间状态量$w[n-1]$和$w[n-2]$:

float w[sections][2]; //filter states

在滤波计算之前,初始化滤波器:

for (int i = 0; i < sections; i++) {

w[i][0] = 0; //w[n-1]

w[i][1] = 0; //w[n-2]

}

正式开始计算:pcmIn[i]是原始的输入信号,输入section 1,section 1的输出则作为section 2的输入,以此类推,由于这个滤波器由4个sections构成,因此要循环4次。 注意输出要乘gain。

y[0] = pcmIn[i];

for (j = 0; j < sections; j++) {

tmp[j] = y[j] - a[j][1] * w[j][0] - a[j][2] * w[j][1]; //calculate w[n]

y[j+1] = tmp[j] + b[j][1] * w[j][0] + b[j][2] * w[j][1]; //calculate the j-th section filter output y[n]

w[j][1] = w[j][0]; //move w[n-1] -> w[n-2]

w[j][0] = tmp[j]; //move w[n] -> w[n-1]

y[j+1] = gain[j] * y[j+1]; //multiply with gain

}

out = y[j];

如果需要得到例如PCM16的输出,那么再对out进行限幅,that's all.

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非常感谢您的提问。以下是使用C语言实现MATLAB同款的巴特沃斯高通滤波器代码: ```c #include <stdio.h> #include <stdlib.h> #include <math.h> #define PI 3.14159265358979323846 typedef struct { double real; double imag; } complex; void butterworth_highpass(int n, double fc, double fs, double *b, double *a) { int i; double w0 = 2 * PI * fc / fs; double bw = w0 / 10; double alpha = sin(w0) / (2 * sqrt(2) * bw); double a0 = 1 + alpha; double a1 = -2 * cos(w0); double a2 = 1 - alpha; double b0 = (1 + cos(w0)) / 2 / a0; double b1 = -(1 + cos(w0)) / a0; double b2 = (1 + cos(w0)) / 2 / a0; a[0] = a0; a[1] = a1; a[2] = a2; b[0] = b0; b[1] = b1; b[2] = b2; for (i = 0; i < n; i++) { b[i] /= a0; a[i] /= a0; } } void complex_multiply(complex *a, complex *b, complex *c) { c->real = a->real * b->real - a->imag * b->imag; c->imag = a->real * b->imag + a->imag * b->real; } void complex_add(complex *a, complex *b, complex *c) { c->real = a->real + b->real; c->imag = a->imag + b->imag; } void complex_subtract(complex *a, complex *b, complex *c) { c->real = a->real - b->real; c->imag = a->imag - b->imag; } void complex_divide(complex *a, complex *b, complex *c) { double denominator = b->real * b->real + b->imag * b->imag; c->real = (a->real * b->real + a->imag * b->imag) / denominator; c->imag = (a->imag * b->real - a->real * b->imag) / denominator; } void complex_exp(complex *a, complex *b) { b->real = exp(a->real) * cos(a->imag); b->imag = exp(a->real) * sin(a->imag); } void fft(complex *x, int n) { int i, j, k; complex t, u; for (i = 0, j = 0; i < n; i++) { if (j > i) { t = x[j]; x[j] = x[i]; x[i] = t; } k = n; while (j >= k) { j -= k; k /= 2; } j += k; } for (k = 1; k < n; k *= 2) { for (j = 0; j < k; j++) { t.real = cos(PI * j / k); t.imag = -sin(PI * j / k); for (i = j; i < n; i += 2 * k) { complex_multiply(&t, &x[i + k], &u); complex_add(&x[i], &u, &x[i + k]); complex_subtract(&x[i], &u, &x[i]); } } } } void ifft(complex *x, int n) { int i; for (i = 0; i < n; i++) { x[i].imag = -x[i].imag; } fft(x, n); for (i = 0; i < n; i++) { x[i].real /= n; x[i].imag /= -n; } } void filter(double *x, int n, double *b, double *a, double *y) { int i, j; complex *X = (complex *) malloc(n * sizeof(complex)); complex *H = (complex *) malloc(n * sizeof(complex)); complex *Y = (complex *) malloc(n * sizeof(complex)); for (i = 0; i < n; i++) { X[i].real = x[i]; X[i].imag = 0; } fft(X, n); for (i = 0; i < n; i++) { H[i].real = b[0]; H[i].imag = 0; for (j = 1; j <= i && j < 3; j++) { complex t; complex_multiply(&H[i - j], &X[i], &t); complex_add(&t, &H[i], &H[i]); complex_multiply(&H[i - j], &X[i - j], &t); complex_subtract(&H[i], &t, &H[i]); } for (j = 1; j < 3 && j < n - i; j++) { complex t; complex_multiply(&H[i + j], &X[i], &t); complex_add(&t, &H[i], &H[i]); complex_multiply(&H[i + j], &X[i + j], &t); complex_subtract(&H[i], &t, &H[i]); } complex_divide(&H[i], &X[i], &H[i]); complex_exp(&H[i], &H[i]); } for (i = 0; i < n; i++) { complex_multiply(&H[i], &X[i], &Y[i]); } ifft(Y, n); for (i = 0; i < n; i++) { y[i] = Y[i].real * a[0]; for (j = 1; j <= i && j < 3; j++) { y[i] -= y[i - j] * a[j]; } for (j = 1; j < 3 && j < n - i; j++) { y[i] -= y[i + j] * a[j]; } } free(X); free(H); free(Y); } int main() { int i, n = 1000; double *x = (double *) malloc(n * sizeof(double)); double *y = (double *) malloc(n * sizeof(double)); double *b = (double *) malloc(3 * sizeof(double)); double *a = (double *) malloc(3 * sizeof(double)); double fc = 50, fs = 1000; for (i = 0; i < n; i++) { x[i] = sin(2 * PI * i * fc / fs); } butterworth_highpass(2, fc, fs, b, a); filter(x, n, b, a, y); for (i = 0; i < n; i++) { printf("%f\n", y[i]); } free(x); free(y); free(b); free(a); return 0; } ``` 这段代码实现了一个二阶巴特沃斯高通滤波器,可以通过调整参数来实现不同的滤波效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值