Skip to main content

rail-predictive-maintenance

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

Train-mounted rail-condition survey: read axlebox/carbody vibration from the on-board ICM-42670, extract DSP features, classify the rail defect, and geotag each verdict to a track position (GNSS lat/lon + along-track chainage). One CSV record per 25 m segment, ready for the customer's GIS / MQTT gateway.

Source: examples/ai/rail-predictive-maintenance/.

This monitors the rail (infrastructure), complementing ai-anomaly-detection-vibration, which monitors a stationary asset (motor/pump bearing). Wheel-side defects (wheel flats) are out of scope. The speed-normalised wavelength λ = v / f makes corrugation detection speed-invariant.

Pipeline

ICM-42670 (I2C) --window--> rail_features (RMS, crest, kurtosis, 8 FFT
bands, dom-freq, rail wavelength = speed/freq) --feature vector-->
<alp/inference.h> classifier (deterministic fallback if no model)
NEO-M9N GNSS (UART NMEA) --> rail_position (haversine chainage + segments)
--> CSV record per segment

The spectral and statistical maths live in <alp/dsp.h>, not in hand-rolled app code. rail_features.c opens a one-stage FFT chain and reduces windows with the library:

alp_dsp_stage_t stages[] = {
{ .kind = ALP_DSP_STAGE_FFT,
.u.fft = { .n_points = RAIL_WINDOW_N,
.output_format = ALP_DSP_FFT_OUTPUT_MAGNITUDE } },
};
alp_dsp_chain_t *chain = alp_dsp_chain_open(stages, 1u);
alp_dsp_chain_apply_bins(chain, samp_q15, RAIL_WINDOW_N, mag, RAIL_WINDOW_N, &got);
alp_dsp_chain_close(chain);

alp_dsp_stats_f32() supplies the RMS / peak reductions. The backend runs CMSIS-DSP arm_rfft_fast_f32 (Helium-vectorised) on the M55 and portable C under native_sim — the app never names an arm_* symbol.

ClassSignature
HEALTHYbaseline
CORRUGATIONperiodic rail roughness (narrowband, stable wavelength)
JOINT_WELDimpulsive transient (high crest + kurtosis)
ROUGH_RCFbroadband roughness / rolling-contact fatigue

board.yaml

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

som:
sku: E1M-AEN801

preset: e1m-evk
supported_boards:
- e1m-evk
- e1m-x-evk

pins:
- { e1m: E1M_I2C0, macro: EVK_I2C_BUS_SENSORS, doc: "ICM-42670 accelerometer bus" }
- { e1m: E1M_UART1, macro: EVK_UART_PORT_ARDUINO, doc: "NEO-M9N GNSS NMEA (Arduino-header UART)" }

cores:
a32_cluster:
os: "off"
m55_hp:
app: ./src
inference:
default_arena_kib: 64
peripherals:
- i2c # ICM-42670 link.
- uart # NEO-M9N GNSS NMEA link.

chips:
- icm42670 # 6-axis IMU; accel only.
- ublox_neo_m9n # Multi-constellation GNSS.

diagnostics:
log_level: info

Flip som.sku to E1M-V2M101 for the DEEPX DX-M1 path.

Expected output

# RAIL,chainage_m,lat,lon,speed_mps,class,severity,dom_freq_hz,rail_wavelength_m,fix
RAIL,100.0,59.334591,18.062400,6.2,CORRUGATION,0.81,120.0,0.0517,1

See also

Questions about this page? Discuss in Community Forum