Skip to main content

acoustic-anomaly-wind-turbine

:::warning [UNTESTED] — v0.6 paper-correct The three DSP cores (acoustic_features, rotor_speed, bpf_modulation) are host-unit-tested on native_sim/native/64; the full app runs end-to-end on native_sim with synthetic acoustics + a canned RPM track. No model ships (stub + deterministic fallback). HiL on a real nacelle with a customer-trained model is bench-gated. :::

Nacelle acoustic condition monitor for wind turbines: a PDM MEMS mic captures audible-band sound, DSP extracts spectral features, blade-periodic energy is normalised to rotor order (RPM-invariant via the blade-pass frequency), and a per-interval anomaly score + advisory subsystem/flag is emitted for both drivetrain tonal faults and gross blade aero-anomalies.

Source: examples/audio/acoustic-anomaly-wind-turbine/.

Honest scope

An airborne nacelle mic credibly detects drivetrain/gearbox/bearing tonals (loudest, most reliable), rotor imbalance (amplitude modulation at the blade-pass frequency), trailing-edge-crack whistle, severe leading-edge erosion, and icing. It does not detect early internal cracks / delamination / fiber breakage — those are Acoustic Emission (ultrasonic, structure-borne, requiring a contact piezo bonded to the blade) and out of scope for an airborne mic.

Blade-pass frequency invariant: BPF = N_blades × RPM / 60 (≈0.75 Hz for a 3-blade turbine at 15 rpm). Evaluating modulation in rotor orders at the current BPF makes the signature RPM-invariant under variable-speed operation.

Pipeline

PDM mic (<alp/audio.h>) --frame--> acoustic_features (FFT bands, flatness,
centroid, kurtosis) --band energy--> bpf_modulation (Goertzel at BPF orders)
tacho GPIO / tacholess --> rotor_speed --> rpm, BPF
--> <alp/inference.h> anomaly score (deterministic fallback) --> WTAC record

Why one hand-rolled Goertzel remains

acoustic_features.c takes its full-spectrum FFT and window statistics from <alp/dsp.h> — a one-stage ALP_DSP_STAGE_FFT chain plus alp_dsp_stats_f32(), backed by CMSIS-DSP arm_rfft_fast_f32 on the M55.

bpf_modulation.c deliberately keeps a single-bin Goertzel instead, and it is not a gap. It needs exactly one bin: the live blade-pass harmonic k × BPF, which shifts with every RPM estimate and therefore never lands on a fixed FFT bin boundary. An N-point FFT would compute O(N log N) work to produce N bins and discard all but one; the O(N) Goertzel recurrence computes only the bin actually needed, at an arbitrary non-bin-aligned frequency. CMSIS-DSP ships no Goertzel kernel to call instead, so it stays a portable loop — the cheaper, textbook-correct tool for this job.

board.yaml

libraries:
- name: tflite-micro
cores: [m55_he]
- name: cmsis-dsp
cores: [m55_he]

som:
sku: E1M-AEN801

preset: e1m-evk
cores:
a32_cluster:
os: "off"
m55_he:
app: ./src
inference:
default_arena_kib: 64
peripherals:
- gpio # tacho pulse input (rotor speed).

diagnostics:
log_level: info

PDM mic input is the Zephyr DMIC audio subsystem (via CONFIG_AUDIO_DMIC=y), not a peripheral enum. Flip som.sku to E1M-V2M101 for the DEEPX DX-M1 path.

Expected output

# WTAC,t_s,rpm,bpf_hz,anomaly_score,dominant_subsystem,top_band_hz,flags,rpm_src
WTAC,12.0,17.4,0.87,0.62,BLADE_BPF,3333.3,IMBALANCE,ESTIMATED

rpm_src{TACHO, ESTIMATED, CANNED}: TACHO = live GPIO pulse counting, ESTIMATED = tacholess envelope-based estimate (demo default when the estimate converges), CANNED = fixed look-up table fallback.

See also

Questions about this page? Discuss in Community Forum