Skip to content

NOTES

PP — Peak Picking: Find Sharp Peaks in the Spectrum

The simplest frequency-domain method. Computes auto-PSD per channel, averages them, finds local maxima as modal frequencies, uses sqrt(PSD) as mode shapes.

Intuition

Core Idea

Imagine a bridge swaying gently in the wind. If you place an accelerometer and record data, in the frequency domain some frequencies will have much larger amplitudes—these peaks correspond to the structure's natural frequencies.

PP does exactly this: finds the prominent peaks in the spectrum.

Why It Works

Ambient excitation (wind, traffic) has a roughly flat spectrum (white noise). The structure acts as a filter—amplifying input at its natural frequencies. So the output spectrum peaks are the structure's modes.

Strengths & Weaknesses

  • Strength: fastest (~50 ms for 5ch×3000), simple implementation, great for quick scans
  • Weakness:
  • Can't separate closely-spaced modes (< 2 bins apart)
  • No damping estimate
  • Depends on averaged PSD quality

Algorithm

1. Welch-averaged PSD per channel
   ├─ segments with 50% overlap
   ├─ Hann window → FFT → power spectrum
   └─ average all segments → channel PSD

2. Average across channels → psd_avg[]

3. Peak detection
   ├─ local maxima (larger than ±2 neighbors)
   ├─ noise floor = 25th percentile
   ├─ SNR threshold: psd[k] > 4× noise floor
   ├─ sort by amplitude descending
   └─ min distance ≥ 5 bins

4. Mode shapes: sqrt(psd[ch][peak_bin]) → normalize

Design Deep Dive

1. Welch Segment Averaging

Why not the periodogram (single FFT on all data)? Single-frame FFT has high variance. Welch averages overlapping segments, trading resolution for variance reduction:

Strategy Segments Resolution Variance reduction
Periodogram 1 \(f_s / N\)
Welch 50% overlap ~3 \(f_s / seg\_len\) ~3×
More segments more worse more

Implementation choice:

int target_seg = (n < 128) ? n : (n / 3 < 512 ? n / 3 : 512);
- n/3: guarantees ≥3 segments (50% overlap → (n-seg)/seg + 1 ≥ 3) - 512 cap: ESP32 512-pt FFT ~0.8ms, 1024-pt ~1.8ms. Cap at 512 keeps pipeline < 50ms - Power-of-2: required by tiny_fft

2. Hann Window

Pre-computed as static array in tiny_sysid_common.c. Hann has 2× main lobe width vs rectangular (sidelobes -31dB), the standard choice for PSD estimation. Hamming gives lower sidelobes but slightly wider main lobe, hurting close-mode resolution.

3. Peak Detection Strategy

±2 bins (vs ±1): more conservative. Well-separated modes span 3-5 bins. Noise floor = 25th percentile (not median or minimum): - Minimum → unstable, too sensitive to spectral nulls - Median → inflated when many modes fill the spectrum - 25th percentile → robust: assume ≥75% of bins are noise-free

4. ESP32 Resource Usage

  • PSD buffer: 5ch × 1024 bins = 20 KB → SRAM fits
  • FFT buffer (reusable): 2048 floats = 8 KB
  • Total: 5ch × 3seg × 0.4ms = ~6ms → PP < 10ms total

Key Parameters

Parameter Default Description
seg_len min(N/3, 512) power-of-2 Segment length
overlap 50% Segment overlap
window Hann Window function
SNR threshold 4× noise_floor Peak detection

When to Use PP

  • Quick frequency scan on first look at data
  • Very short data (≥ 500 samples = 10s)
  • Reference for more accurate methods