基于FPGA的FIR滤波器模块设计(verilog)

一、FIR滤波器模块介绍

        设计该模块作用是,可通过MATLAB产生h(n)序列的系数获得的coe文件(注意该系数需要处理成整数,后面以16bit的数据有符号数为例)。将数据保存rom中,信号输入该模块,该模块可以实现输入信号与h(n)序列的实时卷积输出。

二、该模块用法介绍

1、 用MATLAB生成滤波器系数

首先用MATLAB滤波器设计模块导出滤波器的mat文件,untitled.mat

然后用MATLAB产生COE文件

Hd=load('untitled.mat');     
filtercoeff=Hd.LF.Numerator*80000;
% 将数据量化为8位整数(如果需要)
figure;
filter_coe_quantized_data = int16(fliplr(filtercoeff));
plot(filter_coe_quantized_data)




% 保存为COE文件
coe_file = fopen('filter.coe', 'w');
fprintf(coe_file, 'memory_initialization_radix=10;\n');
fprintf(coe_file, 'memory_initialization_vector=\n');

for i = 1:length(filter_coe_quantized_data)
    fprintf(coe_file, '%d,\n', filter_coe_quantized_data(i));
end

fclose(coe_file);

2、VIVADO RAM IP核设置

这里IP核大小设置的其实比较大,可以实现1000阶的实时卷积,可以根据实际情况设置小些,比如这里MATLAB生成30阶滤波器,64的深度就够了。

3、rom IP核设置

rom 导入COE文件

4、模块使用,输入接口时序。

sys_clk应该是比,数据变换更快的一个时钟,比如Data是由96KHZ的ADC采样的数据,sys_clk使用100MHZ的时钟计算,Data_flag在数据到来时保持多个100MHZ的时钟周期。

这个模块卷积模块兼容WM8731音频采样模块,通常WM8731音频采样模块(采样率96KHZ)的时序就是就会在数据到来时,给一个有12MHZ时钟产生的一个高电平。(之前设计时候就是基于这个音频采样模块设计)

该模块会实现实时的每个数据到来时实现实时得卷积运算,并以和输入数据一样的采样率的rela_data输出。

注意这里用rela_data表示的原因是因为,当rom放置需要一段波形,它也会实现实时的相关运算。

所以注意放置rom中的序列应当是h(n)的倒置,MATLAB中用fliplr函数实现h(n)序列的倒置。

三、verilog代码

`timescale  1ns/1ns

// Author        : 悠志
// Create Date   : 2023/10/10


module low_filter
(
     input      wire            sys_clk             ,
     input      wire            sys_rst_n           ,
     input      wire            data_flag            ,
     input      wire  signed    [15:0]  data           ,

     output     reg   signed [31:0]  rela_data  
   
);

parameter RELA_NUM=         'd30;//31-1

reg  [10:0] ccl_cnt;
reg         judge_en;//卷积运算结果判断
reg         ccl_en  ;
reg         ccl_en_d1;


reg      signed [31:0]  mult_data  ;



// sum_ram
  wire     signed [31:0]  sum_rela_rom_data  ;
  reg      signed [31:0]  sum_data    	;
  reg              sum_ram_wr_en      	;
  reg              sum_ram_rd_en      	;
  reg      [9:0]   sum_ram_wr_addr   	;
  reg      [9:0]   sum_ram_rd_addr    	;






wire  signed    [15:0]  rela_rom_data           ;

 
reg      [9:0]        rela_rom_addr        ;





//ccl_cnt
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
ccl_cnt<=10'd0;
else if(ccl_en==1'b1)
ccl_cnt<=ccl_cnt+1'b1;
else if(ccl_cnt==10'd0||ccl_cnt==RELA_NUM+10'd3)
ccl_cnt<=10'd0;

else
ccl_cnt<=ccl_cnt+1'b1;




//judge_en
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
judge_en<=1'b0;
else if(ccl_cnt==RELA_NUM+10'd2)
judge_en<=1'b1;
else
judge_en<=1'b0;




//ccl_en
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
ccl_en<=1'b0;
else if(data_flag==1'b1)
ccl_en<=1'b1;
else if(ccl_cnt==RELA_NUM)
ccl_en<=1'b0;
else
ccl_en<=ccl_en;


//ccl_en_d1
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
ccl_en_d1<=1'b0;
else
ccl_en_d1<=ccl_en;

//rela_rom_addr
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
rela_rom_addr<=10'd0;
else if(data_flag==1'b1)
rela_rom_addr<=rela_rom_addr+1'b1;
else if(rela_rom_addr==RELA_NUM||rela_rom_addr==10'd0)
rela_rom_addr<=10'd0;
else
rela_rom_addr<=rela_rom_addr+1'b1;


//mult_data
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
mult_data<=32'd0;
else if(ccl_en_d1==1'b1)

mult_data<=rela_rom_data*data;

else
mult_data<=mult_data;




//sum_ram_rd_en
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
sum_ram_rd_en<=1'b0;
else
sum_ram_rd_en<=ccl_en_d1;

//sum_ram_rd_addr
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
sum_ram_rd_addr<=10'd0;
else if(sum_ram_rd_en==1'b0)
sum_ram_rd_addr<=10'd0;
else
sum_ram_rd_addr<=sum_ram_rd_addr+1'b1;



//sum_data
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
sum_data<=16'd0;
else if(sum_ram_rd_en==1'b1)
begin
    if(sum_ram_rd_addr==10'd0)
    sum_data<=mult_data;
    else
    sum_data<=sum_rela_rom_data+mult_data;
end
else
sum_data<=sum_data;


//sum_ram_wr_en
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
sum_ram_wr_en<=1'b0;
else
sum_ram_wr_en<=sum_ram_rd_en;


//sum_ram_wr_addr
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
sum_ram_wr_addr<=10'd0;
else
sum_ram_wr_addr<=sum_ram_rd_addr;



//rela_data
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n==1'b0)
rela_data<='d0;
else if(judge_en==1'b1)
rela_data<=sum_data;
else 
rela_data<=rela_data;



sum_ram sum_ram_inst (
  .clka(sys_clk),    // input wire clka
  .ena(sum_ram_wr_en),      // input wire ena
  .wea(1'b1),      // input wire [0 : 0] wea
  .addra(sum_ram_wr_addr),  // input wire [9 : 0] addra
  .dina(sum_data),    // input wire [31 : 0] dina
  .douta(),  // output wire [31 : 0] douta
  .clkb(sys_clk),    // input wire clkb
  .enb(sum_ram_rd_en),      // input wire enb
  .web(1'b0),      // input wire [0 : 0] web
  .addrb(sum_ram_rd_addr),  // input wire [9 : 0] addrb
  .dinb(),    // input wire [31 : 0] dinb
  .doutb(sum_rela_rom_data)  // output wire [31 : 0] doutb
);



filter_rom filter_rom_inst (
  .clka(sys_clk),    // input wire clka
  .addra(rela_rom_addr),  // input wire [4 : 0] addra
  .douta(rela_rom_data)  // output wire [15 : 0] douta
);







endmodule

总结

本文教大家如何用FPGA实现实时地卷积运算,以实现FIR滤波器,若大家使用该模块过程遇到问题可以私信我。

  • 8
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值