低通FIR滤波器设计+Vivado实现

前言:本文参考了其他博客,自己做了一遍,只是用做记录。

设计目标:

设计一个低通滤波器,可以从1KHZ、3KHZ、4KHZ的叠加信号中,滤除掉3KHZ及以上的信号。

功能设计

总体架构:

总结一下,即:

首先由MATLAB生成一个由三个正弦波叠加的待滤波信号,三个正弦波的频率分别是1KHZ,3KHZ,4KHZ。

然后将待滤波信号送入Vivado,用Verilog编写的FIR滤波器进行仿真,观察滤波后的波形。

再利用MATLAB里面的conv函数将滤波器系数和待滤波信号卷积并观察滤波后的波形图。

将Vivado的仿真结果和MATLAB的仿真结果比较,验证在FPGA中滤波器算法的正确性。

设计步骤

 matlab生成滤波器系数

如图所示,使用matlab中的filterDesigner设计滤波器,滤波器指标总结在表1:

滤波器指标

采样频率(Fs)

10000HZ

通带截止频率(Fpass)

1000HZ

阻带截止频率(Fstop)

3000HZ

滤波器阶数(specify order)

8阶

将滤波器系数export到matlab的workspace,使用图3所示的两行代码进行定点化处理,得到如图4所示的滤波器系数:

 

matlab生成待滤波信号

使用图5所示代码生成KHZ、3KHZ、4KHZ三个正弦波叠加信号,并将其保存成.txt文件:

 Vivado进行FIR的verilog设计

原理框图:

代码实现:

`timescale 1ms / 1ps
module fir(
input[7:0] FIR_IN, 
input CLK,
input RSTn,
output reg[15:0] FIR_OUT
    );    
reg[7:0] delay_pipeline1 ;
reg[7:0] delay_pipeline2 ;
reg[7:0] delay_pipeline3 ;
reg[7:0] delay_pipeline4 ;
reg[7:0] delay_pipeline5 ;
reg[7:0] delay_pipeline6 ;
reg[7:0] delay_pipeline7 ;
reg[7:0] delay_pipeline8 ;
reg[7:0] delay_pipeline9 ;
/*第一级流水,将输入信号进行延时,每到来一个时钟信号,
便将输入信号保存到delay_pipelin1中,然后将剩下的依次移动一位。*/
always@(posedge CLK or negedge RSTn)
      if(!RSTn)
               begin
                    delay_pipeline1 <= 8'b0 ;
                    delay_pipeline2 <= 8'b0 ;
                    delay_pipeline3 <= 8'b0 ;
                    delay_pipeline4 <= 8'b0 ;
                    delay_pipeline5 <= 8'b0 ;
                    delay_pipeline6 <= 8'b0 ;
                    delay_pipeline7 <= 8'b0 ;
                    delay_pipeline8<= 8'b0 ;
                    delay_pipeline9<= 8'b0 ;
               end
       else begin
                    delay_pipeline1 <= FIR_IN     ;
                    delay_pipeline2 <= delay_pipeline1 ;
                    delay_pipeline3 <= delay_pipeline2 ;
                    delay_pipeline4 <= delay_pipeline3 ;
                    delay_pipeline5 <= delay_pipeline4 ;
                    delay_pipeline6 <= delay_pipeline5 ;
                    delay_pipeline7 <= delay_pipeline6 ;
                    delay_pipeline8 <=delay_pipeline7 ;
                    delay_pipeline9<= delay_pipeline8 ;
               end
//滤波器系数
wire[7:0] coeff1 = 8'd7;  
wire[7:0] coeff2 = 8'd5;
wire[7:0] coeff3 = 8'd51;
wire[7:0] coeff4 = 8'd135;
wire[7:0] coeff5 = 8'd179;
wire[7:0] coeff6 = 8'd135;
wire[7:0] coeff7 = 8'd51;
wire[7:0] coeff8 = 8'd5;
wire[7:0] coeff9 = 8'd7;
//乘积结果保存寄存器
reg signed [16:0] multi_data1 ;
reg signed [16:0] multi_data2 ;
reg signed [16:0] multi_data3 ;
reg signed [16:0] multi_data4 ;
reg signed [16:0] multi_data5 ;
reg signed [16:0] multi_data6 ;
reg signed [16:0] multi_data7 ;
reg signed [16:0] multi_data8 ;
reg signed [16:0] multi_data9 ;

//x(n) * h(n-k)
always@(posedge CLK or negedge RSTn) 
      if(!RSTn) 
      begin                                 
          multi_data1 <= 17'b0 ;
       else begin
          multi_data1 <= delay_pipeline1*coeff1 ;    
          end          
//x(1) * h(1)
always@(posedge CLK or negedge RSTn) 
      if(!RSTn)                                   
          multi_data2 <= 16'b0 ;
       else
          multi_data2 <= delay_pipeline2*coeff2 ;
//x(2) * h(2)   
always@(posedge CLK or negedge RSTn) 
      if(!RSTn)                                   
          multi_data3 <= 16'b0 ;
       else
          multi_data3 <= delay_pipeline3*coeff3 ;
  //x(3) * h(3)        
always@(posedge CLK or negedge RSTn) 
      if(!RSTn)                                   
          multi_data4 <= 16'b0 ;
       else
          multi_data4 <= delay_pipeline4*coeff4 ;
//x(4) * h(4)     
 always@(posedge CLK or negedge RSTn) 
      if(!RSTn)                                   
          multi_data5 <= 16'b0 ;
       else
          multi_data5 <= delay_pipeline5*coeff5 ;
//x(5) * h(5)   
always@(posedge CLK or negedge RSTn) 
      if(!RSTn)                                   
          multi_data6 <= 16'b0 ;
       else
          multi_data6 <= delay_pipeline6*coeff6 ;
//x(6) * h(6)          
always@(posedge CLK or negedge RSTn) 
      if(!RSTn)                                   
          multi_data7 <= 16'b0 ;
       else
          multi_data7 <= delay_pipeline7*coeff7;
//x(7) * h(7)          
always@(posedge CLK or negedge RSTn) 
      if(!RSTn)                                   
          multi_data8 <= 16'b0 ;
       else
          multi_data8 <= delay_pipeline8*coeff8;
//x(8) * h(8)        
always@(posedge CLK or negedge RSTn) 
      if(!RSTn)                                   
          multi_data9 <= 16'b0 ;
       else
          multi_data9 <= delay_pipeline9*coeff9 ;
  将乘积累加,累加的结果就是滤波后的信号                                                       
always@(posedge CLK or negedge RSTn)
      if(!RSTn)                                  
          FIR_OUT <= 16'b0 ;
       else
          FIR_OUT <= multi_data1 + multi_data2 + multi_data3 + 
          multi_data4 +multi_data5 + multi_data6 + multi_data7 +
           multi_data8 + multi_data9 ;
endmodule

testbench:

module tb(
);
reg CLK;
reg [7:0] FIR_IN;
reg RSTn;
reg [7:0] mem[1:4096];                                          
wire [15:0] FIR_OUT;
reg [12:0] i;
 //例化FIR滤波器
fir i1 (
       .CLK(CLK),
       .FIR_IN(FIR_IN),
       .FIR_OUT(FIR_OUT),
       .RSTn(RSTn)
);
initial                                               
       begin 
                     $readmemh("C:/Users/fuwen/Desktop/FPGA_final/FIR_EDA_VERSION/project_3/mem.txt",mem);//将待滤波信号读入mem
                     RSTn= 0;
                     CLK= 0;
                     #50;RSTn= 1;
                     #50000;
                     $stop;
       end  
       
initial
       forever
          #50 CLK = ~CLK;//时钟生成,注意与采样率一致
 
always@(posedge CLK or negedge RSTn) 
      if(!RSTn)                                
          FIR_IN <= 8'b0 ;
       else
          FIR_IN <= mem[i];     //读入数据

always@(posedge CLK or negedge RSTn) 
      if(!RSTn)
         i <= 12'd0;
       else
         i <= i + 1'd1;
endmodule

行为仿真波形结果如下图所示:

 

使用matlab自带conv对带滤波数据进行滤波,代码如下:

% Fs = 10000; %采样频率决定了两个正弦波点之间的间隔 
% N = 4096; %采样点数
% N1 = 0 : 1/Fs : (N-1)/Fs;
% s = sin(1000*2*pi*N1) + sin(3000*2*pi*N1) +sin(4000*2*pi*N1);
% fidc = fopen('C:\Users\fuwen\Desktop\FPGA_final\FIR_EDA_VERSION\project_3\mem.txt','wt');  
% for x = 1 : N
%    fprintf(fidc,'%x\n',round((s(x)+2.12)*58));
% end  
% fclose(fidc);  

Fs = 10000; %采样频率决定了两个正弦波点之间的间隔
N = 4096; %采样点数 
N1 = 0 : 1/Fs :(N-1)/Fs;
in =sin(1000*2*pi*N1) + sin(3000*2*pi*N1) + sin(4000*2*pi*N1); 
coeff =[-0.0325,-0.0384,0.0784,0.2874,0.3984,0.2874,0.0784,-0.0384,-0.0325]; %滤波器系数
out =conv(in,coeff);%卷积滤波
subplot(2,1,1);
plot(in);
xlabel('滤波前');
axis([0  200 -3 3]);
subplot(2,1,2);
plot(out);
xlabel('滤波后');
axis([100 200 -2 2]);

输出的仿真波形如下图所示,显然,Verilog实现的滤波器与matlab实现的功能一致,故滤波器功能正确,可以进一步进行综合、实现以及布局布线。 

综合出的原理图:

仅加时钟约束,无其他任何优化策略时的综合实现

综合:

添加时序约束10ns,检查时序报告:

 Slack均为正值,时序没有违例情况:

资源利用率:

采取时序约束+综合约束retiming时的综合实现

综合时勾选Retiming选项:启用该功能,可以通过在组合门和LUT之间移动寄存器(达到寄存器平衡状态)提高内部时钟时序路径的电路性能。该功能会保留原来的功能和电路延迟,也不需要改变RTL源文件。

综合

利用率:可以看出lut数和寄存器数相比默认设置都有增长

采用时序约束+不同的优化策略时的综合实现:

优化面积

利用率:可以看到所用的LUT以及FF都减少很多,但是使用了较多的dsp(5个)。 

还是上述的情况,但是在综合选项中添加约束,设置不允许使用DSP

综合时:利用率:可以看到所用的LUT以及FF都增加了,没有使用dsp。

还有很多种不同方式,这里不一一列举了。

  • 9
    点赞
  • 99
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值