介绍了数字滤波器的基本结构,在分别讨论了IIR与FIR数字滤波器的设计方法的基础上,指出了传统的数字滤波器设计方法过程复杂、计算工作量大、滤波特性调整困难的不足,提出了一种基于Matlab和Modelsim软件的数字滤波器设计方法,完成了高Q值50Hz带通IIR滤波器的设计, 达到了通带45-55Hz,衰减小于3db,阻带40-60Hz,衰减大于80db的参数指标。文中深入分析了该滤波器系统设计的功能特点、实现原理以及技术关键,阐述了使用MATLAB进行带通滤波器设计及仿真的具体方法。最后把整个设计方案用VHDL语言进行了描述并在Modelsim上仿真。Modelsim与Matlab的仿真结果对比说明该设计准确性好,可精确到小数点后六位,稳定后误差小于万分之一;可移植性强,在实际应用中,可根据不同的阶数、精度和速度等要求对IIR 滤波器系数进行灵活的修改,以实现任意阶数的IIR 滤波器。因此,该设计方法可靠性好,效率高,极大的减轻了工作量,有利于滤波器设计的最优化。
作为线形时不变系统的数字滤波器可以用系统函数来表示,而实现一个系统函数表达式所表示的系统可以用两种方法:一种方法是采用计算机软件实现;另一种方法是用加法器、乘法器、和延迟器等元件设计出专用的数字硬件系统,即硬件实现。不论软件实现还是硬件实现,在滤波器设计过程中,由同一系统函数可以构成很多不同的运算结构。对于无限精度的系数和变量,不同结构可能是等效的,与其输入和输出特性无关;但是在系数和变量精度是有限的情况下,不同运算结构的性能就有很大的差异。因此,有必要对离散时间系统的结构有一基本认识。
IIR滤波器的基本结构
可见数字滤波器的功能就是把输入序列x(n)通过一定的运算变换成输出序列y(n)。不同的运算处理方法决定了滤波器实现结构的不同。无限冲激响应滤波器的单位抽样响应h(n)是无限长的,其差分方程如(2-2)式所示,是递归式的,即结构上存在着输出信号到输入信号的反馈,其系统函数具有(2-1)式的形式,因此在z平面的有限区间(0<︱z︱<∞)有极点存在。
前面已经说明,对于一个给定的线形时不变系统的系统函数,有着各种不同的等效差分方程或网络结构。由于乘法是一种耗时运算,而每个延迟单元都要有一个存储寄存器,因此采用最少常熟乘法器和最少延迟支路的网络结构是通常的选择,以便提高运算速度和减少存储器。然而,当需要考虑有限寄存器长度的影响时,往往也采用并非最少乘法器和延迟单元的结构。
IIR滤波器实现的基本结构有:
(1)IIR滤波器的直接型结构;
优点:延迟线减少一半,变为N 个,可节省寄存器或存储单元;
缺点:其它缺点同直接I型。
通常在实际中很少采用上述两种结构实现高阶系统,而是把高阶变成一系列不同组合的低阶系统(一、二阶)来实现。
(2)IIR滤波器的级联型结构;
特点:
缺点:
不能直接调整零点,因多个二阶节的零点并不是整个系统函数的零点,当需要准确的传输零点时,级联型最合适。
(3)IIR滤波器的并联型结构。
优点:
缺点:
a、直接型 b、并联型
c、串联型
图2-1、IIR滤波器的基本结构
FIR滤波器[7]的单位抽样响应为有限长度,一般采用非递归形式实现。通常的FIR数字滤波器有横截性和级联型两种。
FIR滤波器实现的基本结构有:
(1)FIR滤波器的横截型结构
表示系统输入输出关系的差分方程可写作:
直接由差分方程得出的实现结构如图2-2所示:
图2-2、 横截型(直接型﹑卷积型)
若h(n)呈现对称特性,即此FIR滤波器具有线性相位,则可以简化加横截型结构,下面分情况讨论:
图2-3、N为奇数时线形相位FIR滤波器实现结构 图2-4、N为偶数时线性相位FIR滤波器实现结构
(2)FIR滤波器的级联型结构
这时FIR滤波器可用二阶节的级联结构来实现,每个二阶节用横截型结构实现。如图所示:
图2-5、 FIR滤波器的级联结构
这种结构的每一节控制一对零点,因而在需要控制传输零点时可以采用这种结构。
数字滤波器根据其冲激响应函数的时域特性,可分为两种,即无限长冲激响应(IIR)滤波器和有限长冲激响应(FIR)滤波器。IIR滤波器的特征是,具有无限持续时间冲激响应。这种滤波器一般需要用递归模型来实现,因而有时也称之为递归滤波器。FIR滤波器的冲激响应只能延续一定时间,在工程实际中可以采用递归的方式实现,也可以采用非递归的方式实现。数字滤波器的设计方法有多种,如双线性变换法、窗函数设计法、插值逼近法和Chebyshev逼近法等等。随着MATLAB软件尤其是MATLAB的信号处理工作箱的不断完善,不仅数字滤波器的计算机辅助设计有了可能,而且还可以使设计达到最优化。
数字滤波器设计的基本步骤如下:
(1)确定指标
在设计一个滤波器之前,必须首先根据工程实际的需要确定滤波器的技术指标。在很多实际应用中,数字滤波器常常被用来实现选频操作。因此,指标的形式一般在频域中给出幅度和相位响应。幅度指标主要以两种方式给出。第一种是绝对指标。它提供对幅度响应函数的要求,一般应用于FIR滤波器的设计。第二种指标是相对指标。它以分贝值的形式给出要求。在工程实际中,这种指标最受欢迎。对于相位响应指标形式,通常希望系统在通频带中具有线性相位。运用线性相位响应指标进行滤波器设计具有如下优点:①只包含实数算法,不涉及复数运算;②不存在延迟失真,只有固定数量的延迟;③长度为N的滤波器(阶数为N-1),计算量为N/2数量级。因此,本文中滤波器的设计就以线性相位FIR滤波器的设计为例。
(2)逼近
确定了技术指标后,就可以建立一个目标的数字滤波器模型。通常采用理想的数字滤波器模型。之后,利用数字滤波器的设计方法,设计出一个实际滤波器模型来逼近给定的目标。
(3)性能分析和计算机仿真
上两步的结果是得到以差分或系统函数或冲激响应描述的滤波器。根据这个描述就可以分析其频率特性和相位特性,以验证设计结果是否满足指标要求;或者利用计算机仿真实现设计的滤波器,再分析滤波结果来判断。
前面已经介绍了IIR和FIR数字滤波器的设计方法,选择哪一种滤波器取决于每种类型滤波器的优点在设计中的重要性。为了能在实际工作中恰当地选用合适的滤波器,现将两种滤波器特点比较分析[]如下:
(1) 选择数字滤波器是必须考虑经济问题,通常将硬件的复杂性、芯片的面积或计算速度等作为衡量经济问题的因素。在相同的技术指标要求下,由于IIR数字滤波器存在输出对输入的反馈,因此可以用较少的阶数来满足要求,所用的存储单元少,运算次数少,较为经济。例如,用频率抽样法设计一个阻带衰减为20dB的FIR数字滤波器,要33阶才能达到要求,而用双线性变换法只需4~5阶的切比雪夫IIR滤波器就可达到同样的技术指标。这就是说FIR滤波器的阶数要高5~10倍左右。
(2) 在很多情况下,FIR数字滤波器的线性相位与它的高阶数带来的额外成本相比是非常值得的。对于IIR滤波器,选择性越好,其相位的非线性越严重。如果要使IIR滤波器获得线性相位,又满足幅度滤波器的技术要求,必须加全通网络进行相位校正,这同样将大大增加滤波器的阶数。就这一点来看,FIR滤波器优于IIR滤波器。
(3) FIR滤波器主要采用非递归结构,因而无论是理论上还是实际的有限精度运算中他都是稳定的,有限精度运算误差也较小。IIR滤波器必须采用递归结构,极点必须在z平面单位圆内才能稳定。对于这种结构,运算中的舍入处理有时会引起寄生振荡。
(4) 对于FIR滤波器,由于冲激响应是有限长的,因此可以用快速傅里叶变换算法,这样运算速度可以快得多。IIR滤波器不能进行这样的运算。
(5) 从设计上看,IIR滤波器可以利用模拟滤波器设计的现成的闭合公式、数据和表格,可以用完整的设计公式来设计各种选频滤波器。一旦选定了已知的一种逼近方法(如巴特奥兹,切比雪夫等),就可以直接把技术指标带入一组设计方程计算出滤波器的阶次和系统函数的系数(或极点和零点)。FIR滤波器则一般没有现成的设计公式。窗函数法只给出了窗函数的计算公式,但计算通带和阻带衰减仍无显式表达式。一般FIR滤波器设计仅有计算机程序可资利用,因而要借助于计算机。
(6) IIR滤波器主要是设计规格化、频率特性为分段常数的标准低通、高通、带通和带阻滤波器。FIR滤波器则灵活很多,例如频率抽样法可适应各种幅度特性和相位特性的要求。因此FIR滤波器可设计出理想正交变换器、理想微分器、线性调频器等各种网络,适应性很广。而且,目前已经有很多FIR滤波器的计算机程序可供使用。
表2-1、 两种滤波器特点比较分析
|
FIR滤波器 |
IIR滤波器 |
设计方法 |
一般无解析的设计公式,要借助计算机程序完成 |
利用AF的成果,可简单、有效地完成设计 |
设计结果 |
可得到幅频特性(可以多带)和线性相位(最大优点) |
只能得到幅频特性,相频特性未知,如需要线性相位,须用全通网络校准,但增加滤波器阶数和复杂性 |
稳定性 |
极点全部在原点(永远稳定)无稳定性问题 |
有稳定性问题 |
阶数 |
高 |
低 |
结构 |
非递归系统 |
递归系统 |
运算误差 |
一般无反馈,运算误差小 |
有反馈,由于运算中的四舍五入会产生极限环 |
若采用24位乘法器,用1位整数位,1位符号位,共22位定点二进制数进行运算,负数用补码表示,由此将减法运算变成累加求和运算[17]。各系数可用matlab编程[18]转成二进制补码,转换结果如表:
表3-2、 各系数转成二进制的结果
十进制数 |
定点24位补码数 |
0.064426919942375843 |
000001000001111110010010 |
0.086237116875715341 |
000001011000010011101001 |
-0.090446129522962132 |
111110100011011000100001 |
-0.9517888619754914 |
110000110001010111100100 |
-0.086237116875715341 |
111110100111101100010111 |
0.090446129522960383 |
000001011100100111011111 |
0.36083349830553402 |
000101110001011111100101 |
0.23642640306518907 |
000011110010000110011100 |
-0.23451506983909279 |
111100001111110110110101 |
-0.96999789866178998 |
110000011110101110001110 |
-0.23642640306518907 |
111100001101111001100100 |
0.23451506983909134 |
000011110000001001001011 |
0.5945544040902202 |
001001100000110100101110 |
0.30598365902400908 |
001101101001111001111001 |
-0.30583918594063586 |
111011000110110100100001 |
-0.30598365902400908 |
110010010110000110000111 |
0.30583918594063608 |
000100111001001011011111 |
-0.99059830159543105 |
110000001001101000001010 |
可用Matlab程序求截断后系数并进行仿真:
for i=1:1:6
for j=1:1:6
s= to2(SOS(i,j));SOS1(i,j)=to10(r)+s;
end
end
r=to2(G);G1=to10(r);
[B,A] = SOS2TF(SOS1,G1); %转成直接型
freqz(B,A,Nn,fs);
系数截断后图形:
图3-9 系数截断后的幅频、相频响应仿真图形
图3-10系数截断后的零极点图
图3-9与图3-10表明使用24位乘法器不会引入截断误差,通带与阻带衰减都符合设计要求。
对象1滤波器设计方法:MATLAB信号处理工具箱提供了各种滤波器设计函数及滤波器实现函数,根据本系统对象,采用ellipap函数设计创建一低通模拟椭圆滤波器,然后再采用lp2bp函数将模拟低通;滤波器转换成模拟带通滤波器,最后采用bilinear函数现双线性变换法把模拟滤波器转换成数字滤波器。ellipap函数调用格式为[z,p,k]=ellipap(n,rp,rs),[10]其中n为滤波器阶数,rp为该滤波器在通带内的最大衰减,rs为在阻带内的最小衰减;lb2bp函数的调用格式为[At,Bt,Ct,Dt]=lp2bp(A,B,C,D,Wo,Bw),其中Wo为中心频率,Bw为带宽;[At1,Bt1,Ct1,Dt1]=bilinear(At,Bt,Ct,Dt,Fs),其中Fs为抽样频率。
滤波器技术指标:通带下截止频率Wp1=20Hz,通带下截至止频率Wp2=40Hz,在通带内的最大衰减rp为0.2,在通带内的最小衰减rs为40,抽样频率Fs为200Hz。
对象2滤波器设计方法:由于白噪声分布在整个频带,所以需要在不衰减原信号的前提下,对整个频带进行滤波,设计一个带过渡带的多带FIR滤波器。采用firls函数,其调用格式为b=firls(n,f,m),其中n为滤波器阶数,f为转换频率向量,在0到1之间;m为滤波器幅频响应中的频带增益向量。
滤波器技术指标:在[65/500 75/500](即[0.13 0.15]段和[115/500 125/500](即[0.23 0.25])段频带内的幅度是1,在[0 60/500](即[0 0.12])段、[80/500 110/500](即[0.16 0.22])段、[130/500 1](即[0.26 1])段频带内的幅度是0。
双击打开MATLAB,如下图3-1直接在窗口中输入程序得出结果
图3.3-1程序输入画面与结果
4.3.1产生一个含有10Hz、30Hz和60Hz的混合正弦波信号X
MATLAB程序实现如下:
Fs=200;
t=(1:200)/Fs;
x1=sin(2*pi*t*10);
x2=sin(2*pi*t*30);
x3=sin(2*pi*t*60);
X= x1+ x2+ x3;
plot(t,X);
title('混合正弦波信号X(t)-滤波前');
grid;
程序运行结果输出如下
图3.3-2 滤波器前信号波形
4.3.2 产生一个4阶IIR带通椭圆滤波器
MATLAB程序实现如下:
wp1=20;
wp2=40;
Fs=200;
rp=0.2;
rs=40;
wp1=2*pi*wp1;
wp2=2*pi*wp2;
Bw=wp2-wp1;
Wo=sqrt(wp2*wp1);
[z,p,k]=ellipap(4,rp,rs); %创建模拟低通滤波器原型
[A,B,C,D]=zp2ss(z,p,k); %把模拟低通滤波器原型转换成模拟低通滤波器
[At,Bt,Ct,Dt]=lp2bp(A,B,C,D,Wo,Bw); %把模拟低通滤波器转换成带通滤波器
[At1,Bt1,Ct1,Dt1]=bilinear(At,Bt,Ct,Dt,Fs); %双线性变换法把模拟滤波
[num,den]=ss2tf(At1,Bt1,Ct1,Dt1); 器转换成数字滤波器
[H,W]=freqz(num,den);
plot(W*Fs/(2*pi),abs(H));
title('频率响应特性');
grid;
xlabel('频率/Hz');
ylabel('幅值');
程序运行结果输出如下
图3.3-3 IIR带通椭圆滤波器响应特性
4.3.3 对混合正弦波信号X进行滤波
MATLAB程序实现如下
Y=filter(num,den,X);
plot(t,Y);
title('滤波后信号-Y');
grid;
axis([0 1 -1 1]);
程序运行结果输出如下
图3.3-4 滤波器后信号波形
4.3.4 绘出信号滤波前、后的幅频图
MATLAB程序实现如下
S=fft(X,512);
SF=fft(Y,512);
w=(0:255)/256*(Fs/2);
plot(w,abs(S(1:256)),'-',w,abs(SF(1:256)),'k:*');
title('信号滤波前、后的幅频图');
xlabel('频率/Hz');
ylabel('幅值');
legend('滤波前的幅频', '滤波后的幅频');
程序运行结果输出如下
对象2 MATLAB程序仿真设计实现如下
Fs=1000;t=0.5:1/Fs:0.75;
x=sin(2*pi*70*t)+2*sin(2*pi*120*t);
xn=x+randn(size(t));
subplot(311)plot(t,x);grid;
title('原始信号波形');
subplot(312)plot(t,xn);grid;
title('被白噪声污染的信号波形');
n=90;
f=[0 0.12 0.13 0.15 0.16 0.22 0.23 0.25 0.26 1];
m=[0 0 1 1 0 0 1 1 0 0];
b=firls(n,f,m);
xo=filter(b,1,xn);
subplot(313)plot(t,xo);grid;
title('滤波器后恢复的信号波形');
程序运行结果输出如下
图3.3-6 原始、被污染、恢复信号图
滤波器频率响应特性MATLAB程序
[H,W]=freqz(b);
plot(W*Fs/(Fs*pi),abs(H));
title('频率响应特性');
gird;
xlabel('频率/Hz')
ylabel('幅值')
程序运行结果输出如下
附录一、部分程序源码:
1、十进制小数转换为24位二进制补码的程序
function a =to2(x)
%x为小于2的十进制小数;
%a为x对应的24位二进制补码
if x>0
b(0)=0;
else b(0)=1;
b(1)=fix(x);
for i=1:1:22
b(i+1)=fix(x*2);
t=x*2-b(i+1);
x=t;
end
c=[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
if x<0
for i=1:1:23
a(i)= xor (b(i) c(i))
end
end
2、二进制补码转换成十进制小数的程序
function y =to10(a)
y=0;
for i=3:1:24
t=y;y=a(i)*2^(-i+2)+t;
end
if a(1,2)==’11’
y=-y;
elseif a(1,2)==’10’
y=-1-y;
elseif a(1,2)==’01’
y=y+1;
end
3、实现滤波器设计的vhdl代码
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_signed.all;
use ieee.std_logic_unsigned.all;
entity iir is
port(x:in signed(23 downto 0);
rst,clk:in std_logic;
y:out signed(23 downto 0)
);
end entity;
architecture iir_arch of iir is
type arr1 is array (1 to 2) of signed (23 downto 0);
signal x1,x2,x3,x4,x5,x6:arr1;
signal y1,y2,y3,y4,y5,y6:arr1;
signal step:integer range 0 to 6;
constant a1:arr1:=("000001011000010011101000","000001000001111110010010") ;
constant a2:arr1:=("111110100111101100011000","000001000001111110010010") ;
constant a3:arr1:=("000011110010000110011100","000101110001011111100101") ;
constant a4:arr1:=("111100001101111001100100","000101110001011111100101") ;
constant a5:arr1:=("000100111001010100111100","001001100000110100101101") ;
constant a6:arr1:=("111011000110101011000100","001001100000110100101101") ;
constant b1:arr1:=("111110100011011000100010","110000110001010111100101") ;
constant b2:arr1:=("000001011100100111011110","110000110001010111100101") ;
constant b3:arr1:=("111100001111110110110101","110000011110101110001110") ;
constant b4:arr1:=("000011110000001001001011","110000011110101110001110") ;
constant b5:arr1:=("111011000110110100100010","110000001001101000001010") ;
constant b6:arr1:=("000100111001001011011110","110000001001101000001010") ;
begin
process(rst,clk)
variable acc:signed (47 downto 0);
begin
if rst='1' then step<=0;
elsif clk'event and clk='1' then
case(step) is
when 0=>
for i in 2 downto 1 loop
y1(i)<=(others=>'0');
y2(i)<=(others=>'0');
y3(i)<=(others=>'0');
y4(i)<=(others=>'0');
y5(i)<=(others=>'0');
y6(i)<=(others=>'0');
x1(i)<=(others=>'0');
x2(i)<=(others=>'0');
x3(i)<=(others=>'0');
x4(i)<=(others=>'0');
x5(i)<=(others=>'0');
x6(i)<=(others=>'0');
end loop;
when 1=>
acc:=x1(1)*a1(1)+x*a1(2)+x1(2)*a1(2)+y1(1)*b1(1)+y1(2)*b1(2);
y1(2)<=y1(1);
y1(1)<=acc(45 downto 22);
x1(2)<=x1(1);x1(1)<=x;
when 2=> acc:=x2(1)*a2(1)+y1(1)*a2(2)+x2(2)*a2(2)+y2(1)*b2(1)+y2(2)*b2(2);
y2(2)<=y2(1);
y2(1)<=acc(45 downto 22);
x2(2)<=x2(1);x2(1)<=y1(1);
when 3=> acc:=x3(1)*a3(1)+y2(1)*a3(2)+x3(2)*a3(2)+y3(1)*b3(1)+y3(2)*b3(2);
y3(2)<=y3(1);
y3(1)<=acc(45 downto 22);
x3(2)<=x3(1); x3(1)<=y2(1);
when 4=> acc:=x4(1)*a4(1)+y3(1)*a4(2)+x4(2)*a4(2)+y4(1)*b4(1)+y4(2)*b4(2);
y4(2)<=y4(1);
y4(1)<=acc(45 downto 22);
x4(2)<=x4(1); x4(1)<=y3(1);
when 5=>
acc:=x5(1)*a5(1)+y4(1)*a5(2)+x5(2)*a5(2)+y5(1)*b5(1)+y5(2)*b5(2);
y5(2)<=y5(1);
y5(1)<=acc(45 downto 22);
x5(2)<=x5(1);x5(1)<=y4(1);
when 6=> acc:=x6(1)*a6(1)+y5(1)*a6(2)+x6(2)*a6(2)+y6(1)*b6(1)+y6(2)*b6(2);
y6(2)<=y6(1);
y6(1)<=acc(45 downto 22);
x6(2)<=x6(1); x6(1)<=y5(1);
end case;
if step<6 then step<=step+1;
else step<=1;
end if;
end if;
y<=y6(1);
end process;
end iir_arch;