说明¶
PP — Peak Picking:在频谱上找尖峰
最简单的频域方法。计算各通道的自动率谱密度(PSD),取平均,在平均谱上找局部峰值作为模态频率,以 PSD 幅度平方根作为振型。
算法直觉¶
核心思路¶
想象一座桥在风中微微晃动。如果你在桥上装一个加速度计并记录数据,频域里看:某些频率处的振动幅度会特别大——这些尖峰对应的就是结构的固有频率。
PP 就是干这件事的 :在频谱上找出那些"特别突出的尖峰"。
为什么这能工作?¶
环境激励(风、交通)的频谱近似平坦(白噪声),结构就像一个滤波器——在固有频率处"放大"输入。因此输出的频谱尖峰就是结构的模态。
PP 的强项和弱项¶
-** 强** :速度最快(5ch×3000 点约 50 ms),实现简单,适合快速扫描 -** 弱** : - 分不开靠得太近的模态(< 2 个频点间距) - 不估计阻尼 - 依赖平均 PSD 的质量(数据短时分辨率不够)
算法流程¶
1. Welch 平均 PSD(每通道独立)
├─ 信号分成重叠段(50% overlap)
├─ 每段加 Hann 窗 → FFT → 功率谱
└─ 所有段平均 → 各通道 PSD
2. 所有通道 PSD 取平均 → psd_avg[]
3. 峰值检测
├─ 局部最大值掩码(比相邻 2 bin 都大)
├─ 噪声基底 = 全频段 1/4 分位数
├─ SNR 阈值:psd[k] > 4× noise_floor(≈ 6dB)
├─ 按幅度降序排列
└─ 最小间距约束(≥ 5 bins)
4. 振型提取:sqrt(psd[ch][peak_bin]) → 归一化
设计详解¶
1. Welch 分段平均¶
为什么不用周期图(直接对整个信号做 FFT)?因为单一帧的 FFT 方差太大。Welch 将信号分成重叠段后平均,以分辨率换取方差降低:
| 策略 | 段数 | 分辨率 | 方差降低 |
|---|---|---|---|
| 周期图 | 1 段 | \(f_s / N\) | 1× |
| Welch 50% overlap | ~3 段 | \(f_s / seg\_len\) | ~3× |
| Welch 更多段 | 更多 | 更差(seg_len 更小) | 更多 |
代码实现选择:
-n/3:保证至少 3 段(50% overlap → (n-seg)/seg + 1 ≥ 3) - 512 cap:ESP32 上 512 点 FFT 约 0.8ms,1024 点约 1.8ms。cap 在 512 保证全流水线 < 50ms - 向下取 2^n:tiny_fft 要求 FFT 长度为 2 的幂 为什么 50% overlap 而不是 75%? 75% 重叠可降更多方差但计算量翻倍。50% 在 ESP32 上是经过验证的最佳平衡点。
2. Hann 窗¶
在源文件 tiny_sysid_common.c 中预计算为静态数组。Hann 窗的主瓣宽度是矩形窗的 2 倍(旁瓣降低 ~30dB),这是 PSD 估计的标准选择。Hamming 旁瓣更低但主瓣稍宽→过渡带更大,对密集模态识别不利。
3. 峰值检测策略¶
// 局部最大掩码(±2 bins)
is_peak[k] = (psd[k] >= psd[k-2] && psd[k] >= psd[k-1] &&
psd[k] >= psd[k+1] && psd[k] >= psd[k+2]);
// 噪声基底 = 1/4 分位数(非中位数/最小值)
// SNR 阈值:6 dB (4× noise_floor)
±2 bins 比 ±1 更保守:对于良好的分离模态,峰值至少横跨 3-5 个 bin。
为什么噪声基底用 ¼ 分位数? - 最小值 → 受频谱谷值影响太大,不稳定 - 中位数 → 如果模态很多(频谱被填满),中位数偏高,漏掉弱模态 - ¼ 分位数 → 稳健估计:假设至少 75% 的频点不含模态,取第 25% 作为背景噪声的保守估计
6 dB 阈值(4×)的统计意义:在 Welch 平均后,PSD 估计的置信区间约为 ±30%(对 3 段而言)。6 dB ≈ 4× 意味着峰高至少是背景的 4 倍,超出 95% 置信区间。
4. 内存 & 计算(ESP32 视角)¶
- PSD 缓冲区:
n_ch × n_bins = 5 × 1024 = 5120 float ≈ 20 KB→ SRAM 可容纳 - FFT 缓冲区(复用):
fft_len × 2 = 2048 float ≈ 8 KB - 总耗时:5 通道 × 3 段 × (seg_len/2) FFT ≈ 5×3×0.4ms ≈ 6ms → PP 实际耗时 < 10ms
关键参数¶
| 参数 | 默认 | 说明 |
|---|---|---|
| seg_len | min(N/3, 512) 向下取 2^n | 分段长度 |
| overlap | 50% | 段间重叠 |
| window | Hann | 窗函数 |
| SNR threshold | 4× noise_floor | 峰值检出阈值 |
何时使用 PP¶
- 第一次看数据时快速扫一眼频率分布
- 数据很短(≥ 500 点即 10s)
- 作为更精确方法的前置参考