数字滤波器的时域和频域响应
直接型:
1、直接型结构简单直观,用到的延迟器最少,为(N/M中较大者的个数)
2、系数对滤波器的控制关系不直接,因此调整不方便。
3、具体实现滤波器时,系数的量化误差将使滤波器的频响产生很大的改变,甚至影响到系统的稳定性。
4、直接型结构一般用以实现低阶系统,对高阶系统,级联型和并联型结构更有优越性。
级联型:
1、级联型结构便于准确的实现系统的零、极点,也便于进行滤波器性能的调整,从整体看,容易控制零点也难于调整极点
2、级联型结构的零极点陪对方式和基本节级联次序具有很大的灵活性,但由于有限字长的影响对于不同的排列,运算误差各有不同。
3、每个基本节都有相同的结构,硬件实现时可以用一个二阶节进行时分复用,故只需要很少的顺序存储单元和运算部件。
并联型:
1、运算速度快,各基本节的误差无不影响,总误差低于级联型结构
2、从整体上看,并联结构容易调整极点位置,不容易直接控制零点。
4.1 数字滤波器的频率响应
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <math.h>
/**
* @brief 计算数字滤波器的频率响应、幅频响应和相频响应
*
* @param b :长度为(m+1),存放滤波器分子的系数b
* @param a :长度为(n+1),存放滤波器分母的系数a
* @param m :滤波器分子多项式的阶数
* @param n :滤波器分母多项式的阶数
* @param x :长度为len,sign=0时存放滤波器频率响应的实部,
* sign=1时存放滤波器幅频响应H(w),sign=2时存放分贝表示的滤波器幅频响应H(w)
* @param y :长度为len,sign=0时存放滤波器频率响应的虚部,
* sign=1,2的时候存放滤波器的相频响应
* @param len :滤波器响应的长度
* @param sign :sign=0时为滤波器频率响应的实部和虚部,sign=1时输出幅频响应和相频响应
* sign=2时输出dB形式的响应
*/
void gain(double *b, double *a, int m, int n, double *x, double *y, int len, int sign)
{
int i, k;
double ar, ai, br, bi, zr, zi, im, re, den, numi, numr, freq, temp;
for (k = 0; k < len; k++)
{
freq = k * 0.5 / (len - 1);
zr = cos(-8.0 * atan(1.0) * freq);
zi = sin(-8.0 * atan(1.0) * freq);
br = 0.0;
bi = 0.0;
for (i = m; i > 0; i--)
{
re = br;
im = bi;
br = (re + b[i]) * zr - im * zi;
bi = (re + b[i]) * zi + im * zr;
}
ar = 0.0;
ai = 0.0;
for (i = n; i > 0; i--)
{
re = ar;
im = ai;
ar = (re + a[i]) * zr - im * zi;
ai = (re + a[i]) * zi + im * zr;
}
br = br + b[0];
ar = ar + 1.0;
numr = ar * br + ai * bi;
numi = ar * bi - ai * br;
den = ar * ar + ai * ai;
x[k] = numr / den;
y[k] = numi / den;
switch (sign)
{
case 1:
temp = sqrt(x[k] * x[k] + y[k] * y[k]);
y[k] = atan2(y[k], x[k]);
x[k] = temp;
break;
case 2:
temp = x[k] * x[k] + y[k] * y[k];
y[k] = atan2(y[k], x[k]);
x[k] = 10.0 * log10(temp); // 20.0*log10(temp)?
break;
default:
break;
}
}
}
测试函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <stdio.h>
#include "filter_process.h"
int main(int argc, char **argv)
{
int i;
double a[]={1,-0.184213803077536,0.177578118927698};
double b[]={0.248341078962541,0.496682157925081,0.248341078962541};
double f,x[300],y[300];
FILE *fp=NULL;
gain(b,a,2,2,x,y,300,2);
if((fp=fopen("gainam.dat","w"))==NULL)
{
printf("Error opening gainam file\n");
return 1;
}
for(i=0;i<300;i++)
{
f=i*0.5/299;
fprintf(fp,"%lf %lf\n",f,x[i]);
}
fclose(fp);
if((fp=fopen("gainph.dat","w"))==NULL)
{
printf("Error opening gainph file\n");
return 1;
}
for(i=0;i<300;i++)
{
f=i*0.5/299;
fprintf(fp,"%lf %lf\n",f,y[i]);
}
fclose(fp);
printf("done\n");
}
4.2 级联型数字滤波器的频率响应
级联型数字滤波器可以使用卷积,将多级滤波器生成一个高阶滤波器,再使用上面的gain
函数就可以计算了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/**
* @brief 计算级联型数字滤波器的频率响应、幅频响应和相频响应
*
* @param b :长度为ns*(n+1),存放滤波器分子的系数b[j][i],j为阶数i为每阶系数
* @param a :长度为ns*(n+1),存放滤波器分母的系数a[j][i]
* @param n :级联型滤波器每节的阶数
* @param ns :级联型滤波器的n阶节数L
* @param x :长度为len,sign=0时存放滤波器频率响应的实部,
* sign=1时存放滤波器幅频响应H(w),sign=2时存放分贝表示的滤波器幅频响应H(w)
* @param y :长度为len,sign=0时存放滤波器频率响应的虚部,
* sign=1,2的时候存放滤波器的相频响应
* @param len :滤波器响应的长度
* @param sign :sign=0时为滤波器频率响应的实部和虚部,sign=1时输出幅频响应和相频响应
* sign=2时输出dB形式的响应
*/
void gainc(double *b, double *a, int n, int ns, double *x, double *y, int len, int sign)
{
int i, j, k, n1;
double ar, ai, br, bi, zr, zi, im, re, den, numi, numr, freq, temp;
double hr, hi, tr, ti;
n1 = n + 1;
for (k = 0; k < len; k++)
{
freq = k * 0.5 / (len - 1);
zr = cos(-8.0 * atan(1.0) * freq);
zi = sin(-8.0 * atan(1.0) * freq);
x[k] = 1.0;
y[k] = 0.0;
for (j = 0; j < ns; j++)
{
br = 0.0;
bi = 0.0;
for (i = n; i > 0; i--)
{
re = br;
im = bi;
br = (re + b[j * n1 + i]) * zr - im * zi;
bi = (re + b[j * n1 + i]) * zi + im * zr;
}
ar = 0.0;
ai = 0.0;
for (i = n; i > 0; i--)
{
re = ar;
im = ai;
ar = (re + a[j * n1 + i]) * zr - im * zi;
ai = (re + a[j * n1 + i]) * zi + im * zr;
}
br = br + b[j * n1 + 0];
ar = ar + 1.0;
numr = ar * br + ai * bi;
numi = ar * bi - ai * br;
den = ar * ar + ai * ai;
hr = numr / den;
hi = numi / den;
tr = x[k] * hr - y[k] * hi;
ti = x[k] * hi + y[k] * hr;
x[k] = tr;
y[k] = ti;
}
switch (sign)
{
case 1:
temp = sqrt(x[k] * x[k] + y[k] * y[k]);
if (temp != 0.0)
{
y[k] = atan2(y[k], x[k]);
}
else
{
y[k] = 0.0;
}
x[k] = temp;
break;
case 2:
temp = x[k] * x[k] + y[k] * y[k];
if (temp != 0.0)
{
y[k] = atan2(y[k], x[k]);
}
else
{
temp = 1e-40;
y[k] = 0.0;
}
x[k] = 10.0 * log10(temp); // 20.0*log10(temp)?
break;
}
}
}
测试函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
int main(int argc, char **argv)
{
int i,n,ns;
// a[0][3]={1.0f,-0.8f,0.0f};
// a[1][3]={1.0f,-0.95f,0.9f};
// b[0][3]={0.2f,0.0f,0.0f};
// b[1][3]={0.05f,-0.1f,0.0f};
double a[2][3]={0};
double b[2][3]={0};
double f,x[300],y[300];
FILE *fp=NULL;
n=2,ns=2;
gainc((double *)b,(double *)a,n,ns,x,y,300,1);
if((fp=fopen("gainam.dat","w"))==NULL)
{
printf("Error opening gainam file\n");
return 1;
}
for(i=0;i<300;i++)
{
f=i*0.5/299;
fprintf(fp,"%lf %lf\n",f,x[i]);
}
fclose(fp);
if((fp=fopen("gainph.dat","w"))==NULL)
{
printf("Error opening gainph file\n");
return 1;
}
for(i=0;i<300;i++)
{
f=i*0.5/299;
fprintf(fp,"%lf %lf\n",f,y[i]);
}
fclose(fp);
printf("done\n");
}
本文由作者按照 CC BY 4.0 进行授权