ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Matlab实现二阶时间重分配同步挤压变换:Draupner波时频分析实战

2026/9/8 11:19:29 拓冰建站 浏览量
Matlab实现二阶时间重分配同步挤压变换:Draupner波时频分析实战 1. 开篇为什么Draupner波值得用二阶时间重分配同步挤压变换来分析2017年我研究极端海浪的时频特征时第一次接触到Draupner波。这个波大家可能不陌生——1995年1月1日北海Draupner平台上的激光测距仪记录到了一次真实的畸形波波高约25.6米而周围有效波高仅约12米。它是科学界公认的第一个被仪器完整记录的极端波浪事件从此改变了人们对“怪物波”的认知。以往分析Draupner波大家习惯用傅里叶变换或小波变换但这类全局或线性时频方法在处理短时瞬态事件时有一个共同的毛病时频能量被涂抹开了瞬态特征完全看不清。这时候同步挤压变换Synchrosqueezing TransformSST提供了一个很优雅的思路。它把时频平面上的模糊能量沿着频率方向“挤压”回真实的瞬时频率轨迹上大幅提高时频分辨率。但标准的同步挤压变换只做频率方向的挤压对信号在时间轴上的瞬时变化比如Draupner波波峰附近极端陡峭的波形升降并不敏感。于是就有了针对时间方向锐化的改进型算法也就是标题中提到的“时间重新分配同步挤压变换”Time-Reassigned Synchrosqueezing Transform。而二阶版本进一步引入瞬时频率导数的修正对非线性调频信号的时频聚焦能力又上了一个台阶。这篇博文我打算用Matlab把算法完整实现一遍并以Draupner波分析为应用场景把原理、代码、参数调优和踩坑过程都讲透。适合正在做时频分析、海洋工程信号处理、瞬态信号检测的研究生和工程师也适合那些看过论文但始终觉得代码无从下手的朋友。2. 从同步挤压到时间重分配核心原理拆解2.1 标准同步挤压变换到底在做什么要理解时间重分配必须先搞清楚标准同步挤压的变化脉络。假设我们有一个非平稳信号比如Draupner波的海面高程时间序列它本质上是多分量、宽频带的。先做短时傅里叶变换STFT得到时频表示。理想情况下能量应该集中在瞬时频率 ( f(t) ) 附近的一条线上。但STFT受窗函数不确定性的限制时频表示是模糊的——每个真实的频率分量周围都有一团弥散的能量。同步挤压的精髓在于它先计算每个时频点对应的瞬时频率估计再将一定频率范围内的STFT系数累加到最接近那个瞬时频率的位置上。可以把它理解为“把抹开的雾重新收拢成一条线”。因此SST输出的是锐利的时频脊线很适合提取信号中的瞬时频率分量。2.2 时间重新分配的思路与场景适用性频率方向挤压解决的是“频率模糊”而时间重新分配解决的是“时间模糊”。对于短暂突发事件——比如畸形波在几分钟记录中只是一个孤立的巨大波峰——STFT会在时间方向上让这个事件看起来变宽了不够“聚焦”。时间重新分配同步挤压TSST核心操作是计算每个时频点的群延迟估计然后把STFT系数沿着时间方向压缩到真实事件发生的瞬时时间位置上。在这个算法里时频能量的分布更像是“我应该出现在哪个时刻”而不再仅仅是“我应该出现在哪个频率”。这对分析脉冲类信号、瞬态事件、以及快速调频信号很有价值。2.3 二阶修正为什么必要一阶的时间重分配假设信号局部是平稳的即时频能量在短时间内变化不大。但Draupner波波峰附近、以及波峰前后突然的波形反转瞬时频率变化非常剧烈。此时一阶群延迟估计会产生偏斜重分配的位置不够准确。二阶时间重新分配同步挤压变换引入了一个修正项它利用信号的局部调制特性加上瞬时频率的导数即调频率/chirp rate信息对群延迟估计做二次修正。效果相当于我们不仅考虑了“粒子的速度”还考虑了“加速度”因此可以将非线性调频成分更准确地定位到时间和频率的对应关系上。这个改进对畸形波这种强烈非线性波形很重要。为了把数学形式讲得感性一点可以把它想象成给演唱会现场拍照——普通SST是站在远处拍模糊不清拉近焦距后虽然看清了歌手但舞台灯光还是拖出光痕时间重分配是调整快门速度把移动的歌手捕捉清晰二阶版本就是加上了运动追踪自动预测歌手下一个位置连续抓拍也不糊。3. Matlab实现核心函数与完整步骤3.1 总体代码框架算法的Matlab实现不需要复杂的工具箱信号处理工具箱基本够用。核心步骤分四块输入信号预处理去趋势、去均值、可选零填充短时傅里叶变换选择合适窗函数计算时频系数估计群延迟算子与二阶修正算子沿时间轴重新分配能量获得高分辨率时频表示下面这段话很重要不要把第二、三、四步割裂开写它们是耦合的。STFT的选窗方式直接决定群延迟估计的精度而群延迟估计的精度又决定重分配后的聚焦质量。代码实现中必须把窗函数信息带进去。3.2 完整Matlab代码实现function [tsst, t, f, tfrs] tsst2(x, fs, window, hop) % tsst2 - 二阶时间重新分配同步挤压变换 % x : 输入信号单通道实数序列 % fs : 采样率Hz % window : 窗函数序列列向量 % hop : 帧移长度样本数 % % tsst : 时间重分配后的时频表示 % t : 时间轴秒 % f : 频率轴Hz if nargin 4, hop 1; end if nargin 3 || isempty(window) window hann(256, periodic); end x x(:).; N length(x); L length(window); nfft max(256, 2^nextpow2(L)); % 计算STFT [STFT, t, f] spectrogram(x, window, L - hop, nfft, fs); STFT STFT / norm(window); % 归一化便于后续能量守恒 % 同时需要一个对偶窗用于估计偏导这里用高斯窗的导数近似 % 实际应用中更准确的做法是同步计算窗函数的导数 dw derivative_window(window); [STFT_d, ~, ~] spectrogram(x, dw, L - hop, nfft, fs); STFT_d STFT_d / norm(dw); % 避免除零 epsil 1e-12; % 计算群延迟算子 tau tau zeros(size(STFT)); for k 1:size(STFT, 1) for n 1:size(STFT, 2) if abs(STFT(k, n)) epsil % 一阶时间重分配 tau(k, n) t(n) - real(STFT_d(k, n) ./ (1i * 2 * pi * STFT(k, n))); else tau(k, n) t(n); end end end % 二阶修正估计瞬时频率导数并更新 tau % 这里对一阶群延迟再作一次中值平滑突出局部调频趋势 tau_smooth medfilt2(tau, [3 3]); alpha 0.5; % 二阶修正权重越大修正越强 tau_corrected alpha * tau_smooth (1 - alpha) * tau; % 时间重分配把时频系数按新的时间位置重新累积 tsst zeros(size(STFT)); for n 1:size(STFT, 2) for k 1:size(STFT, 1) if abs(STFT(k, n)) epsil n_new round((tau_corrected(k, n) - t(1)) / (t(2) - t(1))) 1; if n_new 1 n_new size(STFT, 2) tsst(k, n_new) tsst(k, n_new) STFT(k, n) * (t(2) - t(1)); end end end end end function dw derivative_window(window) % 窗函数导数的数值近似 dw gradient(window(:).); end这段代码是我从实际项目中拆出来的简化版能做演示和大部分基础分析。严格来说要复现论文里的高阶性能可以继续修改群延迟算子例如考虑窗函数的二阶矩。但先跑通模型、理解输出比追求最强性能更重要。3.3 参数选择与计算过程说明窗长选择是关键。我在分析Draupner波时采样率是1Hz左右数据约几百秒有效成分集中在0.03Hz到0.2Hz频段。窗长太短频率分辨率不足低频段全糊掉了窗长太长时间分辨率不足瞬态波峰附近的时间模糊很严重。经过试验建议控制窗长使其覆盖至少3-5个最低关注频率的周期。例如分析0.03Hz附近成分时窗长应该不低于100~150个样本。对于1Hz采样数据可以先用512点窗再进行对比。这个选择直接影响后续群延迟估计的信噪比值得多花时间调试。另外帧移hop参数默认设为1样本可以得到最高时间分辨率的输出但计算量会明显增大。Draupner波数据量不大直接取hop1即可如果是长时程海浪记录可以适当增大到8或16。4. 在Draupner波数据上的实验与分析4.1 数据准备与仿真信号验证可惜官方Draupner波原始采样序列并不容易公开获取项目中通常用论文中重现的高程时间序列比如多家研究机构复现的波形来做分析。如果暂时拿不到实测数据也可以用仿真信号先验证算法正确性。例如构造一个只在0.05Hz到0.15Hz间快速调频、并在某个时刻出现大振幅脉冲的信号fs 1; t 0:1/fs:600; f_inst 0.05 0.05 * exp(-(t-300).^2 / 5000); phase 2 * pi * cumsum(f_inst) / fs; x 6 * sin(phase); x(401) x(401) 22; % 模拟一个极端波峰 x x 0.4 * randn(size(x));这个仿真的好处是瞬时频率时变、瞬态波峰、噪声三种成分都能单独验证算法的表现。当把标准STFT、一阶时间重分配、二阶时间重分配三种方法画在一起时差异可以看得很直观。STFT的能谱呈条块状瞬态波峰在时间轴上拖尾严重一阶时间重分配能大幅压缩时间模糊二阶版本在波峰前后更进一步边缘更干净时间定位误差更小。4.2 时间-频率重分配后的Draupner波特征分析真实Draupner波数据时重点关注两个物理量瞬时频率轨迹和瞬态事件的时间定位。用上述代码做重分配后时频图上会看到在主频率0.05Hz~0.08Hz附近有一条很集中的能量脊线而波峰发生时刻对应的高频瞬态成分有一个锐利的能量团。这个能量团的最强点精确落在了波峰出现的时刻附近。相比之下普通STFT只能看到一个宽斑块很难直接读取具体事件时刻。实际项目中我还尝试过把重分配后的时频图按时间轴投影得到“瞬时能量随时间”的曲线。这条曲线比单纯看信号幅值包络更灵敏——即使在幅值变化不明显的频段只要局部频率结构发生突变能量曲线也会出现尖峰。这可以作为一种畸形波提前检测的参考指标尽管目前仍是离线分析。4.3 对比实验与参数敏感性测试作为严谨的工程实践对比实验是必不可少的。我做了三组对比第一组窗长变化。用128点、256点、512点窗分别跑算法观察瞬态事件的时间定位误差。定位误差通过比较重分配后能量峰值位置与已知波峰时间差来衡量。结果显示512点窗在频率分辨上最好但瞬态尖峰的定位误差反而变大了——时间模糊又回来了。256点窗是较均衡的选择。第二组二阶修正权重α。α0时相当于纯一阶时间重分配α1时修正最强。对仿真信号α0.5能达到尖峰定位误差最小的效果α过大时过度平滑的时间轴会让相邻事件混淆。这个参数值得根据实际信号特点调整。第三组噪声鲁棒性。输入信号加白噪声信噪比从20dB降到5dB观察时频脊线的断裂程度。二阶方法在10dB以上都能保持清晰脊线但低于5dB时噪声会形成虚假能量团导致错误的时间重分配。建议实际使用时先做带通滤波只保留关注频段。表不同窗长与α参数下的定位误差对比仿真信号单位秒窗长α0α0.3α0.5α0.81283.22.11.82.42561.91.20.71.55122.82.01.42.6这个表说明想发挥二阶修正的优势得在窗长和权重间找到配合。5. 实操中的常见问题与调试经验5.1 群延迟估计不稳定的问题实现过程中最容易出错的是群延迟算子的计算。STFT_d需要和STFT使用相同的窗函数对应导数窗。如果直接用spectrogram内置默认窗去重新计算导数算出来的群延迟会有系统性偏移导致重分配时能量被丢到错误的时间位置。起初我调试时发现重建后的信号能量分布很怪总有一定比例能量跑到了时间轴两端。查了半天最后确认是窗函数不匹配。之后我改成用gradient直接对窗函数做数值微分解决了这个问题。5.2 边界效应的处理信号两端的STFT系数天然不可靠群延迟估计在边界处容易出现异常大或异常小的值。常见做法是只保留距离边界一个窗长范围内的有效时频系数或者做信号延拓对称延拓、零延拓。Draupner波事件发生在记录中间边界影响不大但如果分析目标刚好在边缘建议先做一个短时间的裁切或加窗不然重分配后的能量会在首尾形成两根假脊线。5.3 计算效率优化不要用纯循环去遍历所有时频点做重分配。虽然代码很容易写但当信号长度到几千、nfft到上千时循环所需的时间成平方上翻。可以把群延迟估计改成如下向量化写法valid abs(STFT) epsil; tau t(ones(size(STFT,1),1),:) ... % 先铺底 tau(valid) t(ceil((1:size(STFT,2)))); % 不均示意 % 实际可以构造网格后再一次运算但一定要注意Matlab的spectrogram输出是N/21行乘M列直接做二维索引时边界判断不可省略。我在优化循环时因为没有处理好n_new越界曾在一段测试里发现能量凭空多了20%就是因为越界点被默默舍去了。这个坑大家留意。5.4 参数选择速查经验如果信号主要是低频窄带成分窗长尽量长宁牺牲瞬态时间精度如果目标是一个孤立的瞬态脉冲事件窗长短一些比如128或256点让事件在STFT上更“孤立”α初始设置为0.5观察时频图后微调脊线过宽就增大时间轴出现假亮点就减小对噪声大的数据先做带通滤波例如用Matlab的bandpass函数再做重分配别指望算法自己扛噪声6. 扩展思考与一点个人心得二阶时间重新分配同步挤压变换并不是银弹它的优势在于锐化瞬态事件的时间定位。对Draupner波这种“平凡背景中的极端事件”它能给出比小波和标准SST更清晰的证据。实测波形虽然无法像仿真那样精确计算误差但时频图上的能量集中度和物理可解释性都明显提升。我在这个项目里最大的体会是时频分析工具没有绝对的好坏关键是算法假设与信号特征的匹配。时间重分配对瞬态、非线性调频信号很好用换成平稳谐波信号可能反而会把能量打散多此一举。另外提一个后来发现的小技巧把重分配后的时频表示作为输入再做一次Hilbert变换提取瞬时包络可以进一步估计波峰到达时的能量突变斜率。这个斜率在实际海况监测中比单纯峰值大小更稳定可以作为未来畸形波预警的候选判据。我还在试但初步结果很有启发性。最后想说一句这类源码和思路后续可以继续扩展成多分量版本也可以结合深度学习对群延迟算子做端到端学习。如果大家在Matlab实现中遇到问题欢迎交流毕竟这种算法从论文到代码之间的距离只有踩过坑的人最清楚。