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
curton 2019-5-4 16:46