基于FPGA的FIR滤波器设计与仿真验证,Verilog设计,modelsim仿真

1、设计内容

(1)利用MATLAB设计FIR低通滤波器系数,采样频率为5MHz,截止频率为100kHz,并生成测试数据保存至txt文件,并且在MATLAB上验证FIR滤波器的效果。

(2)在Modelsim进行波形仿真,验证FIR的滤波效果。

2、基本原理

有限冲激响应滤波器 ( Finite Impulse Response),即FIR滤波器,其输入x(n)和输出y(n)之间的关系为: 

FIR滤波器的转移函数可以表示为:

FIR滤波器应用比较普遍,有较多优良的品质。FIR滤波器输出对输入没有反馈,并且系数b(r)长度总是有限的,因此系统总是稳定收敛的。当系数b(r)对称时,FIR滤波器具有线性相位,输出等于输入在时间上的移位,不会产生相位失真。

FIR滤波器应用广泛,有各种各样的设计方法,比如窗函数法、频率抽样法、最小二乘法、等纹波法等,本文采用窗函数法进行设计。

MATLAB软件主要实现的工作是产生混频信号、设计FIR滤波器的系数并进行验证。混频信号是5KHz和800KHz的混频,之后将混频信号存储到mem.txt。在MATLAB的命令行窗口输入filterDesigner命令调出滤波器设计工具,接下来选择低通滤波器,选择Hamming窗,设定阶数为10阶,采样频率为5MHz,截至频率为100KHz,之后导出滤波器系数和FIR函数。得到FIR函数后验证FIR滤波的效果,并对系数进行量化——乘以1024后取整,结果为:14    30    73   128   172   189   172   128    73    30    14。之后根据MATLAB设计的系数,在FPGA端进行实现,并采用Modelsim进行仿真。

采用Verilog HDL实现FIR滤波器的程序流程图如图1所示,首先输入时钟、复位、时钟使能和待滤波的混频信号,接下来将MATLAB设计好的系数乘以1024,并定义为参数,同时定义中间变量。接下来对输入数据用11个寄存器缓存,然后将这11个寄存器的输出与定义的11个系数参数相乘,并将相乘的结果相加,相加后的和右移10位后的数据即为模块的输出。这里右移10位的原因是系数已经乘了一个1024,要使数据结果不变的话,输出要对应的除以1024,本文采用移位的方式实现除法,即右移10位等效的结果就是除以1024。

图1 FPGA实现FIR滤波器的程序流程图

3、程序设计

(1)MATLAB端主要生成混频数据、设计并得到FIR滤波器系数、验证FIR滤波器,程序如下:

%% 
clear;clc;close all;
load("matlab_FIR.mat");

%% 用MATLAB产生5kHz和800kHz的混频信号
Fs=5000000;%采样频率为5MHz
N=8192;%采样点数
N1=0:1/Fs:N/Fs-1/Fs;%以频率Fs采8192个点的数据
s=sin(5000*2*pi*N1)+sin(800000*2*pi*N1)+3;
figure(1);
plot(N1,s);

%% 将波形数据进行量化, 并转换为十六进制保存到mem.txt中
fidc=fopen('mem.txt','wt');
%将结果写入mem.txt文件,便于modelsim使用
for x=1:N
    y=round((s(x)/10)*4096);
    fprintf(fidc,'%x\n',y);%四舍五入取整后写入mem.txt文件
end
fclose(fidc);
% test=s*4096/10;
% plot(N1,test);

%% 在MATLAB中用filterDesigner命令调出滤波器设计工具
%选择低通滤波器
%选择Hamming窗
%设定阶数10阶
%采样频率5MHz
%截止频率100kHz
%选择文件->导出,将滤波器系数和FIR函数导出到工作区

%% 检验FIR滤波器滤波效果
d=filter(FIR,s);
figure(2);
plot(N1,d);

%%对导出的系数进行量化取整
%对导入的系数Num进行量化, 乘以2^10后取整
Num_int=round(Num*2^10);
disp(Num_int);

%需要注意的是, 设计的FIR滤波器的系数有一个特点, 就是系数之和为1
%验证
sum_Num=sum(Num);
disp(sum_Num);

(2)Verilog HDL实现FIR滤波器的思路如图1所示,代码如下:

//FIR 滤波器模块

module FIR_top
(
    input   wire            clk_in          ,
    input   wire            rst_n           ,
    input   wire            clk_en          ,
    input   wire    [15:0]  fir_in          ,   //输入待滤波数据, 16bits
    output  wire    [15:0]  fir_out             //系数为8位宽, 且系数和为1023, 所以和为26bits
                                                //和再右移10bits, 所以滤波后输出的数据仅为16bits
);

localparam [7:0]   coeff0 =    8'd14   ;
localparam [7:0]   coeff1 =    8'd30   ;
localparam [7:0]   coeff2 =    8'd73   ;
localparam [7:0]   coeff3 =    8'd128  ;
localparam [7:0]   coeff4 =    8'd172  ;
localparam [7:0]   coeff5 =    8'd189  ;
localparam [7:0]   coeff6 =    8'd172  ;
localparam [7:0]   coeff7 =    8'd128  ;
localparam [7:0]   coeff8 =    8'd73   ;
localparam [7:0]   coeff9 =    8'd30   ;
localparam [7:0]   coeff10=    8'd14   ;

reg   [15:0]  delay_pipeline [0:10]   ;
wire  [23:0]  product10,product9,product8,product7,product6,product5,
              product4,product3,product2,product1,product0;
wire  [25:0]  sum;//系数之和为1023, 数据为16bits, 所以和为26bits
reg   [25:0]  fir_temp;

always @(posedge clk_in or negedge rst_n ) begin 
    if(!rst_n) begin 
        delay_pipeline[0] <=16'd0;
        delay_pipeline[1] <=16'd0;
        delay_pipeline[2] <=16'd0;
        delay_pipeline[3] <=16'd0;
        delay_pipeline[4] <=16'd0;
        delay_pipeline[5] <=16'd0;
        delay_pipeline[6] <=16'd0;
        delay_pipeline[7] <=16'd0;
        delay_pipeline[8] <=16'd0;
        delay_pipeline[9] <=16'd0;
        delay_pipeline[10]<=16'd0;
        fir_temp<=26'd0;
    end 
    else if(clk_en) begin
        delay_pipeline[0] <=fir_in              ;
        delay_pipeline[1] <=delay_pipeline[0]   ;
        delay_pipeline[2] <=delay_pipeline[1]   ;
        delay_pipeline[3] <=delay_pipeline[2]   ;
        delay_pipeline[4] <=delay_pipeline[3]   ;
        delay_pipeline[5] <=delay_pipeline[4]   ;
        delay_pipeline[6] <=delay_pipeline[5]   ;
        delay_pipeline[7] <=delay_pipeline[6]   ;
        delay_pipeline[8] <=delay_pipeline[7]   ;
        delay_pipeline[9] <=delay_pipeline[8]   ;
        delay_pipeline[10]<=delay_pipeline[9]   ;
        fir_temp<=(sum>>10);//系数已经扩大2^10倍, 这里右移10bits, 恢复正常值
    end 
    //否则保持不变
end 

//FIR中的乘法
assign product0 = delay_pipeline[0 ] *coeff0  ;
assign product1 = delay_pipeline[1 ] *coeff1  ;
assign product2 = delay_pipeline[2 ] *coeff2  ;
assign product3 = delay_pipeline[3 ] *coeff3  ;
assign product4 = delay_pipeline[4 ] *coeff4  ;
assign product5 = delay_pipeline[5 ] *coeff5  ;
assign product6 = delay_pipeline[6 ] *coeff6  ;
assign product7 = delay_pipeline[7 ] *coeff7  ;
assign product8 = delay_pipeline[8 ] *coeff8  ;
assign product9 = delay_pipeline[9 ] *coeff9  ;
assign product10= delay_pipeline[10] *coeff10 ;

//FIR滤波中的加法
assign sum=product10+product9+product8+product7+product6+product5+
           product4+product3+product2+product1+product0;

//数据输出
assign fir_out = fir_temp[15:0];

endmodule

(3)仿真TestBench主要用于产生时钟、复位、时钟使能信号,并读取MATLAB产生的混频信号,并将该混频信号作为输入信号注入到FIR设计文件中,代码如下:

//FIR滤波器仿真模块
`timescale 1ns/1ns
module FIR_top_tb ();
reg             clk_in          ;
reg             rst_n           ;
reg             clk_en          ;
reg     [15:0]  fir_in          ; 
wire    [15:0]  fir_out         ; 

reg     [15:0]  mem [0:8191]    ;//8192个数
reg     [12:0]  num             ;//0~8191循环计数

initial
    $readmemh("D:/FPGA_prj/FPGA_class/prj_three/matlab_prj/mem.txt",mem);//以16进制形式将文本文件mem.txt中的8192个数据读入数组mem中

initial begin 
    clk_in=1'b0;
    rst_n<=1'b0;
    clk_en<=1'b1;
    repeat(3) begin 
        @(negedge clk_in) ;
    end 
    rst_n<=1'b1;
    #8000000;
    $stop;
end 
always #100 clk_in = ~clk_in ;//5MHz

always @(posedge clk_in or negedge rst_n) begin 
    if(!rst_n)
        num<=13'd0;
    else 
        num<=num+1'b1;
end 

always @(posedge clk_in or negedge rst_n ) begin 
    if(!rst_n)
        fir_in<=16'd0;
    else 
        fir_in<=mem[num];
end 

FIR_top FIR_top_inst
(
    . clk_in     ( clk_in  )     ,
    . rst_n      ( rst_n   )     ,
    . clk_en     ( clk_en  )     ,
    . fir_in     ( fir_in  )     ,   //输入待滤波数据, 16bits
    . fir_out    ( fir_out )         //系数为8位宽, 且系数和为1023, 所以和为26bits
                                                //和再右移10bits, 所以滤波后输出的数据仅为16bits
);
endmodule

4、实验结果分析

MATLAB产生的混频信号如图2所示,可以看出,信号比较杂乱,分别是5KHz和800KHz的混频。

图2 MATLAB产生的混频信号

在MATLAB端生成滤波后的图形,如图3所示,800KHz的高频信号基本被滤除,只剩5Khz的低频信号。

图3 MATLAB滤波后的效果

在Modelsim上的仿真波形图如图4所示,fir_in为输入的混频信号,fir_out为输出的FIR滤波后的信号,可以看出,高频信号基本被滤除,达到预期效果。

图4 FIR滤波的仿真波形图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值