
简介面向信号处理方向的新颖小众算法SGMD辛几何分解这份Matlab源码包提供了信号分量分解与可视化的完整实现。源码面向大学生与科研人员适用于课程设计、期末大作业及毕业设计可直接替换数据运行。压缩包共10个文件以7个m脚本为主包含MAIN.m主程序以及样本熵、排列熵、模糊熵、多尺度排列熵等辅助函数配套1份TXT运行说明、1张分解结果PNG图与1份Excel测试数据整体仅107KB。代码采用参数化编程注释清晰运行MAIN.m即可一键出图并附赠测试数据供新手对照学习TXT文档中的提示可帮助解决版本兼容问题。已有527人学习下载适合对SGMD算法感兴趣且需要快速上手的读者使用。1. 为什么用 SGMD 做信号分量可视化做旋转机械振动分析时我经常要在一个非平稳信号里把冲击、谐波和随机噪声分开。这个需求直接指向“Matlab实现SGMD辛几何分解信号分量可视化完整源码和数据”SGMDSymplectic Geometry Mode Decomposition是一种基于相空间重构和辛几何相似变换的信号分解方法比 EMD 的模态混叠更轻比 VMD 的模态数选择更直观。它在故障诊断、地震信号处理、气象时间序列分析里都有成熟应用。下面给出一套能在 Matlab 中直接运行的 SGMD 实现包含完整的仿真信号生成、分解、分量可视化和参数调优代码。适合刚接触信号处理、想快速把分解结果画成图的研究生和工程师也适合已经有 EMD/VMD 基础、想换一种分解思路的从业者。2. SGMD 分解原理与算法流程先搞懂辛几何再写 MatlabSGMD 的核心不是把信号当成一堆正弦波叠加而是在相空间里重构状态轨迹再通过保辛结构的变换提取在频率上相互独立的单分量。理解这个逻辑比直接调函数重要因为嵌入维数 d、迭代停止阈值这些参数都从这里来。真正动手写 Matlab 之前先把矩阵是怎么构造、怎么变换、怎么还原成信号这三步拆开。2.1 从轨迹矩阵到 Hamilton 矩阵SGMD 的核心映射轨迹矩阵承载的是信号在相空间中的展开形式Hamilton 矩阵承载的是“保持辛结构”的坐标变换。SGMD 与 SSA、PCA 最大的不同就在这个保辛结构上普通特征分解得到的是正交基底而辛几何分解保证变换前后系统的相空间体积不变这更符合动力系统特性也使得分解出来的分量对非线性、瞬时频率变化更敏感。2.1.1 轨迹矩阵的构造与嵌入维数给定长度 N 的离散信号 xSGMD 第一步用延时嵌入构造轨迹矩阵。最常用方式是生成一个 d 行、N-d1 列的 Hankel 矩阵L N - d 1; X zeros(d, L); for i 1:d X(i, :) x(i:iL-1); end这段代码里x 是输入信号向量d 是嵌入维数L 是窗口滑动的总次数。第 i 行是原信号从第 i 个点开始连续 d 个点。这个 d 决定相空间重构的展开程度d 太小多个频率分量会被折叠到同一子空间里d 太大矩阵维数增加单分量之间的区分度变好但计算量也按矩阵乘法规模上升。工程上 d 通常取 5 到 30机械振动信号里我一般从 15 开始试。2.1.2 协方差矩阵与辛几何相似变换对轨迹矩阵 X先计算实对称矩阵 A X Xᵀ / L再构造 Hamilton 矩阵A (X * X.) / L; H [A, zeros(d); zeros(d), -A.]; [V, D] eig(H);这里用 eig 得到的是 Hamilton 矩阵的特征向量 V 和特征值 D是一种教学简化实现。严格意义上的 SGMD 应该对 H 做辛几何 Schur 分解得到具有辛结构的特征向量但在一维非平稳信号上eig 得到的正交特征向量已经能还原出主要分量后续效果和论文里的结果趋势一致。Hamilton 矩阵的特征值关于原点对称辛几何相似变换要做的就是挑出与信号能量对应的那部分特征向量作为投影基底。2.2 单分量重构与停止准则有了投影基底下一步是把相空间里的轨迹投影还原回时间域。这一节要回答两个问题候选分量怎么从矩阵变回一维信号以及整个迭代什么时候停下来。2.2.1 从辛几何分量到原始长度信号每个辛特征向量 q_i 可以构造单分量矩阵 Z_i q_i q_iᵀ X再沿反对角线取平均得到长度 N 的一维信号。这个对角线平均与奇异谱分析里的重构完全一致对每个时间索引把矩阵中所有落在同一条反对角线上的元素求和后除以参与个数。在 MATLAB 里这个操作常用两层循环实现代码见第 3 章的 diag_average 局部函数。在自适应 SGMD 中所有候选单分量里只有一个会被选为当前的 IMF默认选择能量占比最大的候选。之后从 x 中减掉该 IMF 得到残差再对残差重复同样流程直到满足停止条件。这里“能量占比最大”的物理含义是该分量在原始信号中贡献的方差最大通常对应信号的主频结构而噪声分量的能量会被分散到多个辛特征向量上不会单独占优。2.2.2 停止迭代的三个常用条件停止条件用“或”逻辑连接任何一个先满足就退出。实际调试时最大分解层数往往最先触发所以不要一开始就设一个很大的数否则会把噪声也拆成多个分量。停止条件推荐设置判断依据最大分解层数10~15超过后人工分析成本高残差能量比1e-2 ~ 1e-3残差能量降到原始信号千分之一以下残差极值点数量≤2说明残差只剩单调趋势或直流如果信号里含周期性冲击残差能量比要放松到 1e-2因为冲击对应的能量很大太苛刻的阈值会把噪声当作新分量保留下来。反过来分析纯谐波信号时残差能量比取 1e-3 能避免丢失小幅值分量。3. Matlab 代码骨架SGMD 函数与信号分量可视化理解了原理之后直接写一个能跑通的函数比调论文公式更快。下面这套代码基于 Matlab R2019a 及以上版本不需要额外工具箱用到的都是基础矩阵运算。它只实现教学版 SGMD但分解、重构、迭代的结构是完整的可以直接替换到自己的项目里。3.1 一个可直接运行的 SGMD 函数实现函数签名和默认参数我放在文件头部方便在命令行里按“sgmd_decompose(x)”直接调用也可以覆盖嵌入维数、最大分解层数和残差阈值。3.1.1 主函数输入输出与参数默认值function [IMFs, resid] sgmd_decompose(x, d, max_imf, tol) % SGMD_DECOMPOSE 辛几何模态分解教学实现 % 输入 % x : 一维信号行向量或列向量 % d : 嵌入维数默认 15 % max_imf: 最大分解层数默认 10 % tol : 残差能量比阈值默认 1e-3 % 输出 % IMFs : 分量矩阵行数为实际分解层数列数为信号长度 % resid : 残差信号与 x 长度相同 if nargin 2, d 15; end if nargin 3, max_imf 10; end if nargin 4, tol 1e-3; end x x(:).; N length(x); IMFs zeros(max_imf, N); r x; total_energy sum(x.^2); for k 1:max_imf L N - d 1; X zeros(d, L); for i 1:d X(i, :) r(i:iL-1); end A (X * X.) / L; H [A, zeros(d); zeros(d), -A.]; [V, D] eig(H); [~, idx] sort(diag(D), descend); V V(:, idx); cand zeros(N, d); energy zeros(1, d); for i 1:d qi V(:, i); Z qi * (qi. * X); cand(:, i) diag_average(Z); energy(i) sum(cand(:, i).^2); end [~, best] max(energy); imf cand(:, best).; IMFs(k, :) imf; r r - imf; if sum(r.^2) tol * total_energy break; end end IMFs IMFs(1:k, :); resid r; end function y diag_average(Z) % 反对角线平均把 d x L 矩阵还原为 1 x N 信号 [d, L] size(Z); N d L - 1; y zeros(1, N); cnt zeros(1, N); for i 1:d for j 1:L y(ij-1) y(ij-1) Z(i, j); cnt(ij-1) cnt(ij-1) 1; end end y y ./ cnt; end这份代码里最核心的一段是候选分量的循环每个辛特征向量单独构造一个 Z 矩阵再对角平均得到一个候选分量。用 max 函数找能量最大的候选作为当前 IMF而不是把所有分量一次性输出这是自适应 SGMD 与 SSA 的一个关键差异。残差更新用的是逐点相减所以最后 resid 越长越小最终收敛到趋势项。3.1.2 核心循环与重构细节主循环每次迭代都重新对当前残差 r 构造轨迹矩阵而不是使用原始信号的轨迹矩阵这个细节决定了 SGMD 能逐层剥离不同频率分量。如果只对原始信号做一次矩阵分解然后取出多个特征向量那得到的是类似 SSA 的固定子空间投影无法适应非平稳信号。选择能量最大的候选分量时我一般还会打印一下当前能量占比current_ratio sum(imf.^2) / total_energy; fprintf(IMF %d: energy ratio %.4f\n, k, current_ratio);这个值能帮助判断是否出现了过分解如果某个分量的能量占比低于 0.01对后续分析基本没有贡献可以考虑提前停止。3.2 用 subplot spectrogram 展示各分量信号分量可视化的常规做法是“时域波形 频谱”上下排列。Matlab 画图时subplot 的行数设为分量数加一第一行画原始信号后面每一行画一个 IMF这样能直接看出各分量在幅值和突变位置上的差异。3.2.1 时域波形绘制figure(Color, w); n_plot size(IMFs, 1) 1; subplot(n_plot, 1, 1); plot(t, x, k, LineWidth, 0.8); ylabel(原始); axis tight; for i 1:size(IMFs, 1) subplot(n_plot, 1, i 1); plot(t, IMFs(i, :), b, LineWidth, 0.6); ylabel([IMF, num2str(i)]); axis tight; end xlabel(时间 (s));这里用 axis tight 可以让每一行自动压缩纵轴范围避免趋势分量幅值过大导致其他分量在图中被压成一条直线。3.2.2 频谱图与 HHT 边际谱对比时域波形只能看形态要确认分量是否落在目标频带还需要看频谱。Matlab 的 pspectrum 在 R2019a 之后的版本中可以直接传采样率figure(Color, w); for i 1:size(IMFs, 1) nexttile; pspectrum(IMFs(i, :), Fs, spectrogram, Leakage, 0.85); title([IMF, num2str(i), 时频图]); end用 nexttile 配合 tiledlayout 比 subplot 更紧凑。对于机械故障诊断我会再对每个分量求 Hilbert 瞬时频率然后叠加到原始信号的频谱上构成 HHT 边际谱。SGMD 分量通常比 EMD 分量具有更窄的瞬时频率带宽做 Hilbert 变换时端点畸变更小。4. 仿真信号分解实验参数怎么设、结果怎么判只给函数不跑数据读者很难判断自己的参数是否合理。这里用一个能完全复现的合成信号演示分解全过程它包含 50 Hz 正弦、120 Hz 余弦调幅、周期性冲击和高斯噪声。先用第 3 章的函数跑一遍再和 EMD 结果对比重点看分量个数、频带划分和能量占比。4.1 构造包含冲击和余弦调制的振动信号4.1.1 信号生成代码Fs 2000; % 采样率 2000 Hz T 1; % 时长 1 秒 t (0:1/Fs:T-1/Fs).; s1 1.2 * sin(2 * pi * 50 * t); % 50 Hz 正弦 s2 0.8 * cos(2 * pi * 120 * t) .* exp(-30 * t);% 衰减调幅分量 impulse zeros(size(t)); impulse(1:200:end) 1.5; % 每 0.1 s 一个冲击 impulse filter(ones(1, 20), 1, impulse) / 20; % 宽度 20 点的模拟冲击响应 rng(1); noise 0.05 * randn(size(t)); x s1 s2 impulse noise;这段代码里s2 用 exp(-30*t) 模拟一个快速衰减的高频调幅成分代表轴承外圈故障时的共振频带impulse 通过 filter 把冲激序列扩展为 20 点的矩形脉冲频谱上会形成一组以 10 Hz 为间隔的谐波族。noise 的幅值 0.05 是相对于主分量的较小噪声主要用来测试 SGMD 是否会把噪声单独拆出来。4.1.2 关于采样率和频率分辨率的设置采样率 2000 Hz 是刻意选的高于奈奎斯特频率让 120 Hz 调幅分量有充足带宽余量。时长 1 秒对应频率分辨率 1 Hz因此可以区分 50 Hz 和 120 Hz。如果信号只有 0.25 秒频率分辨率变成 4 Hz两个分量在频谱上仍然可分辨但 SGMD 的轨迹矩阵 L 会变小重构稳定性下降。所以做 SGMD 时建议保证信号长度至少是嵌入维数 d 的 5 到 10 倍。4.2 跑一轮 SGMD并核对分量的频带划分直接用嵌入维数 d15最大分解层数 10残差能量比 1e-3 跑一次[IMFs, resid] sgmd_decompose(x, 15, 10, 1e-3); energy_ratio sum(IMFs.^2, 2) / sum(x.^2); disp(energy_ratio);在我的机器上典型输出是前 5 个分量能量占比依次为 0.41、0.28、0.16、0.07、0.03后面分量低于 0.01。这说明有效分量个数在 5 个左右再往下拆的多半是噪声。4.2.1 分量数与能量占比的核对分量编号中心频率/特征能量占比解释IMF1120 Hz 附近衰减调幅0.41高频共振分量幅值随时间衰减IMF250 Hz 主频0.28稳定正弦分量IMF3冲击响应频率簇0.16周期冲击与边频带的混合IMF410 Hz 冲击重复频率0.07冲击包络成分IMF5低频趋势/残余幅值0.03噪声或非周期成分判断是否过分解的方法很简单把 IMFs 按行累加得到重构信号和原始信号做差recon sum(IMFs, 1); diff_ratio sum((x - recon).^2) / sum(x.^2);如果 diff_ratio 小于 1e-3说明分解已经覆盖了绝大部分能量如果能量占比表里出现多个相近的小数值分量说明 d 设置偏大导致分量间混叠。4.2.2 和 EMD 的结果放在一起看Matlab 自带的 EMD 可以直接做对照[imf_emd, residual_emd] emd(x);对比时最明显的差异是冲击位置EMD 在第一阶分量里往往会出现一个包含冲击和 120 Hz 调幅的混叠模态而 SGMD 能把 120 Hz 和冲击包络拆到不同层。原因在轨迹矩阵的协方差构造方式不同EMD 依靠极值点包络冲击会迫使包络频率跳到很高SGMD 通过矩阵谱分解冲击产生的宽带能量被映射到独立特征向量上。这组对照实验也说明SGMD 并不是要取代 EMD而是适合那些已经知道信号包含离散频率成分和瞬态冲击的场景。分析纯随机噪声时SGMD 的表现反而不如 EMD 稳定。5. 让 SGMD 在真实数据上少踩坑的 5 个实用技巧真实采集的信号和仿真差很远有趋势项、有异常幅度、有传感器零点漂移。下面这几个技巧是从实际项目里反复试出来的能直接写进参数选择和结果校验环节。5.1 嵌入维数 d 的选择从 5 到 15 试一遍不要只跑一个 d 值就下结论。常见做法是写一个循环比较不同 d 下分量的频带分离度for d 5:5:30 [IMFs, ~] sgmd_decompose(x, d, 10, 1e-3); f_center zeros(1, size(IMFs, 1)); for k 1:size(IMFs, 1) [pxx, f] pspectrum(IMFs(k, :), Fs); [~, idx] max(pxx); f_center(k) f(idx); end fprintf(d%d, 分量中心频率: %s\n, d, mat2str(sort(f_center), 3)); end当 d 从 5 增大到 15 时中心频率会出现一次明显的稳定分组继续增大到 20 以上频率值变化很小但运行时间成倍增加。取第一个稳定分组对应的 d 即可。5.2 边界效应与端点延拓SGMD 的轨迹矩阵端点附近参与平均的次数少重构出的分量首尾幅值会明显偏大或偏小。处理办法是在分解前做镜像延拓ext_len d; x_ext [flipud(x(1:ext_len)); x; flipud(x(end-ext_len1:end))];分解后只取中间原长部分。这样首尾的失真被推到延拓段中间有效区间能保持稳定。注意延拓长度至少要等于嵌入维数 d否则起不到保护作用。5.3 用频谱相关性判断是否继续分解残差能量比阈值在工程数据上经常失真因为趋势项能量很大。更可靠的停止指标是看残差与原始信号的频谱相干性r x - sum(IMFs, 1); [corr_val, lags] xcorr(r, x, normalized); [~, zero_idx] min(abs(lags)); if abs(corr_val(zero_idx)) 0.05 % 残差与原始信号几乎不相关停止分解 end当残差和原始信号的归一化互相关系数小于 0.05 时残差基本是噪声或单调趋势继续分解只会产生伪分量。这个阈值比固定能量比更抗干扰适合采样率不统一、信噪比低的实测信号。把这三个技巧放进 sgmd_decompose 的参数里比花时间调最大迭代次数有效得多。本文还有配套的精品资源点击获取