FIR滤波器仿真--基于Quartus II的FIR Compiler II IP核的脚本仿真

来源:互联网 发布:淘宝水印美图秀秀教程 编辑:程序博客网 时间:2024/05/29 08:13

FIR滤波器仿真
--基于Quartus II的FIR Compiler II IP核的脚本仿真

数字滤波器有更高的精度,更高的信噪比,更高的可靠性。最近和小伙伴探讨了一番FIR滤波器的相关知识,一起把FIR滤波器仿真了一下。总结加深印象,分享交流~


使用工具


MATLAB R2014b,Quartus II v13.1,ModelSim SE 10.0

实现过程


第一步 仿真并生成滤波器的系数

使用MATLAB里面的FDATOOL工具箱设计滤波器

1,设置滤波器参数
响应类型选择低通滤波器;采用窗函数设计滤波器,在窗函数里面选择海明窗,也可以选择其它的窗函数,窗函数的特性不想赘述;滤波器阶数设为31阶,阶数越高占用资源越多,但是会有32个抽头系数,这要联系滤波器的传输函数;采样频率设为10MHz,截止频率设为200KHz,因为滤波器的输入数据是用dds生成的2路正弦波频率分别为100KHz和1MHz的叠加波形。

输入信号通过滤波器, 1MHz的波形被滤除,保留了100KHz的波形,截止频率设为200KHz并不是绝对的,只要满足要求即可,观察图1中的频率响应得100KHz:-0.58dB,1MHz:-46dB。

2,量化滤波器系数
(图1左下小框)Set quantization parameters-->Fixed-point-->16bit量化

如果设计好滤波器之后直接导出系数的话,系数的精度比较高,所以会以科学计数法的形式来表示,但是FIR Compiler II IP核不能识别科学计数法,但是修改起来又比较麻烦,所以可以在导出系数之前对系数进行一次量化,这样导出的系数就方便多了。由图可见,16bit的量化对频率响应几乎没什么影响。

3,导出系数

File-->Export,就把系数导入到MATLAB的工作区,再把这些系数复制粘贴到一个TXT文件中,OK


图1  MATLAB仿真滤波器



第二步 生成FIR Compiler II IP核

Quartus II-->Tools-->MegaWizard Plug-In Manager-->DSP-->Filters-->FIR Compiler II v13.1

1,设置IP核参数:滤波器类型Filter Type:Single Rate,系数位宽Coefficient Bit Width:12bit,输入位宽Input Bit Width:8bit,时钟频率Clock Frequency:50MHz,输入采样率:Input Sample Rate:10MSPS,其它默认设置

2,导入TXT系数文件,可看到相应的频率相应。


图2  FIR Compiler II IP核参数设置



第三步 编写设计文件和测试文件

设计文件里面共有三个模块,一个是顶层模块,例化子模块,相互联系;一个是dds模块,产生两路正弦波100KHz和1MHz的相加波形,作为滤波器的输入,还有一个是FIR模块,例化FIR IP核,产生10MHz的采样脉冲给ast_sink_valid信号,在脉冲有效的时候将滤波器的数据取出。

强调一下ast_sink_valid这个信号,表示数据有效,只有为高时,滤波器才会工作。给一个10MHz的采样脉冲,也就是1/(10M)=100ns工作一次,对应了IP核设置时的10MSPS。而且要在脉冲为高的时候再把滤波器的数据取出,之前没考虑好这个地方,所以滤出来的数据一直是杂乱的。

顶层模块

module fir_top(inputwiresclk,   //50MHzinputwirerst_n,  //复位低有效outputwire    [24:0]lpf_data//滤波输出数据);//DDS例化wire    [7:0]dds_data;dds dds_inst(.sclk(sclk),.rst_n(rst_n),.o_wave(dds_data));//FIR例化fir_IPfir_IP_inst(.sclk(sclk),.rst_n(rst_n),.dds_data(dds_data),.lpf_data(lpf_data));endmodule

FIR模块

module fir_IP(inputwiresclk,inputwirerst_n,inputwire[7:0]dds_data,outputreg[24:0]lpf_data);reg[2:0]cnt;regfs_pulse;//10MHz的脉冲always @ (posedge sclk or negedge rst_n)beginif(rst_n == 1'b0)cnt <= 3'd0;else if(cnt == 3'd4)cnt <= 3'd0;elsecnt <= cnt + 1'b1;endalways @ (posedge sclk or negedge rst_n)beginif(rst_n == 1'b0)fs_pulse <= 1'b0;else if(cnt == 3'd4)fs_pulse <= 1'b1;elsefs_pulse <= 1'b0;end//FIR IP核例化wire[24:0]lpf_datar;wirelpf_valid;wire[1:0]lpf_error;fir_lpf fir_lpf_inst(.clk(sclk),//IP核内部工作时钟.reset_n(rst_n),//复位,低有效.ast_sink_data(dds_data),//输入数据.ast_sink_valid(fs_pulse),//采样脉冲.ast_sink_error(2'd0),//输入错误,使其无效.ast_source_data(lpf_datar),//输出数据.ast_source_valid(lpf_valid),//输出有效.ast_source_error(lpf_error)//输出错误);always @ (posedge sclk or negedge rst_n)beginif(fs_pulse == 1'b1)lpf_data <= lpf_datar;//在valid信号有效的时候才输出数据endendmodule

dds模块

module dds(inputwiresclk,//50MHzinputwirerst_n,outputwire    [7:0]o_wave);parameterFRQ_W1 = 32'd8589935;//100KparameterFRQ_W2 = 32'd85899346;//1Mreg[31:0]phase_sum1,phase_sum2;wire    [7:0]addr1,addr2;wire[7:0]o_wave1,o_wave2;wire[8:0]wave_plus;//产生2路信号的地址always @(posedge sclk or negedge rst_n)beginif(rst_n == 1'b0)phase_sum1 <= 32'd0;else phase_sum1 <= phase_sum1 + FRQ_W1;endassign addr1 = phase_sum1[31:24];always @(posedge sclk or negedge rst_n)beginif(rst_n==1'b0)phase_sum2 <= 32'd0;else phase_sum2 <= phase_sum2 + FRQ_W2;endassign addr2 = phase_sum2[31:24];//2路波形相加输出assignwave_plus = {o_wave1[7],o_wave1} + {o_wave2[7],o_wave2};assigno_wave = wave_plus[8:1];//相加结果寄存器是9位,取高8位作为输出结果//调用2次RAM取数据ram_8x256_spram_8x256_sp_inst1(.address( addr1 ),.clock( sclk ),.data( 8'd0 ),.wren( 1'b0 ),.q( o_wave1 ));ram_8x256_spram_8x256_sp_inst2(.address   ( addr2 ),.clock( sclk ),.data( 8'd0 ),.wren( 1'b0 ),.q( o_wave2 ));endmodule

testbench测试文件

`timescale 1ns/1nsmodule tb_fir();reg        sclk,rst_n;wire    [24:0]lpf_data;initial beginsclk = 0;rst_n = 0;#200rst_n = 1;endalways #10 sclk <= ~sclk;//例化顶层模块fir_top  fir_top_inst(.sclk(sclk),.rst_n(rst_n),.lpf_data(lpf_data));endmodule

第四步 编写测试脚本并仿真

生成FIR Compiler II IP核的时候会附带生成一个sim的文件夹,里面有两个tcl脚本,在这两个脚本的基础上编写我们的测试脚本。脚本的编写参考了尤老师的课程,有兴趣的旁友可以去看看。脚本里面的路径需要修改(Line39)。


测试脚本

quit-sim.mainclear# Create compilation librariesproc ensure_lib { lib } { if ![file isdirectory $lib] { vlib $lib } }ensure_lib          ./libraries/     ensure_lib          ./libraries/work/vmap       work     ./libraries/work/vmap       work_lib ./libraries/work/if ![ string match "*ModelSim ALTERA*" [ vsim -version ] ] {  ensure_lib                  ./libraries/altera_ver/        vmap       altera_ver       ./libraries/altera_ver/        ensure_lib                  ./libraries/lpm_ver/           vmap       lpm_ver          ./libraries/lpm_ver/           ensure_lib                  ./libraries/sgate_ver/         vmap       sgate_ver        ./libraries/sgate_ver/         ensure_lib                  ./libraries/altera_mf_ver/     vmap       altera_mf_ver    ./libraries/altera_mf_ver/     ensure_lib                  ./libraries/altera_lnsim_ver/  vmap       altera_lnsim_ver ./libraries/altera_lnsim_ver/  ensure_lib                  ./libraries/cycloneive_ver/    vmap       cycloneive_ver   ./libraries/cycloneive_ver/    ensure_lib                  ./libraries/altera/            vmap       altera           ./libraries/altera/            ensure_lib                  ./libraries/lpm/               vmap       lpm              ./libraries/lpm/               ensure_lib                  ./libraries/sgate/             vmap       sgate            ./libraries/sgate/             ensure_lib                  ./libraries/altera_mf/         vmap       altera_mf        ./libraries/altera_mf/         ensure_lib                  ./libraries/altera_lnsim/      vmap       altera_lnsim     ./libraries/altera_lnsim/      ensure_lib                  ./libraries/cycloneive/        vmap       cycloneive       ./libraries/cycloneive/      }if ![info exists QUARTUS_INSTALL_DIR] {   set QUARTUS_INSTALL_DIR "D:/altera/13.1/quartus/"}if ![ string match "*ModelSim ALTERA*" [ vsim -version ] ] {    vlog     "$QUARTUS_INSTALL_DIR/eda/sim_lib/altera_primitives.v"              -work altera_ver          vlog     "$QUARTUS_INSTALL_DIR/eda/sim_lib/220model.v"                       -work lpm_ver             vlog     "$QUARTUS_INSTALL_DIR/eda/sim_lib/sgate.v"                          -work sgate_ver           vlog     "$QUARTUS_INSTALL_DIR/eda/sim_lib/altera_mf.v"                      -work altera_mf_ver       vlog -sv "$QUARTUS_INSTALL_DIR/eda/sim_lib/mentor/altera_lnsim_for_vhdl.sv"  -work altera_lnsim_ver    vlog     "$QUARTUS_INSTALL_DIR/eda/sim_lib/cycloneive_atoms.v"               -work cycloneive_ver      vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/altera_syn_attributes.vhd"        -work altera              vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/altera_standard_functions.vhd"    -work altera              vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/alt_dspbuilder_package.vhd"       -work altera              vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/altera_europa_support_lib.vhd"    -work altera              vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/altera_primitives_components.vhd" -work altera              vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/altera_primitives.vhd"            -work altera              vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/220pack.vhd"                      -work lpm                 vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/220model.vhd"                     -work lpm                 vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/sgate_pack.vhd"                   -work sgate               vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/sgate.vhd"                        -work sgate               vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/altera_mf_components.vhd"         -work altera_mf           vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/altera_mf.vhd"                    -work altera_mf           vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/altera_lnsim_components.vhd"      -work altera_lnsim        vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/cycloneive_atoms.vhd"             -work cycloneive          vcom     "$QUARTUS_INSTALL_DIR/eda/sim_lib/cycloneive_components.vhd"        -work cycloneive        }#以上的文件格式基本固定,不用多管vlog./tb_fir.vvlog./../design/*.vvlog./../quartus_prj/ipcore_dir/ram_8x256_sp/*.vvlog./../quartus_prj/ipcore_dir/fir_lpf/*.vvlog./../quartus_prj/ipcore_dir/fir_lpf/fir_lpf/*.v#vhdl文件的编译有顺序,不同的工程只是最后 3 个vhdl文件名需要更改vcom ./../quartus_prj/ipcore_dir/fir_lpf/fir_lpf/auk_dspip_math_pkg_hpfir.vhd                   vcom ./../quartus_prj/ipcore_dir/fir_lpf/fir_lpf/auk_dspip_lib_pkg_hpfir.vhd                    vcom ./../quartus_prj/ipcore_dir/fir_lpf/fir_lpf/auk_dspip_avalon_streaming_controller_hpfir.vhdvcom ./../quartus_prj/ipcore_dir/fir_lpf/fir_lpf/auk_dspip_avalon_streaming_sink_hpfir.vhd      vcom ./../quartus_prj/ipcore_dir/fir_lpf/fir_lpf/auk_dspip_avalon_streaming_source_hpfir.vhd  vcom ./../quartus_prj/ipcore_dir/fir_lpf/fir_lpf/auk_dspip_roundsat_hpfir.vhd                   vcom ./../quartus_prj/ipcore_dir/fir_lpf/fir_lpf/dspba_library_package.vhd                      vcom ./../quartus_prj/ipcore_dir/fir_lpf/fir_lpf/dspba_library.vhdvcom ./../quartus_prj/ipcore_dir/fir_lpf/fir_lpf/fir_lpf_0002_rtl.vhd                           vcom ./../quartus_prj/ipcore_dir/fir_lpf/fir_lpf/fir_lpf_0002_ast.vhdvcom ./../quartus_prj/ipcore_dir/fir_lpf/fir_lpf/fir_lpf_0002.vhd#链接库文件,编译vsim-voptargs=+acc -L work -L work_lib -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L cycloneive_ver -L altera -L lpm -L sgate -L altera_mf -L altera_lnsim -L cycloneive work.tb_fir#添加需要仿真的波形addwavetb_fir/fir_top_inst/sclkaddwavetb_fir/fir_top_inst/rst_naddwavetb_fir/fir_top_inst/fir_IP_inst/fir_lpf_inst/ast_sink_validaddwavetb_fir/fir_top_inst/fir_IP_inst/fir_lpf_inst/ast_source_validaddwave-format analog -height 100 -max 127 -min -128 tb_fir/fir_top_inst/dds_dataaddwave tb_fir/fir_top_inst/lpf_datarun100us


图3  仿真截图

从测试脚本可以看出,这种方法的仿真比较繁琐,ModelSim编译库的时间也比较长,所以打算下一篇学习总结一下联合仿真的大致方法。
原创粉丝点击