|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
本帖最后由 chdaj58 于 2023-11-30 16:05 编辑
(原创声明:该文是作者的原创,面向对象是FPGA入门者,后续会有进阶的高级教程。宗旨是让每个想做FPGA的人轻松入门,作者不光让大家知其然,还要让大家知其所以然!每个工程作者都搭建了全自动化的仿真环境,只需要双击top_tb.bat文件就可以完成整个的仿真(前提是安装了modelsim),降低了初学者的门槛。如需整个工程请留言(WX:Blue23Light),不收任何费用,但是仅供参考,不建议大家获得资料后从事一些商业活动!)
上节课我们将不同频率的正弦波叠加,造成输出波形上有很多毛刺,这在实际应用中,就是在我们需要的信号上叠加了干扰!如何去除干扰呢?那就要设计数字滤波器将干扰频率的波形滤除,保留需要的信号即可。
常用的数字滤波器有无限脉冲响应数字滤波器(Infinite Impulse Response),简称IIR滤波器;还有就是有限脉冲响应数字滤波器(Finite Impulse Response),简称FIR滤波器。
由于本节课程的重点不是讲数字滤波器的,所以要熟悉数字滤波器请去网上收索相关的内容,本节就是使用IIR滤波器来去除高频的干扰,让经过滤波器后的波形平滑。这儿只说明一点,IIR滤波器不光用到输入的数据,还需要输出的反馈数据,而FIR滤波器只需要输入的数据即可,所以从设计难度上来说,IIR设计难度更大一些。
设计IIR滤波器,可以不了解滤波的原理,但是要知道IIR的结构。IIR滤波器的系统函数的标准型如下所示:
但是FPGA设计的时候需要用的是差分型,如下所示:
以二阶的IIR为例,用matlab搭建的simulink仿真图如下所示,需要的参数有coeff_scale,coeff_in,coeff_out1和coeff_out2,只要确定这几个参数就可以完成IIR滤波器的设计。
下面讲述一下如何确定这几个参数,通过matlab的APP打开Filter Designer。
参数设置页面进行如下的设置,Response选择lowpass,IIR的Elliptic,Specify order选择2,采样频率Fs是2MHz(因为系统时钟是100MHz,50个系统时钟输入一个数据就是2MHz),Fpass设置是100KHz。最后点击Design Filter完成参数的设置。
然后点击File,Export。
最终将参数导入到Workspace即可,参数矩阵是SOS,增益参数是G。
SOS的第2个参数就是coeff_in,第5个参数是coeff_out1,第6个参数是coeff_out2;G的第2个参数就是coeff_scale。
得到的参数都是带小数点的,直接在FPGA内部是无法使用的,我们必须转换成16进制的定点数。可以使用指令y=fi(SOS,1,44,40),将SOS的数据转化成1个符号位,3个整数位,40个小数位的定点数,然后再使用y.hex指令将10进制的定点数转换成16进制的定点数。最终的参数如下所示。
有了参数,我们就开始IIR滤波器的设计。根据matlab的simulink仿真图,我们可以得到如下的差分公式:
y(n)=coeff_scale[x(n)+coeff_in*x(n-1)+x(n-2)]-coeff_out1*y(n-1)-coeff_out2*y(n-2),在这儿我们采用串行的方式,用一个乘法器来实现IIR的滤波。
为了模块的通用化,通过参数传递完成数据位宽的传递。这儿对数据位宽进行了扩展,考虑有多个加减法,直接将数据扩展了8位。输入的数据是9位,扩展8位后是17位。乘法运算后数据位宽再扩展44位,即61位。
下面是中间要使用信号的定义,需要注意位宽。
定义了相关的状态机,MULT_SCALE是完成coeff_scale*x(n)的计算,计算的结果存在mult_scale中,然后按照采样率打拍缓存到data_in_dly1(就是coeff_scale*x(n-1))和data_in_dly2(coeff_scale*x(n-2))中;状态机MULT_DI_DLY1是计算coeff_in*data_in_dly1;状态机MULT_DO_DLY1是计算coeff_out1*y(n-1);状态机MULT_DO_DLY2是计算coeff_out2*y(n+1);后面的四个状态机主要完成前面5个数据的加减运行,一个状态机完成一步的加或减。
状态机的跳转用组合逻辑实现,非常的简单,每次乘法或者加减法计算完成跳转到下一个状态,如下所示(代码太长,部分截图)。
例化了一个乘法器,4个时钟周期出计算结果,根据状态机给乘数和被乘数赋不同的值,并产生开始计算的mult_en信号,主要用于4个时钟的计数。如下图所示(代码太长,部分截图)。
乘法相关的信号,包括计数mult_cnt,乘法计算完成mult_vld,和结果mult_scale,mult_din,mult_dout1,mult_dout2等信号(代码太长,部分截图)。需要注意的是对乘法后的结果进行了小数位的截断,因为输入数据是整数,相乘后保留整数位即可,把小数直接舍弃即可。首位是符号位,是一定要取的。
根据状态机产生加减运算的使能信号addsub_en(代码太长,部分截图)。
产生加减法完成有效的信号addsub_vld,同时将输入和输出的数据按照采样率进行打拍,因为这儿用的是二阶的IIR,输入和输出打两拍即可,就是得到x(n-1),x(n-2),y(n-1),y(n-2)。
根据状态机完成加减法数据的运算。
最后就可以得到IIR滤波器的结果,注意经过IIR滤波器后输出数据的结果和输入数据的结果是一样的。
完成设计后,建立仿真文件,双击sim目录下的top_tb.bat文件,完成自动化的仿真。
仿真结果如下所示,经过IIR滤波后,基本恢复出来了低频的正弦波信号。滤波后的数据不是非常的平滑,可以改变滤波器的参数来改善一下。
IIR滤波器使用FPGA设计的流程就是这样的,读者可能会说如果需要更快的采样频率怎么办?我们可以大体评估一下现在的一次IIR需要多少时钟周期。一次乘法共需要8个时钟周期(进入状态机1个时钟,乘法使能1个时钟,计数了6次),一次加减法是3个时钟周期(进入状态机1个时钟,加减法使能1个时钟,出结果1个时钟),IIR的计数共用到了4次乘法和4次加法,那就是8*4+4*3=44个时钟周期,再加上IDLE和END各1个数时钟周期,那1次的IIR需要大约46个时钟周期。
如果想加快采样频率,那一次IIR的计数时间要缩短才可以!这儿就要设计FPGA设计的一个重要思想:用面积来换速度!因为上面的设计只用到了一个乘法器和加减法器,其实是可以使用多个乘法器和加减法器的。IIR可以使用4个乘法器(mult_scale*mult_din可以定义成一个参数),那就是8个时钟周期就可以完成所有乘法的运算;使用2个加减法器,4次的加减法可以缩短2次计数完成,那一次的IIR运算需要8+2*3+2=16个时钟周期!我们可以使用更多的FPGA资源来换取更快的处理速度!建议读者自己设计完成。
使用FIR滤波器也可以实现上面的功能,可能需要的阶数要多一些,建议读者自己来实现一下。
|
|