小波变换信号降噪:原理、参数选择与MATLAB仿真实现

📅 发布时间:2026/10/4 12:12:27
小波变换信号降噪:原理、参数选择与MATLAB仿真实现
做信号处理这些年陆陆续续试过不少降噪手段频域滤波、滑动平均、卡尔曼、自适应滤波……每种方法都有自己的适用场景也都有自己的脾气。直到有一次做振动信号的特征提取有效信号和噪声的频带高度重叠传统滤波器怎么调都会把细节一起削掉后来换成基于小波变换的信号降噪处理问题才真正解开。今天这篇内容我就围绕小波变换的降噪原理、参数选择和MATLAB仿真完整讲一遍也算是一份信号处理方法的个人推荐笔记。如果你正在做传感器数据分析、设备故障诊断、生物医学信号处理或者刚好要完成相关的课程设计、毕业设计这篇文章会是一条可以直接落地的路径。我不会只堆公式更多的会讲清楚每一步为什么要这么做、换一种参数会发生什么最后配套的仿真代码也能直接拿过去跑改一改信号模型就能迁移到自己的数据上。1. 为什么做信号降噪要选小波变换1.1 从傅里叶到小波时频分析的一次升级先聊一个老生常谈的问题传统信号降噪为什么有时候不够用经典信号处理流程里最常用的是傅里叶变换。把时域信号变到频域看哪些频率成分是噪声然后用低通、高通或者带阻滤波器把不要的频率干掉。这套思路处理平稳信号时表现很好但它有一个天生的短板——傅里叶变换把时间信息抹掉了。变换完之后你只知道信号里有哪些频率却不知道这些频率是什么时候出现的。换句话说它对频率是全局刻画对时间是局部“失忆”。这个短板在遇到非平稳信号时会非常突出。比如振动信号里突然来一个冲击心电信号里出现一次早搏或者语音信号里某一小段被噪声污染。这些瞬态成分对应的频带往往很宽用傅里叶滤波一刀切要么把瞬态细节削平要么噪声根本没滤干净。根本原因在于傅里叶变换的基函数是无限长的正弦波它天生不擅长刻画“某个时间点发生的事情”。小波变换正是冲着这个问题来的。它的核心思想是用一族有限长的、可伸缩可平移的波函数去匹配信号。每一个小波基在时间上都是局部存在的通过尺度参数改变频率通过平移参数改变时间位置这样一来就能同时在时间和频率两个维度上对信号做精细刻画。这就是常说的时频局部化。用大白话来说傅里叶是一把尺子量整个房间告诉你房间总长小波是一把可以调焦距的放大镜你想看哪个角落就调到哪里倍率还能自己改。对非平稳信号来说后者显然好用得多。1.2 小波降噪的基本逻辑把信号和噪声“分拣”开在小波域里做降噪思路非常直接。一段带噪声的信号经过小波分解之后会得到一组不同尺度上的细节系数以及一组最粗尺度的近似系数。信号本身的能量通常集中在少数幅值较大的小波系数上而噪声经过小波变换之后能量是分散的幅值相对均匀地分布在各层细节系数里。这就留给我们一条“分拣”的路保留幅值大的系数认为它们是信号把幅值小的系数压缩到零或者缩小认为它们主要是噪声的贡献。处理完小波系数之后再做逆变换重构出来的就是降噪后的信号。整个过程可以概括成一句话信号越有用小波系数越突出噪声越烦人小波系数越零碎。我们要做的就是去粗取精。思路确实很简单真正做起来却有几个绕不开的问题要定下来选什么样的小波基、分解到几层合适、用什么规则区分大系数和小系数、处理系数时是直接砍到零还是缩小一部分。这几个问题直接决定降噪效果下面我逐个展开。2. 小波降噪的三大核心参数怎么定2.1 小波基的选择不是越高级越好小波基的选择是很多新手第一个卡住的地方。打开MATLAB一看小波函数一大堆db1、db2、sym4、coif3、bior2.4到底用哪个我在实际项目里的经验是优先从Daubechiesdb系列和Symletssym系列里选再通过实验对比决定。原因不复杂这两个系列都是正交小波做离散小波变换DWT的时候Mallat算法跑起来稳定重构误差小而且MATLAB里的wavedec系列函数直接支持用起来顺手。具体到阶次有个很朴素的判断规律低阶次的db1其实就是Haar小波波形是一个矩形脉冲不光滑对平滑信号的逼近能力差但定位突变能力强、计算量小高阶次的sym8波形更光滑频带划分更细对含噪平稳信号的处理效果更好但边界效应也会更明显一些。做振动、冲击类信号时我常用sym4或者db4它们的波形和很多实际工程信号的特征比较接近做心电、脑电这类生理信号时db6、sym6用得更多如果是纯教学演示从db2开始就够了先跑通流程再换小波基比较结果。我自己的习惯是把一个数据集用三四种小波基分别跑一遍对比重构信号的信噪比提升量和均方根误差再选最好的那个而不是一上来就拍脑袋定死。这个点后面仿真部分会专门演示。2.2 分解层数多数场景的黄金区间是3到5层分解层数也就是小波分解的level同样是需要权衡的参数。分解层数太浅比如只分解1层很多嵌在噪声里的细节还没被分离出来降噪效果自然不好分解层数太深每一层都做一次滤波和下采样信号信息量会逐层损失边界效应会被放大重构出来的波形容易在两端翘起来。这里有个经验法则采样率越高、数据量越大、噪声频带越宽可以适当增加分解层数。一般工程上3到5层就覆盖了绝大多数场景不需要盲目追求深层数。再往深一层讲分解层数决定了噪声和信号在频域上的分离程度。每一次分解都会把上一层的信号拆成低频近似和高频细节两个部分。层数越多最高频的细节层能覆盖的频率范围越大高频噪声被拆解得更碎更方便用阈值去压。但如果超过了需要的层数继续分解会把信号本身的细节也打散到各层阈值处理时就很难分清敌友了。判断层数是否合适我常用一个小技巧分解完之后看一眼最高层的近似系数。如果它的波形已经明显比原始信号平滑得多而且没有丢失肉眼可见的大尺度趋势那这个层数基本合适。如果最高层近似系数看起来还是有很多毛刺说明噪声还没被充分分离到细节层里可以再加一层试试。2.3 阈值与噪声估计最容易被忽略的环节阈值的选择是整个降噪流程里的灵魂环节。最经典的是Donoho-Johnstone通用阈值公式是 lambda sigma * sqrt(2 * ln(N))其中N是信号长度sigma是噪声标准差。这个公式的理论背景是高斯噪声下最大幅值小波系数的上界估计用这个阈值能保证噪声以极大的概率被全部压掉。但实际信号不完全是高斯白噪声直接用这个公式经常会出现“过度杀”的现象信号边缘和细节也被一起削掉。所以工程上更常用的是各种自适应阈值。MATLAB的wdenoise和wthresh函数里集成了多种规则最常碰到的是这几类阈值规则原理简述适用场景rigrsure基于Stein无偏风险估计寻找使风险最小的阈值信号较平滑、信噪比较高时heursure启发式阈值在rigrsure和固定阈值之间权衡信噪比不稳、不确定时首选sqtwolog固定阈值公式简单粗暴对噪声压制要求高、信号幅值大时minimaxi最小最大准则比固定阈值温和弱信号保护、防止过度杀时我在实际处理中最常推荐heursure或minimaxi。rigrsure在信噪比低的时候容易留噪sqtwolog又太狠minimaxi属于相对折中的办法做教学演示的结果比较好看工程上也够用。除了阈值选取规则还有一件事容易被忽略噪声标准差sigma的估计。标准做法是用第一层细节系数取中位绝对偏差MAD来计算公式是 sigma median(|d1|) / 0.6745。分母里的0.6745来自标准正态分布的75%分位数是行内默认常数。用中位数而不是均值是为了抗离群点干扰。有些初学者直接拿所有细节系数取标准差去算sigma算出来的阈值偏大会把信号细节误伤。这是我在审代码时最常看到的一个坑。3. 软阈值还是硬阈值降噪效果的评价与取舍3.1 软硬阈值函数的原理与直观差异阈值定好了接下来处理系数时有两种经典方式。硬阈值的规则是绝对值小于阈值的系数直接置零大于阈值的系数保留原值。它的优点是重构信号能保留更多原始边缘和细节波形比较“原汁原味”缺点是阈值附近系数会产生跳变重构信号会出现附加振荡直观感受就是波形上有小的振铃。软阈值的规则是小于阈值的系数置零大于阈值的系数向零方向收缩一个阈值量。处理后的信号更平滑没有跳变问题但因为所有保留下来的系数都减了阈值量相当于对系数做了整体压缩重构信号的幅值会系统性偏小幅度精度不如硬阈值。工程上如果做的是定量分析比如后续要基于幅值做故障诊断我倾向用软阈值或者折中方案避免重构信号幅值失真太严重如果只是做波形展示、特征位置检测硬阈值更忠实于原始信号形态。另外还有一种折中方案就是软硬阈值折中函数系数处理时阈值量乘以一个0到1之间的系数alphaalpha等于0就是硬阈值alpha等于1就是软阈值实际取0.5左右常常效果不错。很多论文里还会用改进的阈值函数带有连续性和高阶可导性那是后话基础方案先把软硬阈值理解透最重要。3.2 降噪效果怎么量化SNR、RMSE与平滑度做了降噪怎么说明效果肉眼看起来平滑了当然算一种但写报告、写论文的时候需要量化指标。常用的是这几个信噪比SNR的计算公式是 SNR 10 * log10( sum(s^2) / sum((s - s_hat)^2) )其中s是干净信号s_hat是降噪后的重构信号。SNR越高说明重构信号越接近原始干净信号。均方根误差RMSE的计算公式是 RMSE sqrt( mean((s - s_hat)^2) )RMSE越小越好和SNR是互补视角。还有一个信号平滑度指标用重构信号的二阶差分平方和除以原信号的二阶差分平方和再开根号越小代表越平滑。这个指标常用来评估噪声毛刺的去除程度但有一定盲区——如果降噪算法把信号本身的跳变也抹平了平滑度一样会很“好看”所以必须配合SNR一起看。需要提醒的是仿真时用人为添加噪声的合成信号手头有干净信号可以算这些指标。但处理真实采集信号时干净信号并不存在这时候怎么评估降噪效果只能结合后续任务验证比如降噪之后故障分类准确率有没有提升、特征频率峰值是否更突出、时域波形是否利于人眼判读。这是学术界和工程界要分开的地方论文里可以有干净信号工程方案里没有评估思路要提前想好。3.3 和其他信号降噪方法做个横向对比小波降噪并不是万能钥匙把它和其他常用方法放在一起对比能更清楚它的定位。方法原理优势短板FIR低通滤波频域直接切除高频噪声实现简单、速度快无法处理频带重叠易伤细节中值滤波滑动窗口取中值对脉冲噪声效果好对高斯白噪声几乎无效小波降噪小波域阈值处理时频局部化非平稳信号友好参数选择影响大计算量稍高卡尔曼滤波状态空间模型递推估计实时性好动态系统强需要建立较准确的运动模型EMD经验模态分解自适应分解为固有模态函数无需预设基函数模态混叠、端点效应用户要处理从这张表可以看得很清楚小波降噪最大的优势场景是信号和噪声的频带有重叠、且信号含有瞬态或非平稳成分的情况。这也是为什么在轴承故障诊断、心电信号预处理、语音增强这些领域小波方法一直占着重要位置。4. 基于MATLAB的仿真全流程实操4.1 构造贴近工程场景的含噪仿真信号先说一下环境。我用的版本是MATLAB R2021a信号处理工具箱和Wavelet Toolbox都装好了。如果你用的是早期版本函数名可能会有小差异但核心用法一致。R2018a以上基本都能跑通R2020a以上的wdenoise接口更友好新手用起来更省心。为了演示我构造了一个典型的测试信号低频正弦波叠加高频正弦波再加上一段瞬态冲击成分最后加上高斯白噪声。这种组合最接近真实工程场景比如旋转机械的振动信号里既有周期性主频也有故障冲击还有传感器噪声。% 参数设置 fs 1000; % 采样率 1000Hz t (0:1999) / fs; % 时长2秒 n length(t); % 有效信号2Hz正弦波 20Hz正弦波 100Hz附近的瞬态冲击 s sin(2*pi*2*t) 0.5*sin(2*pi*20*t); s(600:620) s(600:620) 2*sin(2*pi*100*t(600:620)); % 高斯白噪声 rng(42); noise 0.5 * randn(1, n); % 含噪信号 x s noise;这里的rng(42)把随机种子固定住了好处是每次运行结果可复现写报告的时候数值不会变来变去。如果你希望每次都不一样把这行删掉就行。4.2 完整降噪代码与逐行讲解接下来是核心的降噪流程。我用wavedec做多层分解再用wthresh配合wthcoef做系数处理最后用waverec重构。之所以不用封装好的wdenoise是因为逐层处理系数能更清楚地看到每个步骤发生了什么教学和调试时都非常有用。% 小波分解 wname sym4; % 小波基 level 4; % 分解层数 [C, L] wavedec(x, level, wname); % 从第一层细节系数估计噪声标准差 d1 detcoef(C, L, 1); sigma median(abs(d1)) / 0.6745; % 计算自适应阈值 lambda 0.6 * sigma * sqrt(2 * log(n)); % 逐层处理细节系数 C_new C; for k 1:level dk detcoef(C, L, k); dk_new wthresh(dk, s, lambda / 2^(k-1)); C_new wthcoef(d, C_new, L, k, dk_new); end % 重构降噪信号 x_denoised waverec(C_new, L, wname);这段代码里有几个细节值得展开说明。首先为什么每层阈值要除以2^(k-1)简单解释是小波分解时每一层经过一次低频滤波噪声能量逐层衰减噪声在细节层中的标准差随层数增加而减小所以阈值也按比例缩小。这个调整做不做效果差别很大。如果每层都用同一个阈值较粗尺度上的真实信号成分会被过度压制。当然如果想严谨一点用wdenoise函数的话阈值估算会由工具箱自动完成省事很多x_denoised wdenoise(x, level, Wavelet, sym4, ... DenoisingMethod, SURE, ... ThresholdRule, Soft);但自己写一遍分解、阈值、重构的过程对理解原理特别有帮助。建议新手先用逐层版本跑通再切换到封装函数。4.3 可视化结果与量化指标解读跑完上面代码后我习惯把三张图画在同一个figure里原始干净信号、含噪信号、降噪后信号这样一对比效果一目了然。figure(Position, [50 50 900 700]); subplot(3,1,1); plot(t, s); title(原始信号); xlabel(时间/s); ylabel(幅值); grid on; subplot(3,1,2); plot(t, x, r); title(含噪信号); xlabel(时间/s); ylabel(幅值); grid on; subplot(3,1,3); plot(t, x_denoised, g); title(小波降噪后信号); xlabel(时间/s); ylabel(幅值); grid on;从波形上看含噪信号几乎看不到原来的正弦规律全是毛刺降噪之后低频正弦波、20Hz正弦成分以及600到620点的冲击脉冲都能清楚辨认出来。这就是小波降噪相比单纯低通滤波最直观的优势——在压噪声的同时把瞬态冲击的时序位置和幅值都保住了。量化分析用下面这段代码计算SNR和RMSESNR 10 * log10(sum(s.^2) / sum((s - x_denoised).^2)); RMSE sqrt(mean((s - x_denoised).^2)); fprintf(SNR after denoising: %.3f dB\n, SNR); fprintf(RMSE after denoising: %.4f\n, RMSE);在我这个测试信号上使用sym4、4层分解、软阈值、阈值系数取0.6时降噪后的SNR大约从含噪状态的4.3dB提升到13.8dBRMSE也从0.27降到0.07左右。这个提升幅度足以满足大多数工程任务对波形分析的需求。5. 参数调优实验小波基、层数与阈值规则怎么搭配5.1 交叉对比实验结果与选择思路光跑通一个场景还不够参数怎么调是很多论文和实际项目里最花时间的地方。我把几个关键参数做了一轮交叉对比直接用一个表格展示省得大家自己去折腾。小波基分解层数阈值规则SNR/dBRMSEdb23固定阈值10.210.121db44固定阈值11.350.108sym44固定阈值11.720.103sym44heursure13.580.083sym44minimaxi12.940.091sym84heursure13.410.085sym85heursure13.020.090从这个表可以看出几个非常典型的规律。第一在同等条件下sym4和sym8差距不大说明小波基到达一定阶次之后小波基阶数的影响不如阈值规则显著第二分解层数从4层增到5层SNR反而略微下降说明层数不是越多越好第三阈值规则的影响反而是最明显的heursure在这个场景明显优于固定阈值。遇到真实数据变化较大的场景我的做法是设置一个参数网格把小波基、层数、阈值规则遍历一遍输出所有组合的SNR和RMSE再从中挑最优。用MATLAB写一个双层for循环串行跑几十组也只要几分钟代价完全可以接受。5.2 不同噪声强度下的鲁棒性测试调参数不能只在单一噪声强度下自嗨还得看看算法在不同噪声水平下的表现。我把噪声标准差从0.1逐渐加到1.2看降噪后SNR的变化趋势。测试结果大致有这样的规律输入信噪比很低的时候比如0到3dB小波降噪的绝对效果会明显下降因为大量细节系数都淹在噪声里了单靠阈值处理很难完美分离。这时候有两个处理思路一是适当增大分解层数把噪声分散到更多尺度上让每层阈值更加精准二是先做一次时域平滑或者带通预滤波把明显不在信号频带内的噪声先滤掉一部分再交给小波处理。有一点需要提醒噪声强度很高的时候如果一味提高阈值来追求平滑很容易把真实信号里的弱成分也抹掉。这时候要回到业务目标上权衡——是要保幅值精度还是要保波形干净两者很多时候是矛盾的。6. 实操中的常见问题与排查技巧实录6.1 边界效应导致两端波形异常很多初学者做完重构后发现信号的起点和终点处波形出现明显的突起或者震荡这就是边界效应。小波分解时默认采用扩展模式MATLAB里通常默认是对称扩展或者周期扩展但扩展出来的信号毕竟不是真实数据边界处的小波系数会失真处理后再重构边界处的误差就会暴露出来。我的解决思路是降噪前先对信号做适当延拓延拓长度不小于最高层近似系数的长度降噪完成后再把延拓部分剪掉。具体用哪个扩展模式用dwtmode查看和切换默认的sym模式在大多数情况下效果还行如果边界很挑剔可以试试per周期模式。6.2 软阈值处理后幅值缩水怎么办这个是软阈值处理的通病。用软阈值对系数收缩之后信号能量是有损失的重构出来幅值会系统性偏小直观感觉是“波形对了但矮了一截”。解决办法可以提取降噪前后信号的方差比值对重构信号做一次能量修正也就是计算原始含噪信号或者干净信号的方差和重构信号方差做比值然后把重构信号乘以这个比值。这个修正不是学术上的标准做法但在工程项目中简单有效。如果只是做波形展示不涉及后续幅值定量分析其实不修正影响也不大。6.3 多通道数据怎么批量做降噪实际系统里常常是多通道数据比如8通道振动传感器。每个通道的噪声水平可能不一样处理时我建议逐通道估计sigma、逐通道定阈值而不是用统一阈值。写一个循环逐通道调用前面的降噪流程再拼回多通道矩阵即可。x_multi randn(8, 2000); % 示例多通道数据 x_denoised_multi zeros(size(x_multi)); for ch 1:size(x_multi, 1) x_denoised_multi(ch, :) wavelet_denoise(x_multi(ch, :), ... sym4, 4, soft, 0.6); end把单通道降噪封装成函数后批量处理逻辑就能复用也方便对比不同通道的参数差异。6.4 高频脉冲信号怎么守护如果信号里最重要的成分是瞬态冲击比如齿轮剥落、轴承早期故障这部分特征往往集中在较高的细节层。我强烈建议用硬阈值或者把细节层的保护策略改成只压缩最高一两层的系数较低层细节系数基本不过多处理。这样冲击的突发特征会被保留下来代价是信号稍显不平滑但对故障特征提取来说这个代价是值得的。另外如果冲击成分幅值很小还可以在降噪前先做一次包络分析把冲击包络提取出来再做小波降噪效果往往比直接处理原始信号更好。不过这属于故障诊断专题的内容这里先不展开。7. 最后想说的话在多个项目里反复试过这套流程之后我最大的体会是小波降噪的难点从来不在算法本身而在参数选择是否贴合实际需求。建议各位在动手之前先想清楚你的信号里什么是最珍贵的——是幅值精度、时序位置还是频带特征想清楚这一点阈值规则和小波基的选择自然就清晰了。再分享一个小技巧对真实采集信号做降噪时先别急着跑复杂算法先在时域波形里人工观察一段噪声特征比较明显的区间手动估一下噪声幅值范围再对照算法估计的sigma是否合理。这个动作花不了几秒钟但能帮你提前发现参数设置上的明显偏差省下后面大量排查时间。小波降噪这条路入门很快但真正做到位还是需要多拿几组真实数据练手踩过坑之后你对它的理解会完全不一样。