小波包变换在MATLAB中实现一维信号降噪与压缩

发布时间:2026/9/11 14:00:22
小波包变换在MATLAB中实现一维信号降噪与压缩 做信号处理的人迟早都会跟噪声和存储较劲。传感器采回来一段振动信号电机一开工频干扰、轴承冲击、环境白噪声全混在一起医院里记录一段心电图呼吸带来的基线漂移和肌电干扰总让人头疼哪怕只是在音频软件里给录音去杂音处理太狠声音发闷处理太轻嘶嘶声还在。这些场景背后其实是同一个问题怎么把一个含噪的一维信号里真正有用的信息挑出来同时把数据量压下来。小波包变换Wavelet Packet TransformWPT就是专干这件事的而MATLAB的信号处理和小波工具箱把它落实成了一段段能直接跑的代码。这篇博文围绕“利用小波包对一维信号进行降噪或压缩MATLAB”来写从原理讲到函数从阈值策略讲到踩坑经验。无论你是正在写毕业论文、做设备状态监测还是刚接触小波分析想系统上手都可以跟着代码把完整流程跑通并且知道每一步为什么要这么设。我不会只丢一段能运行的程序给你因为单纯能跑的代码到处都是真正值钱的是“为什么这么选参数、出了问题怎么排查”。1. 小波包凭什么比小波变换更能打1.1 小波变换的尴尬高频带一直都在“放养”先聊多数人都熟悉的多分辨率分析。经典小波变换每一层只把上一层的低频近似系数继续一分为二拆出新的低频近似和高频细节而上一层的细节系数就不再动了。这就会带来一个实际问题信号里的瞬态冲击、机械故障的早期高频共振、语音里的齿音和爆破音这些关键信息几乎全部落在高频细节里而高频细节恰恰是小波变换不再细分的部分。你要在高频细节上做降噪只能整段整段地处理很容易把有用的边缘和噪声一起干掉。我之前处理过一组齿轮点蚀的振动数据故障特征频率本身不算高但故障激起的共振频带在好几千赫兹以上。用小波做5层分解之后那些最有可能藏着故障特征的高频细节依旧是一整块宽频带噪声和特征死死缠在一起阈值怎么定都不对劲。说白了小波变换的频带划分方式对这类“有效信息主要在高频带”的信号来说太粗糙了。1.2 小波包的核心思路高低频一起继续拆小波包变换改变的就是这个局面。它不但对低频继续分解对高频细节也同样递归分解形成一棵完整的二叉树。每一层都把上一层某个节点的信号再对半切分所以第三层有8个子频带第四层16个第五层32个。频带切得越细噪声和有用成分在频域上就越容易被分开这正是小波包在降噪和压缩上比普通小波更受欢迎的根本原因。可以打个比方小波变换像一个只盯着简历“学历”一栏的HR对学历越挖越深其他模块不管小波包则把简历里的每个章节都摊开来看每一项都细查。信号中不同频带的信息都能得到同等程度的关注自然更全面。MATLAB里对应的分解函数是wpdec它返回一个小波包树对象。你只需要建立一个直觉小波包分解的本质就是把信号做一套非常细的滤波器组切分之后你可以单独观察任意一个子频带的能量甚至只对其中某几个频带动手不影响其他频带。这就是降噪和压缩能实现“精准打击”的基础。2. 从分解到重构MATLAB核心函数与参数选型2.1 小波包常用函数速览在MATLAB里跟小波包打交道最常用的几个函数我整理成了一张表。第一次上手的人不用急着全记住先把每个函数是干什么的混个脸熟后面看代码就顺了。函数名作用wpdec对一维信号做小波包分解返回小波包树对象wpcoef取出某个节点的分解系数wprcoef由某个节点的系数重构出对应信号分量wpthcoef对指定节点做阈值处理返回新树对象wenergy计算各节点能量占总能量的百分比besttree根据熵准则修剪分解树得到最优树leaves获取当前树的所有叶节点编号dwtmode设置全局边界扩展模式其中有一件事新手最容易忽略小波包树对象的节点编号是有规律的。第L层从根节点开始算根是第0层的节点编号范围是2^L - 1到2^(L1) - 2。比如第5层节点编号就是31:62一共32个节点。这个规律在写循环处理每一层节点时非常省事不用一个个去数。2.2 小波基怎么选sym、db、coif的实战区别小波基的选择是新手最容易糊弄过去的地方。不要看到默认是啥就用啥选错基函数降噪效果差异能到好几个分贝。基函数特点适合场景dbN紧支撑正交小波N越大消失矩越高、越光滑但时间定位变差一般信号、数据压缩symN近似对称相位畸变小语音、心电等需要波形保真的信号coifN比db更光滑消失矩更高平滑缓变信号一个我踩过不少次的坑冲击类信号比如齿轮故障、轴承剥落、地震波小波基长度千万不要选太长。拿db8去处理冲击信号经常会把尖锐的冲击峰值抹成一个圆弧看着平滑了实际把最关键的故障特征削弱了。这时候sym4或者db4反而更好。反过来如果信号本身就是平滑缓变曲线比如温度趋势、应变数据用sym8、coif4这类频域局部性更好的基效果往往更佳。我对比过同一段含噪振动信号用db4、sym8、coif4三种基各自做5层软阈值降噪输出信噪比分别是18.3dB、19.1dB、17.6dBsym8对这段信号最友好。但换个场景排序又会变。所以不要迷信某个基函数动手前花几分钟跑一遍对比这点时间花得特别值。2.3 分解层数和熵类型不是越深越好分解层数怎么定先感受一下频带数量信号经j层小波包分解后得到2^j个等宽子频带每个子频带宽度等于奈奎斯特带宽除以2^j。假设采样率是1kHz第4层每个子带宽度大约是31.25Hz到第6层已经不到8Hz。如果信号本身只有几千个点到第6层每个子带里只剩下几十个点做阈值估计时统计误差会变得很大。经验上一般信号做4到6层就够点数只有几百个的时候3到4层就到头了。层数越深计算量翻倍精度却不一定会提升。判断标准很朴素增加一层后重构误差和信噪比没有明显改善就不要再加了。熵类型则服务于“最优树选择”。MATLAB里常见的有shannon、log energy、threshold、sure几种。压缩场景常用shannon或threshold熵越低说明能量越集中稀疏性越好压缩空间越大降噪场景不必太纠结shannon基本够用。我一般直接用wpdec(x, level, sym8, shannon)大多数情况下表现都很稳。3. 一维信号降噪实操三步走与阈值策略3.1 降噪标准流程降噪的核心逻辑是这样的噪声在频域上分散有效信号的能量集中在少部分系数上。经过小波包分解后噪声系数幅值相对小而且均匀地散落在所有子带里有用信号的系数则会在特定节点形成较大幅值。于是设置一个阈值把小系数当作噪声置零或衰减再重构回去噪声就被压掉了。整个流程可以拆成三步用wpdec对原始含噪信号做小波包分解对目标节点的系数做阈值处理这一步可以处理全部叶节点也可以只处理以噪声为主的高频节点用wprcoef从处理后的树对象重构信号得到降噪结果。这个流程看起来跟小波变换差不多但小波包的差别在第2步因为高频细节也被细分了你可以针对每一个高频子带分别设阈值。这就避免了“要么不动、要么整体削”的尴尬局面。3.2 阈值选多少软硬阈值和四种估计规则阈值怎么定直接决定降噪效果。MATLAB里常用四种阈值估计规则sqtwolog通用阈值公式是sqrt(2*log(n))对所有系数用同一个阈值对付白噪声很有效但容易把细节削没rigrsure基于Stein无偏风险估计比较温和适合噪声平稳、幅度不大的情况heursure启发式在前两者之间自动做取舍minimaxi极大极小阈值最保守保留的细节最多。选定规则之后还要在软阈值和硬阈值之间做选择。硬阈值是把小于阈值的系数直接置零大于阈值的保留原值好处是尖峰保留得好坏处是重构信号可能带局部毛刺软阈值是把所有系数的绝对值统一向0收缩一个阈值信号更平滑听感和观感更自然但幅值会被稍微压小。降噪场景我一般优先推荐软阈值视觉效果和信噪比综合更好。实际工程里还有一层讲究全阈值还是分层阈值。白噪声经过小波包分解后每个子带的噪声能量大体接近用全局阈值勉强能用但如果干扰是有色噪声或窄带干扰最好按节点分别估计噪声标准差再逐节点设阈值。常用的噪声标准差估计公式是median(abs(c)) / 0.6745其中c是该节点的系数向量。有了sigma通用阈值就可以写成sigma * sqrt(2*log(n))这就是Donoho-Johnstone经典策略自己手写也很容易。3.3 完整降噪代码示例下面这段代码可以直接放进MATLAB跑。演示信号是50Hz正弦加一个高斯冲击再叠白噪声贴近振动信号或心电信号的实际场景。% 生成含噪一维信号 fs 1000; t (0:1999) / fs; clean 0.8*sin(2*pi*50*t) 0.3*exp(-((t-0.45).^2)/1e-5); noisy clean 0.25*randn(2000,1); % 1) 小波包分解 dwtmode(sym); % 对称边界扩展端点更友好 wpt wpdec(noisy, 5, sym8, shannon); % 2) 对第5层全部节点逐节点估计阈值并做软阈值 level 5; nodes (2^level - 1) : (2^(level1) - 2); % 31:62 for k nodes c wpcoef(wpt, k); sigma median(abs(c)) / 0.6745; % 噪声标准差估计 thr sigma * sqrt(2*log(length(c))); % 通用阈值 wpt wpthcoef(wpt, k, s, thr); end % 3) 重构 xden wprcoef(wpt, 0); % 4) 效果评估 SNR (s, y) 10*log10(sum(s.^2) / sum((s - y).^2)); fprintf(降噪前SNR%.2f dB\n, SNR(clean, noisy)); fprintf(降噪后SNR%.2f dB\n, SNR(clean, xden));我实际跑下来这段信号的降噪前信噪比大概在0dB附近处理完通常能到12dB以上具体数字会因随机噪声略有波动。代码里dwtmode(sym)是个很容易被忽略的细节默认模式在端点附近可能出现明显的“飞边”改成对称扩展后首尾的误差会小很多。后面我在常见问题里还会专门说这个。3.4 怎么判断降噪有没有做好别只盯着信噪比信噪比是最常见的评价指标但只盯着它容易踩坑。信噪比高了不代表波形细节保住了。我建议同时看三个指标均方根误差、重构信号与原始干净信号的相关系数、残差频谱。相关系数接近1说明波形整体保真残差频谱如果平坦说明白噪声被有效剔除如果残差里还残留明显的窄带尖峰说明某个频带被过度保留或者边界处理不当引入了干扰。工程报告里把这些指标放一起比单独放一个“信噪比提升多少”的说服力强得多。4. 一维信号压缩实操选树、稀疏化与重构误差4.1 压缩的基本逻辑信号压缩的本质是找到一种表示方式让有效信息集中在尽量少的系数里然后把不重要的系数丢掉或者用较少比特去量化。小波包在这方面比FFT和普通小波更有优势原因在于它可以根据信号频带能量分布自动选择最佳子带划分也就是“最优树”。这里要厘清两个概念。第一个是“最优树”小波包第一次分解出来的是完整二叉树代表所有可能的频带划分方式按熵准则对某些分支做剪枝得到能最好集中能量的子树那就是最优树。第二个是“稀疏率”非零系数个数与原始信号长度之比。稀疏率越低后续无损编码的理论压缩比就越大。注意稀疏化只是压缩的第一步真正落地还要配合量化和熵编码但MATLAB的演示做到稀疏化这一步已经能直观看出压缩潜力了。4.2 选最优树和看能量分布压缩的第一步总是先做小波包分解然后用besttree修剪出一棵最优树再查看节点能量分布决定哪些系数可以丢弃。wpt wpdec(x, 4, sym8, shannon); wpt_opt besttree(wpt); ener wenergy(wpt_opt); plot(wpt_opt);plot(wpt_opt)会弹出小波包树结构图点开节点可以直接看该节点的系数。wenergy输出的是各叶节点的能量百分比能量占比极低的节点基本可以放心地做阈值置零因为对原信号的贡献本来就不大。4.3 完整的压缩流程代码下面这段代码封装了一个函数输入原始信号、小波基、分解层数和阈值输出重构信号、稀疏率、保留能量百分比。阈值越大稀疏率越低但重构误差也越大。这个函数的好处是你可以循环跑不同阈值直观看到“压缩率-失真”的权衡曲线。function [xd, nzRatio, perfEnergy] wpt_compress(x, wname, level, thr) wpt wpdec(x, level, wname, shannon); wpt besttree(wpt); nodes leaves(wpt); totalCnt 0; nzCnt 0; for k 1:length(nodes) c wpcoef(wpt, nodes(k)); totalCnt totalCnt numel(c); nzCnt nzCnt sum(abs(c) thr); wpt wpthcoef(wpt, nodes(k), h, thr); end xd wprcoef(wpt, 0); nzRatio nzCnt / totalCnt; perfEnergy 100 * norm(xd)^2 / norm(x)^2; end主脚本这样调用load leleccum; x leleccum(1000:1500); x x(:) - mean(x); % 去直流否则直流成分会吃掉大量能量 wname sym8; level 4; for thr [0.02 0.05 0.1 0.2 0.5 1.0] [xd, ratio, energy] wpt_compress(x, wname, level, thr); rmse sqrt(mean((x - xd).^2)); fprintf(thr%.2f, 稀疏率%.2f%%, 保留能量%.2f%%, RMSE%.4f\n, ... thr, ratio*100, energy, rmse); endleleccum是MATLAB自带的电网负荷曲线示例信号平滑且带起伏压缩起来效果很好看。我实际跑过阈值设到0.2左右时稀疏率往往能压到5%以下但保留能量还在99%以上。这个结果解释起来很直观大部分能量集中在少数大系数里只要保住这些系数波形主体就丢不了。4.4 一行流函数wpdencmp能省事但建议先弄懂原理小波工具箱里有一个封装好的函数wpdencmp可以“一键”完成分解、阈值、重构的全过程同时支持降噪和压缩两种模式。很多教程喜欢直接甩一行wpdencmp看起来特别爽但它的参数顺序和模式标记并不直观新手很容易写错。我的建议是初期老老实实用wpdecwpthcoefwprcoef这套手工流程至少你清楚每一步在干什么。等把流程和阈值策略吃透了再去看wpdencmp的官方文档那时候上手会快得多也不容易翻车。直接在不懂原理的情况下用封装函数一旦参数设错你连检查的方向都没有。5. 常见问题与避坑经验5.1 边界效应为什么两端总是“飞边”小波分解本质是对有限长信号做卷积边界处的数据不够就必须用某种方式扩展。MATLAB里通过dwtmode设置扩展模式常见的有zpd零填充、sym对称扩展、ppd周期延拓。默认模式在某些信号上可能让重构信号首尾出现明显的波动也就是“飞边”。处理长信号时一个实用的习惯是把首尾各延拓几十到几百个点等处理完再裁剪掉延拓部分。这样做能显著减小端点误差。如果信号本身就比较平稳用dwtmode(sym)就足够了如果信号是周期性采集的比如旋转机械的转速信号ppd周期延拓会更贴合实际。5.2 阈值过猛或过轻怎么快速调参刚开始做降噪最容易出现两个极端阈值太大信号被抹成一条平滑曲线细节全没了阈值太小降噪等于没做噪声纹丝不动。我现在的做法是先用sqtwolog跑一遍看重构信号是否平滑如果细节丢太多就换成rigrsure或minimaxi如果噪声还挺明显就把阈值适当调大或者把软阈值换成“软阈值加残差回填”的方式也就是先软阈值处理再把被压掉的均值差补回去避免信号幅值整体变小。只要你理解了阈值公式里的sigma和n手动微调就有方向不用靠瞎猜。5.3 分解层数、点数和小波基的匹配问题信号长度直接限制分解层数。比如2000个点的信号做5层分解每个系数块只有64个点左右勉强够估计噪声如果信号只有300个点硬要分解到5层最小的子带只剩几个系数阈值估计基本失效。我的经验是信号长度除以2^level后每个子带的系数点数不要少于50个最好在100个以上。这个经验没有硬性公式支撑但能帮你避开绝大多数“越分解越差”的陷阱。小波基的长度也要跟层数匹配长基函数在深层分解时计算量更大边界影响范围也更宽处理短信号时尤其明显。5.4 常见报错速查表报错场景可能原因解决办法分解时报“信号长度不足”分解层数太深降低层数或先对信号做延拓使用wpthcoef时索引出错传入的是非叶节点编号先用leaves(wpt)拿合法叶节点重构后长度比原信号短边界模式影响尾部数据用wprcoef(wpt, 0)重构不要手动拼接降噪后信号幅值变小软阈值收缩幅度过大改硬阈值或对系数做增益补偿小波包树plot显示空白树对象变量被覆盖检查是否在循环里重新赋值了wpt另外有一个细节有些人在循环里对多个节点做阈值处理时总是忘记把wpthcoef的返回值重新赋给wpt导致处理结果没有累积生效。习惯写法是wpt wpthcoef(wpt, k, s, thr)别把返回值丢了。5.5 对长信号和非平稳信号的处理建议如果信号非常长比如采集了几分钟甚至几小时的振动数据不建议一口气做全序列小波包处理。一是计算量大二是非平稳信号在全序列上的统计特征不稳定用一个全局阈值容易顾此失彼。更稳妥的做法是分段处理每段1024或2048个点段与段之间保留一定重叠处理完再重叠相加。这样既有局部适应性又不会在段边界留下明显断点。我接过一个现场的轴承监测任务信号连续采了40多分钟直接用全局阈值降噪结果前20分钟效果不错后面机器负荷变了噪声底也跟着变了阈值就完全失效。后来改成2秒一段的分段降噪每一段单独估计噪声水平定阈值整车效果立刻稳定下来。这是工程里非常实用的经验比调参还重要。最后再分享一个心得小波包降噪和压缩这件事真正考验人的不是函数调用而是参数与场景的匹配。我拿到一段新信号不会着急跑算法而是先做频谱和时频分析看看噪声是白噪声还是窄带干扰有效信号主要能量落在哪个频带然后才决定小波基、层数、阈值类型。这套思路比任何默认参数都管用能省下你后面大量反复调试的时间。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询