信号预处理:滤波器的设计与实现

做传感器融合这些年,我最大的体会就是——原始数据不能直接用。

你想想看,传感器出来的信号,哪个不是带着一堆噪声?电源纹波、机械振动、环境干扰……这些乱七八糟的东西混在一起,你要是直接拿去做融合,结果肯定一塌糊涂。

所以,信号预处理是第一步,也是最重要的一步。今天我们就聊聊四种最常用的滤波器:低通、高通、带通、陷波。我会结合Python和Matlab的代码,把设计思路和实战经验都讲清楚。

核心观点:滤波器不是越复杂越好,关键是匹配你的信号特征。选对了,事半功倍;选错了,数据全废。

1. 低通滤波器:把高频噪声滤掉

低通滤波器,说白了就是让低频信号通过,把高频噪声干掉。我在做IMU数据预处理时,最常用的就是它。

为什么?因为加速度计和陀螺仪的输出,有用的信号通常都在低频段(比如人体运动在0-10Hz),而高频部分基本都是噪声。

1.1 一阶低通滤波器(最简单,最实用)

先看一个我在项目中反复用的例子。一阶低通滤波器的传递函数是:

y[n] = α * x[n] + (1-α) * y[n-1]

其中α是滤波系数,取值范围0到1。α越小,滤波效果越强,但延迟也越大。

Python实现:

def low_pass_filter(data, alpha):
    """
    一阶低通滤波器
    data: 输入信号数组
    alpha: 滤波系数 (0 < alpha < 1)
    """
    filtered = np.zeros_like(data)
    filtered[0] = data[0]
    for i in range(1, len(data)):
        filtered[i] = alpha * data[i] + (1 - alpha) * filtered[i-1]
    return filtered

# 使用示例
alpha = 0.1  # 强滤波
filtered_data = low_pass_filter(raw_data, alpha)

我的经验:α值怎么选?我一般先看信号的采样频率。比如采样率100Hz,想滤掉10Hz以上的噪声,α取0.1-0.2就差不多了。别贪心,α太小会导致响应太慢,实时系统会出问题。

Matlab实现:

% 设计一个低通滤波器
fs = 100;           % 采样频率100Hz
fc = 5;             % 截止频率5Hz
[b, a] = butter(2, fc/(fs/2), 'low');
filtered_data = filtfilt(b, a, raw_data);

这里我用了butter函数设计二阶巴特沃斯滤波器。filtfilt是零相位滤波,能消除相位延迟——这个在离线处理时特别好用。

2. 高通滤波器:去掉直流分量和低频漂移

高通滤波器和低通正好相反。它让高频信号通过,滤掉低频成分。

什么时候用?比如你要分析振动信号,或者想去除传感器输出的直流偏置。我记得有一次做压力传感器校准,发现数据一直在缓慢漂移,就是靠高通滤波器解决的。

2.1 一阶高通滤波器实现

def high_pass_filter(data, alpha):
    """
    一阶高通滤波器
    """
    filtered = np.zeros_like(data)
    filtered[0] = data[0]
    for i in range(1, len(data)):
        filtered[i] = alpha * (filtered[i-1] + data[i] - data[i-1])
    return filtered

# 使用示例
alpha = 0.9  # 高通系数
high_passed = high_pass_filter(raw_data, alpha)

注意:高通滤波器会引入相位失真。如果你做实时控制,一定要考虑延迟问题。我曾经在一个无人机项目中吃过这个亏——滤波后的数据延迟太大,导致姿态控制震荡。

3. 带通滤波器:只保留你想要的频段

带通滤波器,就是低通+高通的组合。它只让某个频率范围内的信号通过。

举个例子:心电信号(ECG)的有效频率范围是0.5-40Hz。低于0.5Hz的是基线漂移,高于40Hz的是肌电噪声。这时候带通滤波器就派上用场了。

3.1 Python实现带通滤波器

from scipy import signal

def bandpass_filter(data, lowcut, highcut, fs, order=4):
    """
    带通滤波器
    lowcut: 下限频率
    highcut: 上限频率
    fs: 采样频率
    """
    nyq = 0.5 * fs
    low = lowcut / nyq
    high = highcut / nyq
    b, a = signal.butter(order, [low, high], btype='band')
    filtered = signal.filtfilt(b, a, data)
    return filtered

# 使用示例
fs = 1000  # 采样率1kHz
filtered_ecg = bandpass_filter(ecg_signal, 0.5, 40, fs)

这里我用了scipy的signal模块,设计了一个4阶巴特沃斯带通滤波器。order越高,过渡带越陡,但计算量也越大。

4. 陷波滤波器:精准干掉特定频率

陷波滤波器,也叫带阻滤波器。它只衰减一个很窄的频率范围,其他频率几乎不受影响。

什么时候用?最常见的就是工频干扰。50Hz(或60Hz)的电源噪声,几乎无处不在。我做过一个医疗设备项目,信号里总有50Hz的尖峰,就是靠陷波滤波器搞定的。

4.1 陷波滤波器设计

def notch_filter(data, freq, fs, Q=30):
    """
    陷波滤波器
    freq: 要滤除的频率
    fs: 采样频率
    Q: 品质因数(越大带宽越窄)
    """
    b, a = signal.iirnotch(freq, Q, fs)
    filtered = signal.filtfilt(b, a, data)
    return filtered

# 使用示例:滤除50Hz工频干扰
filtered_signal = notch_filter(raw_signal, 50, 1000, Q=30)

避坑指南:Q值别设太大。我曾经设Q=100,结果滤波器变得极其敏感,稍微有点频率偏移就失效了。一般Q取20-50就够用。

5. 四种滤波器的对比与选择

说了这么多,到底该用哪个?我整理了一个表格,方便你快速决策:

滤波器类型 用途 典型应用场景 注意事项
低通 滤除高频噪声 IMU数据平滑、加速度计去噪 延迟与滤波效果的权衡
高通 去除直流/低频漂移 振动分析、去除基线漂移 会衰减有用低频信号
带通 保留特定频段 ECG信号、语音处理 阶数选择影响计算量
陷波 消除特定频率干扰 工频干扰抑制 Q值设置要合理

6. 实战中的滤波器设计流程

最后,我分享一下自己在项目中常用的滤波器设计流程:

  1. 先做频谱分析——用FFT看看信号里都有哪些频率成分
  2. 确定有用信号的频段——比如人体运动信号在0-10Hz
  3. 识别干扰频率——比如50Hz工频、机械共振频率
  4. 选择合适的滤波器类型——根据上面的表格选
  5. 设计并测试——先用仿真数据验证,再上真实数据
  6. 评估延迟和计算量——实时系统尤其要注意

我的建议:别一上来就搞高阶滤波器。先用一阶低通试试,效果不够再加。很多时候,简单的滤波器反而更可靠。

好了,关于信号预处理滤波器的内容就这些。记住,滤波器是传感器融合的基石,这块做扎实了,后面的融合算法才能发挥真正的作用。

信号预处理滤波器知识体系 信号预处理 低通滤波器 保留低频,滤除高频 高通滤波器 保留高频,滤除低频 带通滤波器 保留特定频段 陷波滤波器 消除特定频率干扰 典型应用场景 IMU数据平滑 加速度计/陀螺仪 振动分析 机械故障诊断 生物信号处理 ECG/EEG去噪 工频干扰抑制 50Hz/60Hz陷波 设计流程 频谱分析 确定频段 选滤波器类型 设计测试 评估优化
可可精品资料库