news 2026/10/28 7:25:52

局部特征尺度分解LCD:MATLAB实现与轴承故障特征提取

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
局部特征尺度分解LCD:MATLAB实现与轴承故障特征提取

简介:这份资源面向信号处理方向的学生、科研人员与工程技术人员,聚焦局部特征尺度分解(LCD)这一非平稳、非线性信号分析方法。资源以MATLAB为实现环境,演示如何通过三次样条插值获得光滑的内禀尺度分量,帮助读者理解尺度空间构建、局部特征检测与分量提取的完整思路,适用于异常检测、模式识别、信号恢复等场景。压缩包共6个文件,以5个m脚本为主要内容,另含1个系统隐藏文件,整体约6KB,体积轻量便于快速查阅与二次开发。目前已有382人学习下载,说明其在同类方法中具备一定参考价值。读者可借助脚本理解LCD从信号预处理、尺度生成到分量提取的实现脉络,并在此基础上调整参数、适配不同信号类型,为后续算法优化与工程落地提供可复用的代码基础。

1. 局部特征尺度分解到底在拆什么:从一段轴承振动信号说起

手里有一段轴承外圈故障的振动信号,采样率 12.8 kHz,长度 8192 点。你把它画出来,看到的是密密麻麻的振荡,故障冲击被淹没在背景噪声和转频调制里。想做包络谱,得先把高频载波和低频趋势分开;想算峭度指标,又得把不同时间尺度的成分剥离开。这时候经验模态分解(EMD)是很多人的第一反应,但一上手就翻车:模态混叠、端点飞掉、筛分次数全靠拍脑袋。局部特征尺度分解(Local Characteristic-scale Decomposition,LCD)就是在这个位置上出现的——它同样把复杂信号拆成若干个内禀尺度分量(Intrinsic Scale Component,ISC),但换了一套更“讲道理”的极值点定义和插值方式,用三次样条插值去构造光滑的基线,从而拿到物理意义更干净的分量。

这篇笔记面向的是已经会用 MATLAB 做信号处理、但被 EMD 的模态混叠和端点效应折磨过的工程师。我会把 LCD 的核心机制、MATLAB 落地代码、参数怎么调、坑在哪,按能直接复现的粒度讲清楚。你不需要先读完一堆论文,跟着代码跑一遍,再回头看原理,反而更快。

2. LCD 的基线构造逻辑:为什么是三次样条插值

2.1 从极值点到内禀尺度分量:LCD 和 EMD 的分岔口

EMD 的做法是找全部极大值和极小值,分别做上、下包络,取均值当基线,反复筛分直到满足 IMF 条件。问题在于,包络均值本身可能引入新的极值,筛分次数一多,分量就被“筛糊”了。LCD 换了个思路:它不追求上下包络,而是直接在相邻极值点之间定义一段“基线”,让信号减去这条基线后剩下的部分成为 ISC。

具体来说,LCD 先找出信号的所有极值点(极大和极小统一处理),然后在每两个相邻极值点之间构造一条基线。这条基线要满足一个条件:在极值点处,基线值等于该极值点与相邻两个极值点连线在对应位置的某种插值。早期实现用的是线性插值,基线是折线,不够光滑,分解出来的 ISC 会有毛刺。后来普遍改用三次样条插值,因为三次样条在节点处一阶、二阶导数连续,能给出光滑的基线,ISC 的波形更干净,后续做包络谱时虚假峰明显减少。

这里的关键参数是极值点的判定方式。LCD 对极值点的定义比 EMD 宽松:它允许在极值点之间插入“伪极值点”,条件是相邻极值点的间隔超过某个阈值。这个阈值通常取信号长度的某个比例,或者用极值点间隔的中位数来定。阈值太大会漏掉细节,太小会引入噪声极值。我一般先用默认的间隔中位数,跑一遍看 ISC 数量,再微调。

2.2 三次样条插值在 LCD 里的具体角色

三次样条插值在 LCD 里承担的是“基线生成器”的角色。给定一组极值点 $(t_i, x_i)$,以及每个极值点对应的基线约束值 $b_i$,三次样条会构造一条分段三次多项式 $B(t)$,满足 $B(t_i)=b_i$,且在内部节点处 $B'(t)$ 和 $B''(t)$ 连续。LCD 的基线约束 $b_i$ 通常取相邻极值点连线的中点值,或者用极值点幅值的加权平均。这样构造出来的基线,既不会像线性插值那样产生尖角,也不会像高阶多项式那样在端点附近剧烈振荡。

在 MATLAB 里,spline函数就是干这个的。但要注意,spline默认使用 not-a-knot 端点条件,对于信号端点附近的基线,这个条件可能让基线外推得比较离谱。LCD 的端点效应很大一部分就来自这里。常见做法是:在信号两端各延拓若干个极值点,延拓方式可以用镜像对称或者极值点周期延拓,然后再做样条插值,最后把延拓部分截掉。延拓长度一般取 1 到 2 个极值点间隔。

下面这段代码展示了 LCD 单次筛分中,如何用三次样条插值构造基线并得到第一个 ISC 的雏形。代码里包含了极值点检测、基线约束计算和样条插值三个步骤。

function [isc, residual] = lcd_sift_once(x, t) % x: 输入信号列向量 % t: 时间轴列向量,与 x 等长 % isc: 本次筛分得到的内禀尺度分量雏形 % residual: 减去 isc 后的剩余部分 % 1. 检测极值点(极大和极小统一索引) dx = diff(x); ext_idx = find(dx(1:end-1) .* dx(2:end) < 0) + 1; % 极值点位置 % 补充端点附近的极值,避免端点无约束 if isempty(ext_idx) error('信号中没有检测到极值点,请检查信号是否过于平滑'); end % 2. 计算相邻极值点间隔,用于伪极值点判定 ext_t = t(ext_idx); ext_x = x(ext_idx); intervals = diff(ext_t); med_interval = median(intervals); % 3. 在间隔过大的地方插入伪极值点(线性插值) new_t = ext_t(1); new_x = ext_x(1); for k = 1:length(intervals) if intervals(k) > 1.5 * med_interval % 在中间插入一个伪极值点,幅值取两端平均 mid_t = (ext_t(k) + ext_t(k+1)) / 2; mid_x = (ext_x(k) + ext_x(k+1)) / 2; new_t = [new_t; mid_t; ext_t(k+1)]; new_x = [new_x; mid_x; ext_x(k+1)]; else new_t = [new_t; ext_t(k+1)]; new_x = [new_x; ext_x(k+1)]; end end % 4. 端点延拓:镜像对称延拓两个极值点间隔 left_ext = 2 * new_t(1) - new_t(3:-1:2); right_ext = 2 * new_t(end) - new_t(end-1:-1:end-2); ext_t_full = [left_ext; new_t; right_ext]; ext_x_full = [new_x(3:-1:2); new_x; new_x(end-1:-1:end-2)]; % 5. 计算基线约束值:相邻极值点连线的中点 b = zeros(size(ext_x_full)); for k = 2:length(ext_x_full)-1 b(k) = (ext_x_full(k-1) + ext_x_full(k+1)) / 2; end b(1) = ext_x_full(1); b(end) = ext_x_full(end); % 6. 三次样条插值构造基线 baseline_full = spline(ext_t_full, b, t); % 7. 减去基线,得到 ISC 雏形 isc = x - baseline_full; residual = baseline_full; end

这段代码的逻辑是:先找极值点,再根据间隔中位数插入伪极值点,然后做端点镜像延拓,接着用相邻极值点连线的中点作为基线约束值,最后用spline做三次样条插值得到基线。参数方面,1.5 * med_interval这个阈值控制伪极值点的插入密度,调大它会让 ISC 数量减少,调小则增加。端点延拓的长度我固定延拓两个极值点间隔,实际使用时可以根据信号长度调整,信号短就延拓一个,信号长就延拓三个。

注意:spline函数在极值点数量少于 4 个时会报错,所以代码里加了isempty检查。如果信号本身极值点很少,说明它可能已经是一个单调趋势,不需要继续分解。

2.3 筛分停止条件:ISC 判据怎么设才不玄学

EMD 的筛分停止条件通常是“连续两次筛分结果的标准差小于某个阈值”,这个阈值取 0.2 到 0.3 之间,但具体取多少很玄学。LCD 的 ISC 判据更直接:一个分量如果满足“极值点数量与过零点数量之差不超过 1”,并且“在整个数据段内,任意一点的局部极大值包络和局部极小值包络的均值接近零”,就认为它是一个 ISC。实际实现时,为了效率,通常只检查第一个条件,第二个条件用基线幅值的均方根来近似。

我一般用两个条件联合判断:一是极值点数和过零点数之差小于等于 1,二是本次筛分得到的isc的均方根与上一次筛分的均方根之比大于 0.95。第二个条件防止筛分次数过多把分量筛成常数。筛分次数上限设 10 次,超过就强制停止,避免死循环。

function [isc_list, res] = lcd_decompose(x, t, max_isc, sift_max) % x: 输入信号 % t: 时间轴 % max_isc: 最大 ISC 数量 % sift_max: 单次筛分最大迭代次数 isc_list = []; res = x; for i = 1:max_isc % 对当前剩余信号做筛分 h = res; for s = 1:sift_max [isc_tmp, ~] = lcd_sift_once(h, t); % 判据1:极值点与过零点数量差 dx = diff(isc_tmp); ext_num = sum(dx(1:end-1) .* dx(2:end) < 0); zero_num = sum(isc_tmp(1:end-1) .* isc_tmp(2:end) < 0); % 判据2:均方根变化 if s > 1 rms_ratio = rms(isc_tmp) / rms(prev_isc); else rms_ratio = 1; end if abs(ext_num - zero_num) <= 1 && rms_ratio > 0.95 break; end prev_isc = isc_tmp; h = isc_tmp; end isc_list = [isc_list, isc_tmp]; res = res - isc_tmp; % 剩余信号如果是单调趋势或幅值过小,停止分解 if sum(diff(res(1:end-1)) .* diff(res(2:end)) < 0) < 2 || rms(res) < 1e-6 break; end end end

这段代码把单次筛分和整体分解串起来。max_isc一般取 5 到 8,取决于信号复杂度。sift_max取 10 足够。判据里的0.95这个比例,如果信号噪声大,可以放宽到 0.9,让筛分早点停,避免把噪声当成 ISC 反复筛。

3. 在 MATLAB 里跑通 LCD:从单分量到多分量分解

3.1 构造一个可复现的测试信号

要验证 LCD 能不能用,先别拿真实轴承信号,那个太复杂,出了问题不知道是算法还是数据。我习惯先构造一个已知成分的合成信号:两个不同频率的调幅分量加一个趋势项。这样分解出来的 ISC 应该对应这两个调幅分量和趋势项,顺序和幅值都能对得上。

fs = 12800; % 采样率 T = 1; % 信号时长 t = (0:1/fs:T-1/fs)'; % 时间轴 % 分量1:200 Hz 载波,被 20 Hz 调制 x1 = (1 + 0.5*sin(2*pi*20*t)) .* sin(2*pi*200*t); % 分量2:500 Hz 载波,被 50 Hz 调制 x2 = (0.8 + 0.3*cos(2*pi*50*t)) .* sin(2*pi*500*t); % 趋势项:低频多项式 x3 = 0.5 * (t - 0.5).^2; % 合成信号 x = x1 + x2 + x3; % 加少量高斯噪声 rng(0); x = x + 0.05 * randn(size(t));

这个信号里,200 Hz 和 500 Hz 两个载波成分的极值点间隔分别对应不同的时间尺度,趋势项则是一个缓慢变化的基线。LCD 分解后,前两个 ISC 应该分别对应这两个调幅分量,第三个 ISC 或残余对应趋势项。如果分解出来的 ISC 顺序乱了,或者某个 ISC 里混了两个频率,说明参数需要调。

3.2 调用 LCD 分解并画出 ISC 时域波形

把第 2 章的lcd_decompose函数拿来用,设置max_isc = 4,sift_max = 10,然后画图。

max_isc = 4; sift_max = 10; [isc_list, res] = lcd_decompose(x, t, max_isc, sift_max); % 画图:原始信号 + 各 ISC + 残余 figure('Position', [100 100 800 600]); subplot(max_isc+2, 1, 1); plot(t, x); title('原始信号'); ylabel('幅值'); grid on; for i = 1:size(isc_list, 2) subplot(max_isc+2, 1, i+1); plot(t, isc_list(:, i)); title(['ISC ', num2str(i)]); ylabel('幅值'); grid on; end subplot(max_isc+2, 1, max_isc+2); plot(t, res); title('残余分量'); xlabel('时间 (s)'); ylabel('幅值'); grid on;

跑完这张图,你会看到 ISC1 主要是 500 Hz 分量,ISC2 是 200 Hz 分量,ISC3 是趋势项,残余接近零。如果 ISC1 和 ISC2 的顺序反了,或者某个 ISC 里同时出现 200 Hz 和 500 Hz,说明伪极值点插入阈值1.5 * med_interval需要调。调大阈值,ISC 数量减少,高频和低频容易混在一个 ISC 里;调小阈值,ISC 数量增加,可能把噪声也拆出来。

3.3 用包络谱验证分解效果

时域波形只能看个大概,真正要验证 LCD 有没有把故障特征分离出来,得做包络谱。对每个 ISC 做 Hilbert 变换取包络,再对包络做 FFT,看故障特征频率处有没有峰。

% 对每个 ISC 做包络谱 for i = 1:size(isc_list, 2) env = abs(hilbert(isc_list(:, i))); env = env - mean(env); % 去直流 L = length(env); Y = fft(env .* hann(L)); P2 = abs(Y / L); P1 = P2(1:L/2+1); P1(2:end-1) = 2 * P1(2:end-1); f = fs * (0:(L/2)) / L; figure; plot(f, P1); xlim([0 1000]); title(['ISC ', num2str(i), ' 包络谱']); xlabel('频率 (Hz)'); ylabel('幅值'); grid on; end

对于合成信号,ISC1 的包络谱应该在 50 Hz 处有峰(对应 500 Hz 载波的调制频率),ISC2 的包络谱应该在 20 Hz 处有峰。如果峰的位置不对,或者峰被淹没,说明该 ISC 里混入了其他分量,需要回到分解参数调整。真实轴承信号里,外圈故障特征频率(比如 BPFO)会在包络谱里出现,LCD 的作用就是让这个峰比直接对原始信号做包络谱更突出。

提示:包络谱的频率分辨率取决于信号长度,1 秒 12800 点,分辨率 1 Hz。如果故障特征频率间隔小于 1 Hz,需要加长信号或提高采样率。

4. LCD 落地时的避坑与排查:端点、模态混叠和参数选择

4.1 端点效应:为什么你的 ISC 两端总是翘起来

现象:分解出来的 ISC 在信号两端幅值异常增大,包络谱里出现低频虚假峰。原因:三次样条插值在端点附近没有足够的约束点,not-a-knot 条件会让基线外推,导致端点处的 ISC 被“拉”起来。解决:在分解前对信号做端点延拓,延拓方式用镜像对称或极值点周期延拓,延拓长度取 1 到 2 个极值点间隔。代码里已经在lcd_sift_once里做了镜像延拓,但延拓长度是固定的两个间隔。如果信号端点本身极值点很少,可以手动增加延拓长度,或者改用“极值点预测延拓”:用端点附近几个极值点的趋势外推一个极值点。

4.2 模态混叠:一个 ISC 里混了两个频率成分

现象:某个 ISC 的包络谱里同时出现两个不同频率的峰,或者时域波形里能看到明显的拍频。原因:伪极值点插入阈值太大,导致高频成分的极值点被忽略,低频成分的极值点被当成基线约束,两个分量被分到同一个 ISC 里。解决:把1.5 * med_interval里的系数从 1.5 降到 1.2 或 1.0,让更多伪极值点被插入,增加基线约束的密度。但系数太小会增加计算量,而且可能把噪声极值也插进来。我一般从 1.5 开始,如果发现混叠就降到 1.2,再不行就 1.0。另一个办法是先用带通滤波把信号分成几个频段,再对每个频段单独做 LCD,但这会引入滤波器相位问题,需要零相位滤波。

4.3 筛分次数过多:ISC 变成一条直线

现象:分解到后面几个 ISC 时,波形几乎是一条直线,幅值接近零,但程序还在继续筛分。原因:筛分停止条件里的均方根比例阈值0.95太宽松,或者极值点与过零点数量差判据在低幅值信号上失效。解决:在筛分循环里加一个幅值下限判断,如果当前isc_tmp的均方根小于原始信号均方根的 1e-4,直接跳出。另外,max_isc不要设太大,一般 5 到 8 足够,设 10 以上容易产生无意义的 ISC。

4.4 参数选择:极值点间隔中位数受噪声影响大

现象:同一个信号,加不同强度的噪声,分解出来的 ISC 数量不一样。原因:极值点间隔中位数对噪声敏感,噪声极值点会拉低中位数,导致伪极值点插入阈值变小,ISC 数量增加。解决:在检测极值点之前,先对信号做一次轻微的平滑滤波,比如 5 点滑动平均,或者用smoothdata函数。但平滑会削弱高频成分,所以平滑窗口不能太大,一般 3 到 5 点。另一个办法是用极值点间隔的 75% 分位数代替中位数,分位数对噪声更鲁棒。

4.5 计算速度:三次样条插值在大数据量下的开销

现象:信号长度 10 万点以上时,LCD 分解跑一次要几十秒。原因:每次筛分都要做一次三次样条插值,而spline函数的计算复杂度是 O(n),筛分次数乘以 ISC 数量,总开销很大。解决:把信号分段处理,每段 1 万点,段间重叠 10%,分解完再拼接。或者用interp1的'spline'方法替代spline函数,两者结果一致,但interp1在某些 MATLAB 版本里更快。另外,如果只是做包络谱,不需要完整分解,可以只分解前 3 个 ISC,后面的残余直接忽略。

5. 把 LCD 用出效果:从分解到故障特征提取的最后一公里

LCD 分解本身只是手段,最终要落到故障特征提取上。我一般不会把全部 ISC 都拿去做包络谱,而是先算每个 ISC 的峭度指标,挑峭度最大的那个 ISC 做包络谱。峭度对冲击成分敏感,故障冲击越明显,峭度越大。但峭度也会被噪声干扰,所以我会同时看 ISC 的均方根和峭度,选均方根不是最小、峭度最大的那个。

% 计算每个 ISC 的峭度和均方根 kurt_vals = zeros(1, size(isc_list, 2)); rms_vals = zeros(1, size(isc_list, 2)); for i = 1:size(isc_list, 2) kurt_vals(i) = kurtosis(isc_list(:, i)); rms_vals(i) = rms(isc_list(:, i)); end % 选峭度最大的 ISC [~, best_idx] = max(kurt_vals); fprintf('选中的 ISC 编号:%d,峭度:%.2f,均方根:%.4f\n', ... best_idx, kurt_vals(best_idx), rms_vals(best_idx));

选好 ISC 后,做包络谱,然后跟理论故障特征频率对比。如果理论频率处有峰,且峰高比相邻频段高 3 倍以上,就认为特征提取成功。如果峰不明显,可以尝试对选中的 ISC 做一次带通滤波,滤波频带根据 ISC 的主频来定,通常取 ISC 中心频率的 0.5 到 1.5 倍。

还有一个技巧:LCD 分解出来的 ISC 顺序是从高频到低频,但有时候趋势项会混在第一个 ISC 里。这时候可以先把原始信号减去一个低通滤波后的趋势项,再做 LCD。低通截止频率取信号主频的 0.1 倍,用零相位滤波filtfilt实现。

% 先去趋势,再做 LCD fc = 0.1 * 200; % 假设主频 200 Hz [b, a] = butter(4, fc/(fs/2), 'low'); trend = filtfilt(b, a, x); x_detrend = x - trend; % 对 x_detrend 做 LCD 分解 [isc_list2, res2] = lcd_decompose(x_detrend, t, 4, 10);

去趋势后,ISC 的数量通常会减少一个,而且前几个 ISC 的物理意义更清晰。这个步骤不是必须的,但如果你的信号里趋势项幅值很大,建议加上。

最后说一个我自己的习惯:每次用 LCD 处理新信号,先拿一段已知成分的合成信号跑一遍,确认分解逻辑和参数没问题,再上真实数据。真实数据出问题时,回头检查极值点检测和端点延拓,这两个地方最容易翻车。LCD 不是黑匣子,它的每一步都能在代码里找到对应,调参的时候心里有数,比盲目试要快得多。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 7:25:52

OpenAI Dots深度解析:AI Agent如何从“回答问题”走向“执行工作”

上周OpenAI发布Dots的时候&#xff0c;我正蹲在群里看开发者们争论它和Codex到底什么关系。有人说是套壳&#xff0c;有人说是ChatGPT的升级版&#xff0c;也有人一脸懵&#xff1a;OpenAI不好好做大模型&#xff0c;怎么开始折腾这种“派活”的东西了&#xff1f;我花了两天把…

作者头像 李华
网站建设 2026/10/28 7:24:33

现代前端技术演进与工程实践全解析

1. 前端技术全景概览&#xff1a;从基础到前沿作为一名从业八年的前端开发者&#xff0c;我见证了前端技术从jQuery时代到现代框架生态的完整演进。2023年的前端领域已形成清晰的层级结构&#xff1a;底层是HTML/CSS/JavaScript三大基石&#xff0c;中间层是React/Vue/Angular等…

作者头像 李华
网站建设 2026/10/28 7:24:21

AI投研工具的核心竞争力:不在模型数量,而在数据与框架

去年下半年我深度参与了一个AI投研工具从0到1的搭建过程&#xff0c;当时碰到的第一个高频问题就是&#xff1a;“你们接了多少个大模型&#xff1f;”——问的人里有产品经理、有投资人&#xff0c;甚至内部研发也有这种倾向。后来工具上线跑了三个月&#xff0c;真实用户反馈…

作者头像 李华
网站建设 2026/10/28 7:24:21

GeoXCP:可解释AI与空间不确定性的融合技术

1. GeoXCP&#xff1a;当可解释AI遇上空间不确定性在医疗影像分析领域&#xff0c;有个典型案例&#xff1a;某AI系统将肺部CT上的窗帘褶皱误判为肿瘤&#xff0c;当医生追问判断依据时&#xff0c;系统只能高亮显示"重要区域"。这种"黑箱解释"正是GeoXCP要…

作者头像 李华
网站建设 2026/10/28 7:23:51

云豹直播系统源码拆包:从搭建到直播带货全链路实战

简介&#xff1a;云豹直播系统源码是一套面向直播平台搭建者与二次开发者的完整解决方案&#xff0c;覆盖网页直播、手机直播APP、微信直播等多终端场景&#xff0c;可实现跨平台互通。源码内置礼物系统&#xff08;普通、豪华、热门、守护、幸运礼物&#xff09;、连麦送礼PK、…

作者头像 李华
网站建设 2026/10/28 7:23:26

安全壳不背算力锅:Muse调度与亲和性优化如何拉满CPU利用率

“拿 DSec 来套&#xff1f;”这句话是我在一场项目评审会上被问到最多的。起因是 Muse 接入一个客户现场时&#xff0c;对方负责人第一反应就是&#xff1a;“你们是不是也和 DSec 那套一样&#xff0c;靠安全壳把算力需求包装起来&#xff1f;”我愣了几秒才想明白&#xff0…

作者头像 李华