Verilog99题——38-42题(Fir滤波器)
前言
不忘出芯veriloig99题的38-42题是Fir滤波器的Verilog实现
-
- 前言
- FIR理论
- 38.用verilog实现一个3-tap低通FIR滤波器,输入输出为8bit无符号数,滤波器系数
[1/4 1/2 1/4]
- 综合结果
- 39. 用verilog实现一个3-tap低通FIR滤波器,输入输出为8bit无符号数,滤波器系数
[1/4 1/2 1/4]
,支持bypass功能:fir_bypass为1时输出原始数据。 - 40. 用verilog实现一个低通FIR滤波器,输入输出为8bit无符号数,滤波器系数根据mode选择:
- 41. 用verilog实现一个参数化的FIR滤波器。
- 42. 用verilog实现一个3-tap低通FIR滤波器,Y通路输入输出为8bit无符号数,滤波器系数
[1/4 1/2 1/4]
。C通路bypass输出。
- 前言
FIR理论
线性时不变( linear time-invariant,LTI)滤波器是一种最为普通的数字滤波器。LTI通过如下的线性卷积过程与其输入信号相互作用。
y[n]=x[n]∗f[n]=k∑x[k]f[n−k]=k∑f[k]x[n−k]
直接形式的FIR滤波器
带有常系数的FIR滤波器是一种LTI滤波器。对于输入序列x[n],长度为L或N=L-1阶FIR的输出可通过上式的有限卷积和的形式给出,即:
y[n]=x[n]∗f[n]=k=0∑L−1f[k]x[n−k]
其中f[0]=0直到f[L−1]=0都是FIR的L个系数,同时也对应FIR的脉冲响应。对于LTI系统,在z域描述上式更便捷:
Y(z)=F(z)X(z)
其中F(z)是FIR的传递函数,其在z域的定义:F(z)=∑k=0L−1f[k]z−k
下图给出长度为L的LTI型FIR滤波器的图解。FIR滤波器由“抽头延迟线”、加法器、乘法器混合构成。该图展示了直接形式的FIR滤波器。
FIR滤波器的转置结构
FIR滤波器的卷积公式可以表示成另一种形式,即
y[n]=f[n]∗x[n]=k=0∑L−1f[n−k]x[k]
这种形式的FIR滤波器结构是直接FIR滤波器的转置结构。如下图所示,给出FIR滤波器的转置结构。
两种结构的粗略对比
直接FIR滤波器结构需要在两个加法器之间插入额外的流水线寄存器,来降低加法器树的延迟,以实现高吞吐量。而转置结构在加法器之间都存在寄存器,因此在不插入额外寄存器的情况下,就可以达到和直接FIR滤波器相同的吞吐量。转置滤波器结构需要更多的延迟寄存器,转置FIR延迟寄存器的个数比直接FIR滤波器使用的寄存器的个数的2倍还要多一点。在某种程度上,这可能是转置FIR相比于标准FIR的一个缺点。但是,在FPGA中,由于可用的延迟/触发器的数量很多,所以可以不必太在意这个问题。
改进FIR硬件实现的方法
- 通过对系数采用CSD编码,如3.75=22−2−2。
- 注意系数是否具有对称性,并加以利用。
- 采用流水线技术。
接下来看题目:
38.用verilog实现一个3-tap低通FIR滤波器,输入输出为8bit无符号数,滤波器系数[1/4 1/2 1/4]
module fir_lpf_3tap (
input clk,
input rst_n,
input [7:0] din,
output [7:0] dout
);
...
endmodule
verilog描述
本题采用直接结构的FIR,由于系数简单直接采用截位的方式实现,并为采用流水线和对称结构。
module fir_lpf_3tap(
input clk ,
input rst_n ,
input [7:0] din ,
output reg [7:0] dout
);
reg [7:0] tap [0:2];
integer i;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for (i = 0; i<=2; i=i+1) begin
tap[i] <= 0;
end
dout <= 8'd0;
end else begin
// dout <= (tap[0] >> 2) + (tap[1] >> 1) + (tap[2] >> 2);
dout <= tap[0][7:2] + tap[1][7:1] + tap[2][7:2];
/* for (i = 2; i > 0; i=i-1) begin
tap[i] <= tap[i-1];
end */
tap[2] <= tap[1];
tap[1] <= tap[0];
tap[0] <= din;
end
end
endmodule
综合结果
该综合结果与直接形式的FIR滤波器的结构图对比,可以很明显看出两种结构完全一致。
39. 用verilog实现一个3-tap低通FIR滤波器,输入输出为8bit无符号数,滤波器系数[1/4 1/2 1/4]
,支持bypass功能:fir_bypass为1时输出原始数据。
注:bypass即为全通
module fir_lpf_3tap (
input clk,
input rst_n,
input fir_bypass,
input [7:0] din,
output [7:0] dout
);
...
endmodule
verilog描述
module fir_lpf_3tap(
input clk ,
input rst_n ,
input fir_bypass ,
input [7:0] din ,
output reg [7:0] dout
);
reg [7:0] tap [0:2];
integer i;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for (i = 0; i<=2; i=i+1) begin
tap[i] <= 0;
end
dout <= 8'd0;
end else if (!fir_bypass)begin
// dout <= (tap[0] >> 2) + (tap[1] >> 1) + (tap[2] >> 2);
dout <= tap[0][7:2] + tap[1][7:1] + tap[2][7:2];
/* for (i = 2; i > 0; i=i-1) begin
tap[i] <= tap[i-1];
end */
tap[2] <= tap[1];
tap[1] <= tap[0];
tap[0] <= din;
end else begin
dout <= din;
end
end
endmodule
40. 用verilog实现一个低通FIR滤波器,输入输出为8bit无符号数,滤波器系数根据mode选择:
mode 0:bypass
mode 1:[1 2 1]/4
mode 2:[1 2 2 2 1]/8
mode 3:[1 2 3 4 3 2 1]/16
module fir_lpf (
input clk,
input rst_n,
input [1:0] mode,
input [7:0] din,
output [7:0] dout
);
...
endmodule
简要分析
- 系数是关于中间对称的。
- 系数可以通过移位实现。
- 可以使用流水线:
- 延迟(获取输入采样)。
- 与系数相乘,获得乘积(乘法、移位)。
- 乘积作和(计算结果)。
verilog描述
仍然采用直接形式设计,但是使用了系数对称和流水线来改进设计。
module test40(
input clk ,
input rst_n ,
input [1:0] mode ,
input [7:0] din ,
output [7:0] dout
);
reg [7:0] tap [6:0];
reg [8:0] product [3:0];
reg [7:0] dout_r;
//延迟(获取输入采样)
integer i;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for (i = 0; i <= 6; i = i + 1) begin
tap[i] <= 8'd0;
end
end else begin
for (i = 6; i > 0; i = i - 1) begin
tap[i] <= tap[i-1];
end
tap[0] <= din;
end
end
//与系数相乘,获得乘积(乘法、移位)
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for (i = 0; i <= 3; i = i + 1) begin
product[i] <= 8'd0;
end
end else begin
case (mode)
2'd1: begin
product[0] = (tap[0] + tap[2]) >> 2;
product[1] = tap[1] >> 1;
end
2'd2: begin
product[0] = (tap[0] + tap[4]) >> 3;
product[1] = (tap[1] + tap[2] + tap[3]) >> 2;
end
2'd3: begin
product[0] = (tap[0] + tap[6]) >> 4;
product[1] = (tap[1] + tap[5]) >> 3;
product[2] = ((tap[2] + tap[4]) * 3) >> 4;
product[3] = tap[3] >> 2;
end
default: ;
endcase
end
end
//乘积作和(计算结果)
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
dout_r <= 8'd0;
end else begin
case (mode)
2'd1: dout_r <= product[0] + product[1];
2'd2: dout_r <= product[0] + product[1];
2'd3: dout_r <= (product[0] + product[1]) + (product[2] + product[3]);
default: dout_r <= din;
endcase
end
end
assign dout = dout_r;
endmodule
41. 用verilog实现一个参数化的FIR滤波器。
可配置参数包括 1. 输入输出数据位宽N 2. 滤波器阶数T 3. 滤波器系数位宽M
(输入数据与滤波器系数为无符号数)
verilog描述
//基于SOP(乘积和)的转置结构的FIR滤波器。
//load_sw为低时为缓存系数过程,load_sw为高时为计算和输出过程。
module fir
#(
parameter DIN_WIDTH = 8 , //输入数据位宽
FIR_TAP = 4 , //滤波器阶数
COEF_WIDTH = 8 , //系数位宽
DOUT_WIDTH = 8 //输出数据位宽
)
(
input clk ,
input rst_n ,
input load_sw , // load/run switch
input [ DIN_WIDTH-1:0] data_in , //数据
input [COEF_WIDTH-1:0] coff_in , //系数
output [DOUT_WIDTH-1:0] data_out //输出
);
localparam PROD_WIDTH = DIN_WIDTH + COEF_WIDTH, //乘积位宽
ADD_WIDTH = PROD_WIDTH + clogb2(FIR_TAP) ;//乘积和位宽
reg [DIN_WIDTH-1:0] data_in_r;
wire [ADD_WIDTH-1:0] data_out_w;
reg [COEF_WIDTH-1:0] coff [FIR_TAP-1:0]; //系数
wire [PROD_WIDTH-1:0] prod [FIR_TAP-1:0]; //乘积
reg [ADD_WIDTH-1:0] sum [FIR_TAP-1:0]; //乘积和
//----> Load Data or Coefficient
always @(posedge clk or negedge rst_n) begin: LOAD
integer i;
if (!rst_n) begin
for (i = 0; i <= FIR_TAP-1; i = i +1) begin
coff[i] <= 'd0;
end
data_in_r <= 'd0;
end else if(!load_sw) begin //缓存系数
coff[FIR_TAP-1] <= coff_in;
for (i = FIR_TAP-1; i > 0; i = i -1) begin
coff[i-1] <= coff[i];
end
end else begin
data_in_r <= data_in; //缓存数据
end
end
//----> Compute products
genvar k;
generate
for (k = 0; k < FIR_TAP; k = k + 1) begin
assign prod[k] = data_in_r * coff[k];
end
endgenerate
//----> Compute sum-of-products
always @(posedge clk or negedge rst_n) begin: SOP
integer m;
if (!rst_n) begin
for (m = 0; m < FIR_TAP; m = m + 1) begin
sum[m] <= 'd0;
end
end else begin
for (m = 0; m < FIR_TAP - 1; m = m + 1) begin
sum[m] <= prod[m] + sum[m+1];
end
sum[FIR_TAP-1] <= prod[FIR_TAP-1];
end
end
assign data_out_w = sum[0];
assign data_out = data_out_w[ADD_WIDTH-1:ADD_WIDTH-DOUT_WIDTH];
function integer clogb2 (input integer depth);
begin
for(clogb2=0; depth>1; clogb2=clogb2+1)
depth = depth >> 1;
end
endfunction
endmodule
综合结果
42. 用verilog实现一个3-tap低通FIR滤波器,Y通路输入输出为8bit无符号数,滤波器系数[1/4 1/2 1/4]
。C通路bypass输出。
module fir_lpf_3tap_YC (
input clk,
input rst_n,
input [7:0] yin,
output [7:0] yout,
input [7:0] cin,
output [7:0] cout
);
...
endmodule
verilog描述
module fir_lpf_3tap(
input clk ,
input rst_n ,
input [7:0] yin ,
output [7:0] yout ,
input [7:0] cin ,
output [7:0] cout
);
reg [7:0] tap [0:2];
reg [8:0] product [0:1];
reg [7:0] yout_r ;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
tap[0] <= 8'd0;
tap[1] <= 8'd0;
tap[2] <= 8'd0;
end else begin
tap[2] <= tap[1];
tap[1] <= tap[0];
tap[0] <= yin;
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
product[0] <= 9'd0;
product[1] <= 9'd0;
end else begin
product[0] = (tap[0] + tap[2]) >> 2;
product[1] = tap[1] >> 1;
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
yout_r <= 8'd0;
end else begin
yout_r <= product[0] + product[1];
end
end
assign yout = yout_r;
assign cout = cin;
endmodule
即将入行的数字IC设计工程师