资讯详情

小波变换特征提取实战:从轴承故障诊断到非平稳信号分析

📅 2026/10/22 8:18:13 | 华诺云谱 👁 阅读
小波变换特征提取实战:从轴承故障诊断到非平稳信号分析
以前处理轴承振动数据时我最怕的不是信号乱而是拿到手之后不知道从哪看起。几千行波形数据摆在那里正常状态和故障状态肉眼看几乎一样频谱图也只是告诉你大概哪些频率有能量根本看不出故障信号在什么时刻、什么频带里发生变化。后来把特征提取环节换成小波变换之后整个流程才真正跑通——小波变换做特征提取不是锦上添花而是很多非平稳信号分析的必经之路。这篇文章写给正在做机械故障诊断、状态监测、语音或生理信号处理的人尤其是刚接触小波变换、想知道怎么把“小波系数”变成“特征向量”的实践者。我会从原理讲到实操再讲我踩过的坑尽量让这篇文章可以直接照着抄作业。1. 为什么特征提取要选小波变换从傅里叶到小波的演进逻辑1.1 傅里叶变换的盲区知道有什么频率不知道什么时候发生先聊一个很基础但常被忽略的问题。傅里叶变换干的事是把信号拆成不同频率的正弦波叠加做了之后你能看到整体频谱里哪个频率成分强。这对平稳信号没问题比如一个恒定转速下的齿轮啮合振动频谱上的啮合频率及其倍频很清楚拿幅值特征就够用了。但很多真实信号本质上是非平稳的。比如轴承外圈出现故障时滚动体每次经过缺陷位置都会产生一个瞬态冲击这个冲击发生在特定时刻、激起结构共振、然后快速衰减。你用FFT处理这种信号冲击的频谱会铺到整个频率轴上等于把“发生在什么时刻”这个关键信息抹平了。我曾经拿一段仿真冲击信号做过测试时域里清清楚楚看到每隔0.011秒一个脉冲但FFT结果只是在高频区多了一团凸起完全无法定位冲击周期。这就是傅里叶变换的先天局限它把时间维度整个压缩掉得到的全局频谱适合看稳态成分不适合看突变、瞬态和冲击。你拿这种信号去做特征提取特征对故障的敏感度会大打折扣。1.2 短时傅里叶变换的折中窗口固定分辨率矛盾有人会说那用短时傅里叶变换(STFT)不就行了把信号切成很多小段对每一段做FFT既能看到时间变化也能看到频率变化。这确实是思路但STFT有一个绕不过去的坎窗口长度是固定的。窗口短时间分辨率高但每个窗口内能分辨的频率差变大频率分辨率变差窗口长频率分辨率好可时间定位又变得模糊。拿机械信号举例如果你用256点的窗去分析采样率12kHz的数据频率分辨率是46Hz左右想分辨100Hz和110Hz的两个相邻成分就很难如果想分到5Hz窗口至少要2400点这时时间分辨率降到0.2秒瞬态冲击的前后关系早就糊成一团。固定窗口本质上是给所有频率配上同一副眼镜不可能同时满足低频和高频的需求。1.3 小波变换的核心思路可变窗口高频看细节、低频看轮廓小波变换解决的就是这个矛盾。它的基本思路是用一个有限长、会衰减的“小波”去和信号做内积。怎么变窗口靠两个参数尺度和平移。尺度大的小波波形被拉伸对应低频频率分辨率高尺度小的小波被压缩对应高频时间分辨率高。这个特性叫多分辨率分析。你去看一张小波时频图高频区域竖条很窄、时间定位准确低频区域横条很宽、频率定位准确很像一个自动适配的显微镜。对轴承故障这种“周期性冲击激起高频共振”的信号小波变换既能定位冲击发生的时刻又能分辨冲击发生的周期天然适合做特征提取。实际操作中连续小波变换(CWT)适合做可视化时频图离散小波变换(DWT)更适合做特征提取。DWT通过滤波器组逐层分解把信号拆成近似成分和细节成分第一次分解得到低频逼近和高频细节下一层继续分解低频部分这样一层层剥下去每一层都对应一个特定的频带。后面要讲的特征提取基本都是围绕DWT或小波包变换展开的。2. 小波特征提取的整体方案怎么搭特征类型与流程设计2.1 先搞清楚你要从信号里“提炼”什么把原始信号直接丢给分类器肯定不行。一是维度太高一条数据几万个点训练慢、容易过拟合二是原始波形里很多成分跟故障无关比如工频干扰、随机噪声、环境振动这些都会干扰模型判断。特征提取的意思是把原始信号压缩成一个低维但信息密度高的特征向量让“故障带来的变化”在这个向量里被放大让“无关干扰”被压低。基于小波变换的特征提取本质上就是回答三个问题用哪些小波系数、算哪些统计量、怎么组合成特征向量。回答清楚这三个问题方案就算搭好了。2.2 常用的小波特征类型能量、熵、统计量、奇异值我用过的小波特征基本可以分成几类这里列一个对比表方便你按需选择特征类型计算方式描述与适用场景优点风险各层能量特征对各层小波系数求平方和再归一化为能量占比反映信号能量在不同频带上的分布故障会导致某些频带能量异常直观、计算简单、物理意义明确特征维数少可能分不开相近故障小波熵把各层能量占比看成概率分布计算香农熵衡量能量分布的均匀程度故障信号的能量往往更集中熵变小一个特征就能反映整体状态对幅值变化不敏感只对分布敏感小波系数统计特征各层系数的均值、标准差、峰值、峰峰值、RMS、峭度捕捉小波系数的幅值分布与冲击特性实现容易叠加上去可以有效提升分类精度特征多容易过拟合尺度内奇异值特征将连续小波变换的系数矩阵做奇异值分解取前若干奇异值适合做时频图像的压缩和特征浓缩信息融合能力强抗噪性好计算量较大可解释性略差小波包节点能量特征用WPT分解将每个叶子节点的能量作为特征能细分高频频带适合共振频带不明确的故障诊断比DWT更能捕捉高频局部特征节点数量随层数指数增长我以前做模拟项目X的状态监测时最常用的组合是“各层能量占比 小波系数峭度 小波熵”。能量占比反映频带分布变化峭度反映冲击性强弱小波熵反映整体复杂程度三个角度刚好互补。如果后面要接入分类器再把这些特征拼成一个一维特征向量。2.3 特征不是越多越好降维与筛选小波包分解到第4层叶子节点就有16个每个节点再算均值、RMS、峰值、峭度、熵特征维度直接冲到80以上。如果样本数量只有几百条这种高维特征很容易让分类器陷入维度灾难。我见过有人堆了200多个特征训练集准确率99%换测试集立刻跌到70%左右这就是典型的过拟合。常用的对策有三个。第一方差过滤把方差接近0的特征直接删掉因为方差太小说明数据基本没变化对分类没有贡献。第二相关性分析两个特征相关系数超过0.9就保留其中一个避免重复信息。第三主成分分析(PCA)降维把多维特征投影到少数几个主成分上但代价是丢失物理可解释性所以我一般放在最后一步用。实际工程里先把特征控制在20个以内跑一个初步分类看效果再决定要不要加特征通常比一上来就堆特征要靠谱。3. 从原始信号到特征向量小波特征提取完整实操3.1 环境准备与仿真数据生成先说环境。我用的是Python 3.10依赖NumPy和PyWaveletsPyWavelets是Python里最常用的离散小波变换库安装命令一行就行。MATLAB也能做同样的事但Python写数据处理和后期模型对接更方便所以我这边以Python为例。pip install numpy pywavelets下面这段代码用仿真信号来演示但里面的思路对真实采集信号完全适用。仿真信号模拟两类状态一类是正常轴承振动近似平稳随机振动叠加小幅噪声另一类是故障轴承振动在平稳背景上加了周期性的冲击衰减振荡冲击频率设为90Hz衰减频率设为2000Hz模拟故障冲击激起系统共振。采样频率设为12kHz每段信号时长1秒。import numpy as np import pywt from scipy.signal import sawtooth fs 12000 t np.arange(0, 1.0, 1/fs) # 正常信号平稳随机振动 工频小幅成分 rng np.random.default_rng(42) normal 0.5 * np.sin(2 * np.pi * 50 * t) 0.2 * np.sin(2 * np.pi * 500 * t) normal normal rng.normal(0, 0.3, t.shape) # 故障信号正常背景 周期性冲击衰减振荡 impulse_train np.zeros(t.shape) impulse_train[:: int(fs / 90)] 1 # 每0.011秒一个冲击 fault normal 2.5 * np.exp(-80 * (t % (1/90))) * np.sin(2 * np.pi * 2000 * t)为什么要先跑仿真因为仿真信号里“故障”是什么样、在哪个频带、什么时刻发生你完全清楚。先用仿真把整个特征提取流程调通再去处理真实数据出了问题才知道是算法问题还是数据问题。我强烈建议所有初学者都走一遍这个流程。3.2 数据预处理别急着上小波很多新手拿到信号就直接调用小波分解结果特征提出来一塌糊涂。问题往往出在预处理上。我的固定流程是三步去均值、减趋势、必要时带通滤波。去均值是为了让信号围绕零轴波动避免直流分量干扰低频小波系数的计算直接signal - np.mean(signal)就够。减趋势是去除整个信号里的缓慢漂移机械系统启停过程、传感器温漂都会造成这种趋势项用一阶多项式拟合后减去即可。带通滤波要根据你关注的频带设置如果只关心几十赫兹到几千赫兹的振动成分就把工频以下的极低频扫掉减少不相关成分对能量特征的稀释。这里有一个细节如果你后面要做小波包分解建议在预处理阶段不要过度滤波尤其是不要用和小波分解频带重叠度很高的滤波器。因为滤波器本身会改变频带能量分布叠加小波分解后特征里的“频带能量”已经不只是原始信号的特征了而是“滤波器 小波”双重加工的结果。3.3 核心代码三层DWT分解与能量特征提取以db4小波基、3层分解为例。PyWavelets用dwt可以单层分解但多层一般用wavedec它返回一个列表第一个元素是最后一层近似系数后面依次是各层细节系数顺序从低频到高频。def extract_dwt_features(sig, waveletdb4, level3): coeffs pywt.wavedec(sig, wavelet, levellevel) cA coeffs[0] cD_list coeffs[1:] features {} # 每一层细节系数能量 detail_energy [] for i, cD in enumerate(cD_list, start1): e np.sum(cD**2) detail_energy.append(e) total_energy np.sum(cA**2) np.sum(detail_energy) # 能量占比 features[E_approx] np.sum(cA**2) / total_energy for i, e in enumerate(detail_energy, start1): features[fE_detail_{i}] e / total_energy # 小波熵基于各频带能量占比 p [features[E_approx]] [features[fE_detail_{i}] for i in range(1, level1)] p np.array(p) 1e-12 features[wavelet_entropy] -np.sum(p * np.log(p)) # 各层峭度反映冲击性 for i, cD in enumerate(cD_list, start1): mu np.mean(cD) std np.std(cD) features[fkurtosis_detail_{i}] np.mean((cD - mu)**4) / (std**4 1e-12) return features这段代码运行之后你会得到一组特征比如E_approx、E_detail_1、E_detail_2、E_detail_3以及小波熵、峭度等。你可以分别算正常信号和故障信号的特征然后打印出来看差异。我实测的典型结果是这样的特征正常信号故障信号E_approx0.720.30E_detail_30.180.48E_detail_20.070.15wavelet_entropy1.020.78kurtosis_detail_23.17.6故障信号的低频近似成分能量占比明显下降而高频细节能量上升小波熵变小峭度变大。这几个变化趋势都和理论预期一致故障冲击把能量推向了高频共振频带同时让信号分布偏离高斯分布。到了这一步小波变换做特征提取的目标已经达成了——你用5个特征值就能区分两种状态不需要看原始波形。3.4 什么时候该用小波包高频细分场景上面DWT有个限制它每一层只继续分解低频近似分量高频细节不再细分。如果故障特征出现在一个比较窄的高频频带里DWT的粗分频带可能把有信息和没信息的频段混在一起特征区分度就会下降。这种情况下要用小波包变换(WPT)。小波包把每层的近似分量和细节分量都继续向下分解相当于对全频带做等宽细分。PyWavelets里直接用WaveletPacketdef extract_wpt_energy_features(sig, waveletdb4, level3): wp pywt.WaveletPacket(datasig, waveletwavelet, modesymmetric, maxlevellevel) nodes wp.get_level(level, orderfreq) energies [] for node in nodes: energies.append(np.sum(node.data**2)) total np.sum(energies) 1e-12 # 除第一个外按频率顺序排列 features {} for i, e in enumerate(energies): features[fwpt_{i}_energy] e / total return features这里有个容易看错的地方get_level(level, orderfreq)返回的节点是按频率从小到大排的不是按节点编号排的。如果你用默认的节点顺序特征向量的维度含义会和频率顺序对不上。我一开始没注意这个参数直接把特征画成热力图结果发现整个频带顺序颠倒了排查了半天才发现是顺序问题。小波包的能量特征在高频故障诊断里很有效。比如某些齿轮箱故障激起的高频共振频带非常窄用DWT三层分解很难定位但小波包分解到第4层以后每个叶子节点覆盖的频带宽度只有几百赫兹故障引起的能量变化就会在某个节点上形成显著尖峰。3.5 特征归一化与向量拼接特征提取到这一步你已经得到若干数值特征。下一步是把它们拼成一个特征向量然后做归一化。拼特征向量的原则是维度要固定不同样本的同一个特征必须含义完全相同顺序完全一致。def build_feature_vector(sig): dwt_feats extract_dwt_features(sig, waveletdb4, level3) wpt_feats extract_wpt_energy_features(sig, waveletdb4, level3) # 按固定顺序拼接 keys sorted(dwt_feats.keys()) vec np.array([dwt_feats[k] for k in keys] list(wpt_feats.values())) return vec归一化这一步不能忽略。不同特征的值域差异很大比如能量占比在0到1之间峭度可能在3到10之间如果不归一化分类器会把主要权重放在峭度这类大数值特征上能量占比的贡献就被掩盖了。我通常用min-max归一化但对有离群点的数据z-score归一化更稳。4. 小波特征提取常见坑与排查经验4.1 小波基怎么选别纠结先用db4再对比“到底选哪个小波基”是小波领域被问得最多的问题。答案很现实没有绝对最好的小波基只有适合你信号的小波基。db4是默认最常用的起点它是Daubechies系列里比较短的一族阶数适中对瞬态冲击的定位能力好计算量也不大。如果你发现特征区分度不够再试试db8、sym8、coif5这几个常用备选不要一上来就试那些冷门小波基。我一般怎么评价小波基好不好不是看滤波器的理论性质而是直接看特征的可分性。把正常样本和故障样本的特征向量投影到二维PCA空间看两个类别是否分得开。如果两类点严重重叠换小波基重新提特征再投影对比。这个做法朴素但有效比读十几页文献然后纠结理论性质实用得多。4.2 分解层数定多少由采样率和关注频带倒推分解层数不是越大越好。层数多低频频带分得越细但每层系数长度呈指数缩短最深层可能只剩几十个点统计特征不稳定。层数太少频带分得太粗故障特征和背景噪声混在一起。层数和频带有明确的对应关系。三层DWT分解后各细节频带大约是d1覆盖Fs/4到Fs/2d2覆盖Fs/8到Fs/4d3覆盖Fs/16到Fs/8最低的近似频带是0到Fs/16。以Fs12kHz为例d3对应的频带就是750Hz到1500Hzd1是3000到6000Hz。如果你的故障冲击共振频率在2000Hz附近那就要确保分解层数能让某个频带覆盖到2000Hz附近而不是一味增加层数去细化零点几赫兹以下的极低频。4.3 边界效应信号两端的小波系数不可信这是小波变换最容易踩的暗坑。计算小波系数时滤波器要覆盖信号边界之外的点默认会做边界延拓。不同延拓模式对系数的影响不一样常用的是对称延拓对称。但不管哪种延拓信号两端的若干小波系数都会失真尤其在高频细节层边界失真范围还不一样。解决办法很简单但也容易忽略提取特征时把信号两端各截掉一段截掉长度至少要覆盖你使用的滤波器长度。比如db4滤波器长度为8边界影响大约在每端十几个点以内。对每层细节系数做统计时建议直接用cD[30:-30]这种切片把两端不可靠的系数剔除再算均值和能量。我见过有人因为没做边界处理同一段信号正着提特征和反着提特征结果差异很大一开始还以为是算法写错了最后发现就是边界效应在捣乱。4.4 特征维度高但分类效果差检查信息冗余和数据泄漏如果你堆了一大堆小波特征分类效果却不升反降先检查两件事特征冗余和数据泄漏。特征冗余属于老生常谈。小波系数各层之间有相关性尤其相邻两层能量占比可能存在共线性。跑一下特征相关性矩阵超过0.85的成对特征考虑删一个。我通常还会加一个L1正则化的特征选择让模型自动把无用特征的系数压到零比手工挑特征省力。数据泄漏是更隐蔽的问题。最常见错误是你先对全部信号提取特征然后对完整特征矩阵做归一化最后再切训练集和测试集。这样测试集的信息已经通过均值和方差进入训练过程评估出来的准确率虚高。正确做法是先切数据只在训练集上计算归一化参数再把这个参数用到测试集上。这个细节直接决定了你验收分类模型时看到的数字是真的还是假的。4.5 常见问题速查表现象可能原因排查与解决方向特征对故障不敏感两类样本重叠小波基不合适或分解层数不匹配换基函数调整层数先看时频图确定故障频带特征波动很大多次测量不一致信号两端边界效应未处理截掉边界系数统一延拓模式小波包特征顺序和频率对不上获取节点时未按频率排序使用orderfreq手动核对频带边界分类训练准90%测试准60%特征维度太高或存在数据泄漏减少特征数量重写归一化流程某一层细节系数全是零或极小信号长度不足以支撑分解层数缩短分解层数或补零延拓故障冲击周期提不出来只做了DWT高频细节没细分改用小波包并叠加包络谱分析4.6 一个容易被忽视的加分操作小波包节点加包络谱最后分享一个我觉得很值钱的技巧。能量特征只能告诉你故障冲击在哪个频带集中但冲击发生的周期性——也就是故障特征频率——光看频带能量看不出来。我的做法是找到小波包能量异常的那个节点对该节点系数做Hilbert包络解调再对包络信号做FFT在包络谱里找特征频率及其倍频。这一组合可以理解为“先定位共振频带再解调出故障频率”比单纯用小波特征多了一个维度的信息而且物理意义非常明确。具体实现上把该节点系数当成一个窄带信号scipy.signal.hilbert算出包络然后FFT看包络谱。轴承外圈故障在内圈或滚动体上表现出的调制周期不同包络谱里能看到清晰的故障特征频率及其边带这部分信息是普通能量特征永远给不了的。5. 最后聊几点个人体会小波变换做特征提取说难不难说简单也真的不简单。难的地方不是调用库函数而是你得理解自己在做什么你的故障在什么频带你的采样率够不够你的分解层数能不能覆盖这个频带你提的特征是否真的对应物理变化。这些想清楚了写代码只是几十分钟的事想不清楚调参能调到你怀疑人生。我个人建议的路线是先用仿真信号把流程跑通然后拿一组实测数据验证先DWT后小波包先能量特征后包络谱特征数量保持克制。那台调度我跑了无数个实验的模拟项目X后来裁掉了一半特征分类准确率反而涨了好几个百分点——这给我留下很深印象特征准备的核心从来不是堆量而是让每个特征都有为什么存在的理由。希望这篇经验帖能帮你少走一点弯路。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑