news 2026/9/5 7:42:43

数字滤波器实战:避免低通滤波磨平信号边沿的选型与调参指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数字滤波器实战:避免低通滤波磨平信号边沿的选型与调参指南

在调试信号处理流程时,很多人遇到过这样的场景:传感器数据采集回来,想通过滤波把波形处理得干净一些,再送给后续算法使用。第一版低通滤波器跑完,波形确实平滑了,可你真正关心的“尖峰”“突变沿”也一起消失了;第二版把截止频率抬高,噪声又卷土重来。翻资料、改参数、重新出图,半小时过去,盯着屏幕你只想问一句话:滤波器,我的刀呢?

这里的“刀”,并不是真正的手术刀或菜刀,而是滤波器的选型思路、截止频率和滤波器参数。滤波本身是一门关于“取舍”的技术:把不需要的频率分量切掉,把需要保留的成分完整留下来。如果只会照抄一段代码,不知道自己在频域上做了什么,就容易把信号磨圆、切钝,甚至把最有价值的特征一刀切没。

这篇文章会把数字滤波器从概念、频谱分析、SciPy 实现,到参数调整和实时嵌入式落地过程中最容易踩坑的地方完整过一遍。适合刚入门信号处理、正在做传感器数据分析,或者需要在 Python / C 中实现滤波但对参数选择没有把握的开发者。

1. 为什么我会喊出“我的刀呢”

1.1 一个典型的滤波故障现场

先看一个抽象但很常见的处理流程。

原始信号大概长这样:

  • 包含一个缓慢变化的有用趋势;
  • 叠加了一个 50Hz 的电源工频干扰;
  • 还有传感器自身的高频随机噪声;
  • 波形里可能存在一个短促的冲击或上升沿,这是后续算法判断“是否发生异常事件”的关键特征。

处理人员第一反应是:“噪声太多,做个低通滤波吧。”于是在网上找到一段类似代码,把截止频率设成 5Hz。结果波形干净得可怕,连那个冲击特征的“刀锋”也被磨成小土坡。后续算法基于这个波形开始漏报,项目结论变成了“这个特征不明显”。

问题出在哪?不是低通滤波这个操作错了,而是“用错了刀”。

1.2 “刀”到底指什么

在滤波器语境里,“找到合适的刀”,至少要回答下面几个问题:

  1. 有效信号的频段是多少?
  2. 噪声的频段是多少?
  3. 两者之间有没有明显的间隔?
  4. 我需要的特征是“平滑趋势”,还是“陡峭边沿”,还是“某一个窄带振动”?

不同答案对应不同滤波器:低通、高通、带通、带阻,甚至可能是组合滤波。

如果一开始不分析频谱,只凭感觉设置截止频率,就像不看病灶位置就在身上乱切一样,很容易切掉好的部分。很多时候,不是滤波器不好用,而是我们没有找到合适的“下刀点”。

2. 数字滤波器基本概念与使用场景

2.1 数字滤波器在做什么

模拟滤波器处理连续电压信号,数字滤波器则处理离散的采样序列。每次滤波,本质上是对一个时间序列做卷积或递归运算,让某些频率分量通过,让另一些频率分量衰减。

在频域里,一段信号可以拆成不同频率的正弦波叠加。比如一个 50Hz 的工频正弦干扰,如果把它从时域信号中移除,而尽量不影响 5Hz、20Hz 这样的有效分量,这就是滤波器的典型目标。

2.2 四种幅频特性

类型通过频率衰减频率常见用途
低通 Low-pass低于截止频率高于截止频率去掉高频毛刺、平滑波形
高通 High-pass高于截止频率低于截止频率去除基线漂移、直流偏置
带通 Band-pass某个区间内区间外提取特定频段的振动特征
带阻 Band-stop区间外某个区间内滤除单一窄带干扰,如 50Hz 工频

实际项目中,低通最常用,但它不是万能的。如果一个干扰信号与有效信号在频带上存在重叠,单纯靠低通很难同时做到“有效信号不衰减、干扰信号被压掉”。这时候就需要考虑陷波滤波,也就是窄带带阻滤波器。

2.3 IIR 与 FIR 怎么选

数字滤波器从结构上分为两大类:无限脉冲响应滤波器(IIR)和有限脉冲响应滤波器(FIR)。

对比维度IIRFIR
相位线性非线性,频率越高延迟越明显可以做到严格线性相位
阶数与计算量实现同等滤波效果时阶数更低通常需要较高阶数
数值稳定性存在反馈,设计不当可能不稳定没有反馈,基本稳定
典型例子Butterworth、Chebyshev、陷波器窗函数设计、等纹波滤波器
适合场景资源敏感的嵌入式、实时滤波对波形形态、相位延迟敏感的场景

工程里没有绝对好坏。IIR 计算效率高,适合实时和嵌入式;FIR 相位特性好,适合需要保留波形形态的离线数据分析。如果既想减少相位失真,又希望计算简单,也可以在离线环境使用filtfilt做零相位滤波,或者先用 IIR 再把延迟补偿掉。

3. 环境准备与测试信号

3.1 Python 环境约定

本文代码采用 Python + SciPy 实现,因为 SciPy 的signal模块封装了滤波器设计、滤波执行和频谱分析函数,非常适合快速验证算法。

建议环境如下:

  • Python 3.9 及以上;
  • NumPy 1.21 及以上;
  • SciPy 1.8 及以上;
  • Matplotlib 3.5 及以上。

版本不需要完全一致,只要不是特别老的版本,下面接口基本都能使用。如果你用的是公司内网环境,也可以把依赖下载后离线安装。

python -m venv venv source venv/bin/activate # Windows 下使用 # venv\Scripts\activate pip install numpy scipy matplotlib

3.2 合成一段测试信号

在动手设计滤波器之前,先合成一段测试信号,避免用真实数据来回猜测。

import numpy as np from scipy import signal import matplotlib.pyplot as plt fs = 1000.0 # 采样率 1000Hz duration = 2.0 # 时长 2 秒 n = int(fs * duration) t = np.arange(n) / fs # 2Hz 方波,用于模拟带边沿的开关量或脉冲特征 base_wave = signal.square(2 * np.pi * 2 * t, duty=0.5) # 高频随机噪声,模拟传感器毛刺 rng = np.random.default_rng(42) noise = rng.normal(0, 0.3, size=t.shape) # 原始测试序列 raw = base_wave + noise

这里故意把“有效信号”设计成方波,是因为方波包含丰富的奇次谐波。方波的边沿看起来锐利,其实需要较高频率的谐波来共同塑造。低通滤波器保留的谐波次数越少,方波边沿越模糊。这个特征可以非常直观地解释“为什么滤波后波形钝了”。

建议先用 Matplotlib 画出原始波形确认一下:

plt.figure(figsize=(10, 4)) plt.plot(t, raw, lw=0.8) plt.xlabel("Time (s)") plt.ylabel("Amplitude") plt.title("Raw Square Wave with Noise") plt.grid(True) plt.show()

4. 先看频谱:不要凭感觉选截止频率

4.1 FFT 能告诉我们什么

滤波前先看频谱,是信号处理里非常基础且重要的习惯。快速傅里叶变换可以把时域信号转换到频域,让我们看清信号能量分布在哪些频率上。

def plot_spectrum(x, fs, title="Spectrum"): n = len(x) freq = np.fft.rfftfreq(n, d=1 / fs) mag = np.abs(np.fft.rfft(x)) plt.figure(figsize=(10, 4)) plt.plot(freq, mag, lw=0.8) plt.xlabel("Frequency (Hz)") plt.ylabel("Magnitude") plt.title(title) plt.grid(True) plt.xlim(0, fs / 2) plt.show() plot_spectrum(raw, fs, "Raw Signal Spectrum")

如果运行这段代码,会看到方波频谱并不是单一谱线,而是在 2Hz、6Hz、10Hz、14Hz、18Hz 等奇次谐波位置有能量。频率越高,谐波幅值越低。随机噪声则像一层“地板”一样铺在整个频带上。

接下来的滤波器设计,就是根据这张频谱图判断:哪些频率成分可以留,哪些频率成分要切掉。

4.2 频谱图的观察要点

  • 有用信号的频谱主要落在哪个区间: 如果只关心 2Hz 方波的基本形态,保留 6~10Hz 以内的谐波就够用;如果关心边沿是否陡峭,往往需要保留到几十甚至上百 Hz。
  • 噪声频谱的主要集中位置: 如果是 50Hz 工频干扰,会在 50Hz 处出现很明显的谱峰;如果是白噪声,则均匀分布。
  • 信号与噪声是否重叠: 重叠越严重,滤波难度越大。不存在完美一刀切,只能权衡。

先用频谱建立全局认知,再设置滤波器参数,比对着时域波形猜要高效得多。

5. 核心案例一:低通滤波为什么把边沿“磨圆”了

5.1 方波中的谐波与边沿

回到刚才的 2Hz 方波。方波的傅里叶展开可以近似看成:

基波 2Hz + 三次谐波 6Hz + 五次谐波 10Hz + 七次谐波 14Hz……

理论上,如果只保留基波,得到的波形就是一个 2Hz 正弦波,完全看不出方波形态。保留的谐波越多,波形的上升沿和下降沿越接近原始方波。

“刀锋般的边沿”之所以会消失,就是因为低通滤波器把高阶谐波全部削掉了。

5.2 不同截止频率对比

下面分别用 15Hz 和 80Hz 截止频率做低通滤波。

# 15Hz 低通 sos_15 = signal.butter(4, 15 / (fs / 2), btype="low", output="sos") filtered_15 = signal.sosfiltfilt(sos_15, raw) # 80Hz 低通 sos_80 = signal.butter(4, 80 / (fs / 2), btype="low", output="sos") filtered_80 = signal.sosfiltfilt(sos_80, raw) plt.figure(figsize=(12, 8)) plt.subplot(3, 1, 1) plt.plot(t, raw, lw=0.8) plt.title("Raw") plt.grid(True) plt.subplot(3, 1, 2) plt.plot(t, filtered_15, lw=0.8, color="tab:orange") plt.title("Low-pass 15Hz") plt.grid(True) plt.subplot(3, 1, 3) plt.plot(t, filtered_80, lw=0.8, color="tab:green") plt.title("Low-pass 80Hz") plt.grid(True) plt.tight_layout() plt.show()

从输出结果可以清楚看到:

  • 15Hz 低通后,波形非常光滑,高频噪声几乎消失,但方波变成了圆头波浪。如果真实业务中需要判断“开关切换”的时刻,这种波形很难给出精确边界。
  • 80Hz 低通后,方波边沿明显更陡,基本保持了原始方波的形态,但噪声并没有完全滤除,因为高频噪声也被保留了一部分。

15Hz 和 80Hz 之间没有绝对的对错,只有适不适合业务目标。如果你要的是平滑趋势,15Hz 合适;如果你要找边沿、尖峰或者异常突变,那么 80Hz 甚至更高频带才更像一把趁手的“刀”。

5.3 为什么不能只看时域波形去调参

很多开发者习惯不去看频谱,只盯着时域波形调截止频率。看到一个毛刺就去压低截止频率,看到波形太平就把截止频率调高,反复拉扯。这种方式很容易陷入局部最优。

正确流程是:先用 FFT 看看有效信号的能量集中在哪个频段,再确定截止频率。比如想保留一个 100Hz 以内的振铃特征,普通低通截止频率就不能设在 20Hz 以下,否则该特征会被误伤。

如果目标只是去掉工频干扰,而有效信号在 100Hz 以下,那么更合理的是先做一个 50Hz 陷波器,再根据噪声情况决定后续低通截止频率。下面就来演示这种情况。

6. 核心

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 7:41:06

AI图像修复消除游戏图集边缘模糊:原理、实践与效果对比

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/5 7:40:37

给娃选线上英语课,别光看外教!2026家长选课前先搞懂这5个问题

很多家长都有这样的困惑:花了几万块给孩子报线上英语课,学了大半年,孩子还是不敢开口、成绩也没起色。问题到底出在哪?其实,不是线上英语没用,而是大多数家长选课的逻辑从一开始就错了。今天这篇文章&#…

作者头像 李华
网站建设 2026/9/5 7:40:11

开源关键词工具open-seo实测:到底能不能平替Semrush?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/5 7:39:04

AI辅助Web开发全流程指南:从设计到部署的效能提升实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/5 7:38:38

赛车车载视频技术分析:从数据采集到工程应用实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/5 7:34:16

FPGA编译时间优化:Vivado增量编译与约束设置实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华