一、项目背景详细介绍

在信号处理领域,滤波器(Filter) 是核心工具之一,用于从信号中去除噪声、提取有用频率分量或平滑时间序列。滤波器可分为两大类:

  • FIR(Finite Impulse Response)有限脉冲响应滤波器

  • IIR(Infinite Impulse Response)无限脉冲响应滤波器

FIR 滤波器的特点是结构稳定、线性相位、实现简单,但阶数高、计算量大;
而 IIR 滤波器具有阶数低、性能强、计算量小的优点,是许多实时信号处理(音频处理、传感器数据滤波、控制系统等)中的主力算法。

为什么要自己实现 IIR 滤波器?

在嵌入式系统或算法验证中,我们往往不能直接依赖 MATLAB / Python SciPy 等高层工具,需要在 C/C++ 环境中实现可嵌入的滤波器。
而理解并实现一套 IIR 数字滤波器框架,不仅可以用于信号处理,还能深入理解差分方程系统函数Z 域传递函数 等数字信号处理核心概念。

本项目目标是实现一个可扩展、可配置的 C++ IIR 滤波器类,支持:

  • 任意阶 IIR 滤波器;

  • 支持典型滤波器设计(低通、高通、带通);

  • 支持通过传递函数系数 a、b 实例化;

  • 支持实时单点滤波与整段信号滤波;

  • 支持双精度浮点计算;

  • 输出频率响应与滤波前后信号可视化(可选)。


二、项目需求详细介绍

功能性需求


三、相关技术详细介绍


四、实现思路详细介绍

实现步骤如下:

  1. 定义 IIRFilter 类

    • 存储向量 a_b_z_(状态延迟线);

    • 构造函数传入系数;

    • 提供 filterSample() 处理单个样本;

    • 提供 filterSignal() 处理整个数组。

  2. 系数设计函数

    • butterworthLowpass(fc, fs, order):计算标准化二阶低通系数;

    • butterworthHighpass(fc, fs, order):高通滤波器;

    • (可选)带通设计。

  3. 信号测试模块

    • 生成带噪正弦波;

    • 调用滤波器平滑;

    • 保存结果到文件。

  4. 可视化结果

    • 用 Python/Matlab 绘图,或输出到 .csv 文件。


五、完整实现代码

/********************************************************************
 * 文件名: iir_filter.cpp
 * 功能: C++ 实现 IIR 数字滤波器(含巴特沃斯低通、高通示例)
 * 编译: g++ -std=c++17 iir_filter.cpp -O2 -o iir
 * 运行: ./iir
 * 输出: filter_result.csv (输入信号与输出信号)
 ********************************************************************/

#include <bits/stdc++.h>
using namespace std;

/**************************************************************
 * IIR 滤波器类 - Direct Form II 结构实现
 **************************************************************/
class IIRFilter {
private:
    vector<double> a_;  // 分母系数 (a0=1)
    vector<double> b_;  // 分子系数
    vector<double> z_;  // 延迟线状态

public:
    // 构造函数
    IIRFilter(const vector<double>& b, const vector<double>& a)
        : a_(a), b_(b)
    {
        int order = max(a_.size(), b_.size());
        z_.assign(order, 0.0);
    }

    // 过滤单个样本
    double filterSample(double x) {
        // Direct Form II Transposed 实现
        double w = x - a_[1]*z_[0];
        double y = b_[0]*w + b_[1]*z_[0];

        // 更新状态
        z_[0] = w;
        return y;
    }

    // 过滤整段信号
    vector<double> filterSignal(const vector<double>& x) {
        vector<double> y(x.size());
        for (size_t i=0;i<x.size();++i)
            y[i] = filterSample(x[i]);
        return y;
    }

    // 重置状态
    void reset() {
        fill(z_.begin(), z_.end(), 0.0);
    }
};

/**************************************************************
 * 一阶巴特沃斯滤波器设计(低通、高通)
 * 公式来源:双线性变换法
 **************************************************************/
struct FilterCoefficients {
    vector<double> b;
    vector<double> a;
};

// 一阶低通 Butterworth
FilterCoefficients butterworthLowpass(double fc, double fs) {
    double c = 1.0 / tan(M_PI * fc / fs);
    double a0 = 1.0 / (1.0 + c);
    double a1 = a0;
    double b1 = (1.0 - c) / (1.0 + c);
    FilterCoefficients coeffs;
    coeffs.b = {a0, a1};
    coeffs.a = {1.0, -b1};
    return coeffs;
}

// 一阶高通 Butterworth
FilterCoefficients butterworthHighpass(double fc, double fs) {
    double c = tan(M_PI * fc / fs);
    double a0 = 1.0 / (1.0 + c);
    double a1 = -a0;
    double b1 = (1.0 - c) / (1.0 + c);
    FilterCoefficients coeffs;
    coeffs.b = {a0, a1};
    coeffs.a = {1.0, -b1};
    return coeffs;
}

/**************************************************************
 * 测试信号生成与滤波测试
 **************************************************************/
int main() {
    // 采样参数
    double fs = 1000.0; // 采样率
    double f1 = 50.0;   // 信号频率
    double f_noise = 200.0; // 噪声频率
    int N = 1000;

    // 生成带噪信号
    vector<double> x(N);
    for (int n=0;n<N;++n) {
        double t = n / fs;
        x[n] = sin(2*M_PI*f1*t) + 0.5*sin(2*M_PI*f_noise*t);
    }

    // 设计低通滤波器
    double fc = 100.0; // 截止频率
    auto coeffs = butterworthLowpass(fc, fs);
    IIRFilter filter(coeffs.b, coeffs.a);

    // 滤波
    vector<double> y = filter.filterSignal(x);

    // 保存结果
    ofstream fout("filter_result.csv");
    fout << "n,input,output\n";
    for (int i=0;i<N;++i)
        fout << i << "," << x[i] << "," << y[i] << "\n";
    fout.close();

    cout << "滤波完成,结果已保存至 filter_result.csv" << endl;
    cout << "可用Python或Excel绘制输入输出波形对比" << endl;

    return 0;
}

六、代码详细解读

函数名 作用说明
IIRFilter::filterSample(double x) 实现单点输入的 Direct Form II 结构 IIR 计算公式。
IIRFilter::filterSignal(const vector<double>& x) 对输入序列逐点调用 filterSample,输出滤波后的信号。
IIRFilter::reset() 清空滤波器状态(延迟线)。
butterworthLowpass(fc, fs) 计算一阶低通滤波器系数。
butterworthHighpass(fc, fs) 计算一阶高通滤波器系数。
main() 生成测试信号、滤波、保存结果。

七、项目详细总结

本项目以教学为目标,完整实现了 C++ 版本的 IIR 滤波器,涵盖:

  • IIR 数学原理与差分方程推导;

  • 数字实现结构(Direct Form II);

  • 一阶巴特沃斯滤波器系数计算;

  • 实时与离线滤波接口;

  • 可直接运行与验证的测试主程序。

相比 FIR 滤波器,IIR 实现紧凑、计算量少,适用于嵌入式与实时信号处理。

该项目的教学价值在于——你可以:

  1. 直观理解数字滤波系统的数学模型;

  2. 掌握系数计算与数值稳定性;

  3. 将其嵌入音频、传感器或控制系统中。


八、项目常见问题及解答(FAQ)

Q1:为什么输出出现震荡?
A1:可能由于截止频率太高或采样率不够。请确保 fc<fs/2f_c < f_s / 2fc​<fs​/2,并使用双精度避免数值误差。

Q2:为什么输出信号幅值减小?
A2:滤波器存在幅度衰减特性,低通滤波器会抑制高频成分,从而整体振幅降低。

Q3:如何实现高阶滤波器?
A3:可通过级联多个一阶或二阶滤波器(biquad 结构),或自行扩展 a、b 数组长度。

Q4:是否能实时使用?
A4:完全可以。filterSample() 可在实时采样循环中逐点调用。

Q5:能否直接用于音频滤波?
A5:可以,只需将输入改为音频帧数据,保持采样率一致。


九、扩展方向与性能优化

  1. 支持二阶节(biquad)结构
    扩展为支持二阶 IIR 滤波器,更稳定并能处理更复杂的频率响应。

  2. 支持多通道处理
    批量滤波多路信号,可应用于立体声音频。

  3. 动态参数调节
    运行时可修改截止频率,实现动态滤波(如自适应低通)。

  4. 支持滤波器设计工具输入
    从 MATLAB / SciPy 导出系数并加载使用。

  5. 频率响应分析函数
    增加 frequencyResponse() 方法计算滤波器的幅频/相频响应。

  6. 使用模板与 SIMD 优化
    针对高性能场景,可引入 SSE/AVX 或模板化设计以优化性能。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐