一阶数字低通滤波器α系数计算:原理、公式与工程实践指南
一阶数字低通滤波器应该是嵌入式工程师最容易写进代码的滤波算法之一。差分方程极短计算量小内存只需要两个变量很多项目的传感器数据平滑、控制环反馈滤波都用它。但就是这个小到不能再小的算法网上随便一搜都能看到好几种α取法有人用 α 2π·fc/fs有人用 α Δt/(RCΔt)还有人干脆试凑。对新手来说最迷惑的一点就在这里——同样标称“10Hz截止频率、100Hz采样”三种写法算出来的α居然还不一样结果滤波效果自然大相径庭。这篇指南专门解决“α怎么根据采样频率和截止频率计算”的问题。我会先把一阶数字低通滤波器的原理模型拆开再把几种主流α公式都推导一遍告诉你什么时候用哪一个然后给出一套完整的参数设计流程和可以照着算的具体例子最后结合我在实际项目里踩过的坑整理成一份直接拿来用的避坑清单。内容适合做传感器信号处理、嵌入式控制系统、音频处理的工程师也适合刚开始学数字滤波器的新手。1. 一阶数字低通滤波器的核心原理1.1 差分方程与α的直观意义一阶数字低通滤波器的标准递推形式是y[n] y[n-1] α · (x[n] - y[n-1])也可以等价写成y[n] α · x[n] (1 - α) · y[n-1]这里的 x[n] 是当前输入采样值y[n] 是当前滤波输出y[n-1] 是上一次输出α 是我们关心的滤波系数。从第二个等式看输出实际上是当前输入 x[n] 和历史输出 y[n-1] 的加权平均。α 越大输出中“新输入”的权重就越大响应快但噪声抑制能力弱α 越小输出中“历史值”的权重越大平滑效果好但输出对输入变化的跟随就很迟钝。用生活里的类比来说这有点像牵狗散步。狗输出想跟着主人输入走但牵引绳滤波器会让狗的行动变得迟缓。绳子越长狗虽然大方向跟着主人但动作很平缓绳子越短狗几乎和主人步调一致。α 就是这根绳子的松紧程度。这种“历史记忆”效应来自滤波器的递归结构每次输出都带上一次输出的信息因此信号会被逐渐“拖慢”噪声则因为每次都被平均掉一部分而明显下降。1.2 连续域模型从RC低通电路说起数字一阶低通滤波器的“祖先”是模拟RC低通滤波电路。一个电阻 R 和一个电容 C 串联后电容两端的电压和输入电压之间的传递函数是H(s) 1/(1 sRC)对应的微分方程是RC · dy(t)/dt y(t) x(t)令 τ RCτ 就是电路的时间常数。模拟一阶低通滤波器的截止频率 fc 和时间常数的关系是fc 1/(2πτ)这个关系非常重要它是后面所有 α 公式的源头。时间常数越大截止频率越低滤波越重时间常数越小截止频率越高滤波越轻。这一点和 α 的作用正好对应。想用数字方式实现一个和 RC 电路行为相近的滤波器核心任务就是把这个连续域的微分方程离散化。离散化的方式不同得到的 α 表达式就会略有不同这也是网上各种公式看起来不一致的根本原因。1.3 离散化为什么α会跟采样周期扯上关系对上述微分方程做数值近似时最常用的方法是后向欧拉法也就是用差分代替微分dy(t)/dt ≈ (y[n] - y[n-1]) / Δt其中 Δt 1/fs 是采样周期。把它代入 RC 低通的微分方程RC · (y[n] - y[n-1])/Δt y[n] x[n]整理一下(RC Δt) · y[n] Δt · x[n] RC · y[n-1]两边同除 (RC Δt)得到y[n] (Δt/(RCΔt)) · x[n] (RC/(RCΔt)) · y[n-1]对照标准形式立刻可以得到α Δt/(RCΔt) Δt/(τΔt)到这里为什么 α 一定要和采样频率挂钩就非常清楚了采样周期 Δt 直接参与离散化过程。采样频率越高Δt 越小同样的时间常数下 α 就越小每次新输入对输出的“冲击”就越弱需要更多次采样才能把信号推到新值。这正是高中物理里“RC 电路充放电要经过若干个时间常数才能稳定”的数字版本。2. α系数计算公式三种写法的推导与对比2.1 基于时间常数的基本公式从上一节推导得到的基本公式是α Δt / (τ Δt)这个形式物理意义最直观它表示采样周期在“采样周期时间常数”总时间里的占比。采样周期相对时间常数越小α 越小滤波越重。工程上更常用的写法是把时间常数 τ 替换成截止频率 fcτ 1/(2π·fc)代入上式α (1/fs) / (1/(2π·fc) 1/fs)进一步化简α (2π·fc/fs) / (1 2π·fc/fs)这是我在实际项目里最常用的一条公式。它只依赖两个参数截止频率 fc 和采样频率 fs逻辑直接便于在代码里通过宏定义或者配置文件实时调整。2.2 指数精确公式连续域匹配更准确除了后向欧拉法还有另一种离散化思路不直接用差商代替微分而是把连续系统的脉冲响应精确采样。对 RC 低通滤波器做零阶保持离散化之后得到的递推系数是α 1 - exp(-Δt/τ) 1 - exp(-2π·fc/fs)这条公式的数学性质更好它对阶跃响应和正弦稳态响应的匹配度更高。当 fc/fs 的比值较大时后向欧拉法离散化会引入明显的频率失真而指数形式的误差要小得多。我在 MATLAB 里对比过这两种形式当 fc 10Hz、fs 100Hz 时后向欧拉法得到的实际 -3dB 点大约在 9Hz 左右而指数形式的实际 -3dB 点基本就在 10Hz。如果系统对截止频率精度要求比较高一定要用指数形式。2.3 小角度近似公式手算和快速估算用当 fc 远小于 fs 时也就是滤波器工作频率远低于采样频率的典型场景上述公式可以做进一步近似。因为当 x 很小时 exp(-x) ≈ 1 - x指数公式就退化成α ≈ 2π·fc/fs这个公式在很多快速实现和文档中出现优点是计算量极小、手算方便缺点是在 fc/fs 比值较大时误差明显。我拿一个示例算一下fc 50Hz、fs 200Hzfc/fs 0.25近似公式给出 α π/2 ≈ 1.57这显然不对因为 α 的取值范围被限制在 0 到 1 之间。所以这条近似公式只能用于 fc/fs 0.05 的场景。2.4 三种公式的定量对比为了更清楚地展示差异我列成一个表格。下面以不同的 fc/fs 比值分别计算三种 αfc/fs 比值近似公式 2π·fc/fs后向欧拉公式指数精确公式0.0010.006280.006240.006240.010.06280.05910.06090.050.3140.2390.2740.100.6280.3860.467可以看到当 fc/fs 0.01 以下时三条公式的结果几乎一样误差在 1% 以内随便用哪条都行。但在 fc/fs 0.1 时后向欧拉和指数形式差了大约 20%近似公式更是已经偏离到不能用的程度。我的经验是如果 fc/fs 小于 0.01用最简单的近似公式没问题如果比值在 0.01 到 0.05 之间用后向欧拉形式足够如果比值超过 0.05或者对截止频率精度有明确要求统一用指数精确公式最稳妥。3. α参数选择的完整工程设计流程3.1 第一步确定截止频率截止频率不是一个可以随便拍脑袋决定的数值它应该由信号特征和噪声环境共同决定。先看你要保留的信号频率范围。比如陀螺仪角速度信号的主要成分集中在 5Hz 以内那截止频率至少要高于 5Hz如果还希望保留运动过程中的主要动态变化通常把 fc 取在目标信号最高频率的 25 倍。再看噪声的频率分布。常见的 50Hz 工频干扰、机械振动噪声、PWM 开关噪声频率远高于有效信号时把 fc 设置在两者之间即可。比如有效信号在 5Hz 以内噪声在 50Hz 附近那么 fc 取 1020Hz 是比较合理的范围。这里有一个权衡fc 越低平滑越强但滞后也越大fc 越高滞后越小但噪声残留越多。控制系统中滞后过大会影响稳定性所以控制环路的反馈滤波通常把 fc 取得比较高甚至不用滤波而测量数据显示类应用则可以接受较大的滞后fc 可以压得比较低。3.2 第二步确定采样频率采样频率首先要满足奈奎斯特采样定理即 fs 必须大于信号最高频率的两倍。对于数字低通滤波器来说实际工程中这个约束需要留出更富裕的余量。我习惯让采样频率至少是截止频率的 20 倍。为什么是 20 倍因为一阶滤波器在截止频率附近的滚降只有 -20dB/十倍频程如果 fc 和 fs 靠得太近滤波器的过渡带会覆盖太大的频带范围超过 fs/2 的频谱还会发生混叠导致实际滤波效果和理论计算差距很大。另外采样频率也受硬件资源限制。ADC 的转换时间、CPU 的处理时间、通信接口的传输速率都会限制最高可用采样频率。如果采样频率无法再提高而截止频率又必须保持在某个值那就只能接受较大的 fc/fs 比值并选用指数精确公式来保证截止频率尽量准确。3.3 第三步计算α并设定初值假设有一个实际场景IMU 姿态传感器以 fs 500Hz 采样需要把 30Hz 以上的振动噪声滤掉保留 5Hz 以内的姿态变化。这里的截止频率取多少合适参考前面“信号最高频率的 25 倍”原则取 fc 15Hz 既能保住 5Hz 的有效信号又能对 30Hz 以上的噪声形成明显衰减。这时 fc/fs 15/500 0.03介于 0.01 到 0.05 之间三种公式结果接近用后向欧拉形式计算就够α (2π · 15 / 500) / (1 2π · 15 / 500) (0.1885) / (1.1885) ≈ 0.1586也就是说每次采样后新的输入只占输出的 15.9%剩下 84.1% 来自历史累计值。这个数值意味着滤波时间常数 τ 1/(2π·15) ≈ 10.6ms换算成采样点数大约是 5.3 个采样周期。换句话说输入突变后大约需要经过 5 个采样周期输出才能体现出一半左右的变化这个滞后对 IMU 姿态显示来说是完全可以接受的。如果使用指数精确公式α 1 - exp(-2π · 15/500) 1 - exp(-0.1885) ≈ 0.1716和后向欧拉的 0.1586 相差约 8%在多数情况下这个差别不影响系统行为。但如果后续做算法仿真时发现滤波曲线相位偏移不符合预期记得先回来确认自己用的是哪条公式。计算完成后别忘了处理初始值。滤波器启动时y[n-1] 还没有有效值。最粗暴的做法是置 0但这会让前几十个采样点出现明显的阶跃响应过程。我更推荐在滤波开始前连续采集 N 个原始样本取平均把这个平均值作为 y 的初始值或者直接把第一次采样的原始值塞给 y。这样启动阶段就能快速进入稳态避免开头一大段数据没法用。3.4 第四步用仿真或在线调试验证参数计算出来后一定不要直接固化到程序里就完事。我每次都会先拿真实采集的数据离线跑一遍滤波观察时域波形和频谱是否达到预期。用 Python 做这个验证非常方便import numpy as np import matplotlib.pyplot as plt fs 500.0 fc 15.0 alpha (2 * np.pi * fc / fs) / (1 2 * np.pi * fc / fs) t np.arange(0, 2, 1/fs) clean 1.0 * np.sin(2 * np.pi * 2 * t) # 2Hz 有效信号 noise 0.3 * np.sin(2 * np.pi * 35 * t) # 35Hz 噪声 x clean noise y np.zeros_like(x) y[0] x[0] for n in range(1, len(x)): y[n] y[n-1] alpha * (x[n] - y[n-1]) plt.figure(figsize(10, 4)) plt.plot(t, x, alpha0.5, labelraw) plt.plot(t, y, linewidth2, labelfiltered) plt.xlabel(t / s) plt.ylabel(amplitude) plt.legend() plt.grid(True) plt.show() freq np.fft.rfftfreq(len(x), 1/fs) amp_raw np.abs(np.fft.rfft(x)) amp_filt np.abs(np.fft.rfft(y)) print(amp_filt[int(35 * len(x) / fs)] / amp_raw[int(35 * len(x) / fs)] if amp_raw[int(35 * len(x) / fs)] else 0)如果对频谱分析还不够熟悉直接在时域看滤波后曲线的平滑程度再对比原始波形判断滞后量是否可接受也能完成基本验证。真正上板之后再用示波器或者上位机实时波形确认一遍把这个步骤固化成习惯可以省掉后面非常多的调试时间。4. 不同应用场景下的参数选择策略4.1 传感器数据平滑IMU、光敏、压力传感器原始数据通常带有高频噪声而有效信号本身变化缓慢这是最适合使用一阶数字低通滤波器的场景之一。拿 IMU 的加速度计数据举例静止时测得数据仍然会叠加零点几 g 的高频抖动如果直接用于姿态解算解算结果也会抖。此时把截止频率定在 1030Hz 之间采样频率 100500Hz用指数精确公式算 α可以得到相当平滑的姿态角。要注意的是人体运动、机械臂运动这类动态场景信号频率并不低。跑步时脚步落地会产生明显的冲击脉冲此时 fc 如果定得太低步态峰值会被削平计步算法反而失真。这类场景我建议把 fc 提到 5080Hz宁可多留一点噪声也不能丢掉动作特征。光敏传感器、压力传感器如果用于缓慢环境监测fc 可以压到 15Hzα 会非常小。此时要注意浮点精度问题计算时如果使用单精度 floatα 过小会导致 y[n] 的增量低于浮点分辨率滤波完全失效。这种情况要么改用 double要么用下面的定点方案。4.2 工业控制与电机反馈控制环路里的滤波要格外谨慎因为滤波器引入的相移会影响系统稳定性。一个典型例子是电机编码器速度反馈。编码器速度信号在低速时量化噪声很严重如果不滤波速度环的输出会抖动但如果滤波太狠速度反馈滞后加大整个速度环的带宽会降低严重时导致振荡。这里有一个经验法则反馈滤波器的截止频率应该设置为控制环路带宽的 510 倍以上。比如速度环带宽设计为 20Hz反馈滤波器的 fc 至少取 100Hz。如果采样频率是 1kHzfc/fs 0.1此时必须用指数精确公式后向欧拉已经不准确了。还有一种做法是在控制环路之外对给定值做斜坡平滑不对反馈量滤波。这种“只平滑目标、不平滑反馈”的策略同时避免了滞后和噪声问题很多运动控制项目中我都推荐优先尝试这个方案。电流环的滤波情况更特殊。电流采样通常伴随 PWM 开关噪声截止频率往往要放到几百赫兹甚至上千赫兹而采样频率也高达 10kHz 以上。这种情况下 fc/fs 比值通常在 0.05 以内滤波效果比较理想但需要特别注意采样时刻和 PWM 开关周期的同步性否则无论 α 怎么调噪声都滤不干净。4.3 音频与语音处理场景音频处理里一阶低通滤波器常用于去除直流偏移、作为均衡器的一部分或者做简单的降噪。音频采样率往往是固定的常见 44.1kHz 或 48kHz。如果你要把 10kHz 以上的高频噪声滤掉fc 可能取 8kHz此时 fc/fs 8000/48000 ≈ 0.167比值非常大。如果还傻乎乎用近似公式得到的 α 会超过 1滤波器直接变高通。这种情况下必须用指数精确公式α 1 - exp(-2π · 8000/48000) ≈ 1 - exp(-1.047) ≈ 0.649这个 α 已经不“小”了滤波器的平滑作用有限但这是由截止频率和采样频率的物理关系决定的。音频应用追求更陡峭的滚降时通常不靠提高 α 实现而是换用二阶或更高阶滤波器。音频处理还要注意滤波器的相位失真对立体声成像的影响左右声道如果用完全相同的 α 和结构相位一致性还能保持。不同声道用不同参数的滤波器会让声像偏移这是很多 DIY 音频项目里被忽视的问题。4.4 便携设备与低功耗系统低功耗单片机上做滤波浮点运算常常是奢侈的。很多 MCU 没有硬件浮点单元用软件浮点库算一遍滤波可能要几十微秒功耗和延时都上去了。这时可以把 α 换算成定点数来算。具体做法是选一个比例因子比如 Q12 格式用 4096 代表 1.0。把 α 和 (1-α) 分别乘以 4096 后取整滤波递推完全用整数乘加完成。以之前 IMU 例子中的 α 0.1586 为例α_q12 (int)(0.1586 × 4096) 650beta_q12 4096 - 650 3446递推式变为y_q (int32_t)((y_q × 3446 x_q × 650) 12)这个写法只需要两次整数乘法和一次移位在 8 位单片机上也能轻松跑。唯一要注意的是中间结果要用 32 位变量承接防止乘法溢出。我实际遇到过在 STM32F103 上用浮点滤波导致主循环周期从 1ms 变成 3ms 的情况改成 Q12 定点后恢复到 0.9ms滤波效果几乎不变。如果你的系统对实时性敏感这条优化经验可以直接复制。5. 常见问题、调试经验与实用技巧5.1 α取值不当的表现与对策α 太大滤波输出会紧贴原始信号噪声依然明显看起来像是滤波器“没有生效”。这个现象很多人第一反应是提高阶数但我建议先回头检查是不是 fc 设置得过高或者采样频率选得太低导致 fc/fs 比值过大。把 fc 降下来之后一阶滤波通常就能解决问题。α 太小输出会变得非常平滑但输入一旦发生突变输出要经过很长一段爬坡才能跟上。这时候信号的有效瞬态特征会被抹掉控制系统里甚至会出现明显的延迟误差。对策是检查 fc 是否过低或者升级为自适应滤波——在信号变化剧烈时临时增大 α平稳时再减小。还有一种很容易误判的情况数据里存在周期性低频干扰比如 0.5Hz 的呼吸噪声叠加在 2Hz 的有效信号上。此时你一阶低通无论怎么调都很难两全压掉 0.5Hz 干扰意味着 fc 必须低于 0.5Hz但这样 2Hz 有效信号也没了。这种情况需要换用带通、自适应滤波或其他算法不要硬撑。5.2 浮点精度与数值稳定性一阶低通滤波是 IIR 结构理论上只要 α 在 0 到 1 之间就稳定。但浮点实现中当 α 非常小、采样点数量很大时会出现一种“数值粘滞”现象y[n] 把大部分历史信息保存在低位新增增量太小被浮点舍入吃掉输出就卡在某个值上不动了。这在 32 位 float 下尤其容易发生。我的处理方式有两个层面。一是在滤波公式上尽量使用增量形式y[n] y[n-1] α · (x[n] - y[n-1])这种形式能避免直接计算大数比例误差累积更小。二是在工程上给 α 设置下限比如 float 下不要小于 1e-5。如果确实需要 α 1e-6 这种极小的值建议重构算法改用滑动平均或者降低采样频率而不是硬压。还有一个容易被忽略的细节如果把 α 定义成浮点常量但后续做算法移植时不小心把参与计算的变量从 double 降成 float滤波效果可能发生肉眼可见的变化。我调试过一个问题最后定位到是编译器优化选项把中间运算强制用了 float加上 -O2 后精度下降滤波输出出现抖动。定位到问题后用 volatile 修饰和强制 double 计算就解决了。5.3 初始化和阶跃响应问题滤波器上电初始化的瞬间输出可能飞出去。如果 y[0] 被置为 0而输入第一次采到的是一个较大数值输出会从 0 开始爬升形成一个本来不存在的“爬坡”后续统计特征全部被污染。前面提到用首样本或 N 点平均初始化可以解决这个问题这里再补充一个细节对于需要快速启动的在线系统可以先用较大的 α 运行 50 个采样点再切换到目标 α这样既能快速接近真实值又不影响稳态滤波效果。阶跃响应还有一个特性是一阶低通滤波器输出到目标值的 63.2% 需要恰好一个时间常数 τ到 95% 需要 3 个 τ到 99.3% 需要 5 个 τ。这意味着如果 τ 100ms你要等大约 500ms 才能让输出基本稳定。很多项目验收时只给几百毫秒的启动时间如果滤波器太重数据预热时间不够就得考虑用加权平均初始化或者缩短 τ。5.4 MATLAB fdatool 交叉验证如果你手边有 MATLAB可以用 fdatool 做一次交叉验证。这个工具虽然主要用于设计 FIR/IIR 滤波器但设计一阶 IIR 低通后可以直接查看生成的系数拿来和手算的 α 对比。具体操作是在 fdatool 里选择 IIR 类型、Butterworth、指定阶数为 1设置采样频率 Fs 和截止频率 Fc点击设计后查看滤波器的分子分母系数。标准一阶 Butterworth 的分子系数是 [b0 b1]分母是 [1 a1]转换后的滤波方程可以写成 y[n] b0·x[n] b1·x[n-1] - a1·y[n-1]。这和 y[n] α·x[n] (1-α)·y[n-1] 在结构上有差异因为双线性变换会加入前馈项 b1使得同一截止频率下的响应略有不同。我通常在无 MATLAB 环境时用 Python 的 scipy.signal.butter 做同样验证两者都能给出理论截止频率对应的数字滤波器系数。对比手算 α 和工具生成的 α 值如果差异在 5% 以内说明设计合理如果差异超过 10%就要回头检查采样频率和截止频率是否输入正确。5.5 多级滤波与级联的误区一阶滤波器滚降速度只有 -20dB/十倍频程也就是频率升高 10 倍衰减增加 20dB。如果想在 100Hz 处衰减 40dB而噪声源从 20Hz 就开始出现单靠一阶很难满足要求。这时很多人会串两个一阶滤波但要注意串联后的截止频率会改变。串联两个一阶滤波器总传递函数是 H(z)²截止频率不再是原来的 fc而是向低频移动。如果希望两级串联后总截止频率还是 fc每一级的截止频率需要按 fc / sqrt(2^(1/2)-1) 那个思路调整工程上简化处理时直接用 fc × 0.64 作为单级目标。复杂一点的话直接用 MATLAB 设计二阶 Butterworth系数直接出来省去换算麻烦。如果需要更陡峭的滚降也可以直接切换到二阶滤波器。但二阶滤波对系数量化误差更敏感定点实现时尤其要注意零极点紊乱问题。这条路径一旦走深建议先用工具仿真再落代码。写在最后的一点体会在我做过的项目里一阶数字低通滤波器出现的问题十次里有八次不是算法本身不行而是参数选择环节想得太少。采样频率受硬件限制、截止频率受需求约束α 不过是这两个约束的数学投影。先把 fc 和 fs 想清楚α 的计算就只是一个机械步骤。还有一点想分享的是滤波器参数最好做成可配置项不要硬编码在函数里。哪怕现在看起来参数已经调好了设备量产后遇到新的环境噪声能通过配置文件远程改 α会省掉一次重新烧录的麻烦。这个小习惯我后来一直保持到现在。