FPGA学习记录(8)<8bit输入的FIR滤波器的FPGA实现>

Written by @hzj
//JinXing Project
#2021.11.2 V1.0
#2021.11.3 V1.1

8bit的FIR滤波器的FPGA实现

为了让滤波器的处理速度更快,可以使用8bit的同时输入,那么此文就将改写前文写的FIR滤波器进行改写,原来8个clk_sig只能处理一个信号,现在同时传输8个信号进行处理。但是由于输出信号的局限(只能一个一个clk周期输出一个滤波后的信号),因此是每8个周期统一一次性输入8个信号,然后一个clk出去一个。注意 :后期是可以实现一个周期输入一个8bit信号,然后同时在这个周期输出8bit滤波后的信号,只需要改变成为8个卷积单元即可。(相当于增加更多的器件,让整个系统的处理速度更快),但由于本文的实现方式的局限性(需要根据每一个clk输出一个滤波信号),没有采用这样的方式。
前文的实现: FPGA学习记录(5)<低通&带通FIR滤波器FPGA实现>.

`timescale 1ns / 1ps

module FIR_low8(
    input clk                            , //输入的系统时钟,时钟驱动
    input clk_sig                        , //计数信号
    input rst_n                          , //定义复位信号,供里面所有的参量进行复位,复位信号使用的是低电平有效  
    input signed [15:0] data_in_1        , //一个clk_sig信号,输入第一位数据位
    input signed [15:0] data_in_2        , //一个clk_sig信号,输入第二位数据位
    input signed [15:0] data_in_3        , //一个clk_sig信号,输入第三位数据位
    input signed [15:0] data_in_4        , //一个clk_sig信号,输入第四位数据位 
    input signed [15:0] data_in_5        , //一个clk_sig信号,输入第五位数据位
    input signed [15:0] data_in_6        , //一个clk_sig信号,输入第六位数据位
    input signed [15:0] data_in_7        , //一个clk_sig信号,输入第七位数据位
    input signed [15:0] data_in_8        , //一个clk_sig信号,输入第八位数据位

    output reg signed [15:0] data_out    , //定义滤波之后的数据,使用reg变量进行保存,有效位为16bit
    output reg signed [15:0] input_wave
    );

parameter U_DELAY = 1;//时序仿真信号,加上u_delay模拟信号的电路中传输的延迟

/*定义16个数据寄存器,用来存储待滤波信号的数据,每8个clk_sig信号输入8个数据进去,然后将源8个地位搬移到高8位上去
再将data_in_*中的数据打入到x1-x8这个低八位中去*/
reg signed [15:0] x1;   
reg signed [15:0] x2;
reg signed [15:0] x3;
reg signed [15:0] x4;
reg signed [15:0] x5;
reg signed [15:0] x6;
reg signed [15:0] x7;
reg signed [15:0] x8;
reg signed [15:0] x9;
reg signed [15:0] x10;
reg signed [15:0] x11;
reg signed [15:0] x12;
reg signed [15:0] x13;
reg signed [15:0] x14;
reg signed [15:0] x15;
reg signed [15:0] x16;

reg [2:0] count;

/* 根据时钟信号进行切换卷积器mul中的数据值,依次切换进行卷积。本次移位使用的是系统时钟,采用的下降沿rst_n进行复位,低有效位生效*/
always @ (posedge clk_sig or negedge rst_n) begin
    if (rst_n == 1'b0) begin
        x1 <= #U_DELAY 16'b0    ;
        x2 <= #U_DELAY 16'b0    ;
        x3 <= #U_DELAY 16'b0    ;
        x4 <= #U_DELAY 16'b0    ;
        x5 <= #U_DELAY 16'b0    ;
        x6 <= #U_DELAY 16'b0    ;
        x7 <= #U_DELAY 16'b0    ;
        x8 <= #U_DELAY 16'b0    ;
        x9 <= #U_DELAY 16'b0    ;
        x10 <= #U_DELAY 16'b0   ;
        x11 <= #U_DELAY 16'b0   ;
        x12 <= #U_DELAY 16'b0   ;
        x13 <= #U_DELAY 16'b0   ;
        x14 <= #U_DELAY 16'b0   ;
        x15 <= #U_DELAY 16'b0   ;
        x16 <= #U_DELAY 16'b0   ;
    end
    else begin
        x9  <= #U_DELAY x1                  ;//数据的搬移,以及新数据的打入
        x10 <= #U_DELAY x2                  ;
        x11 <= #U_DELAY x3                  ;
        x12 <= #U_DELAY x4                  ;
        x13 <= #U_DELAY x5                  ;
        x14 <= #U_DELAY x6                  ;
        x15 <= #U_DELAY x7                  ;
        x16 <= #U_DELAY x8                  ;
        x1  <= #U_DELAY data_in_8           ;
        x2  <= #U_DELAY data_in_7           ;
        x3  <= #U_DELAY data_in_6           ;
        x4  <= #U_DELAY data_in_5           ;   
        x5  <= #U_DELAY data_in_4           ;
        x6  <= #U_DELAY data_in_3           ;
        x7  <= #U_DELAY data_in_2           ;
        x8  <= #U_DELAY data_in_1           ;
    end
end

/*定义一个位宽大小位3的参数变量,这里的3位宽是由我们的滤波器系数决定的,由于参数个数的量=7,因此这个地方就应该有能够表示7种可能的大小即2^3=8*/
/*定义count的参数大小;每一个计数周期来临时自加一,该参数可以控制该时钟周期与何进行乘积;遇到下降沿的rst_n时,进行count初值恢复*/

always@(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0) begin
        count = 3'd0;
    end
    else begin
        count <= count + 1'b1;
    end
end


/* 加法器,根据量化系数的对称性,进行两者的加法,得到三个变量add2_7, add3_6, add4_5 */
wire signed [16:0] add2_7;
wire signed [16:0] add3_6;
wire signed [16:0] add4_5;

reg [15:0] num_x_2;
reg [15:0] num_x_3;
reg [15:0] num_x_4; 
reg [15:0] num_x_5;
reg [15:0] num_x_6;
reg [15:0] num_x_7;

assign add2_7 = {num_x_2[15] ,num_x_2} + {num_x_7[15], num_x_7};
assign add3_6 = {num_x_3[15], num_x_3} + {num_x_6[15], num_x_6};
assign add4_5 = {num_x_4[15], num_x_4} + {num_x_5[15], num_x_5};

wire signed [24:0] out_temp;

//例化调用模块,卷积层
mul mul_conv
(
    .add_2_7 (add2_7[16:0])   ,
    .add_3_6 (add3_6[16:0])   ,
    .add_4_5 (add4_5[16:0])   , 
    .mul_out (out_temp [24:0])
);

/*根据上述的count的值,轮流切换mul_a以及mul_b的值*/
always @ (posedge clk or negedge rst_n) begin
    if (rst_n == 1'b0) begin
                num_x_2 <= #U_DELAY 0        ;
                num_x_3 <= #U_DELAY 0        ;
                num_x_4 <= #U_DELAY 0        ;
                num_x_5 <= #U_DELAY 0        ;    
                num_x_6 <= #U_DELAY 0        ;
                num_x_7 <= #U_DELAY 0        ;
                input_wave <= 16'b0          ;
    end
    else begin
        case(count)
            3'b000 : begin
                num_x_2 <= #U_DELAY x10      ;
                num_x_3 <= #U_DELAY x11      ;
                num_x_4 <= #U_DELAY x12      ;
                num_x_5 <= #U_DELAY x13      ;    
                num_x_6 <= #U_DELAY x14      ;
                num_x_7 <= #U_DELAY x15      ;
                input_wave <= x8             ;
            end
            3'b001 : begin
                num_x_2 <= #U_DELAY x9       ;
                num_x_3 <= #U_DELAY x10      ;
                num_x_4 <= #U_DELAY x11      ;
                num_x_5 <= #U_DELAY x12      ;    
                num_x_6 <= #U_DELAY x13      ;
                num_x_7 <= #U_DELAY x14      ;
                input_wave <= x7             ;
            end
            3'b010 : begin
                num_x_2 <= #U_DELAY x8       ;
                num_x_3 <= #U_DELAY x9       ;
                num_x_4 <= #U_DELAY x10      ;
                num_x_5 <= #U_DELAY x11      ;    
                num_x_6 <= #U_DELAY x12      ;
                num_x_7 <= #U_DELAY x13      ;
                input_wave <= x6             ;
            end
            3'b011 : begin
                num_x_2 <= #U_DELAY x7       ;
                num_x_3 <= #U_DELAY x8       ;
                num_x_4 <= #U_DELAY x9       ;
                num_x_5 <= #U_DELAY x10      ;    
                num_x_6 <= #U_DELAY x11      ;
                num_x_7 <= #U_DELAY x12      ;
                input_wave <= x5             ;
            end
            3'b100 : begin
                num_x_2 <= #U_DELAY x6       ;
                num_x_3 <= #U_DELAY x7       ;
                num_x_4 <= #U_DELAY x8       ;
                num_x_5 <= #U_DELAY x9       ;    
                num_x_6 <= #U_DELAY x10      ;
                num_x_7 <= #U_DELAY x11      ;
                input_wave <= x4             ;
            end
            3'b101 : begin
                num_x_2 <= #U_DELAY x5       ;
                num_x_3 <= #U_DELAY x6       ;
                num_x_4 <= #U_DELAY x7       ;
                num_x_5 <= #U_DELAY x8       ;    
                num_x_6 <= #U_DELAY x9       ;
                num_x_7 <= #U_DELAY x10      ;
                input_wave <= x3             ;
            end
            3'b110 : begin
                num_x_2 <= #U_DELAY x4       ;
                num_x_3 <= #U_DELAY x5       ;
                num_x_4 <= #U_DELAY x6       ;
                num_x_5 <= #U_DELAY x7       ;    
                num_x_6 <= #U_DELAY x8       ;
                num_x_7 <= #U_DELAY x9       ;
                input_wave <= x2             ;
            end
            default : begin
                num_x_2 <= #U_DELAY x3       ;
                num_x_3 <= #U_DELAY x4       ;
                num_x_4 <= #U_DELAY x5       ;
                num_x_5 <= #U_DELAY x6       ;    
                num_x_6 <= #U_DELAY x7       ;
                num_x_7 <= #U_DELAY x8       ;
                input_wave <= x1             ;
            end
        endcase     
    end
end

/*定义一个输出的中间寄存器,out_temp,用来存储中间的变量值*/
always @ (posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0) begin
        data_out <= #U_DELAY 16'b0                ;
    end
    else begin
        data_out <= #U_DELAY out_temp[24:9]       ;
    end
end
endmodule

mul卷积层实现如下所示,里面特定了固定数的乘法:

module  mul(
    input [16:0] add_2_7       ,
    input [16:0] add_3_6       ,
    input [16:0] add_4_5       ,

    output signed [24:0] mul_out 
);

wire [23:0] mul_2_d;//绝对值乘积后的值
wire [23:0] mul_2;//乘积后取补码后的结果
wire [23:0] mul_3;
wire [23:0] mul_4;

/*进行三个乘法进行相加,完成整个卷积运算,对于mul_1,由于量化系数的大小为0,因此这个地方给予省略*/
assign mul_2_d = {{6{add_2_7[16]}}, add_2_7, 1'b0}            ;//11111110,这个地方先进行绝对值相乘,再进行取反的操作
assign mul_2   = (~mul_2_d) + 1'b1                            ;//取反进行取反加一

assign mul_3   = {{7{add_3_6[16]}}, add_3_6 
                    + {6{add_3_6[16]}}, add_3_6, 1'b0
                    + {3{add_3_6[16]}}, add_3_6, 4'b0}        ;//1 0011

assign mul_4   = {{3{add_4_5[16]}}, add_4_5, 4'b0 
                    + {2{add_4_5[16]}}, add_4_5, 5'b0
                    + {1{add_4_5[16]}}, add_4_5, 6'b0}        ;//111 0000

/*进行加法运算,将上述的三个乘法进行相加,完成整个卷积运算*/
assign mul_out = {mul_2[23], mul_2}
                 + {mul_3[23], mul_3}
                 + {mul_4[23], mul_4}                         ;  

endmodule

tb测试文件

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2021/10/16 14:50:22
// Design Name: 
// Module Name: tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
`timescale  1ns / 1ps

module tb_FIR_low8;

// FIR_low8 Parameters
parameter PERIOD  = 10;


// FIR_low8 Inputs
reg   clk                   ;
reg   clk_sig               ;
reg   rst_n                 ;
reg   signed [15:0]  data_in_1       ;
reg   signed [15:0]  data_in_2       ;
reg   signed [15:0]  data_in_3       ;
reg   signed [15:0]  data_in_4       ;
reg   signed [15:0]  data_in_5       ;
reg   signed [15:0]  data_in_6       ;
reg   signed [15:0]  data_in_7       ;
reg   signed [15:0]  data_in_8       ;
// FIR_low8 Outputs
wire  signed [15:0]  data_out      ;
integer i;

initial
begin
    clk                          = 0 ;
    clk_sig                      = 0 ;
    rst_n                        = 0 ;
    data_in_1                    = 0 ;
    data_in_2                    = 0 ;                    
    data_in_3                    = 0 ;
    data_in_4                    = 0 ;
    data_in_5                    = 0 ;
    data_in_6                    = 0 ;
    data_in_7                    = 0 ;
    data_in_8                    = 0 ;
    i                            = 1 ; //此处是从1开始计数,也就是说data_men中的第一个数的下标为[1],而非[0]
end

initial
begin
    forever #(PERIOD/2)  clk =~clk; //clk的周期
end

initial
begin
    forever begin
        clk_sig = ~clk_sig;
        #(PERIOD);
        clk_sig = ~clk_sig;
        #(PERIOD*7);
    end
end

initial
begin
    #(PERIOD*2) rst_n  =  1;  //复位信号
end


parameter data_num = 32'd10000;
reg [15:0] data_men[data_num:1];


initial begin
    $readmemb("C:/路径/tb/sin.txt",data_men);   //注意斜杠的方向,不能反<<<<<<<
end

always @(posedge clk_sig) begin //每1个clk_sig信号来临后,进行一次数据输入,将新的一个波形数据输入data_in中。
    data_in_1 <= data_men[i];
    data_in_2 <= data_men[i+1];
    data_in_3 <= data_men[i+2];
    data_in_4 <= data_men[i+3];
    data_in_5 <= data_men[i+4];
    data_in_6 <= data_men[i+5];
    data_in_7 <= data_men[i+6];
    data_in_8 <= data_men[i+7];
    i <= i+8;
end


FIR_low8  u_FIR_low8 (
    .clk                     ( clk              ),
    .clk_sig                 ( clk_sig          ),
    .rst_n                   ( rst_n            ),
    .data_in_1               ( data_in_1   [15:0] ),
    .data_in_2               ( data_in_2   [15:0] ),
    .data_in_3               ( data_in_3   [15:0] ),
    .data_in_4               ( data_in_4   [15:0] ),
    .data_in_5               ( data_in_5   [15:0] ),
    .data_in_6               ( data_in_6   [15:0] ),
    .data_in_7               ( data_in_7   [15:0] ),
    .data_in_8               ( data_in_8   [15:0] ),

    .data_out                ( data_out  [15:0] )
);

integer w_file;
initial w_file = $fopen("C:/路径/tb/simulation_out.txt");
always @(i)
begin
    $fdisplay(w_file,"%d",data_out);
    if(i == 32'd1000000)    //共写入个数据
        $stop;
end  


endmodule

滤波后的结果如下所示,可以看出与前文的结果相符。达到了滤波效果。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值