赞
踩
实验任务:使用NCO ip核分别生成1Mhz和10Mhz正弦波,叠加两个列波作为输入数据,通过FIR滤波器处理得到输出波形,分析FIR输入输出两列波形,查看FIR滤波器效果。
基本原理
数控振荡器的作用是产生正交的正弦和余弦样本。传统方法是采用查表法(LUT),即事先根据各个正余弦波相位计算好相位的正余弦值,并按相位角度作为地址存储该相位的正余弦值,构成一个幅度P相位转换电路(即波形存储器)。在系统时钟的控制下,由相位累加器对输入频率字不断累加,得到以该频率字为步进的数字相位,再通过相位相加模块进行初始相位偏移,得到要输出的当前相位,将该值作为取样地址值送入幅度P相位转换电路,查表获得正余弦信号样本。
FPGA实现
频率控制字寄存器将接收到的的频率控制字送入相位累加器,相位累加器对系统时钟进行计数,每到达输入频率控制字的值即对相位进行累加,随后将累加值送入相位相加器,与相位控制字寄存器接收到的初始相位进行相加,得到当前的相位值。
有关更多的NCO认识,可参考链接:
NCO (数字振荡器)
FIR滤波处理如下式所示,其中x(n)为输入信号,h(n)为FIR滤波系数,y(n)为经过滤波后的信号;N表示FIR滤波器的抽头数,滤波器阶数为N-1;
FIR滤波器在FPGA中的实现结构
主要由延迟单元Z-1、乘法器和累加器组成。此结构为直接型FIR滤波器结构,也称横向结构(transverse)。
调用ip核
进入配置界面,修改ip名称以及保存路径
界面认识
Generation ALgorithm:
Outputs:
界面认识
(1)32bits 是累加器的精度。因为FPGA产生的是数字信号,故精度越高,产生的波形肉眼看上去越平滑;
(2)18bits是输出数据的位宽;
(3)Dither Level,用于提高输出信号质量,默认4即可;
(4)Clock Rate 是时钟频率,根据板子上的频率自由选择;
(5)Desired Output Frequency:理想输出信号的频率;
(6)Phase Increment Value:是后续计数器需要计数的值,在后续编写testbench时需要把这个数据在initial语句中赋值给[31:0]phi_inc_i。
频畴图
时域图
界面认识
相关信号以及位宽
将.sip文件和.qip文件添加到工程中
调用IP核
进入配置界面
界面认识
界面认识
界面认识
界面认识
界面认识(保持默认)
界面认识 保持默认
调用ip核
界面认识
界面认识
时钟与时钟使能
点击NEXT,勾选方框文件,点击Finish
ip核查看
例化NCO数字振荡器以及FIR滤波器模块,并进行正弦信号叠加
fir.v
module fir( input sys_clk ,//系统时钟 input sys_rst_n ,//系统复位 低电平有效 output signed[11:0] sin1 ,//1Mhz正弦波 output sin1_vld ,//数据输出有效 output signed[11:0] sin10 ,//10Mhz正弦波 output sin10_vld ,//输出数据有效 output signed[12:0] add_sin ,//正弦波叠加输出 output add_vld ,//叠加输出有效 output signed[34:0] fir_out //滤波输出 ); //信号定义 reg signed[12:0] sum_sin ;//叠加结果寄存 wire signed[11:0] sin1_do ; wire signed[11:0] sin10_do ; wire out_en ; wire s_val ; wire s_err ; //结果赋值 assign sin1 = sin1_do; assign sin10 = sin10_do; assign add_sin = sum_sin; assign add_vld = sin1_vld & sin10_vld; //波形叠加 always @(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n)begin sum_sin <= 13'd0; end else begin if(sin1_vld & sin10_vld) sum_sin <= sin1 + sin10; else sum_sin <= sum_sin; end end //模块例化 //1Mhz sin1 u_sin1 ( .clk ( sys_clk ), .reset_n ( sys_rst_n ), .clken ( 1'b1 ), .phi_inc_i ( 11'd41 ), .fsin_o ( sin1_do ), .out_valid ( sin1_vld ) ); //10Mhz sin10 u_sin10 ( .clk ( sys_clk ), .reset_n ( sys_rst_n ), .clken ( 1'b1 ), .phi_inc_i ( 11'd410 ), .fsin_o ( sin10_do ), .out_valid ( sin10_vld ) ); //fir fir_do u_fir_do ( .clk ( sys_clk ), .reset_n ( sys_rst_n ), .ast_sink_data ( add_sin ), .ast_sink_valid ( add_vld ), .ast_sink_error ( 2'b0 ), .ast_source_data ( fir_out ), .ast_source_valid ( s_val ), .ast_source_error ( s_err ) ); endmodule
通过FIR滤波器,进行滤波处理
fir_lb.v
module fir_lb( input sys_clk ,//系统时钟 input sys_rst_n ,//系统复位 低电平有效 input [12:0] fir_sin ,//输入叠加的正弦波信号 input fir_vld ,//输入数据有效 output reg [33:0] fir_out ,//滤波输出 output reg out_vld //输出有效 ); //信号定义 reg [20:0] vld_r ;//对数据有效进行打拍 reg [12:0] fir_data_in [22:0] ;//输入数据寄存 reg [13:0] add_data [11:0] ;//加法寄存器 reg [29:0] mult_data [11:0] ;//乘法寄存器 reg [30:0] sum [5:0] ;//第一次求和 reg [31:0] s6,s7,s8 ;//第二次求和 reg [32:0] s9,s10 ;//第三次求和 wire mult_en ;//乘法器使能 assign mult_en = (vld_r[1] | vld_r[2] |vld_r[3]); //抽头系数定义 wire [15:0]h[11:0]; assign h[ 0] = 16'd623 ; assign h[ 1] = 16'd1370 ; assign h[ 2] = 16'd3469 ; assign h[ 3] = 16'd6495 ; assign h[ 4] = 16'd9481 ; assign h[ 5] = 16'd11332 ; assign h[ 6] = 16'd11332 ; assign h[ 7] = 16'd9481 ; assign h[ 8] = 16'd6495 ; assign h[ 9] = 16'd3469 ; assign h[10] = 16'd1370 ; assign h[11] = 16'd623 ; //对输入有效数据打拍 always @(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n)begin vld_r <= 6'b0; end else begin vld_r <= {vld_r[19:0],fir_vld}; end end //循环变量定义 integer i,j; //输入数据 移位寄存 always @(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n)begin for(i=0;i<23;i=i+1)begin fir_data_in[i] <= 8'd0; end end else begin if(fir_vld)begin fir_data_in[i] <= fir_sin; for(j=1;j<23;j=j+1)begin fir_data_in[j] <= fir_data_in[j-1];//移位寄存 end end end end //对称相加 always @(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n)begin for(i=0;i<12;i=i+1)begin add_data[i] <= 9'd0; end end else begin add_data[11] <= fir_data_in[11]; if(vld_r[0])begin for(j=0;j<10;j=j+1)begin add_data[j] <= fir_data_in[j] + fir_data_in[22-j]; end end end end //乘法器 genvar k; generate for(k=0;k<12;k=k+1)begin:bit mult_do u_mult_do ( .clock ( sys_clk ), .clken ( 1'b1 ), .dataa ( h[k] ), .datab ( add_data[k] ), .result ( mult_data[k] ) ); end endgenerate //s0~s5 always @(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n)begin for(i=0;i<6;i=i+1)begin sum[i] <= 26'd0; end end else begin if(vld_r[16])begin for(j=0;j<6;j=j+1)begin sum[j] <= mult_data[j*2] + mult_data[j*2+1]; end end end end //s6~s8 always @(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n)begin s6 <= 27'd0; s7 <= 27'd0; s8 <= 27'd0; end else begin if(vld_r[17])begin s6 <= sum[0] + sum[1]; s7 <= sum[2] + sum[3]; s8 <= sum[4] + sum[5]; end end end //s9~s10 always @(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n)begin s9 <= 26'd0; s10 <= 26'd0; end else begin if(vld_r[18])begin s9 <= s6 + s7 ; s10 <= s8; end end end //结果输出 always @(posedge sys_clk or negedge sys_rst_n) begin if(!sys_rst_n)begin fir_out <= 30'd0; end else begin if(vld_r[19])begin fir_out <= s9 + s10; out_vld <= 1'b1; end else out_vld <= 1'b0; end end endmodule
仿真文件
fir_tb.v
//时间尺度 `timescale 1ns/1ns module fir_tb(); //激励信号 reg sys_clk ; reg sys_rst_n ; //输出信号 wire [11:0] sin1 ; wire sin1_vld ; wire [11:0] sin10 ; wire sin10_vld ; wire [12:0] add_sin ; wire add_vld ; wire [34:0] fir_out ; //模块例化 fir u_fir_nco ( .sys_clk ( sys_clk ), .sys_rst_n ( sys_rst_n ), .sin1 ( sin1 ), .sin1_vld ( sin1_vld ), .sin10 ( sin10 ), .sin10_vld ( sin10_vld ), .add_sin ( add_sin ), .add_vld ( add_vld ), .fir_out ( fir_out ) ); //产生时钟 parameter CLK_PRE = 20; //时钟周期 always #(CLK_PRE/2) sys_clk = ~sys_clk; integer i;//循环变量 //产生激励 initial begin sys_clk = 1'b1; sys_rst_n = 1'b0; i=0; #(CLK_PRE*10); sys_rst_n = 1'b1; forever begin #(CLK_PRE); i=i+1; if(i==4000) $stop; end end endmodule
编译工程
添加仿真文件
启动仿真
添加波形
显示正弦波
sin 1Mhz波形
sin 10Mhz波形(采样点太少)
叠加波形
滤除后的波形
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。