FPGA实现4阶IIR低通滤波器:Verilog设计与稳定性处理

发布时间:2026/7/19 5:18:06
FPGA实现4阶IIR低通滤波器:Verilog设计与稳定性处理 在实际 FPGA 或 ASIC 数字信号处理系统中IIR无限脉冲响应滤波器因其在相同阶数下能提供比 FIR 滤波器更陡峭的过渡带而备受青睐。然而IIR 滤波器的反馈结构使其硬件实现特别是定点化和稳定性处理比 FIR 滤波器更具挑战性。本文将以一个具体的 4 阶低通 IIR 滤波器为例详细讲解如何从零开始使用 Verilog 语言在 FPGA 上实现一个稳定、可综合的数字滤波器。我们将从滤波器系数的生成与量化开始逐步深入到直接 II 型结构的 RTL 设计、仿真验证并重点分析定点运算中的精度控制、溢出处理以及实际工程中的关键注意事项。无论你是正在学习数字信号处理硬件实现的学生还是需要在实际项目中部署 IIR 滤波器的工程师本文提供的完整设计流程和代码都将为你提供清晰的参考。1. IIR 滤波器基础与设计指标确定1.1 IIR 滤波器核心概念与硬件实现挑战IIR 滤波器的系统函数包含零点和极点其输出不仅与当前及过去的输入有关还与过去的输出有关。这种递归特性用差分方程表示为 ( y[n] \sum_{k0}^{M} b_k x[n-k] - \sum_{k1}^{N} a_k y[n-k] ) 其中( b_k ) 是前馈系数( a_k ) 是反馈系数。在硬件实现中IIR 滤波器面临两个主要挑战稳定性由于存在反馈环极点的位置必须在单位圆内才能保证系统稳定。系数量化误差可能导致极点移动到单位圆外从而引发振荡。有限字长效应FPGA 内部使用有限位宽的定点数进行运算。系数量化、乘法舍入以及溢出都可能引入误差甚至导致滤波器功能异常。1.2 明确设计指标与系数获取假设我们的设计指标如下滤波器类型4 阶巴特沃斯低通滤波器采样频率8 MHz截止频率2 MHz阻带衰减 40 dB量化位数12 位在 MATLAB 或 Python (scipy.signal) 中可以轻松生成满足指标的滤波器系数。% MATLAB 示例生成 4 阶巴特沃斯低通滤波器系数 fs 8e6; % 采样频率 8 MHz fc 2e6; % 截止频率 2 MHz n 4; % 滤波器阶数 % 计算归一化截止频率 Wn fc/(fs/2); % 设计巴特沃斯滤波器 [b, a] butter(n, Wn, low); % 显示系数 fprintf(分子系数 b: ); disp(b); fprintf(分母系数 a: ); disp(a(2:end)); % a(1) 总是 1通常不显式实现运行上述代码可能得到如下浮点系数b [0.145, 0.579, 0.579, 0.145](近似值)a [1.000, -0.671, 0.252, -0.028](近似值a[0]为 1)注意硬件实现时我们通常处理的是a[1]到a[N]即-a_k。2. 系数定点量化与直接 II 型结构选择2.1 将浮点系数转换为定点整数FPGA 内部使用二进制数进行运算因此需要将浮点系数转换为定点数。我们选择 12 位量化并采用 Q格式例如 Q1.11表示 1 位整数11 位小数来保证精度。% 系数定点量化示例 Q 11; % 小数部分位数 (Q1.11格式总位宽12) scale 2^Q; % 量化分子系数 b假设值为示例 b_float [0.145, 0.579, 0.579, 0.145]; b_quant round(b_float * scale); % 可能得到b_quant [297, 1186, 1186, 297] (十进制) % 量化分母系数 a注意符号硬件实现通常用 -a_k a_float [-0.671, 0.252, -0.028]; % 对应 a[1], a[2], a[3] a_quant round(a_float * scale); % 可能得到a_quant [-1374, 516, -57] (十进制) % 验证量化误差 b_error b_float - b_quant / scale; a_error a_float - a_quant / scale; fprintf(系数量化误差应足够小。\n);量化后的系数将作为常数在 Verilog 代码中使用。2.2 为什么选择直接 II 型结构IIR 滤波器有多种实现结构直接 I 型、直接 II 型、级联型、并联型。对于 FPGA 实现直接 II 型规范型是最常用的选择因为它需要最少的延迟单元寄存器从而节省硬件资源。直接 II 型结构将系统函数分解为两部分全零点部分前馈( w[n] x[n] \sum_{k1}^{N} a_k w[n-k] )全极点部分反馈( y[n] \sum_{k0}^{M} b_k w[n-k] )其中( w[n] ) 是中间状态变量。这种结构只需要max(N, M)个延迟单元。3. Verilog RTL 设计与关键参数说明3.1 模块接口与参数定义首先定义滤波器的模块接口和用参数表示的量化系数。module iir_lowpass_filter ( input wire clk, // 系统时钟 (假设与 8MHz 采样率同步或更高) input wire rst_n, // 异步低电平复位 input wire signed [11:0] data_in, // 12位有符号输入数据 output reg signed [11:0] data_out // 12位有符号输出数据 ); // -- 滤波器系数参数Q1.11格式12位有符号 -- // 这些系数应由 MATLAB/python 计算并量化后填入 localparam signed [11:0] B0 12sd297; // b0 量化值 localparam signed [11:0] B1 12sd1186; // b1 量化值 localparam signed [11:0] B2 12sd1186; // b2 量化值 localparam signed [11:0] B3 12sd297; // b3 量化值 localparam signed [11:0] A1 -12sd1374; // -a1 量化值 localparam signed [11:0] A2 12sd516; // -a2 量化值 localparam signed [11:0] A3 -12sd57; // -a3 量化值 // -- 中间状态变量寄存器 -- // 用于存储 w[n-1], w[n-2], w[n-3] reg signed [11:0] w1, w2, w3; // 当前中间变量 w[n] wire signed [11:0] w_current; // -- 乘法结果需要更宽的位宽以防止溢出 -- // 假设输入和系数都是12位乘法结果最多24位。 // 但连续累加可能使位宽增长需要合理截断或舍入。 wire signed [23:0] feedback_sum; // 反馈部分求和 wire signed [23:0] feedforward_sum; // 前馈部分求和 // 定义 w_current 的计算逻辑 // w[n] x[n] A1*w[n-1] A2*w[n-2] A3*w[n-3] assign feedback_sum (A1 * w1) (A2 * w2) (A3 * w3); // 注意由于是Q1.11格式乘法结果实际是Q2.22格式需要调整。 // 一种简单做法是取中间有效位。这里先计算后在always块中处理。 assign w_current data_in (feedback_sum 11); // 近似除以 2^11转换回 Q1.11 // 前馈部分求和y[n] B0*w[n] B1*w[n-1] B2*w[n-2] B3*w[n-3] assign feedforward_sum (B0 * w_current) (B1 * w1) (B2 * w2) (B3 * w3); // 主时序逻辑更新状态寄存器和输出 always (posedge clk or negedge rst_n) begin if (!rst_n) begin // 复位时清空状态 w1 12sb0; w2 12sb0; w3 12sb0; data_out 12sb0; end else begin // 更新状态变量移位寄存器 w3 w2; w2 w1; w1 w_current; // 处理前馈部分求和并转换回Q1.11格式输出 data_out feedforward_sum 11; // 近似处理 end end endmodule3.2 定点运算精度与溢出处理详解上面的代码是一个简化模型实际项目中必须仔细处理运算精度和溢出。乘法位宽12 位数乘以 12 位数结果是 24 位。这个 24 位数是 Q2.22 格式如果两个 Q1.11 数相乘。累加位宽多个 24 位的数相加位宽会增长。3 个系数相加最少需要 24 ceil(log2(3)) ≈ 26 位来保证不溢出。但在资源受限时可能需要饱和处理或更高位宽。截断与舍入将宽位数的乘法累加结果如 Q2.22转换回输出格式Q1.11时简单的右移 11 位是截断会引入精度损失。更好的方法是舍入(sum (1 10)) 11。一个更健壮的版本会对位宽进行扩展// 使用更宽的内部位宽进行运算 localparam INT_WIDTH 2; // 整数部分位宽根据系数最大值估计 localparam FRAC_WIDTH 11; // 小数部分位宽 localparam MULT_WIDTH INT_WIDTH * 2 FRAC_WIDTH * 2; // 乘法后位宽 reg signed [MULT_WIDTH-1:0] feedback_sum_reg; // 用于寄存累加结果防止长路径 // ... 在always块中顺序计算反馈和前馈部分并应用舍入4. 测试平台与仿真验证设计完成后必须通过仿真验证滤波器的功能是否正确。编写一个 Testbench。timescale 1ns / 1ps module tb_iir_filter; // 输入输出信号 reg clk; reg rst_n; reg signed [11:0] data_in; wire signed [11:0] data_out; // 实例化被测试模块 iir_lowpass_filter uut ( .clk(clk), .rst_n(rst_n), .data_in(data_in), .data_out(data_out) ); // 生成时钟信号 (假设 100MHz 时钟远快于 8MHz 采样率实际可能用同步使能信号) initial begin clk 0; forever #5 clk ~clk; // 10ns 周期 - 100MHz end // 测试激励 initial begin // 初始化 rst_n 0; data_in 0; #100; // 保持复位一段时间 // 释放复位 rst_n 1; #20; // 测试案例 1: 输入一个脉冲信号 data_in 12sd1000; // 输入一个阶跃 #10; // 等待一个时钟周期采样周期 data_in 0; // 观察输出衰减波形应符合IIR滤波器的脉冲响应 // 等待足够长时间观察响应 #500; // 测试案例 2: 输入正弦波频率低于截止频率 // 这里可以用循环生成正弦波数据 // ... // 测试案例 3: 输入正弦波频率高于截止频率 // 观察输出幅度是否被显著衰减 // ... #1000; $finish; end // 将信号变化记录到VCD文件用于波形分析 initial begin $dumpfile(iir_filter.vcd); $dumpvars(0, tb_iir_filter); end endmodule在仿真中你需要观察脉冲输入的响应确认输出是衰减震荡的且稳定到零。输入不同频率的正弦波测量输出幅度验证截止频率附近的衰减特性是否与理论设计相符例如2MHz 信号应有 -3dB 衰减。5. 常见问题与工程实践要点5.1 稳定性与极限环振荡即使理论系数是稳定的系数量化也可能导致极点移动到单位圆外。此外在零输入条件下由于舍入误差滤波器输出可能不会衰减到零而是在一个小的范围内持续振荡这称为极限环振荡。应对策略系数灵敏度分析在 MATLAB 中检查量化后系数的极点位置。使用级联结构将高阶滤波器分解为多个二阶节SOS级联。二阶节对系数量化误差更不敏感。H(z) H1(z) * H2(z) * ...舍入处理采用收敛舍入向最近偶数舍入而不是直接截断。饱和运算在输出级加入饱和处理防止溢出导致的大幅度振荡。5.2 资源优化与速度权衡优化目标实现方法潜在代价减少逻辑资源使用单乘法器/累加器分时复用处理速度降低需要更高时钟和控制逻辑提高吞吐率使用全并行结构每个系数配专属乘法器消耗大量 DSP 片和寄存器资源降低功耗使用时钟门控在无数据输入时关闭部分逻辑增加设计复杂性对于我们的 4 阶滤波器如果目标 FPGA 的 DSP 资源充足全并行实现是最简单的。如果资源紧张可以考虑将 4 阶滤波器拆分为两个二阶节级联每个二阶节复用一套计算单元。5.3 同步与时序约束采样率与时钟率如果系统时钟如 100MHz高于采样率8MHz必须在数据输入端口使用一个采样使能信号data_valid确保只在有效的采样点进行滤波计算。时序约束综合和实现后必须对设计施加时序约束确保乘法器和累加器的组合逻辑路径能够在一个时钟周期内稳定。否则会出现建立时间违例导致功能错误。// 带有使能信号的改进版接口 module iir_lowpass_filter ( input wire clk, input wire rst_n, input wire data_valid, // 数据有效信号高电平表示 data_in 有效 input wire signed [11:0] data_in, output reg signed [11:0] data_out, output reg data_out_valid // 输出有效信号 );6. 进阶方向与最佳实践清单掌握了基本实现后可以考虑以下进阶方向来提升滤波器性能或适用性自适应滤波器使系数能够根据输入信号动态调整用于系统辨识、信道均衡等。多速率滤波器结合抽取和插值实现采样率变换常用于无线通信。CIC 滤波器一种无需乘法器的特殊 IIR 结构非常适合高倍率的采样率变换。使用 IP 核Xilinx 和 Intel FPGA 都提供了经过高度优化的 DSP IP 核如 FIR Compiler它们也支持某些 IIR 结构可以节省开发时间并保证性能。IIR 滤波器 Verilog 实现检查清单[ ] 浮点系数设计是否满足频率响应指标[ ] 定点量化方案Q格式是否合理量化误差是否可接受[ ] 仿真是否验证了脉冲响应和频率响应通过 DFT/FFT[ ] 运算位宽是否足够宽以防止中间结果溢出[ ] 是否采用了舍入而非简单截断来减少精度损失[ ] 输出是否有饱和处理机制[ ] 在零输入条件下仿真是否未出现明显的极限环振荡[ ] 综合后的时序报告是否满足要求[ ] 是否在真实信号或更复杂的测试向量下进行了验证从理论系数到稳定可靠的硬件实现是一个需要反复迭代和验证的过程。建议先在仿真环境中充分验证功能与性能再上板调试。利用 MATLAB 或 Python 生成测试向量并与 Verilog 仿真结果进行对比是确保设计正确性的高效方法。