300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > FPGA:verilog实现直接型巴特沃斯高通IIR滤波器

FPGA:verilog实现直接型巴特沃斯高通IIR滤波器

时间:2022-06-05 18:12:44

相关推荐

FPGA:verilog实现直接型巴特沃斯高通IIR滤波器

目录

前言

1、matlab设计滤波器

1.1、通过FDATOOL设计滤波器

1.2、对滤波器系数进行量化

2、verilog设计IIR滤波器

2.1 零点模块

2.2 极点模块

2.3 顶层文件

3、vivado仿真

3.1 matlab生成测试数据

3.2vivado添加测试数据

3.3添加tb文件运行仿真

总结

前言

在matlab设计7阶(8级)高通IIR巴特沃斯滤波器,并实现verilog代码,并在vivado中进行仿真

1、matlab设计滤波器

1.1、通过FDATOOL设计滤波器

打开matlab,在APP这一栏的搜索框中搜索 ’filter‘ 或直接搜索 ’滤波器‘ ,单击打开(matlab版本为a)

我们要设计的滤波器的相应类型为高通,设计方法为IIR 巴特沃斯,采样频率Fs设置为1M(1000k),Fc设置为200k。在下面的界面填好这些参数,并点击设计滤波器。

我们可以从当前滤波器信息窗口看到,我们设计的滤波器目前的结构是级联型,七阶(8)级的滤波器被设计为4个节,其中三个节是2阶(3级),一个节是1阶(2级),2*3+1 = 7,组成了我们的七阶滤波器。

为了设计成直接型,我们对滤波器的结构进行转换

打开编辑-转换结构

选择Direct-Form Ⅰ

转化为单节

到这里就完成了到直接型的转化,下一步我们可以看看量化效应,对滤波器效果的影响,根据下图操作,可以看到幅值响应区域出现了量化前后的幅频响应曲线。

可以看到16位量化后,滤波器的性能产生了恶化,但在可接受范围内,实际工程中可以通过级联型的滤波器来减小量化带来的误差。

进行如下操作,将滤波器系数导出到matlab工作区

Den Num这里分别是分母和分子

1.2、对滤波器系数进行量化

在matlab中运行下面代码(来自杜勇老师的《数字滤波器的matlab与fpga实现》)

Qcoe = 16b = Num;a = Den;%对滤波器系数进行量化,四舍五入截尾m=max(max(abs(a),abs(b)));Qm = floor(log2(m/a(1)))if Qm<log2(m/a(1))Qm = Qm + 1;endQm = 2^Qm;Qb16=round(b/Qm*(2^(Qcoe-1)-1))Qa16=round(a/Qm*(2^(Qcoe-1)-1))

运行结果如下:

Qb16 =列 1 至 5742 -5197 15590-25982 25982列 6 至 8-15590 5197 -742Qa16 =列 1 至 516384-22761 27443-17266 8332列 6 至 8-2373 430 -33

可以看到零点系数Qb16具有对称性

2、verilog设计IIR滤波器

2.1 零点模块

module Zero(input rst, input clk,input signed [11:0]Xin,output signed [30:0]Xout);//-------------------------------------------------------// 将数据移位寄存//-------------------------------------------------------reg signed [11:0] Xin_Reg[6:0];reg [3:0] i,j; always @(posedge clk or posedge rst)if (rst)begin for (i=0; i<7; i=i+1)Xin_Reg[i]=12'd0;endelsebeginfor (j=0; j<6; j=j+1)Xin_Reg[j+1] <= Xin_Reg[j];Xin_Reg[0] <= Xin;end//-------------------------------------------------------// 将对称数据相加,结果存储在数组中 2个12bit数据相加,结果为13bit//-------------------------------------------------------wire signed [12:0] Add_Reg[3:0];assign Add_Reg[0] = {Xin[11],Xin}- {Xin_Reg[6][11],Xin_Reg[6]};assign Add_Reg[1] = {Xin_Reg[0][11],Xin_Reg[0]} - {Xin_Reg[5][11],Xin_Reg[5]};assign Add_Reg[2] = {Xin_Reg[1][11],Xin_Reg[1]} - {Xin_Reg[4][11],Xin_Reg[4]};assign Add_Reg[3] = {Xin_Reg[2][11],Xin_Reg[2]} - {Xin_Reg[3][11],Xin_Reg[3]};//-------------------------------------------------------// 将数据与系数相乘,结果存储在数组中 13bit与16bit相乘,结果为28bit//-------------------------------------------------------wire signed [27:0] Mult_Reg[3:0];wire signed [15:0] coe [3:0];assign coe[0] = 16'd742;assign coe[1] = -16'd5196;assign coe[2] = 16'd15589;assign coe[3] = -16'd25982;//-------------------------------------------------------// 调用4个乘法器,设置为13bit有符号数和16bit有符号数相乘//-------------------------------------------------------mult_gen_0Umultz0 (.A (Add_Reg[0]),.B (coe[0]),.P (Mult_Reg[0]));mult_gen_0Umultz1 (.A (Add_Reg[1]),.B (coe[1]),.P (Mult_Reg[1]));mult_gen_0Umultz2 (.A (Add_Reg[2]),.B (coe[2]),.P (Mult_Reg[2]));mult_gen_0Umultz3 (.A (Add_Reg[3]),.B (coe[3]),.P (Mult_Reg[3]));assign Xout = {{3{Mult_Reg[0][27]}},Mult_Reg[0]}+ {{3{Mult_Reg[1][27]}},Mult_Reg[1]}+{{3{Mult_Reg[2][27]}},Mult_Reg[2]}+{{3{Mult_Reg[3][27]}},Mult_Reg[3]};endmodule

这里的乘法器调用了vivado的乘法IP,设置为13bit有符号数和16bit有符号数相乘,输出结果设置为28bit,因为输入数据不可能同时出现最大负值。流水线级数设置为0。

这种做法的缺点是比较浪费资源,在资源比较宝贵的项目中不要采取这种方法。可以采取移位相加法来节省资源,也可以对不同的大小的系数,用不同输入位宽的乘法器,比方说乘以742可以设置IP核的输入为11位,相比于16位,可以节省资源。

但这样做的好处是,移植起来很方便,调用的时候把参数填进coe[]数组就好了,可以节省很多时间

可以按照下图进行设置,如果仿真结果有问题,很有可能就是乘法IP设置出错了。

2.2 极点模块

module Pole(inputrst , inputclk , input signed [11:0]Yin , outputsigned [30:0]Yout);reg signed[11:0] Yin_Reg[6:0];reg [3:0] i,j; //-------------------------------------------------------// 将数据移位寄存//-------------------------------------------------------always @(posedge clk or posedge rst)if (rst)begin for (i=0; i<7; i=i+1)Yin_Reg[i]=12'd0;endelsebeginfor (j=0; j<6; j=j+1)Yin_Reg[j+1] <= Yin_Reg[j];Yin_Reg[0] <= Yin;end//-------------------------------------------------------// 将数据与系数相乘,结果存储在数组中 12bit与16bit相乘,结果为27bit//-------------------------------------------------------wire signed [16:0] coe[6:0] ; wire signed [26:0] Mult_Reg[7:0]; assign coe[0]= -16'd22761 ;assign coe[1]= 16'd27443 ;assign coe[2]= -16'd17266 ; assign coe[3]= 16'd8332 ;assign coe[4]= -16'd2373 ;assign coe[5]= 16'd430 ; assign coe[6]= -16'd33 ;//-------------------------------------------------------// 调用七个乘法器,设置为12bit有符号数和16bit有符号数相乘//-------------------------------------------------------mult_gen_1Umult1 (.A (Yin_Reg[0]),.B (coe[0]),.P (Mult_Reg[0]));mult_gen_1Umult2 (.A (Yin_Reg[1]),.B (coe[1]),.P (Mult_Reg[1]));mult_gen_1Umult3 (.A (Yin_Reg[2]),.B (coe[2]),.P (Mult_Reg[2]));mult_gen_1Umult4 (.A (Yin_Reg[3]),.B (coe[3]),.P (Mult_Reg[3]));mult_gen_1Umult5 (.A (Yin_Reg[4]),.B (coe[4]),.P (Mult_Reg[4]));mult_gen_1Umult6 (.A (Yin_Reg[5]),.B (coe[5]),.P (Mult_Reg[5]));mult_gen_1Umult7 (.A (Yin_Reg[6]),.B (coe[6]),.P (Mult_Reg[6]));assign Yout = {{4{Mult_Reg[0][26]}},Mult_Reg[0]}+{{4{Mult_Reg[1][26]}},Mult_Reg[1]}+{{4{Mult_Reg[2][26]}},Mult_Reg[2]}+{{4{Mult_Reg[3][26]}},Mult_Reg[3]}+{{4{Mult_Reg[4][26]}},Mult_Reg[4]}+{{4{Mult_Reg[5][26]}},Mult_Reg[5]}+{{4{Mult_Reg[6][26]}},Mult_Reg[6]};endmodule

这里的乘法IP设计跟零点模块基本相同,就不重复了

2.3 顶层文件

module IIR_Direct (inputrst,inputclk,input signed [11:0]din,outputsigned [11:0]dout);wire signed [30:0] Xout;Zero U0 (.rst (rst),.clk (clk),.Xin (din),.Xout (Xout));wire signed [11:0] Yin;wire signed [30:0] Yout;Pole U1 (.rst (rst),.clk (clk),.Yin (Yin),.Yout (Yout));wire signed [30:0] Ysum;assign Ysum = Xout - Yout;//将Ydiv右移14位,相当于除了16384wire signed [30:0] Ydiv;assign Ydiv = {{14{Ysum[30]}},Ysum[30:14]};//直接对结果进行截尾assign Yin = (rst ? 12'd0 : Ydiv[11:0]);assign dout = Yin;endmodule

3、vivado仿真

vivado仿真需要测试数据,以及仿真tb文件,给出代码如下:

3.1 matlab生成测试数据

为了验证高通滤波器,我们生成的测试信号由50k和250k的正弦信号叠加而成。生成的二进制文件为Bin_s.txt

f1=50000; %信号1频率为50KHzf2=250000; %信号2频率为250KHzFs=1000000; %采样频率为1MHzN=12; %量化位数%产生信号t=0:(1/Fs):0.0012;c1=2*pi*f1*t;c2=2*pi*f2*t;s1=sin(c1);%产生正弦波s2=sin(c2);%产生正弦波s=0.5*s1+0.5*s2;plot(t,s1,t,s);Q_s=round(s*(2^(N-1)-1));%% 生成txt文件们%将生成的数据以十进制数据格式写入txt文件中fid=fopen('Int_s.txt','w');fprintf(fid,'%8d\r\n',Q_s);fprintf(fid,';'); fclose(fid);%将生成的数据以二进制数据格式写入txt文件中fid=fopen('Bin_s.txt','w');for i=1:length(Q_s)B_s=dec2bin(Q_s(i)+(Q_s(i)<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);

3.2vivado添加测试数据

需要将测试数据添加到vivado环境中,仿真才能正常运行,我的做法如下

3.3添加tb文件运行仿真

tb文件如下

`timescale 1ns / 1psmodule IIR_tb();reg clk;reg [11:0] din;reg rst;wire [11:0] dout;IIR_Direct i1 (.clk(clk),.din(din),.dout(dout),.rst(rst));parameter clk_period=626; parameter clk_half_period=clk_period/2;parameter data_num=2000; parameter time_sim=data_num*clk_period/2; initialbeginclk=1;rst=1;#10000 rst=0;#time_sim $finish;din=12'd10;endalways #clk_half_period clk=~clk;integer Pattern;reg [11:0] stimulus[1:data_num];initialbegin$readmemb("Bin_s.txt",stimulus);Pattern=0;repeat(data_num)beginPattern=Pattern+1;din=stimulus[Pattern];#clk_period;endendinteger file_out;initial begin file_out = $fopen("Bin_s_out.txt");if(!file_out)begin$display("could not open file!");$finish;endendwire rst_write;wire signed [11:0] dout_s;assign dout_s = dout; assign rst_write = clk& (!rst);always @(posedge rst_write )$fdisplay(file_out,"%d",dout_s);endmodule

局部放大如下:

总结

本篇文章在matlab设计7阶(8级)高通IIR巴特沃斯滤波器,并实现verilog代码,并在vivado中进行仿真,结果符合预期。

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