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

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(
	input	wire			sclk,   //50MHz
	input	wire			rst_n,  //复位低有效
	output	wire	    [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_IP	fir_IP_inst(
	.sclk		(sclk),
	.rst_n		(rst_n),
	.dds_data	(dds_data),
	.lpf_data	(lpf_data)
);

endmodule

FIR模块

module fir_IP(
	input	wire			sclk,
	input	wire			rst_n,
	input	wire		[7:0]	dds_data,
	output	reg		[24:0]	lpf_data
);

reg		[2:0]	cnt;
reg				fs_pulse;//10MHz的脉冲
always @ (posedge sclk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		cnt <= 3'd0;
	else if(cnt == 3'd4)
		cnt <= 3'd0;
	else
		cnt <= cnt + 1'b1;
end
always @ (posedge sclk or negedge rst_n)
begin
	if(rst_n == 1'b0)
		fs_pulse <= 1'b0;
	else if(cnt == 3'd4)
		fs_pulse <= 1'b1;
	else
		fs_pulse <= 1'b0;
end

//FIR IP核例化
wire	[24:0]	lpf_datar;
wire			lpf_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)
begin
	if(fs_pulse == 1'b1)
		lpf_data <= lpf_datar;//在valid信号有效的时候才输出数据
end

endmodule

dds模块

module dds(
	input	wire			sclk,	//50MHz
	input	wire			rst_n,
	output	wire	    [7:0]	o_wave
);

parameter		FRQ_W1 = 32'd8589935;//100K
parameter		FRQ_W2 = 32'd85899346;//1M
reg		[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)
begin
	if(rst_n == 1'b0)
		phase_sum1 <= 32'd0;
	else 
		phase_sum1 <= phase_sum1 + FRQ_W1;
end
assign addr1 = phase_sum1[31:24];

always @(posedge sclk or negedge rst_n)
begin
	if(rst_n==1'b0)
		phase_sum2 <= 32'd0;
	else 
		phase_sum2 <= phase_sum2 + FRQ_W2;
end
assign addr2 = phase_sum2[31:24];
//2路波形相加输出
assign	wave_plus = {o_wave1[7],o_wave1} + {o_wave2[7],o_wave2};
assign	o_wave = wave_plus[8:1];	//相加结果寄存器是9位,取高8位作为输出结果

//调用2次RAM取数据	
ram_8x256_sp	ram_8x256_sp_inst1(
	.address	( addr1 ),
	.clock		( sclk ),
	.data		( 8'd0 ),
	.wren		( 1'b0 ),
	.q		( o_wave1 )
);
ram_8x256_sp	ram_8x256_sp_inst2(
	.address	   ( addr2 ),
	.clock		( sclk ),
	.data		( 8'd0 ),
	.wren		( 1'b0 ),
	.q		( o_wave2 )
);

endmodule

testbench测试文件

`timescale 1ns/1ns
module tb_fir();
reg		        sclk,rst_n;
wire	    [24:0]	lpf_data;

initial begin
	sclk = 0;
	rst_n = 0;
	#200
	rst_n = 1;
end

always #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
.main	clear

# Create compilation libraries
proc 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.v
vlog	./../design/*.v
vlog	./../quartus_prj/ipcore_dir/ram_8x256_sp/*.v
vlog	./../quartus_prj/ipcore_dir/fir_lpf/*.v
vlog	./../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.vhd
vcom 	./../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.vhd
vcom 	./../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.vhd
vcom 	./../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

#添加需要仿真的波形
add		wave	tb_fir/fir_top_inst/sclk
add		wave	tb_fir/fir_top_inst/rst_n
add		wave	tb_fir/fir_top_inst/fir_IP_inst/fir_lpf_inst/ast_sink_valid
add		wave	tb_fir/fir_top_inst/fir_IP_inst/fir_lpf_inst/ast_source_valid
add		wave	-format analog -height 100 -max 127 		-min -128 		tb_fir/fir_top_inst/dds_data
add		wave 	tb_fir/fir_top_inst/lpf_data

run		100us


图3  仿真截图

从测试脚本可以看出,这种方法的仿真比较繁琐,ModelSim编译库的时间也比较长,所以打算下一篇学习总结一下联合仿真的大致方法。
评论 59
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值