当前位置:   article > 正文

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

fir滤波器 verilog

一、FIR滤波器模块介绍

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

二、该模块用法介绍

1、 用MATLAB生成滤波器系数

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

然后用MATLAB产生COE文件

  1. Hd=load('untitled.mat');
  2. filtercoeff=Hd.LF.Numerator*80000;
  3. % 将数据量化为8位整数(如果需要)
  4. figure;
  5. filter_coe_quantized_data = int16(fliplr(filtercoeff));
  6. plot(filter_coe_quantized_data)
  7. % 保存为COE文件
  8. coe_file = fopen('filter.coe', 'w');
  9. fprintf(coe_file, 'memory_initialization_radix=10;\n');
  10. fprintf(coe_file, 'memory_initialization_vector=\n');
  11. for i = 1:length(filter_coe_quantized_data)
  12. fprintf(coe_file, '%d,\n', filter_coe_quantized_data(i));
  13. end
  14. 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代码

  1. `timescale 1ns/1ns
  2. // Author : 悠志
  3. // Create Date : 2023/10/10
  4. module low_filter
  5. (
  6. input wire sys_clk ,
  7. input wire sys_rst_n ,
  8. input wire data_flag ,
  9. input wire signed [15:0] data ,
  10. output reg signed [31:0] rela_data
  11. );
  12. parameter RELA_NUM= 'd30;//31-1
  13. reg [10:0] ccl_cnt;
  14. reg judge_en;//卷积运算结果判断
  15. reg ccl_en ;
  16. reg ccl_en_d1;
  17. reg signed [31:0] mult_data ;
  18. // sum_ram
  19. wire signed [31:0] sum_rela_rom_data ;
  20. reg signed [31:0] sum_data ;
  21. reg sum_ram_wr_en ;
  22. reg sum_ram_rd_en ;
  23. reg [9:0] sum_ram_wr_addr ;
  24. reg [9:0] sum_ram_rd_addr ;
  25. wire signed [15:0] rela_rom_data ;
  26. reg [9:0] rela_rom_addr ;
  27. //ccl_cnt
  28. always@(posedge sys_clk or negedge sys_rst_n)
  29. if(sys_rst_n==1'b0)
  30. ccl_cnt<=10'd0;
  31. else if(ccl_en==1'b1)
  32. ccl_cnt<=ccl_cnt+1'b1;
  33. else if(ccl_cnt==10'd0||ccl_cnt==RELA_NUM+10'd3)
  34. ccl_cnt<=10'd0;
  35. else
  36. ccl_cnt<=ccl_cnt+1'b1;
  37. //judge_en
  38. always@(posedge sys_clk or negedge sys_rst_n)
  39. if(sys_rst_n==1'b0)
  40. judge_en<=1'b0;
  41. else if(ccl_cnt==RELA_NUM+10'd2)
  42. judge_en<=1'b1;
  43. else
  44. judge_en<=1'b0;
  45. //ccl_en
  46. always@(posedge sys_clk or negedge sys_rst_n)
  47. if(sys_rst_n==1'b0)
  48. ccl_en<=1'b0;
  49. else if(data_flag==1'b1)
  50. ccl_en<=1'b1;
  51. else if(ccl_cnt==RELA_NUM)
  52. ccl_en<=1'b0;
  53. else
  54. ccl_en<=ccl_en;
  55. //ccl_en_d1
  56. always@(posedge sys_clk or negedge sys_rst_n)
  57. if(sys_rst_n==1'b0)
  58. ccl_en_d1<=1'b0;
  59. else
  60. ccl_en_d1<=ccl_en;
  61. //rela_rom_addr
  62. always@(posedge sys_clk or negedge sys_rst_n)
  63. if(sys_rst_n==1'b0)
  64. rela_rom_addr<=10'd0;
  65. else if(data_flag==1'b1)
  66. rela_rom_addr<=rela_rom_addr+1'b1;
  67. else if(rela_rom_addr==RELA_NUM||rela_rom_addr==10'd0)
  68. rela_rom_addr<=10'd0;
  69. else
  70. rela_rom_addr<=rela_rom_addr+1'b1;
  71. //mult_data
  72. always@(posedge sys_clk or negedge sys_rst_n)
  73. if(sys_rst_n==1'b0)
  74. mult_data<=32'd0;
  75. else if(ccl_en_d1==1'b1)
  76. mult_data<=rela_rom_data*data;
  77. else
  78. mult_data<=mult_data;
  79. //sum_ram_rd_en
  80. always@(posedge sys_clk or negedge sys_rst_n)
  81. if(sys_rst_n==1'b0)
  82. sum_ram_rd_en<=1'b0;
  83. else
  84. sum_ram_rd_en<=ccl_en_d1;
  85. //sum_ram_rd_addr
  86. always@(posedge sys_clk or negedge sys_rst_n)
  87. if(sys_rst_n==1'b0)
  88. sum_ram_rd_addr<=10'd0;
  89. else if(sum_ram_rd_en==1'b0)
  90. sum_ram_rd_addr<=10'd0;
  91. else
  92. sum_ram_rd_addr<=sum_ram_rd_addr+1'b1;
  93. //sum_data
  94. always@(posedge sys_clk or negedge sys_rst_n)
  95. if(sys_rst_n==1'b0)
  96. sum_data<=16'd0;
  97. else if(sum_ram_rd_en==1'b1)
  98. begin
  99. if(sum_ram_rd_addr==10'd0)
  100. sum_data<=mult_data;
  101. else
  102. sum_data<=sum_rela_rom_data+mult_data;
  103. end
  104. else
  105. sum_data<=sum_data;
  106. //sum_ram_wr_en
  107. always@(posedge sys_clk or negedge sys_rst_n)
  108. if(sys_rst_n==1'b0)
  109. sum_ram_wr_en<=1'b0;
  110. else
  111. sum_ram_wr_en<=sum_ram_rd_en;
  112. //sum_ram_wr_addr
  113. always@(posedge sys_clk or negedge sys_rst_n)
  114. if(sys_rst_n==1'b0)
  115. sum_ram_wr_addr<=10'd0;
  116. else
  117. sum_ram_wr_addr<=sum_ram_rd_addr;
  118. //rela_data
  119. always@(posedge sys_clk or negedge sys_rst_n)
  120. if(sys_rst_n==1'b0)
  121. rela_data<='d0;
  122. else if(judge_en==1'b1)
  123. rela_data<=sum_data;
  124. else
  125. rela_data<=rela_data;
  126. sum_ram sum_ram_inst (
  127. .clka(sys_clk), // input wire clka
  128. .ena(sum_ram_wr_en), // input wire ena
  129. .wea(1'b1), // input wire [0 : 0] wea
  130. .addra(sum_ram_wr_addr), // input wire [9 : 0] addra
  131. .dina(sum_data), // input wire [31 : 0] dina
  132. .douta(), // output wire [31 : 0] douta
  133. .clkb(sys_clk), // input wire clkb
  134. .enb(sum_ram_rd_en), // input wire enb
  135. .web(1'b0), // input wire [0 : 0] web
  136. .addrb(sum_ram_rd_addr), // input wire [9 : 0] addrb
  137. .dinb(), // input wire [31 : 0] dinb
  138. .doutb(sum_rela_rom_data) // output wire [31 : 0] doutb
  139. );
  140. filter_rom filter_rom_inst (
  141. .clka(sys_clk), // input wire clka
  142. .addra(rela_rom_addr), // input wire [4 : 0] addra
  143. .douta(rela_rom_data) // output wire [15 : 0] douta
  144. );
  145. endmodule

总结

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/846019
推荐阅读
相关标签
  

闽ICP备14008679号