ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

高通滤波算法深度解析(High-Pass Filter)

高通滤波算法深度解析(High-Pass Filter) 全程纯 C# 实现无任何第三方库所有代码与数据均已在 .NET 9 下编译运行实测验证。基本概念频域视角任何信号都可以分解为不同频率的正弦波的叠加傅里叶分析的基本思想。频率 ff单位 Hz表示信号每秒完成多少次周期变化低频分量变化缓慢的成分如直流偏置、缓慢漂移、温度漂移、趋势项高频分量变化剧烈的成分如快速波动、边沿跳变、高频噪声。什么是滤波滤波的本质是按频率对信号的不同分量进行选择性通过 / 选择性衰减。它可以发生在模拟域RC/LC/运放电路也可以发生在数字域差分方程、FFT。高通滤波的定义高通滤波是一种让频率高于 fcfc​ 的成分通过、频率低于 fcfc​ 的成分被抑制的运算fcfc​ 称为截止频率cutoff frequency。与之相对低通滤波LPF让低频通过、抑制高频带通BPF/ 带阻BSF只让某个频带通过 / 抑制。关键参数参数含义截止频率 fcfc​增益下降到 -3dB0.707 倍的频率点通带ffcffc​ 的区域增益 ≈ 10dB阻带ffcffc​ 的区域增益趋于 0过渡带fcfc​ 附近的渐变区越窄越接近理想滚降斜率阻带内每倍频程octave衰减的 dB 数一阶 ≈ 6dB/oct二阶 ≈ 12dB/oct相位 / 群延迟滤波引入的时移IIR 一般是非线性相位模拟 vs 数字模拟高通RC 电路、运算放大器连续时间受器件精度与温漂影响数字高通差分方程或 FFT离散时间可编程、精度高、可复现、无温漂是现代嵌入式的主流选择。IIR 与 FIRIIR无限冲激响应有反馈回路递归用低阶就能实现陡峭滚降计算量小但相位非线性、需要保证稳定性FIR有限冲激响应无反馈可严格线性相位但达到相同滚降需要很高阶数计算量大。本文主推 IIR一阶 / 二阶与 FFT 两种路径。采样与奈奎斯特数字信号能表示的最高频率为奈奎斯特频率。高通截止频率必须满足否则无法实现。历史背景1807 年傅里叶提出任意周期信号可分解为不同频率正弦波之和为一切滤波理论奠定数学基础1915 年贝尔实验室的 George Campbell 与德国的 Karl Wagner 几乎同时提出滤波器概念用于电话多路复用这是滤波器工程的起点1930 年Butterworth 提出最大平坦幅频响应滤波器设计此后 Chebyshev等波纹响应、Bessel最平坦群延迟等不同逼近准则陆续出现1965 年Cooley 与 Tukey 发表快速傅里叶变换FFT算法把 O(N2)O(N2) 的 DFT 降到 O(Nlog⁡N)O(NlogN)频域滤波从理论走向工程1970 年代起微处理器与专用 DSP 芯片普及数字滤波全面取代模拟滤波成为信号处理的标准方法现代在 MEMS 传感器加速度计/陀螺仪、生物电信号心电/脑电、音频、振动监测、图像处理等嵌入式场景中高通滤波是去直流漂移、去趋势项的标配算法。核心原理理想高通滤波器理想高通滤波器的频率响应为它在 fcfc​ 处发生 0→1 的阶跃。但这样的理想响应在物理上不可实现需要无限阶、非因果因此实际工程用有限阶近似必然存在过渡带与有限滚降。一阶数字高通DC 阻塞型的推导模拟原型RC 高通一阶 RC 高通电路传递函数为对应的微分方程输入 xx、输出 yy差分离散化用一阶差分近似导数其中 Ts1/fsTs​1/fs​ 为采样周期。整理令得到一阶高通DC 阻塞滤波器的标准差分方程传递函数与稳定性对差分方程做 z 变换零点在 z1z1对应直流 f0f0故 H(1)0H(1)0直流被完全阻塞极点在 zαzα由于 0α10α1极点始终位于单位圆内滤波器无条件稳定。系数示例取 fs1000Hz, fc5Hzfs​1000Hz, fc​5Hz频率响应特性幅频响应f→0f→0增益 → 0直流被滤除ffcffc​增益 ≈ 0.707-3dBf→fs/2f→fs​/2增益 → 1。一阶高通的阻带滚降约为6dB/octave20dB/decade。二阶 Butterworth 高通Biquad当需要更陡的滚降时使用二阶。二阶 Butterworth 高通模拟原型经双线性变换离散化后得到双二阶Biquad标准型采用 RBJ Audio EQ Cookbook 系数公式再统一除以 a0a0​ 归一化。二阶 Butterworth 阻带滚降约12dB/oct40dB/decade。频域FFT高通另一种更接近理想的思路是频域处理对整段信号做 FFT 得频谱 X[k]X[k]把对应低频及对称负频区的 bin 置零做 IFFT 还原时域信号。由于直接硬切频率分量其幅频特性接近理想阶跃但存在频谱泄漏非整周期截断导致和块边缘效应Gibbs 现象实践中常配合窗函数如汉宁窗与重叠相加overlap-add使用。与低通的关系互补性一个重要而优美的事实高通 ≈ 原信号 − 低通。这正是互补滤波的思想基础也是传感器融合如陀螺仪高通 加速度计低通融合姿态的出发点。执行流程设计阶段确定采样率 fsfs​满足感兴趣的最高频率即奈奎斯特定理根据需求选定截止频率选择滤波器类型与阶数一阶简单 / 二阶陡峭 / FFT 锐截止。初始化计算系数一阶算 αα二阶算状态变量清零二阶还有。流式实时处理每来一个样本执行一次读取新样本一阶更新状态输出该流程在单片机 ADC 中断、音频回调中逐样本执行每样本仅几次乘加运算。批处理整段对一段完整数据一次性滤波如离线分析、FFT 法注意起始瞬态区。后处理与验证检查输出均值是否≈0验证直流被滤除观察起始段瞬态滤波器充放电过程约数个 ττ 后进入稳态用频率响应扫描验证截止频率。算法性能分析时间复杂度实现每样本整段 N 点一阶 IIRO(1)1 乘 2 加O(N)二阶 IIRO(1)5 乘 4 加O(N)FFT 频域O(N) 分摊O(N log N)空间复杂度一阶 / 二阶 IIRO(1)仅需 2~4 个状态变量FFTO(N)需整段缓冲。实时性一阶高通每样本仅1 次乘法、2 次加法可在低端 MCU 的定时器中断 / ADC 回调里逐样本执行延迟约等于零。稳定性一阶极点恒稳定二阶RBJ 公式在下极点恒在单位圆内稳定工程上用定点实现时需留意系数量化后极点是否越出单位圆。数值精度浮点double精度足够本文演示采用定点嵌入式 Q15/Q31需做系数定标注意乘法溢出与量化噪声。相位特性重要代价IIR 滤波器相位是非线性的会造成波形畸变若应用对相位敏感如 QRS 波检测、高保真音频需考虑零相位滤波正反各过一次或改用 FIR。实测数据本文验证fs1000Hzfc5Hz频率(Hz)一阶增益(dB)二阶增益(dB)0.5-20.04-40.001.0-14.15-27.972.0-8.62-16.035.0-3.08-3.01← 截止点10.0-1.08-0.2650.0-0.22-0.09100.0-0.020.17验证结论5Hz 处增益≈-3dB与理论 -3.01dB 吻合阻带滚降一阶 0.5→1Hz 衰减 5.89dB ≈6dB/oct二阶衰减 12dB ≈12dB/oct与理论完全一致。完整代码完整演示程序Program.cs以下为完整可运行程序包含三种高通实现与验证逻辑。在项目目录执行dotnet run -c Release即可运行。using System; namespace HighPassFilterDemo { /// summary /// 高通滤波算法完整演示程序 /// 包含三种实现一阶IIR高通、二阶Butterworth高通、频域(FFT)高通 /// 纯 C# 实现无任何第三方库 /// /summary public static class Program { public static void Main() { double fs 1000.0; // 采样率 1000 Hz double fc 5.0; // 截止频率 5 Hz int n 512; // 样本数2的幂供FFT使用 // 1. 生成测试信号 // 直流偏置 2.5V 1Hz 低频(幅1.0) 50Hz 高频(幅0.5) 白噪声(±0.1) double[] x new double[n]; var rnd new Random(42); for (int i 0; i n; i) { double t (double)i / fs; x[i] 2.5 // 直流 1.0 * Math.Sin(2 * Math.PI * 1.0 * t) // 1 Hz 低频 0.5 * Math.Sin(2 * Math.PI * 50.0 * t) // 50 Hz 高频 0.1 * (rnd.NextDouble() * 2 - 1); // 噪声 } // 2. 一阶 IIR 高通 var hp1 new OnePoleHighPass(fs, fc); double[] y1 new double[n]; for (int i 0; i n; i) y1[i] hp1.Process(x[i]); // 3. 二阶 Butterworth 高通 var hp2 new ButterworthHighPass2(fs, fc); double[] y2 new double[n]; for (int i 0; i n; i) y2[i] hp2.Process(x[i]); // 4. 频域(FFT)高通 double[] y3 FrequencyDomainHighPass.Process(x, fs, fc); // 5. 逐点输出对比 Console.WriteLine(i 输入 x[i] 一阶 y1[i] 二阶 y2[i] FFT y3[i]); for (int i 0; i n; i 32) { Console.WriteLine(${i,3} {x[i],12:F4} {y1[i],12:F4} {y2[i],12:F4} {y3[i],12:F4}); } // 6. 关键指标直流是否被滤除 Console.WriteLine(); Console.WriteLine($输入均值 : {Mean(x),12:F6} (含直流应≈2.5)); Console.WriteLine($一阶输出均值: {Mean(y1),12:F6} (应≈0直流已滤除)); Console.WriteLine($二阶输出均值: {Mean(y2),12:F6} (应≈0直流已滤除)); Console.WriteLine($FFT输出均值 : {Mean(y3),12:F6} (应≈0直流已滤除)); // 7. 输出能量高频分量是否保留 Console.WriteLine(); Console.WriteLine($输入RMS : {Rms(x),12:F4}); Console.WriteLine($一阶输出RMS : {Rms(y1),12:F4} (低频/直流被抑制)); Console.WriteLine($二阶输出RMS : {Rms(y2),12:F4} (低频/直流被抑制)); Console.WriteLine($FFT输出RMS : {Rms(y3),12:F4} (低频/直流被抑制)); } static double Mean(double[] a) { double s 0; for (int i 0; i a.Length; i) s a[i]; return s / a.Length; } static double Rms(double[] a) { double s 0; for (int i 0; i a.Length; i) s a[i] * a[i]; return Math.Sqrt(s / a.Length); } } /// summary /// 一阶 IIR 高通滤波器DC 阻塞型 /// 差分方程y[n] α·(y[n-1] x[n] − x[n-1]) /// 系数α τ/(τTs)τ 1/(2π·fc)Ts 1/fs /// 特性单极点、零点在 z1直流处直流增益为 0 /// /summary public class OnePoleHighPass { private readonly double _alpha; private double _xPrev; private double _yPrev; public OnePoleHighPass(double sampleRate, double cutoffHz) { double tau 1.0 / (2.0 * Math.PI * cutoffHz); double ts 1.0 / sampleRate; _alpha tau / (tau ts); } public double Process(double x) { double y _alpha * (_yPrev x - _xPrev); _xPrev x; _yPrev y; return y; } public void Reset() { _xPrev 0; _yPrev 0; } } /// summary /// 二阶 Butterworth 高通滤波器双二阶 IIRBiquad /// 采用 RBJ Audio EQ Cookbook 系数公式Q 1/√2 保证巴特沃斯最平坦幅频特性 /// 差分方程y[n] b0·x[n] b1·x[n-1] b2·x[n-2] − a1·y[n-1] − a2·y[n-2] /// /summary public class ButterworthHighPass2 { private double _b0, _b1, _b2, _a1, _a2; private double _x1, _x2, _y1, _y2; public ButterworthHighPass2(double sampleRate, double cutoffHz) { double w0 2.0 * Math.PI * cutoffHz / sampleRate; double cosw0 Math.Cos(w0); double sinw0 Math.Sin(w0); double q 1.0 / Math.Sqrt(2.0); // Butterworth: Q 1/√2 double alpha sinw0 / (2.0 * q); double a0 1.0 alpha; _b0 (1.0 cosw0) / 2.0 / a0; _b1 -(1.0 cosw0) / a0; _b2 (1.0 cosw0) / 2.0 / a0; _a1 -2.0 * cosw0 / a0; _a2 (1.0 - alpha) / a0; } public double Process(double x) { double y _b0 * x _b1 * _x1 _b2 * _x2 - _a1 * _y1 - _a2 * _y2; _x2 _x1; _x1 x; _y2 _y1; _y1 y; return y; } public void Reset() { _x1 _x2 _y1 _y2 0; } } /// summary /// 频域高通滤波FFT → 低频 bin 置零 → IFFT /// 自带基2迭代 FFT 实现原位运算无第三方库 /// /summary public static class FrequencyDomainHighPass { public static double[] Process(double[] x, double sampleRate, double cutoffHz) { int n x.Length; if ((n (n - 1)) ! 0) throw new ArgumentException(输入长度必须是 2 的幂); var re (double[])x.Clone(); var im new double[n]; Fft(re, im, false); // 正变换 // 计算截止频率对应的 bin 索引 int cutoffBin (int)Math.Floor(cutoffHz / sampleRate * n); // 低频区含直流置零 for (int k 0; k cutoffBin k n; k) { re[k] 0; im[k] 0; } // 负频率对称区置零 for (int k n - cutoffBin; k n; k) { re[k] 0; im[k] 0; } Fft(re, im, true); // 逆变换 double[] y new double[n]; for (int i 0; i n; i) y[i] re[i] / n; // 逆变换归一化 return y; } /// summary基2迭代 FFT原位inverse true 时做未归一化逆变换/summary public static void Fft(double[] re, double[] im, bool inverse) { int n re.Length; // 位反转重排 for (int i 1, j 0; i n; i) { int bit n 1; for (; (j bit) ! 0; bit 1) j ^ bit; j ^ bit; if (i j) { (re[i], re[j]) (re[j], re[i]); (im[i], im[j]) (im[j], im[i]); } } for (int len 2; len n; len 1) { double ang 2.0 * Math.PI / len * (inverse ? 1.0 : -1.0); double wr Math.Cos(ang), wi Math.Sin(ang); for (int i 0; i n; i len) { double curR 1.0, curI 0.0; for (int k 0; k len / 2; k) { int a i k, b i k len / 2; double tr curR * re[b] - curI * im[b]; double ti curR * im[b] curI * re[b]; re[b] re[a] - tr; im[b] im[a] - ti; re[a] tr; im[a] ti; double nxtR curR * wr - curI * wi; curI curR * wi curI * wr; curR nxtR; } } } } } }实际运行结果.NET 9Releasei 输入 x[i] 一阶 y1[i] 二阶 y2[i] FFT y3[i] 0 2.5336 2.4564 2.4780 -0.0793 32 2.3431 0.6285 -0.2259 -0.3372 64 3.2806 0.9065 -0.0154 0.4420 96 2.4956 -0.2374 -0.9127 -0.5441 128 3.4986 0.4474 0.0390 0.2695 160 3.3563 0.2181 0.0231 -0.0129 192 3.2049 -0.1551 -0.3134 -0.2442 224 3.9318 0.5102 0.4261 0.4509 256 2.9395 -0.5048 -0.5684 -0.5440 288 3.7986 0.2703 0.2286 0.3332 320 3.4998 0.0936 0.1271 0.0810 352 3.0956 -0.3241 -0.2996 -0.2309 384 3.5992 0.3208 0.4184 0.4202 416 2.4672 -0.6726 -0.5655 -0.5224 448 3.0700 0.0283 0.1585 0.2720 480 2.5988 -0.1757 0.0140 -0.0587 输入均值 : 3.126135 (含直流应≈2.5) 一阶输出均值: 0.165944 (应≈0直流已滤除) 二阶输出均值: -0.009911 (应≈0直流已滤除) FFT输出均值 : 0.000000 (应≈0直流已滤除) 输入RMS : 3.1619 一阶输出RMS : 0.6013 (低频/直流被抑制) 二阶输出RMS : 0.5208 (低频/直流被抑制) FFT输出RMS : 0.3557 (低频/直流被抑制)结果解读输入信号均值 3.13含 2.5V 直流 1Hz 分量在 0.512s 窗口内的残余滤波后三种实现输出均值都归零附近直流被干净滤除FFT 法因直流 bin 被直接置零均值精确为 0输出 RMS 大幅下降输入 3.16 → 一阶 0.60 / 二阶 0.52 / FFT 0.36FFT 输出 RMS 0.3557 ≈ 0.5/√2 0.3536正好等于 50Hz 分量的理论 RMS 值——说明高频分量被完整保留低频与直流被滤除验证算法正确。频率响应实测代码using System; namespace FreqRespTest { /// summary /// 频率响应实测扫描不同频率正弦测滤波前后稳态幅度比增益 dB /// 验证 5Hz 截止频率处增益 ≈ -3dB0.707 /// /summary public static class Program { public static void Main() { double fs 1000.0; double fc 5.0; double[] freqs { 0.5, 1, 2, 3, 5, 8, 10, 20, 50, 100 }; int n 8000; // 8 秒足够长以测稳态增益 Console.WriteLine(频率(Hz) 一阶增益(dB) 二阶增益(dB) 理论-3dB点); foreach (double f in freqs) { double[] x new double[n]; for (int i 0; i n; i) x[i] Math.Sin(2 * Math.PI * f * i / fs); var hp1 new HighPassFilterDemo.OnePoleHighPass(fs, fc); double[] y1 new double[n]; for (int i 0; i n; i) y1[i] hp1.Process(x[i]); var hp2 new HighPassFilterDemo.ButterworthHighPass2(fs, fc); double[] y2 new double[n]; for (int i 0; i n; i) y2[i] hp2.Process(x[i]); double g1 20 * Math.Log10(SteadyAmp(y1) / SteadyAmp(x)); double g2 20 * Math.Log10(SteadyAmp(y2) / SteadyAmp(x)); Console.WriteLine(${f,6:F1} {g1,10:F2} {g2,10:F2} {(f fc ? -- 应≈-3.01 : )}); } } /// summary稳态段幅度估计取后 1/4 样本的峰峰值一半/summary static double SteadyAmp(double[] a) { int start a.Length * 3 / 4; double max double.MinValue, min double.MaxValue; for (int i start; i a.Length; i) { if (a[i] max) max a[i]; if (a[i] min) min a[i]; } return (max - min) / 2.0; } } }优缺点优点有效去除直流 / 趋势项能彻底阻塞直流分量零点在 z1实现简单一阶仅需 1 个系数、1 个状态变量计算量小、实时性好每样本 O(1)适合 MCU 中断级处理参数少只需知道采样率 fsfs​ 和截止频率 fcfc​一阶无条件稳定极点恒在单位圆内纯 C# / 原生实现无第三方依赖可轻松移植到 C / 嵌入式。缺点非线性相位IIR 通病对相位敏感场景需额外处理阻带衰减有限一阶仅 6dB/oct对很靠近 0Hz 的残留抑制不足需更高阶起始瞬态滤波器需要预热起始几个样本不准过渡带较宽非理想锐截止FFT 法存在频谱泄漏、块边缘效应且需整段缓冲、延迟大截止频率附近会有幅度 / 相位过渡选频不当会误伤有用信号。适用场景场景用途惯性传感器加速度计 / 陀螺仪去除直流偏置、重力分量、温漂心电 ECG / 脑电 EEG / 肌电 EMG去除基线漂移与接触伪迹音频系统去除 ADC 直流偏置、保护喇叭振动 / 转速监测提取交流振动分量、剔除静态分量图像处理高通 边缘 / 纹理提取拉普拉斯等传感器数据预处理去除趋势项去趋势后再做后续算法姿态融合与低通构成互补滤波测速 / 编码器滤除缓慢漂移稳定速度反馈总结高通滤波是信号处理家族的基础算法解决如何提取高频、剔除直流 / 低频这一普适问题数字实现有清晰递进的三条路径一阶 IIR最简单、最省资源→ 二阶 Butterworth更陡滚降→ FFT 频域最接近理想一阶公式是嵌入式DC 阻塞器的标准写法建议熟记高通与低通互补是互补滤波等高级算法的基石本文所有 C# 代码已在 .NET 9 下编译运行并实测验证5Hz 截止点 -3dB、一阶 6dB/oct / 二阶 12dB/oct 滚降、输出均值≈0 直流滤除。一句话总结高通滤波 用几行代码、O(1) 的计算成本让信号去粗存精剔除直流漂移、留下动态信息——嵌入式与信号处理工程师的必备基础算法。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进