300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > FPGA学习记录(7)<巴特沃斯低通IIR滤波器FPGA实现>

FPGA学习记录(7)<巴特沃斯低通IIR滤波器FPGA实现>

时间:2024-01-03 11:13:45

相关推荐

FPGA学习记录(7)<巴特沃斯低通IIR滤波器FPGA实现>

目录

Matlab仿真IIR巴特沃斯低通滤波器并使用FPGA实现(1)IIR实现原理分析(2)IIR滤波器的设计①采用Matlab中的FDA设计软件进行参数设计②zero零点模块书写:③pole极点模块书写:④顶层模块书写:⑤testbench测试文件的书写:⑥Matlab生成待滤波的wave数据:⑦使用Modelsim仿真波形

Written by @hzj//JinXing Project#.10.24 V1.0#.10.25 V1.1#.10.27 V1.2#.10.28 V1.3

Matlab仿真IIR巴特沃斯低通滤波器并使用FPGA实现

(1)IIR实现原理分析

IIR滤波器:IIR滤波器的系统函数和差分方程如下所示:

H(z)=∑i=0Mbiz−i/(1−∑l=1Nalz−l)H(z)= \sum_{i=0}^Mb_iz^{-i} /(1-\sum_{l=1}^Na_lz^{-l})H(z)=∑i=0M​bi​z−i/(1−∑l=1N​al​z−l)

y(n)=∑i=0Mx(n−i)b(i)+∑l=1Ny(n−l)a(l)y(n)= \sum_{i=0}^Mx(n-i)b(i)+ \sum_{l=1}^Ny(n-l)a(l)y(n)=∑i=0M​x(n−i)b(i)+∑l=1N​y(n−l)a(l)

这里进行设计一个直接Ⅱ型的IIR滤波器 。还是以设计一个低通滤波器为目的,选择巴特沃斯滤波器为设计的主要目的。下午的为结构显示图,右边为零点部分,左边为极点部分。相对于直接Ⅰ型的滤波器,消耗的资源相对较小。根据我们上述的理论分析,其实IIR实质之上就是两个FIR进行一个叠加。零点部分的模块进行一个N位的移位,极点部分的模块进行一个N-1位的移位。由上述的理论分析可以知道,由于IIR的模块设计,那么可以使用一个顶层设计的方案,分别设计两个子模块进行调用。最终达到滤波的效果,下面开始进行设计IIR滤波器。

(2)IIR滤波器的设计

①采用Matlab中的FDA设计软件进行参数设计

设计一个低通滤波器,滤波器的采样频率为3000Hz,截至频率Fc为1000Hz,采用的IIR设计方法为巴特沃斯滤波器(Butterworth),指定阶数为7阶。由此构建的滤波器如下图所示。

下面开始导出系数:

选择Direct-Form Ⅰ, SOS

使用Ctrl +e快捷键进行导出系数

在命令行窗口进行输出,如下所示

>> NumNum =列 1 至 60.0817953182464095 0.572567227724866 1.71770168317462.862836138624332.86283613862433 1.7177016831746列 7 至 80.572567227724866 0.0817953182464095>> DenDen =列 1 至 612.317460277367333.028352850454992.391762487900611.24027554135094 0.407050515894209列 7 至 80.0782116476869789 0.00668741488534553

进行8bit的放大,放大后的结果如下,format long g这个参数就是可是让原来科学技术法的结果不按照科学计数法显示。

因此整理之后,可以获得:

>> round(Den * 2^6)ans =64 148 194 153 79 2650>> round(Num * 2^6)ans =5 37 110 183 183 110 375

②zero零点模块书写:

根据前面仿真得出的量化系数5 37 110 183 183 110 37 5,可以推断出,由于系数有对称性,那么这里只需使用到8/2=4个乘法器,现将data_reg[m]与data_reg[n-m]求和之后,再进行乘积。例如(data_reg[0] + data_reg[7]) * 5 = mul_reg[0]。因此只需要再在程序中进行二级制乘法转换即可。

`timescale 1ns/1ps//-------------------------------------------------------// IIR滤波器零点系数模块//-------------------------------------------------------//-------------------------------------------------------// 引脚模块定义//-------------------------------------------------------module zero_module(input clk, //时钟信号clkinput rst_n , //定义一个复位信号,复位信号按照下降沿有效input signed [11:0] zero_input , //零点模块的输入output signed [20:0] zero_output //零点模块的输出);//-------------------------------------------------------// IIR滤波器中进行移位的部分,按照clk时钟周期,依次输入波// 形数据,同时也应该在rst_n为1'b0的时候进行置零//-------------------------------------------------------reg signed [11:0] data_reg [6:0];always@(posedge clk or negedge rst_n) beginif(rst_n == 1'b0) begin//复位信号,系统进行置零操作,复位信号低电平有效data_reg[0] <= 12'b0 ;data_reg[1] <= 12'b0 ;data_reg[2] <= 12'b0 ;data_reg[3] <= 12'b0 ;data_reg[4] <= 12'b0 ;data_reg[5] <= 12'b0 ;data_reg[6] <= 12'b0 ;endelse begin //普通时钟周期信号,依次进行移位操作,将新的数据进行送入data_reg[6] <= data_reg[5] ;data_reg[5] <= data_reg[4] ; data_reg[4] <= data_reg[3] ;data_reg[3] <= data_reg[2] ;data_reg[2] <= data_reg[1] ;data_reg[1] <= data_reg[0] ;data_reg[0] <= zero_input ;endend//-------------------------------------------------------// IIR滤波器的零点由于系数都是对称的,因此可以通过这样子减// 少器件,先进行加法运算//-------------------------------------------------------wire signed [12:0] add_reg [3:0];assign add_reg[0] = {zero_input[11], zero_input} + {data_reg[6][11], data_reg[6]} ;assign add_reg[1] = {data_reg[0][11], data_reg[0]} + {data_reg[5][11], data_reg[5]} ;assign add_reg[2] = {data_reg[1][11], data_reg[1]} + {data_reg[4][11], data_reg[4]} ;assign add_reg[3] = {data_reg[2][11], data_reg[2]} + {data_reg[3][11], data_reg[3]} ;//-------------------------------------------------------// IIR滤波器使用已经加好的数进行卷积//-------------------------------------------------------wire signed [20:0] mult_reg [3:0];assign mult_reg[0] = {{{6{add_reg[0][12]}}, add_reg[0], 2'b0} + {{8{add_reg[0][12]}}, add_reg[0]}} ;//*5_101assign mult_reg[1] = {{{3{add_reg[1][12]}}, add_reg[1], 5'b0} + {{6{add_reg[1][12]}}, add_reg[1], 2'b0} + {{8{add_reg[1][12]}}, add_reg[1]}} ;//*37_100101assign mult_reg[2] = {{{2{add_reg[2][12]}}, add_reg[2], 6'b0} + {{3{add_reg[2][12]}}, add_reg[2], 5'b0} + {{5{add_reg[2][12]}}, add_reg[2], 3'b0} + {{6{add_reg[2][12]}}, add_reg[2], 2'b0} + {{7{add_reg[2][12]}}, add_reg[2], 1'b0}} ;//*110_1101110assign mult_reg[3] = {{{1{add_reg[3][12]}}, add_reg[3], 7'b0} + {{3{add_reg[3][12]}}, add_reg[3], 5'b0} + {{4{add_reg[3][12]}}, add_reg[3], 4'b0} + {{6{add_reg[3][12]}}, add_reg[3], 2'b0} + {{7{add_reg[3][12]}}, add_reg[3], 1'b0} + {{8{add_reg[3][12]}}, add_reg[3]}} ;//*183_10110111 //-------------------------------------------------------// 卷积运算之后进行求和输出//-------------------------------------------------------assign zero_output = mult_reg[0] + mult_reg[1] + mult_reg[2] + mult_reg[3];endmodule

③pole极点模块书写:

与零点一样,当成一个FIR滤波器进行操作,但是由于这里的系数不再具有对称性,因此,我们使用时就不能再进行相加再乘。不能偷懒就很烦…只能依次进行移位乘法(注意一下,若是这个里面有负数,我们可以先乘这个数的绝对值,在进行取补码的操作,但是一定要保证符号位多一位,不然可能会出现问题,解决方案也很简单,扩充一个符号位就可以了)。根据前文求出来的系数:64 148 194 153 79 26 5 0,按照原理中的要求,从第一位开始(这里要舍弃第0位),依次进行与波形数据的乘法,如果有疑问,可以再在前文看看公式。

`timescale 1ns/1ps//-------------------------------------------------------// IIR滤波器极点系数模块//-------------------------------------------------------//-------------------------------------------------------// 引脚模块定义//-------------------------------------------------------module pole_module(input clk,//时钟信号input rst_n ,//复位信号,使能高电平有效input signed [11:0] pole_input,//输入信号output signed [25:0] pole_output//输出信号);//-------------------------------------------------------// 还是pole模块由于是N-1位,因此这个地方我们只需要8-1个寄存器进行存储// 因此该处定义的是7位的reg信号,信号的带宽与输入的带宽相同,也就是即// 12位。复位信号清零;clk信号进行移位;//-------------------------------------------------------reg signed [11:0] data_reg [6:0];always@(posedge clk or negedge rst_n)if(rst_n == 1'b0) begin //复位信号,系统进行置零操作,复位信号低电平有效data_reg[0] <= 12'd0 ;data_reg[1] <= 12'd0 ;data_reg[2] <= 12'd0 ;data_reg[3] <= 12'd0 ;data_reg[4] <= 12'd0 ;data_reg[5] <= 12'd0 ;data_reg[6] <= 12'd0 ;end else begin //普通时钟周期信号,依次进行移位操作,将新的数据进行送入data_reg[6] <= data_reg[5] ;data_reg[5] <= data_reg[4] ;data_reg[4] <= data_reg[3] ;data_reg[3] <= data_reg[2] ;data_reg[2] <= data_reg[1] ;data_reg[1] <= data_reg[0] ;data_reg[0] <= pole_input ; end//-------------------------------------------------------// 滤波器的系数,量化之后,量化2^6// 使用组合逻辑进行乘法的操作。//-------------------------------------------------------wire [25:0] mult_pole [6:0];assign mult_pole[0] = {{{7{data_reg[1][11]}}, data_reg[1], 7'b0} + {{10{data_reg[1][11]}}, data_reg[1], 4'b0} + {{12{data_reg[1][11]}}, data_reg[1], 2'b0}};//*148_10010100assign mult_pole[1] = {{{7{data_reg[2][11]}}, data_reg[2], 7'b0} + {{8{data_reg[2][11]}}, data_reg[2], 6'b0} + {{13{data_reg[2][11]}}, data_reg[2], 1'b0}};//*194_11000010assign mult_pole[2] = {{{7{data_reg[3][11]}}, data_reg[3], 7'b0} + {{10{data_reg[3][11]}}, data_reg[3], 4'b0} + {{11{data_reg[3][11]}}, data_reg[3], 3'b0} + {{14{data_reg[3][11]}}, data_reg[3]}};//*153_10011001assign mult_pole[3] = {{{8{data_reg[4][11]}}, data_reg[4], 6'b0} + {{11{data_reg[4][11]}}, data_reg[4], 3'b0} + {{12{data_reg[4][11]}}, data_reg[4], 2'b0} + {{13{data_reg[4][11]}}, data_reg[4], 1'b0} + {{14{data_reg[4][11]}}, data_reg[4]}};//*79_1001111assign mult_pole[4] = {{{10{data_reg[5][11]}}, data_reg[5], 4'b0} + {{11{data_reg[5][11]}}, data_reg[5], 3'b0} + {{13{data_reg[5][11]}}, data_reg[5], 1'b0}};//*26_11010assign mult_pole[5] = {{{12{data_reg[6][11]}}, data_reg[6], 2'b0} + {{14{data_reg[6][11]}}, data_reg[6]}};//*5_101assign mult_pole[6] = 26'b0;//-------------------------------------------------------// 求卷积和;将前面所有的乘积进行求和,并且输出置Yout// 将前面7个已经完成乘法的寄存器中的数据进行加法运算//-------------------------------------------------------assign pole_output = {mult_pole[0] + mult_pole[1] + mult_pole[2] + mult_pole[3] + mult_pole[4] + mult_pole[5] + mult_pole[6]};endmodule

④顶层模块书写:

顶层模块的目的就是要构造成为一个IIR,前文相当于可以看成是两个FIR模块。因此,程序中调用前面的两个子模块module_zero以及module_pole。然后将零极点的输出值进行相减,除法的操作,最终输出我们滤波后的波形数据。输入波形的数据位数位12位,输出波形数据的数据位也为12位。

`timescale 1ns/1ps//-------------------------------------------------------// IIR滤波器顶层模块//-------------------------------------------------------module IIR_top(input clk ,input rst_n,input signed [11:0] IIR_input ,output reg signed [11:0] IIR_output);//-------------------------------------------------------// 调用零点模块//-------------------------------------------------------wire signed [20:0] zero_out ;wire signed [11:0] pole_in ;wire signed [25:0] feedback ;//-------------------------------------------------------// 根据时钟信号,来控制波形的输入值wave_in;//-------------------------------------------------------always@(posedge clk or negedge rst_n)if(rst_n == 1'b0)beginIIR_output <= 12'b0; //复位信号,下降沿有效endelse beginIIR_output <= pole_in; //正常周期信号clk状态下依次进行输入波形数据endzero_module zero(.rst_n (rst_n) ,.clk (clk) ,.zero_input (IIR_input) ,.zero_output(zero_out));//-------------------------------------------------------// 调用极点模块//-------------------------------------------------------pole_module pole(.clk (clk) ,.rst_n (rst_n) ,.pole_input (pole_in) ,.pole_output(feedback) );//-------------------------------------------------------// 顶层模块进行求差值以及乘积的工作,构成IIR模块//-------------------------------------------------------wire signed [25:0] sub_module;wire signed [25:0] div_module;assign sub_module = {{5{zero_out[20]}}, zero_out} - feedback ;//零点的输出与极点的输出进行相减assign div_module = {{9{sub_module[25]}}, sub_module[25:9]} ;//求出的差值进行移位除法assign pole_in = div_module[11:0] ;//输入信号的位数是12位。输出信号的位数也是12位endmodule

⑤testbench测试文件的书写:

//~ `New testbench`timescale 1ns / 1psmodule tb_IIR_top;// IIR_top Parametersparameter PERIOD = 10;// IIR_top Inputsreg clk ;reg rst_n ;reg [11:0] wave_in ;// IIR_top Outputswire [11:0] wave_out;integer i ;initial beginclk = 0;rst_n= 0;wave_in = 0;i= 0;endinitialbeginforever #(PERIOD/2) clk=~clk;endinitialbegin#(PERIOD*2) rst_n = 1;endparameter DATA_NUM = 32'd10000;reg [11:0] data_men[DATA_NUM:1];initial begin$readmemb("绝对路径/tb/sin.txt",data_men); //注意斜杠的方向,不能反<<<<<<<endalways @(posedge clk or negedge rst_n) begin //每1个clk信号来临后,进行一次数据输入,将新的一个波形数据输入Din中。wave_in <= data_men[i];i <= i+1;endIIR_top u_IIR_top (.clk ( clk ),.rst_n ( rst_n ),.IIR_input( wave_in [11:0] ),.IIR_output ( wave_out [11:0] ));endmodule

⑥Matlab生成待滤波的wave数据:

所有准备工作完成之后,就应该准备输入信号,因为这里是做的一个低通滤波器,因此,我们的输入信号中,有一个较高频率的信号,一个在通带里面的信号。根据采样频率为3000Hz,那么据采样定理最多可以采到的波形频率为1500Hz,这样的话,便设置一个杂波信号的频率为1400Hz的正弦波,源信号为500Hz,Fs采样频率为3000Hz,量化位数与Verilog代码相匹配,采用的是12位的量化。生成一组十进制采样的正弦信号以及一个二进制化的正弦信号。Matlab波形生成程序的名称命名为IIR_IN_DES.m

f1 = 500;f2 = 1400;Fs = 3000;N = 12;End = 100;t = 0:1/Fs:End-1/Fs;c1 = 2*pi*f1*t;c2 = 2*pi*f2*t;s1 = sin(c1);s2 = 0.5*sin(c2);s = s1+s2;s = s/max(abs(s));Q_s = round(s*(2^(N-1) - 1));fid = fopen('..\tb\sin_ten.txt','w');fprintf(fid, '%12d\r\n',Q_s);fprintf(fid, ';');fclose(fid);fid = fopen('..\tb\sin.txt','w');for k=1:length(Q_s)%二进制变换B_s=dec2bin(Q_s(k)+((Q_s(k))<0)*2^N,N);for j=1:Nif B_s(j)=='1'tb=1;elsetb=0;endfprintf(fid,'%d',tb);endfprintf(fid,'\r\n');endfprintf(fid,';');fclose(fid);

⑦使用Modelsim仿真波形

书写sim.do文件,如下所示,同时加入modelsim_run.bat批处理文件,进行一键执行仿真。do文件如下所示。

vlib work vmap work workvlog -work work "../src/*.v"vlog -work work "../tb/*.v"vsim -voptargs=+acc work.tb_IIR_topadd wave -position insertpoint \sim:/tb_IIR_top/*do wave.dorun 10000ns

点击批处理文件进行一键执行,仿真后的波形如下所示

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。