理解和掌握 FIR 串行滤波器是踏入数字信号处理领域的重要一步。
那么,什么是 FIR 串行滤波器?它是如何工作的?又有着怎样的神奇之处呢?让我们一起揭开它的神秘面纱。
一、FIR 滤波器简介
FIR 滤波器,全称为有限脉冲响应(Finite Impulse Response)滤波器,是数字信号处理系统中最基本的元件之一。
与其他滤波器相比,FIR 滤波器具有独特的优势。它可以在保证任意幅频特性的同时具有严格的线性相频特征,这意味着它能够在对信号进行滤波处理时,不会对信号的相位产生扭曲,从而保证了信号的准确性。
此外,FIR 滤波器的单位抽样响应是有限长的,这使得滤波器是稳定的系统,不会像某些无限脉冲响应滤波器那样可能出现不稳定的情况。
二、FIR滤波器的工作原理
FIR滤波器的核心在于输入信号与单位冲击响应函数的卷积运算。
简单来说,就是将输入信号与滤波器的系数进行逐点相乘,然后将乘积结果累加起来,得到输出信号。
在并行结构中,同一个时刻,每个输入数据都与对应的滤波器系数相乘,并同时将上一个时刻各项乘法的结果进行求和,这样就能得到滤波结果,每个周期输出一个数据,也就是说滤波计算处理频率与输入信号采样频率一样,但消耗的资源会随着滤波器阶数而增加。
在串行结构中,只需要一个乘法器即可,可以节省资源,为了满足输入信号采样频率下同步输出滤波结果,也就是在一个输入信号周期内,需要完成所有计算,所以对于一个N阶FIR滤波器,考虑到对称系数的特性只要做N/2个乘法运算,也就是计算处理频率是输入信号采样频率的N/2倍。
三、FPGA代码实现
module fir_serial
(
input rst,
input clk,
input [11:0] data_in,
output [28:0] data_out
);
reg [12:0] add_a, add_b;
wire [12:0] add_s;
reg [11:0] coe; //12bit量化滤波器系数
wire [24:0] Mout;
reg [2:0] cnt;
reg [11:0] data_reg[15:0];
integer i;
reg [28:0] sum;
reg [28:0] data_out_temp;
always @ (posedge clk or posedge rst)
if (rst) cnt <= 'd0;
else cnt <= cnt + 1'b1;
always @ (posedge clk or posedge rst)
if (rst) begin //清0
data_reg[15] <= 'd0;
for (i=0; i<15; i=i+1'b1)
data_reg[i] <= 'd0;
end else begin
if (cnt == 'd7) begin
for (i=0; i<15; i=i+1'b1) //移位
data_reg[i+1] <= data_reg[i];
data_reg[0] <= data_in;
end
end
always @ (posedge clk or posedge rst)
if (rst) begin
add_a <= 'd0; add_b <= 'd0; coe <= 'd0;
end
else begin
case (cnt)
'd0: begin
add_a <= {data_reg[0][11], data_reg[0]};
add_b <= {data_reg[15][11], data_reg[15]};
coe <= 12'h000;
end
'd1: begin
add_a <= {data_reg[1][11], data_reg[1]};
add_b <= {data_reg[14][11], data_reg[14]};
coe <= 12'hffd;
end
'd2: begin
add_a <= {data_reg[2][11], data_reg[2]};
add_b <= {data_reg[13][11], data_reg[13]};
coe <= 12'h00f;
end
default: begin //第四个周期
add_a <= {data_reg[3][11], data_reg[3]};
add_b <= {data_reg[12][11], data_reg[12]};
coe <= 12'h02e;
end
endcase
end
assign add_s = add_a + add_b;
mult_gen_0 mult_inst
(
.CLK (clk),
.A (coe),
.B (add_s),
.P (Mout)
);
always @ (posedge clk or posedge rst)
if (rst) begin
sum <= 'd0; data_out_temp <= 'd0;
end
else begin
if (cnt == 'd2) begin
data_out_temp <= sum; sum <= {{4{Mout[24]}}, Mout};
end else
sum <= sum + {{4{Mout[24]}}, Mout};
end
assign data_out = data_out_temp;
endmodule
如果需要更多学习资料和源码,想要学习FPGA实战入门进阶,请阅读下面这篇文章:
FPGA入门真的难吗?少走弯路,少踩坑。