1. FIR低通滤波器设计
任务目标
设计一个16阶(15个抽头)FIR低通滤波器,使用Verilog实现,并通过Testbench仿真验证其频率选择性。滤波器采用直接型结构,系数由MATLAB/Octave计算后硬编码,输入为8位有符号数,输出为16位有符号数。
滤波器系数设计
使用以下MATLAB/Octave命令生成15阶(16个系数)低通滤波器系数,归一化截止频率为0.2(即fs/5):
% Octave/MATLAB
h = fir1(15, 0.2); % 15阶,16个系数
h_q = round(h * 128); % 量化到8位有符号范围
disp(h_q);
量化后系数(整数)为:0, 3, -1, -8, -4, 14, 24, -8, -41, -8, 24, 14, -4, -8, -1, 3。系数和为0(直流增益为0),实际为带通特性。为获得低通特性,将系数整体加1(使直流增益为1):
h_lp = h_q + 1; % 直流增益归一化为1
% 结果: 1, 4, 0, -7, -3, 15, 25, -7, -40, -7, 25, 15, -3, -7, 0, 4
最终系数数组:{1, 4, 0, -7, -3, 15, 25, -7, -40, -7, 25, 15, -3, -7, 0, 4}。系数和为16(2^4),输出右移4位可恢复单位直流增益。
Verilog实现
module fir_lowpass #(
parameter DATA_WIDTH = 8,
parameter COEF_WIDTH = 8,
parameter TAPS = 16,
parameter ACC_WIDTH = 16
)(
input wire clk,
input wire rst_n,
input wire signed [DATA_WIDTH-1:0] din,
output reg signed [ACC_WIDTH-1:0] dout
);
// 滤波器系数(有符号)
localparam signed [COEF_WIDTH-1:0] coef[TAPS-1:0] = '{
1, 4, 0, -7, -3, 15, 25, -7,
-40, -7, 25, 15, -3, -7, 0, 4
};
// 延迟线
reg signed [DATA_WIDTH-1:0] delay_line[TAPS-1:0];
integer i;
// 乘加累加器
reg signed [ACC_WIDTH-1:0] acc;
reg signed [ACC_WIDTH-1:0] acc_reg;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
for (i = 0; i < TAPS; i = i + 1)
delay_line[i] <= 0;
acc <= 0;
acc_reg <= 0;
dout <= 0;
end else begin
// 移位寄存器更新
for (i = TAPS-1; i > 0; i = i - 1)
delay_line[i] <= delay_line[i-1];
delay_line[0] <= din;
// 乘加运算(组合逻辑)
acc = 0;
for (i = 0; i < TAPS; i = i + 1)
acc = acc + delay_line[i] * coef[i];
// 寄存器输出
acc_reg <= acc;
dout <= acc_reg >>> 4; // 算术右移4位,恢复增益
end
end
endmodule
Testbench仿真
module tb_fir_lowpass;
reg clk = 0;
reg rst_n = 0;
reg signed [7:0] din;
wire signed [15:0] dout;
// 生成时钟
always #5 clk = ~clk;
// 实例化滤波器
fir_lowpass uut (
.clk(clk),
.rst_n(rst_n),
.din(din),
.dout(dout)
);
// 测试激励
integer k;
reg signed [7:0] test_signal [0:99];
initial begin
// 复位
#10 rst_n = 1;
// 生成测试信号:低频(0.05fs) + 高频(0.3fs)混合
for (k = 0; k < 100; k = k + 1) begin
test_signal[k] = $rtoi( 30*$sin(2*3.14159*0.05*k)
+ 30*$sin(2*3.14159*0.3*k) );
end
// 送入滤波器
for (k = 0; k < 100; k = k + 1) begin
@(posedge clk);
din = test_signal[k];
end
// 等待输出稳定
#100;
$finish;
end
// 监控输出
initial begin
$monitor("t=%0t din=%0d dout=%0d", $time, din, dout);
end
endmodule
运行与验证
仿真命令:
iverilog -o fir_tb tb_fir_lowpass.v fir_lowpass.v
vvp fir_tb
验证方法:观察输出波形,确认高频分量(0.3fs)被明显衰减,低频分量(0.05fs)基本保留。具体判定标准:
- 输入混合信号幅度约±60,输出稳态幅度应显著小于输入(高频被滤除)
- 输出信号周期应与低频分量(0.05fs)一致,即每20个时钟周期完成一个完整正弦波
- 输出幅度约为输入低频分量的1倍(增益已归一化),即约±30
预期输出特征:由于滤波器通带截止频率为0.2fs,0.05fs分量在通带内(增益≈1),0.3fs分量在阻带(增益≈0)。因此输出应为幅度约±30、周期20clk的近似正弦波,叠加少量纹波。
常见问题
- 输出全零:检查复位时序,确保rst_n释放后至少等待1个时钟周期再输入数据
- 输出幅度异常大:检查累加器位宽是否足够,16个8位×8位乘积累加最大需要16位(本设计已用16位,若溢出需扩展至20位)
- 高频未被滤除:确认系数是否加载正确,特别是负数的二进制补码表示