原创 第三章 3.2——FIR滤波器的FPGA实现(2)

2017-9-15 22:40 1651 13 2 分类: FPGA/CPLD

FIR 滤波器的Verilog 代码实现

(1)FIR滤波器的串行实现

根据FIR滤波器的表达式,滤波器实质就是做一个乘累加运算。乘累加运算的次数由滤波器的阶数来决定,其串行结构如图所示。




      利用串行结构来实现FIR滤波器所使用的资源较少,只要一些寄存器、一个乘累加器就可以完成整个滤波运算,但是它的最大缺点是滤波速度慢,一次滤波需要的时钟数由滤波器的阶数决定。要设计一个32阶的滤波器,就需要32个时钟周期才能得到一次滤波的结果。

      由于FIR滤波器具有对称系数,因此可先进行加法运算,然后把加法运算的的结果再进行乘累加运算。如图所示。



  在上面的实现中,虽然比纯粹的串行滤波器多用 N/2 (N为滤波器的阶数)个加法器,但完成一次滤波结果所需时钟的周期数也减半,只需 N/2个乘累加运算。这正是硬件设计中面积和速度相互转换的结果,即多消耗了硬件资源,但同时也可以把处理的速度提高。串行滤波器只使用一个乘累加器,在硬件资源上比较节省。

(2)用verilog 实现一个8阶改进串行FIR低通滤波器,输入数据的位宽12

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2017/09/13 14:15:03
// Design Name:
// Module Name: fir
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////

module fir(
    clk,rst_n,fir_in,fir_out
    );
   
parameter IDATA_WIDTH = 12; //输入数据位宽
parameter PDATA_WIDTH = 13; //处理数据位宽
parameter FIR_TAP = 8; //FIR 抽头
parameter FIR_TAPHALF = 4;
parameter COEFF_WIDTH = 12; //系数位宽
parameter OUT_WIDTH = 27; //输出位宽
parameter cof1 = 12'd41;
parameter cof2 = 12'd132;
parameter cof3 = 12'd341;
parameter cof4 = 12'd510;
input clk,rst_n; // clk的频率是数据速率的4倍
input [IDATA_WIDTH-1:0] fir_in;
output [OUT_WIDTH-1:0] fir_out;
reg [OUT_WIDTH-1:0] fir_out;
reg [IDATA_WIDTH-1:0] fir_in_reg;
//定义一个8位移位寄存器
reg [PDATA_WIDTH-1:0] shift_buf[FIR_TAP-1:0];
reg [PDATA_WIDTH-1:0] add07;
reg [PDATA_WIDTH-1:0] add16;
reg [PDATA_WIDTH-1:0] add25;
reg [PDATA_WIDTH-1:0] add34;
reg [COEFF_WIDTH-1:0] cof_reg_maca;
reg [PDATA_WIDTH-1:0] add_reg_macb;
wire [COEFF_WIDTH+PDATA_WIDTH-1:0] result;
reg [OUT_WIDTH-1:0] sum;
reg [2:0] count;
integer i,j;
always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
        fir_in_reg <= 12'd0;
   else
        if (count[2]==1'b1)
            fir_in_reg <= fir_in;
end
 
always @(posedge clk or negedge rst_n)begin
   if(!rst_n)
        for(i=0; i<=FIR_TAP-1; i=i+1)
            shift_buf <= 13'd0;
   else
        if(count[2]==1'b1)begin
            for(j=0; j<FIR_TAP-1;j=j+1)
                shift_buf[j+1] <= shift_buf[j];
            shift_buf[0] <= {fir_in_reg[IDATA_WIDTH-1],fir_in_reg};
           
       
        end
   
   
end
always @(posedge clk or negedge rst_n)begin
   if(!rst_n)begin
        add07 <= 13'd0;
        add16 <= 13'd0;
        add25 <= 13'd0;
        add34 <= 13'd0;
    end
   
    else
        if(count[2]==1'b1)begin
           add07 <= shift_buf[0] + shift_buf[7];
           add16 <= shift_buf[1] + shift_buf[6];
           add25 <= shift_buf[2] + shift_buf[5];
           add34 <= shift_buf[3] + shift_buf[4];
        end
   
end
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        count <= 3'd0;
    else begin
        if(count==3'b100)
            count <= 3'b000;
        else
            count <= count + 1'b1;
    end
   
end
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        cof_reg_maca <= 12'd0;
        add_reg_macb <= 13'd0;  
       
    end
    else begin
       case(count)
       
            3'b000:begin
                cof_reg_maca <= cof1;
                add_reg_macb <=add07;
            end
               
            3'b001:begin
                cof_reg_maca <= cof2;
                add_reg_macb <= add16;
                end
               
            3'b010:begin
                 cof_reg_maca <= cof3;
                 add_reg_macb <= add25;
                end
                 
            3'b011:begin
                  cof_reg_maca <= cof4;
                  add_reg_macb <= add34;
                end
             
            default:begin
                 cof_reg_maca <= 12'b0;
                 add_reg_macb <= 13'b0;  
                end
               
       endcase
    end
end

mult_gen_0 your_instance_name (
  .CLK(clk),  // input wire CLK
  .A(cof_reg_maca),      // input wire [11 : 0] A
  .B(add_reg_macb),      // input wire [12 : 0] B
  .P(result)      // output wire [24 : 0] P
);   
wire [OUT_WIDTH-1 : 0] result_out = {{3{result[23]}},result};
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        sum <= 27'b0;
    else
        if(count == 3'b000)
            sum <= 27'b0;
        else
            sum <= sum + result_out;
   
end
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        fir_out <= 27'b0;
    else
        if(count == 3'b000)
            fir_out <= sum;
end


endmodule


 



PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

curton 2019-5-4 16:46

好资源 学习了
相关推荐阅读
LoneSurvivor 2018-02-25 08:26
C++输入/输出流(2)
1. get()函数#include<iostream>using namespace std;int main(){    char s1[80], s2[...
LoneSurvivor 2018-02-23 12:19
C++输入/输出流(1)
1. 输入/输出流类层次 C++的输入/输出流类库是用派生方法建立起的,它有2个平行的基类,streambuf和ios。其他的流类都是从这两个基类直接或间接派生的。1.1   s...
LoneSurvivor 2018-02-19 11:36
C++多态(4)——特殊运算符重载和类类型转换
1.“++”和“--”的重载     运算符“++”和“--”的重载要区分前置和后置两种形式。如果不区分前置和后置,则使用operator++()或operator—()即可,否...
LoneSurvivor 2018-02-12 11:15
C++多态(3)——运算符重载
1.     运算符重载的定义     运算符重载也是实现多态的一个重要手段。运算符重载实现的是编译时的多态,即静态多态性。C++预定义的...
LoneSurvivor 2018-02-12 10:31
C++多态(2)——纯虚函数与抽象类
   抽象类是一种特殊的类,它提供了统一的操作界面。建立抽象类是为了多态地使用抽象类的成员函数。抽象类是包含纯虚函数的类。 1.     ...
LoneSurvivor 2018-02-11 16:24
C++多态(1)
1.     多态      多态是人类思维方式的一种直接模拟,多态性是指不同对象接收到相同的消息时,根据对象类的不同而产生不同...
EE直播间
更多
我要评论
1
13
关闭 站长推荐上一条 /3 下一条