赞
踩
设计该模块作用是,可通过MATLAB产生h(n)序列的系数获得的coe文件(注意该系数需要处理成整数,后面以16bit的数据有符号数为例)。将数据保存rom中,信号输入该模块,该模块可以实现输入信号与h(n)序列的实时卷积输出。
首先用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);
这里IP核大小设置的其实比较大,可以实现1000阶的实时卷积,可以根据实际情况设置小些,比如这里MATLAB生成30阶滤波器,64的深度就够了。
rom 导入COE文件
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)序列的倒置。
- `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滤波器,若大家使用该模块过程遇到问题可以私信我。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。