第三章 信号预处理:去趋势项、滤波、重采样与降噪
各位同学,咱们今天聊聊信号预处理。说实话,这一步在很多人眼里是「苦力活」,觉得不如后面做特征提取、故障识别来得高级。但我得说句实在话——预处理做不好,后面全是白搭。我见过太多人拿着原始信号直接扔进模型,结果跑出来一堆漂亮曲线,仔细一看全是噪声和趋势项在跳舞。
信号预处理,说白了就是给原始信号「洗个澡」。把脏东西洗掉,把有用的部分露出来。咱们一步步来。
3.1 去趋势项:把「地基」找平
什么是趋势项?你想想看,一个轴承从冷机启动到稳定运行,温度在变,润滑油膜在变,传感器可能也在慢慢漂移。这些变化反映在信号上,就是一个缓慢的、非周期性的偏移。这就是趋势项。
趋势项的危害在哪?它会压低或抬高信号的均值,让你算出来的均方根值、峰值这些特征全部失真。我有个项目,现场测振动数据,算出来趋势项占了总能量的30%多,不把它去掉,你根本看不到真正的故障频率。
去趋势项最常用的方法就是多项式拟合。说白了,就是用一条曲线去拟合信号的整体走势,然后把它减掉。
import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
# 生成带趋势项的模拟信号
t = np.linspace(0, 10, 1000)
trend = 0.5 * t + 2 # 线性趋势
vibration = np.sin(2 * np.pi * 5 * t) + 0.3 * np.sin(2 * np.pi * 12 * t)
signal_with_trend = vibration + trend + 0.2 * np.random.randn(len(t))
# 去趋势项
detrended_signal = signal.detrend(signal_with_trend, type='linear')
# 可视化对比
plt.figure(figsize=(12, 4))
plt.subplot(1,2,1)
plt.plot(t, signal_with_trend)
plt.title('原始信号(含趋势项)')
plt.subplot(1,2,2)
plt.plot(t, detrended_signal)
plt.title('去趋势后信号')
plt.show()
3.2 滤波:把「噪音」挡在门外
滤波这件事,我刚开始做的时候也犯过迷糊。低通、高通、带通,到底用哪个?其实很简单——
- 低通滤波:保留低频,滤掉高频。适合看轴承的旋转频率、转频及其谐波。
- 高通滤波:保留高频,滤掉低频。适合看轴承的固有频率、早期故障冲击。
- 带通滤波:只保留某个频段。这是最常用的,因为故障特征往往集中在某个频带里。
我举个例子。有一次诊断一台离心泵的轴承,原始信号里低频有工频干扰,高频有电磁噪声。我用了带通滤波,把500Hz到2000Hz之间的信号提取出来,故障频率一下就清晰了。嗯,这里要注意——滤波器的阶数别太高,否则会有相位失真。
from scipy.signal import butter, filtfilt
def butter_bandpass(lowcut, highcut, fs, order=4):
nyq = 0.5 * fs
low = lowcut / nyq
high = highcut / nyq
b, a = butter(order, [low, high], btype='band')
return b, a
def bandpass_filter(data, lowcut, highcut, fs, order=4):
b, a = butter_bandpass(lowcut, highcut, fs, order=order)
y = filtfilt(b, a, data)
return y
# 使用示例
fs = 10000 # 采样率10kHz
filtered_signal = bandpass_filter(detrended_signal, 500, 2000, fs, order=4)
3.3 重采样:让数据「对齐」
重采样,说白了就是改变信号的采样率。什么时候需要?
- 两个传感器采样率不同,需要统一
- 原始采样率太高,数据量太大,想降采样
- 变转速工况下,需要角域重采样
我最常用的是scipy的resample函数。它内部会先做抗混叠滤波,再插值,效果不错。
from scipy import signal
# 降采样:从10000Hz降到2000Hz
original_fs = 10000
target_fs = 2000
num_samples = int(len(filtered_signal) * target_fs / original_fs)
resampled_signal = signal.resample(filtered_signal, num_samples)
3.4 降噪:把「杂质」筛掉
降噪的方法很多,我挑几个最实用的说说。
| 方法 | 适用场景 | 我的评价 |
|---|---|---|
| 小波阈值降噪 | 非平稳信号、冲击特征 | 效果好,但参数调起来麻烦 |
| EMD(经验模态分解) | 非线性、非平稳信号 | 自适应,但模态混叠是个坑 |
| SVD(奇异值分解)降噪 | 周期性信号 | 简单粗暴,适合批量处理 |
| 中值滤波 | 脉冲噪声 | 速度快,但会平滑掉细节 |
我个人最常用的是小波阈值降噪。为什么?因为轴承故障信号往往是瞬态冲击,小波变换在时频域都有很好的局部化能力,能把冲击保留下来,把噪声滤掉。
import pywt
def wavelet_denoise(data, wavelet='db4', level=4):
# 小波分解
coeffs = pywt.wavedec(data, wavelet, level=level)
# 计算阈值(使用通用阈值)
sigma = np.median(np.abs(coeffs[-1])) / 0.6745
threshold = sigma * np.sqrt(2 * np.log(len(data)))
# 软阈值处理
coeffs_thresh = [pywt.threshold(c, threshold, mode='soft') for c in coeffs]
# 重构信号
denoised = pywt.waverec(coeffs_thresh, wavelet)
return denoised
# 使用示例
denoised_signal = wavelet_denoise(resampled_signal, wavelet='db4', level=4)
核心要点总结:
- 去趋势项是第一步,不做的话后续特征全偏
- 滤波要选对类型,带通滤波最常用
- 重采样前先抗混叠,否则会出假频
- 降噪方法选小波,参数调好效果佳
好了,信号预处理这块就聊到这儿。你想想看,这些步骤其实都是在做同一件事——把信号里「不想要」的部分去掉,把「想要」的部分留下来。做得好,后面的故障诊断就事半功倍;做得不好,那就是在垃圾堆里找金子。
下一章咱们聊聊时域特征提取,到时候我会分享一些我踩过的坑,保证让你少走弯路。