差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
fpga滤波器实现 [2020/07/22 14:17] zili |
— (当前版本) | ||
---|---|---|---|
行 1: | 行 1: | ||
- | ### FPGA滤波器实现 | ||
- | \\ | ||
- | |||
- | #### FPGA滤波器实施概述 | ||
- | 我协助我的一位研究生进行了一些有关FPGA滤波器实现的定向研究。她的任务是了解并实现FPGA硬件上的几种类型的过滤器。设计的所有滤波器均为15阶滤波器,并使用16位定点数学运算。然后检查了过滤器的性能和资源使用情况。她关于研究的最终演讲可以在下面查看:\\ | ||
- | |||
- | [[https://www.eetree.cn/wiki/_media/filter_implementation_on_a_fpga_board_xueyan_lu_06152017.pdf|FPGA滤波器实现]]\\ | ||
- | |||
- | 研究项目期间创建的Verilog源文件如下。\\ | ||
- | \\ | ||
- | |||
- | #### FIR滤波器 | ||
- | FIR滤波器是四个滤波器中最简单,最快的。它利用了预加器的对称性。而且,使用加法器树来最小化组合路径延迟。\\ | ||
- | |||
- | ##### FIR_Filter.v | ||
- | <code verilog> | ||
- | |||
- | `define FILT_LENGTH 16 | ||
- | |||
- | module FIR_Filter( | ||
- | input clk, | ||
- | input en, | ||
- | input [15:0]din, | ||
- | output [15:0]dout | ||
- | ); | ||
- | |||
- | reg signed [15:0]coeff[`FILT_LENGTH/2-1:0]; //Filter coefficients. | ||
- | reg signed [15:0]delay_line[`FILT_LENGTH-1:0]; //Input delay line. | ||
- | wire [31:0]accum; //Accumulator for output filter calculation. | ||
- | integer i; //Initialization integer. | ||
- | genvar c; //Delay line generation variable. | ||
- | |||
- | reg signed [16:0]preadd_regs[7:0]; //Save calc after preadd. | ||
- | reg signed [31:0]mult_regs[7:0]; //Save calc after multiplication. | ||
- | reg signed [31:0]tree1_regs[3:0]; //Save calc after first layer of adder tree. | ||
- | reg signed [31:0]tree2_regs[1:0]; //Save calc after first layer of adder tree. | ||
- | reg signed [31:0]treeout_reg; //Save calc after complete. | ||
- | |||
- | //assign dout = treeout_reg[31:16]; | ||
- | | ||
- | //Calculate value in the accumulator. | ||
- | assign accum = (delay_line[0] + delay_line[15]) * coeff[0] + | ||
- | (delay_line[1] + delay_line[14]) * coeff[1] + | ||
- | (delay_line[2] + delay_line[13]) * coeff[2] + | ||
- | (delay_line[3] + delay_line[12]) * coeff[3] + | ||
- | (delay_line[4] + delay_line[11]) * coeff[4] + | ||
- | (delay_line[5] + delay_line[10]) * coeff[5] + | ||
- | (delay_line[6] + delay_line[9]) * coeff[6] + | ||
- | (delay_line[7] + delay_line[8]) * coeff[7]; | ||
- | |||
- | //Assign upper 16-bits to output. | ||
- | assign dout = accum[31:16]; | ||
- | | ||
- | initial begin | ||
- | //Load the filter coefficients. | ||
- | coeff[0] = 16'd2320; | ||
- | coeff[1] = 16'd4143; | ||
- | coeff[2] = 16'd4592; | ||
- | coeff[3] = 16'd7278; | ||
- | coeff[4] = 16'd8423; | ||
- | coeff[5] = 16'd10389; | ||
- | coeff[6] = 16'd11269; | ||
- | coeff[7] = 16'd12000; | ||
- | |||
- | //Initialize delay line. | ||
- | for(i = 0; i < `FILT_LENGTH; i = i+1'b1) begin | ||
- | delay_line[i] = 16'd0; | ||
- | end | ||
- | | ||
- | //Initialize the preadder regs. | ||
- | for(i = 0; i < 8; i = i+1'b1) begin | ||
- | preadd_regs[i] = 17'd0; | ||
- | end | ||
- | | ||
- | //Initialize the multiplier regs. | ||
- | for(i = 0; i < 8; i = i+1'b1) begin | ||
- | mult_regs[i] = 32'd0; | ||
- | end | ||
- | | ||
- | //Initialize the first layer of the adder tree regs. | ||
- | for(i = 0; i < 4; i = i+1'b1) begin | ||
- | tree1_regs[i] = 32'd0; | ||
- | end | ||
- | | ||
- | //Initialize the second layer of the adder tree regs. | ||
- | for(i = 0; i < 2; i = i+1'b1) begin | ||
- | tree2_regs[i] = 32'd0; | ||
- | end | ||
- | | ||
- | //Initialize the adder tree output reg. | ||
- | treeout_reg = 32'd0; | ||
- | end | ||
- | | ||
- | //Advance the data through the delay line every clock cycle. | ||
- | generate | ||
- | for (c = `FILT_LENGTH-1; c > 0; c = c - 1) begin: inc_delay | ||
- | always @(posedge clk) begin | ||
- | if(en) delay_line[c] <= delay_line[c-1]; | ||
- | end | ||
- | end | ||
- | endgenerate | ||
- | | ||
- | //Update with input data. | ||
- | always @(posedge clk) begin | ||
- | if(en) delay_line[0] <= din; | ||
- | end | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | ##### filter_top.v | ||
- | <code verilog> | ||
- | |||
- | module filter_top( | ||
- | input clk, | ||
- | input [7:0]sw, | ||
- | output [7:0]JA | ||
- | ); | ||
- | | ||
- | wire [15:0]tout; //The output of the tone lookup table. | ||
- | wire [15:0]fout; //The output of the FIR filter. | ||
- | wire [15:0]mout; //Selected output. | ||
- | wire en; //Clock enble. | ||
- | wire clk_out; //264MHz System clock. | ||
- | | ||
- | assign en = 1'b1; | ||
- | | ||
- | clk_wiz_0 cw (.clk_in1(clk), .clk_out1(clk_out)); | ||
- | //clk_en ce(.clk(clk_out), .en(en)); | ||
- | ToneGen tg(.clk(clk_out), .en(en), .dout(tout)); | ||
- | FIR_Filter ff(.clk(clk_out), .en(en), .din(tout), .dout(fout)); | ||
- | | ||
- | //Choose filtered or unfiltered output based on sw0. | ||
- | assign mout = sw[0] ? fout : tout; | ||
- | | ||
- | //Take only the upper 8 bits and make it unsigned. | ||
- | //assign JA = mout[15:8] + 8'd128; | ||
- | assign {JA[3:0], JA[7:4]} = mout[15:8] + 8'd128; | ||
- | | ||
- | endmodule | ||
- | |||
- | </code> | ||
- | \\ | ||
- | |||
- | |||
- | |||
- | |||