阶段二:FIR滤波器

🎛️ 第07课:FIR滤波器原理

有限冲激响应滤波器——线性相位的守护者

1. FIR滤波器基本概念

FIR(Finite Impulse Response)滤波器的输出仅取决于当前和过去的输入值,不依赖过去的输出值,因此冲激响应是有限长的:

y[n] = Σ(k=0 to M) h[k] · x[n-k] = h[0]x[n] + h[1]x[n-1] + ... + h[M]x[n-M]

其中M为滤波器阶数,h[k]为滤波器系数(抽头),x[n]为输入,y[n]为输出。FIR的系统函数为:

H(z) = Σ(k=0 to M) h[k] · z⁻ᵏ = h[0] + h[1]z⁻¹ + ... + h[M]z⁻ᴹ

注意H(z)只有零点,没有极点(除z=0),因此FIR滤波器始终稳定。

1.1 FIR vs IIR 全面对比

特性FIRIIR
冲激响应长度有限(M+1点)无限(递归衰减)
稳定性始终稳定(无极点)需确保极点在单位圆内
线性相位可实现严格线性相位一般无法线性相位
相同指标所需阶数较高(10-100+)较低(4-10)
计算量较大(每输出M+1次MAC)较小(每输出2N+1次MAC)
系数量化敏感度较低较高(极点偏移影响大)
反馈回路
设计方法窗函数法、频率采样法、最优等波纹法双线性变换法、脉冲响应不变法
群延迟常数 = M/2频率相关(非线性)

2. FIR滤波器的线性相位

线性相位意味着所有频率分量经过滤波器后延迟相同的时间,不会产生相位失真。这是FIR最大的优势,在音频处理、图像处理等需要保持波形形状的应用中至关重要。

线性相位条件:H(z)的相位响应 φ(ω) = -αω(α为常数,即群延迟)
等价条件:h[n] = h[M-n](偶对称)或 h[n] = -h[M-n](奇对称)

2.1 四种线性相位FIR

类型对称性阶数M频率响应在ω=0频率响应在ω=π适用
I型偶对称 h[n]=h[M-n]偶数无约束无约束通用滤波器
II型偶对称 h[n]=h[M-n]奇数无约束H(π)=0低通/带通(不含高通)
III型奇对称 h[n]=-h[M-n]偶数H(0)=0H(π)=0微分器/Hilbert变换
IV型奇对称 h[n]=-h[M-n]奇数H(0)=0无约束微分器/Hilbert变换

2.2 群延迟的物理意义

群延迟 τ(ω) = -dφ(ω)/dω 表示信号各频率分量通过滤波器的延迟时间。对于线性相位FIR:

τ = M/2 个样本周期(常数)
物理延迟时间 = M/(2·fs) 秒

例如,一个40阶FIR在48kHz采样率下,群延迟为20个样本 = 416.7μs。

3. FIR滤波器的频率响应

对y[n] = Σh[k]x[n-k]做DTFT,得到频率响应:

H(e^jω) = Σ(k=0 to M) h[k]·e^(-jkω) = |H(e^jω)|·e^(jφ(ω))

对于I型线性相位FIR(M偶,偶对称),可分解为:

H(e^jω) = e^(-jMω/2) · H̃(ω)
H̃(ω) = h[M/2] + 2Σ(k=0 to M/2-1) h[k]·cos((M/2-k)ω)

其中H̃(ω)为实函数,称为幅度响应(Amplitude Response),可取正负值。而|H(e^jω)|是幅度谱(Magnitude Response),始终非负。

4. Verilog实现:基本FIR滤波器

//=============================================
// dsp_fir_direct.v
// FIR直接型滤波器
// y[n] = Σ h[k] * x[n-k]
//=============================================
module dsp_fir_direct #(
    parameter DATA_WIDTH = 16,
    parameter COEFF_WIDTH = 16,
    parameter TAP = 16,             // 滤波器抽头数
    parameter OUT_WIDTH = 32
)(
    input  wire                          clk,
    input  wire                          rst_n,
    input  wire                          data_valid,
    input  wire signed [DATA_WIDTH-1:0]  data_in,
    input  wire signed [COEFF_WIDTH-1:0] coeffs [0:TAP-1],
    output reg  signed [OUT_WIDTH-1:0]   data_out,
    output reg                           out_valid
);

    // 延迟线(移位寄存器)
    reg signed [DATA_WIDTH-1:0] shift_reg [0:TAP-1];

    integer i;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (i = 0; i < TAP; i = i + 1)
                shift_reg[i] <= 0;
            data_out <= 0;
            out_valid <= 1'b0;
        end else if (data_valid) begin
            // 移入新数据
            shift_reg[0] <= data_in;
            for (i = 1; i < TAP; i = i + 1)
                shift_reg[i] <= shift_reg[i-1];

            // 乘累加(MAC)
            data_out <= mac_compute();
            out_valid <= 1'b1;
        end else begin
            out_valid <= 1'b0;
        end
    end

    // MAC函数
    function signed [OUT_WIDTH-1:0] mac_compute;
        reg signed [OUT_WIDTH-1:0] acc;
        reg signed [DATA_WIDTH+COEFF_WIDTH-1:0] product;
        integer k;
        begin
            acc = 0;
            for (k = 0; k < TAP; k = k + 1) begin
                product = shift_reg[k] * coeffs[k];
                acc = acc + product;
            end
            mac_compute = acc;
        end
    endfunction

endmodule

5. Verilog实现:对称FIR滤波器(线性相位优化)

利用线性相位FIR系数的对称性 h[k] = h[M-k],将乘法器数量减半:

//=============================================
// dsp_fir_symmetric.v
// 对称系数FIR滤波器
// 利用 h[k] = h[M-k] 减半乘法器
//=============================================
module dsp_fir_symmetric #(
    parameter DATA_WIDTH = 16,
    parameter COEFF_WIDTH = 16,
    parameter TAP = 16,             // 必须为偶数
    parameter OUT_WIDTH = 32
)(
    input  wire                          clk,
    input  wire                          rst_n,
    input  wire                          data_valid,
    input  wire signed [DATA_WIDTH-1:0]  data_in,
    input  wire signed [COEFF_WIDTH-1:0] coeffs [0:TAP/2-1],
    output reg  signed [OUT_WIDTH-1:0]   data_out,
    output reg                           out_valid
);

    reg signed [DATA_WIDTH-1:0] shift_reg [0:TAP-1];
    integer i;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (i = 0; i < TAP; i = i + 1)
                shift_reg[i] <= 0;
            data_out <= 0;
            out_valid <= 1'b0;
        end else if (data_valid) begin
            shift_reg[0] <= data_in;
            for (i = 1; i < TAP; i = i + 1)
                shift_reg[i] <= shift_reg[i-1];
            data_out <= sym_mac();
            out_valid <= 1'b1;
        end else begin
            out_valid <= 1'b0;
        end
    end

    function signed [OUT_WIDTH-1:0] sym_mac;
        reg signed [OUT_WIDTH-1:0] acc;
        reg signed [DATA_WIDTH:0] sym_sum;
        reg signed [DATA_WIDTH+1+COEFF_WIDTH-1:0] product;
        integer k;
        begin
            acc = 0;
            for (k = 0; k < TAP/2; k = k + 1) begin
                // 先加对称位置的数据,再乘系数
                sym_sum = shift_reg[k] + shift_reg[TAP-1-k];
                product = sym_sum * coeffs[k];
                acc = acc + product;
            end
            sym_mac = acc;
        end
    endfunction

endmodule

6. Verilog实现:FIR测试台与验证

//=============================================
// tb_fir_direct.v
// FIR直接型滤波器测试台
//=============================================
`timescale 1ns/1ps

module tb_fir_direct;

    parameter DATA_WIDTH  = 16;
    parameter COEFF_WIDTH = 16;
    parameter TAP         = 8;
    parameter OUT_WIDTH   = 32;
    parameter CLK_PERIOD  = 10;

    reg                          clk;
    reg                          rst_n;
    reg                          data_valid;
    reg  signed [DATA_WIDTH-1:0] data_in;
    reg  signed [COEFF_WIDTH-1:0] coeffs [0:TAP-1];
    wire signed [OUT_WIDTH-1:0]  data_out;
    wire                         out_valid;

    dsp_fir_direct #(
        .DATA_WIDTH(DATA_WIDTH),
        .COEFF_WIDTH(COEFF_WIDTH),
        .TAP(TAP),
        .OUT_WIDTH(OUT_WIDTH)
    ) uut (
        .clk(clk), .rst_n(rst_n),
        .data_valid(data_valid),
        .data_in(data_in),
        .coeffs(coeffs),
        .data_out(data_out),
        .out_valid(out_valid)
    );

    initial clk = 0;
    always #(CLK_PERIOD/2) clk = ~clk;

    initial begin
        $dumpfile("fir_direct.vcd");
        $dumpvars(0, tb_fir_direct);

        // 初始化移动平均系数
        coeffs[0] = 17'sd4096;  // 1/8 * 32768
        coeffs[1] = 17'sd4096;
        coeffs[2] = 17'sd4096;
        coeffs[3] = 17'sd4096;
        coeffs[4] = 17'sd4096;
        coeffs[5] = 17'sd4096;
        coeffs[6] = 17'sd4096;
        coeffs[7] = 17'sd4096;

        rst_n = 0; data_valid = 0; data_in = 0;
        #100;
        rst_n = 1;

        // 测试脉冲响应
        data_in = 32767;  // 单脉冲
        data_valid = 1;
        @(posedge clk);
        data_in = 0;
        repeat(TAP + 5) @(posedge clk);
        data_valid = 0;

        $display("脉冲响应测试完成");
        $display("=== FIR直接型测试通过 ===");
        $finish;
    end

endmodule

7. FIR滤波器设计指标

📋 典型FIR设计规格

参数符号说明典型值
通带截止频率ωp通带边沿频率0.2π
阻带起始频率ωs阻带边沿频率0.3π
过渡带宽度Δωωs - ωp0.1π
通带波纹δp通带最大偏差0.01 (~-40dB)
阻带衰减δs阻带最大增益0.001 (~-60dB)
滤波器阶数M由过渡带和衰减决定经验公式估算
阶数估算(Kaiser公式):M ≈ (A - 7.95) / (2.285 · Δω)
其中 A = -20log₁₀(min(δp, δs)),Δω = ωs - ωp(弧度)

7.1 滤波器类型选择指南

8. 练习

📝 练习1:FIR手动计算

3阶FIR系数 h[n] = {1, 2, 2, 1},输入 x[n] = {1, -1, 2, 0, -1},手动计算输出y[n]。

提示:y[n] = h[0]x[n] + h[1]x[n-1] + h[2]x[n-2] + h[3]x[n-3]

📝 练习2:线性相位验证

验证 h[n] = {1, 2, 3, 2, 1} 是否为线性相位FIR,并确定其类型。计算群延迟。

📝 练习3:阶数估算

设计FIR低通滤波器:通带0-4kHz,阻带5kHz以上,通带波纹0.1dB,阻带衰减50dB,采样率20kHz。用Kaiser公式估算所需阶数。

📝 练习4:系数对称性扩展

修改 dsp_fir_symmetric.v,支持奇数抽头数(即中心抽头不需要配对乘法,单独处理)。

🏆 成就解锁:FIR先锋

✅ 理解了FIR滤波器的基本原理与系统函数

✅ 掌握了FIR vs IIR的核心区别

✅ 实现了直接型FIR滤波器

✅ 实现了对称系数优化FIR(乘法器减半)

✅ 理解了线性相位四种类型和群延迟

✅ 掌握了FIR设计指标与阶数估算

11. 补充:FIR滤波器原理的进阶主题

FIR滤波器原理在进阶应用中还有以下重要主题值得深入研究:

📚 进阶研究方向

12. 与前后课程的关联

本课内容在整个DSP课程体系中处于承上启下的位置:

🔗 课程关联图

13. 设计经验总结

在实际工程中,FIR滤波器原理的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。

📌 关键设计检查清单

13. 设计经验总结

在实际工程中,FIR滤波器原理的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。

📌 关键设计检查清单

13. 设计经验总结

在实际工程中,FIR滤波器原理的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。

📌 关键设计检查清单

13. 设计经验总结

在实际工程中,FIR滤波器原理的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。

📌 关键设计检查清单

13. 设计经验总结

在实际工程中,FIR滤波器原理的设计经验总结如下:(1)始终从系统级需求出发,不要过早陷入实现细节;(2)先用浮点仿真验证算法正确性,再转为定点;(3)系数量化后必须重新验证频率响应;(4)硬件实现前用C/MATLAB模型作为参考;(5)综合后检查时序和资源是否符合预期;(6)板级验证时用已知的测试信号对比参考输出。每一步验证都是必要的,跳过任何一步都可能导致最终的调试时间成倍增加。

📌 关键设计检查清单