IIR与FIR滤波器设计与比较Word文档格式.docx
《IIR与FIR滤波器设计与比较Word文档格式.docx》由会员分享,可在线阅读,更多相关《IIR与FIR滤波器设计与比较Word文档格式.docx(38页珍藏版)》请在冰豆网上搜索。
利用DSP可以实时地对信号进行数字滤波。
本设计要求利用DSP的DMA方式进行信号采集和信号输出,同时对外部输入的信号进行数字滤波。
在滤波时同时用fir与iir滤波器进行滤波,并比较二者的区别。
二、设计内容
(1)对DMA进行初始化;
(2)对A/D、D/A进行初始化;
(3)编写DMA中断服务程序,实现信号的实时滤波;
(4)利用CCS信号分析工具分析信号的频谱成分,确定滤波器的参数,利用MATLAB设计数字滤波器,提取滤波器参数;
(5)设计数字滤波算法,或调用DSPLIB中的滤波函数,实现对信号的fir滤波。
(6)比较加不同窗和阶数时fir滤波器的滤波效果;
(7)设计数字滤波算法,或调用DSPLIB中的滤波函数,实现对信号的iir滤波。
(8)比较fir数字滤波器与iir数字滤波器的效果
三、设计方案、算法原理说明
(一)硬件原理:
McBSP是多通道缓冲串行口,他支持全双工通信,双缓冲数据寄存器,允许连续的数据流。
支持传输的数据字长可以是8位、12位、16位、20位、24位或32位。
并且内置u律和A律压扩硬件。
McBSP在结构上可以分为一个数据通道和一个控制通道。
数据通道完成数据的发送和接受。
控制通道完成的任务包括内部时钟的产生、帧同步信号产生、对这些信号的控制及多通道的选择等。
控制通道还负责产生接口信号送往CPU,产生同步事件通知DMA控制器。
在CCS集成开发环境中,与McBSP相关的头文件有:
regs54xx.h、mcbsp54.h。
在这两个头文件中,定义了McBSP串行口的寄存器资源及使用方法。
TLC320AD50C是TI公司生产的SIGMA-DELTA型的16位A/D、D/A转换电路,他的采样速率最高可达22.05kb/s,内涵抗混叠滤波器和重构滤波器,属于模拟接口芯片(AIC),它有一个能与多种昂DSP芯片相连的同步串行通信接口,其采样速率课通过DSP编程来设置。
在DAC之前有一个插值滤波器一保证输出信号平滑,在ADC之后有一个抽取滤波器以提高输入信号的信噪比。
AD50C片内还包括一个定时器(调整采样率和帧同步延时)和控制器(可编程的增益放大器,锁相环PLL,通信协议等)。
AD50有28脚的塑料SOP封装(带DW后缀)和48脚的塑料扁平QFP封装(带PT后缀),体积较小,适用于便携设备。
AD50C的工作温度范围是0-70摄氏度,单一5V电源供电或5V模拟电源和3.3V数字电源供电,最大功耗为120mW。
在CCS集成开发环境中,与TLC320AD50CCODEC相关的头文件是codec.h。
在这个头文件中,定义了与ad50CODEC相关的枚举变量和库函数。
除了可以调用codec.h中提供的库函数之外,还可以利用这些枚举变量自己重新编写codec函数,使用枚举变量相互产生所需要的ad50寄存器的初始化值。
Codec.h中的库函数位于函数库dsk5402.lib和drv5402.lib中。
(二)滤波器的理论设计分析
1.直接存储器访问DMA:
直接存储器访问(DirectMemoryAccess,简称DMA)是C54xDSP非常重要的片上外设,
DMA控制器可以完成数据传输而不影响CPU,因此数据传输速度快。
在要求信号实时采集和处理的系统中常采用DMA方式进行信号采集与传输。
本实验利用DMA通道2与McBSP1通道结合来读取A\D转换数据,利用DMA通道3与McBSP1通道结合来将处理后的数据发送至D\A。
当一组数据处理完后,将数据存放在存储区out_buffer+frame*0x100中,选择out_buffer+frame*0x100为DMA通道3传送数据首地址,并选择源地址工作在不调整模式。
2.IIR滤波原理:
IIR数字滤波器差分方程的一般形式为:
式中ai、bi为滤波系数。
当bi全为零时,该滤波器为FIR数字滤波器;
当bi不全为零时,则为IIR滤波器。
IIR数字滤波器可用直接型、级联型和并联型三种基本结构实现,其基本组成单元如图1所示。
对于二阶IIR数字滤波器,其传递函数为:
n时刻IIR数字滤波器输出和输入关系为:
其中x(n)是输入序列,y(n)是输出序列,ai、bI为滤波器系数。
因此滤波器的输出可以用硬件乘法器和加法器实现。
在本实验中将IIR滤波器的系统函数H(z)分解为n个二阶IIR滤波器级联的形式进行运算,这样可以减小量化误差。
3.IIR滤波函数
本实验信号滤波算法是直接从TMS320c54XDSPLIB库中调用IIR函数。
IIR函数调用格式:
iircas4(DATA*x,DATA*h,DATA*r,DATA**d,ushortnbiq,ushortnx);
iircas5(DATA*x,DATA*h,DATA*r,DATA**d,ushortnbiq,ushortnx);
iircas51(DATA*x,DATA*h,DATA*r,DATA**d,ushortnbiq,ushortnx);
iir32(DATA*x,LDATA*h,DATA*r,LDATA**d,ushortnbiq,ushortnx);
其中,iircas32函数用于双精度IIR滤波器;
iircas4函数用于二阶级联直接II型滤波器,每项含4个系数;
iircas5函数用于二阶级联直接II型滤波器,每项含5个系数;
iircas51二阶级联直接I型滤波器,每项含五个系数。
调用matlab产生滤波器系数时,由于a0始终为1,所以可以产生二阶级联型系数,每项调用a1,a2,b0,b1,b2五个系数。
iircas5用于通过各部分的放缩系数使各部分增益小于1的情况同时防止溢出的情况。
在IIR数字滤波器的实现中,直接II型相比直接I型节省了一半的延迟单元,因而成为IIR滤波器实现最常用的形式。
综上所述,我们采用irrcas5函数实现信号的滤波。
调用参数说明:
iircas5(DATA*x,DATA*h,DATA*r,DATA**dbuffer,ushortnbiq,ushortnx)
x[k]为输入数组,
h[k]为H(s)系数数组,按照a11a21b21b01b11....a1ia2ib2ib0ib1i的顺序输入,其中i为biquad的个数;
r[nx]为输出数组,
dbuffer为延迟数据区,
nbiq为H(s)分成二阶滤波器的个数
nx为输入长度.
相比较与其他几种调用函数,
4.Fir滤波原理:
假设FIR滤波器的单位脉冲响应为h[0]、h[1]、...、h[N-1],x[k]为待滤波的输入信号,则滤波器输出为y[k]=h[k]*x[k]=
进行信号滤波实际上师计算序列的线性卷积。
在实验中滤波器单位脉冲响应h[k]是有限长N,而x[k]一般是外部输入的长序列,因而采用重叠像假发计算卷积。
重叠相加法是求解段序列与长序列卷积的一种方法。
首先将输入长序列分解为短序列,这些短序列分别于h[k]卷积,将每段计算结果中后N-1个数据保留在一个缓冲区中,以便于下一段卷积结果进行重叠相加。
5.FIR滤波函数
本实验信号滤波算法是直接从TMS320c54XDSPLIB库中调用FIR函数。
FIR函数调用格式:
oflag=shortfir(DATA*x,DATA*h,DATA*r,DATA**dbuffer,ushortnh,ushortnx)
功能用FIR滤波器对信号滤波
调用参数说明:
x[nx]表示含有nx个实数的实输入信号向量;
h[nh]表示含有nh个实数的系数向量,按自然顺序
排列,即滤波器的单位脉冲响应。
r[nx]表示含有nx个实数的输出向量;
允许原位运算,即r=x。
dbuffer[nh]延迟缓冲区;
对存储器的要求同h[nh]。
nx向量x中实数的个数;
nh向量h中系数的个数;
oflag=1有溢出;
oflag=0无溢出
(三)设计流程图:
分配各数据段,并且给个数据段赋值
利用硬件实现滤波器的信号滤波,就是将MATLAB所产生的系数,与被取样的实时信号进行运算。
将滤波器系数导入程序当中一般有两种方式:
一、是将MATLAB产生的系数,生成头文件,在程序中进行调用。
二、将MATLAB产生的系数写入数据段中,在程序中调用,此过程涉及到IIR滤波器的系数被截取,量化,调整和量化误差的产生。
信号与滤波器系数的运算也有两种方法:
一、调用DSPLIB中的IIR、FIR调用函数。
二、利用C语言,编辑一段程序进行运算。
(四)系数的导入与量化
1.头文件方式导入
在MATLAB中利用FDATOOL产生所需滤波器,选择菜单Targets一>
ExporttoCodeComposerStudio™IDE.打开ExporttoCHeaderFile对话框,选择Cheaderfile,指定变量名(滤波器阶数和系数向量),输出数据类型可选浮点型或32b、16b整型等。
根据自己安装选择目标板板号和处理器号。
单击OK。
保存该头文件,需指定文件名和路径,打开IIR工程文件夹,该滤波器系数头文件已含在工程中。
该头文件用到MatLab中的tmwpytes.h,需把该文件也包含在工程中.还要在原文件中声明包含滤波器参数头文件.即:
#include头文件名称
includetmwpytes.h
然后编译、链接工程.添加的头文件自动在工程目录中显示.目标DSP自动为滤波器系数分配相应的存储空间。
打开系数文件查看生成的滤波器系数,可看到系数是对称的,这由所选滤波器类型而定。
由于本次的设计的拓展部分主要以设计IIR滤波器为主要目标,IIR滤波器系数存在着格式转换和量化的问题,不能够直接导入到CCS中直接去进行硬件实现,这样会导致滤波器系数的信息被截断,信息丢失,导致滤波器无法实现。
所以我采用第二种方法。
2.直接写入存储器
滤波器的系数可以用FDATOOL进行计算出来,也可以导出到MATLAB的workspace中去计算量化。
我们所使用的DSK5402实验板是16位定点运算,而MATLAB所产生的系数,并不是定点数而是浮点数。
所以需要将MATLAB所产生的浮点数进行转化,使其转换为浮点数,浮点数格式的导出:
一般在FIR滤波器中这种定点的转化都是使用MATLAB中FDATOOL的ExporttoCHeaderFile方式来进行转化。
但是与FIR不同的是IIR不一定是稳定的系统,即使稳定,也未必能够达到硬件实现。
MATLAB提供的转化方法并没有对于越界的系数进行量化。
例如:
Sos=[1,2,1,1,-1.19,0.45]
本是一个稳定的高阶IIR滤波器的系数矩阵中的一维向量,表示直接II型级联形式的一部分。
经过MATLAB的16位定点量化后成为了
Sos=[32767,32767,32767,32767,-32768,14715]
成为了一个不稳定的系统,从而硬件实现就不可能了。
A.系数的转化
MATLAB的带符号定点16位转化是,将所有大于1,小于-1的数值全部归一化,造成了巨大的量化误差,众所周知,IIR滤波器的实现过程中存在着反馈,于是累进量化误差越来越大造成了系统的不稳定。
量化问题中不得不提的还有一个标准格式问题。
由于MATLAB所产生的浮点系数并没有依照CCS中DSPLIB的IIR能够调用的数据格式。
经过查阅资料以及多次的失败尝试积累出的经验,了解到我所要设计的IIR滤波器所需使用的IIRCAS5调用命令使用的是Q15数据格式,而MATLAB所产生的浮点值是Q14数据格式,而在进行定点转换时,MATLAB没有将Q14的数据格式量化,进行大误差归一化直接转化为Q15的定点形式所以造成硬件实现的失败。
MATLAB产生的系数一般已经是满足ccs调用函数的second-order形式了。
一次滤波器为例,产生的系数为:
∙--------------------------
∙Section#1
∙Numerator:
∙1
∙2
∙Denominator:
∙-1.195433962890738
∙0.69059892324149696
∙Gain:
∙0.12379124008768973
∙Section#2
∙-0.94280904158206336
∙0.33333333333333343
∙0.09763107293781749
∙Section#3
∙-0.84028692165132679
∙0.18834516088404471
∙0.087014559808179473
∙OutputGain:
其中Numerator就是分子部分,也就是b,其中Deneminator就是分母部分也就是a,Gain就是增益,一般计算系数,只需将分子部分乘以各部分增益,在转化为定点数。
分母部分只需将其转化为定点部分就可以了。
但是,这个系数中,存在着一项a1<
-1,就是第二部分的a1,所以直接转化,就会出现巨大的错误,就需要先对其进行量化,防止这个系数所造成的溢出情况。
Q14,Q15数据格式Q后的数字分别表示小数的位数,Q15表示的是15位小数,由于16位的系统,所以只有一位是标志位,其余的15位全部表示的是小数,所以Q15表示的数值范围近似于是(-1,1)。
同理可见,Q14所表示的位数为14位,其数值范围近似为(-2,2)。
于是MATLAB产生的浮点数的大小是不确定的,这要根据所设计的滤波器的系数产生。
Q14浮点数向Q15定点数的转化,往往采取以下公式,
B=A/2*32767;
其中B为Q15格式,A位Q14格式。
B.系数的量化
由上面的IIR滤波器的理论分析可知其原理,D(n)作为中间变量,如果系数中出现了比1大或是比-1小的情况,如若存在在分子上面可以通过调整各部分增益来减少溢出的产生,就会造成IIR滤波器的溢出,而这大于1的系数往往存在在a1的系数上,无法类似于采用级联方式改变增益和衰减来调整,这对于DSP的影响是毁灭性的,所以IIR滤波器的系数量化是非常重要的。
经过查阅资料,对于滤波器的量化,一般采取将系数向量除以一个数,使他满足Q15数据格式的要求,一般这个数值要大于最大的系数,往往是2的幂,这样在进行转化的时候,能够减小因四舍五入截断时的误差。
对于a1>
1的情况,我才用了如下的公式来进行量化和数据格式转换:
a=[];
b=[];
a=a/2*32767*g;
b=b/2*32767
其中,a为分母,b为分子;
g为各项增益
这个公式所形成的矩阵就可以应用到IIRCAS5的数据格式要求中,减小了溢出的可能性。
C.误差分析
(1)对IIR数字滤波器的系数,采用定点Q0格式进行数据的处理,将引入系数量化误差;
(2)对输入的测试信号,采用定点Q0格式进行数据的处理,将引入输入信号的量化误差;
(3)由于使用的A/D,D/A转换器件为有限字长,如D/A转换器的字长仅10b或12b。
在软件程序中事先要把数据化为相同的字长位数,再送到D/A转换器,也将引入量化误差。
(4)对数字滤波的运算过程编制相应的程序,其中滤波器选用直接型、级联型还是并联型,将产生不同的运算量化误差。
四、程序设计、调试与结果分析
本次试验使用的FIR与IIR滤波器程序主体大致相同,所以只是对fir_dma.c中的与IIR与FIR两种不同的滤波器的相关系数进行了修改,下面列出的是IIR滤波器的设计程序。
(一)准备工作:
需要将头文件等库函数都装入到指定位置:
1、drv5402.lib是软件仿真所用的仿真器所必需的库文件;
2、dsk5402.lib是驱动DSK板所必需的库文件;
3、rts.lib,这个库提供目标DSP运行时间支持(runtime-support)。
由于程序没有#include,因此本程序不需要头文件。
上图是编译成功的结果显示:
无错误和警告!
这是最终调试成功的结果,首次运行时有11个错误,主要是_cosx和_COSX的混淆,分号的误写等。
因此,本程序所使用的配置文件有:
(1)、-c,即源程序文件;
(2)、-o,ifr_dma.out即输出文件(默认在Debug目录);
(3)、-lrts.lib等库文件。
(二)程序清单:
通过理解iir的基本原理,也可以通过c语言或是汇编语言进行编写,同样可以达到滤波的效果。
因为有调用函数,使用起来比此程序方便,所以只是用了函数来实现。
1.主程序:
/*声明头文件*/
#include<
type.h>
board.h>
codec.h>
firlab.h>
string.h>
dsplib.h>
/*****************************************************************************/
/*FunctionPrototypes*/
voiddelay(s16period);
externvoidDMAC2ISR();
/*声明DMAC2ISR为外部函数*/
/*全局变量的定义*/
HANDLEhHandset;
unsignedintdmsefc,dmmcr,dmctr,src_addr,dst_addr;
unsignedintdmpre,dmsrcp,dmdstp,dmidx0,dmidx1,dmfri0,dmfri1,dmgsa,dmgda,dmgcr,dmgfr;
/*给输入缓冲区建立字段*/
#pragmaDATA_SECTION(inp_buffer,"
audio_buffer"
);
intinp_buffer[0x200];
/*给输出缓冲区建立字段*/
#pragmaDATA_SECTION(out_buffer,"
outt_buffer"
intout_buffer[0x200];
/*为系数建立字段*/
#pragmaDATA_SECTION(coeffs,"
coefficients"
/*iir,butterworth低通滤波器fs=16000fc=2000Hz*/
intcoeffs[15]={
-13765,
3085,
1425,
2851,
-19585,
11314,
1756,
3513,
-15446,
5461,
1846,
3693
};
/*firhann低通fs=16000,fc=2000*/
//intcoeff[16]={-43,-178,-407,-353,671,2968,5860,7903,7903,
5860,2968,671,-353,-407,-178,-43};
#pragmaDATA_SECTION(delaybuff,"
delayb"
intdelaybuff[6]={0};
//intdelaybuff[16]={0}
/*给中断服务寄存器定义变量*/
intframe=0;
intflag=0;
inttemp;
intcurrbuff=0;
/*delayptr指针变量指向延迟缓冲区的首地址*/
int*delayptr1=&
(delaybuff[0]);
interruptvoidDMAC2ISR();
/*主程序*/
voidmain()
{
s16cnt=2;
/*需要用到的bois的部分定义*/
BSCR=0x8806;
XPC=0;
PMST=0xA0;
brd_set_cpu_freq(100);
TIMER_HALT(0);
brd_set_wait_states(7,7,9);
TIMER_RESET(0);
IMR=0;
//禁止所有中断
if(brd_init_bios())
return;
while(cnt--)
{
brd_led_toggle(BRD_LED0);
//切换LED指示灯0的显示状态
delay(1000);
brd_led_toggle(BRD_LED1