Flight Log Anomaly Detector (UAV) — Hampel + Optional STL
A lean, explainable tool to flag battery voltage spikes, GPS jumps, and IMU outliers in your UAV telemetry. CSV in → anomalies JSON out.
A lean and explainable detector that flags weird events in UAV flight logs: battery voltage spikes, GPS drift/jumps, and IMU outliers. Perfect for quick maintenance triage, post-flight QA, and demos.
Why this exists: you shouldn’t need a black box to spot obvious problems. This tool favors robust statistics, small dependencies, and clear reasons for each flag.
What it does
- Hampel filter (rolling median + MAD) on numeric telemetry columns.
- Optional STL decomposition to remove trend/seasonality before Hampel.
- GPS jump detector comparing per-sample displacement against speed-based allowance.
- Writes a single
anomalies.jsonlist with timestamps, columns, values, and reasons.
How it works (plain English)
- Hampel filter: for each sample, compare the value to the median of its window. If the deviation exceeds
n_sigma × 1.4826 × MAD, it’s flagged.- Robust to spikes and drift; much less sensitive to outliers than mean/std.
- STL (optional): decompose a series into trend + seasonal + residual, then run Hampel on the residual only. Helpful for voltage sag curves or periodic speed patterns.
- GPS jumps: compute Haversine distance between consecutive lat/lon, and allow up to
gps_alpha × speed × dt + gps_margin_m. Exceed that? It’s a jump.
📦 Download
Contents:
flight_log_anomaly_detector.py— CLI toolexample_log.csv— synthetic 1 Hz, 10-minute log with planted anomaliesrequirements.txt—pandas,numpy,statsmodelsREADME.md— usage & notes
Quick start
# optional: create & activate a virtual env
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scriptsctivate
pip install -r requirements.txt
# run the detector on the example data
python flight_log_anomaly_detector.py detect --csv example_log.csv --time-col timestamp --cols batt_voltage_v,gps_speed_mps,imu_ax,imu_ay,imu_az --out anomalies.json --k 7 --n-sigma 3.0 --stl-cols batt_voltage_v --stl-period 60 --gps-jump 1 --gps-alpha 2.0 --gps-margin-m 30
You’ll get anomalies.json plus a summary in the console.
Expected CSV columns
Required
timestamp— ISO 8601 or parseable datetime at uniform frequency (e.g., 1 Hz)
Common numeric columns
batt_voltage_v— battery voltage (V)gps_speed_mps— ground speed (m/s)imu_ax,imu_ay,imu_az— accelerometer (m/s²) or normalized glat,lon— needed for GPS jump detection
Use the
--colsflag to list which numeric columns to scan with Hampel.
CLI options (most used)
--csv <path.csv> Input telemetry CSV
--out <anomalies.json> Output JSON file
--time-col <name> Timestamp column (ISO/parseable)
--cols <c1,c2,...> Numeric columns to Hampel-scan (comma-separated)
--k <int> Hampel half-window (neighbors per side), default 7
--n-sigma <float> MAD threshold, default 3.0
--stl-cols <c1,c2,...> Columns to detrend/seasonal-remove via STL before Hampel
--stl-period <int> Seasonal period (in samples), e.g., 60 for 1 Hz × 1 minute
--gps-jump <0|1> Enable GPS jump detector (needs lat, lon, gps_speed_mps)
--gps-alpha <float> Multiplier on speed×dt (default 2.0)
--gps-margin-m <float> Extra fixed margin in meters (default 30)
Tuning tips
- Start with
--k 7 --n-sigma 3.0. - If you get too many flags, increase
n-sigmaork. - If voltage has a strong curve, add
--stl-cols batt_voltage_v --stl-period <your-period>.
Output format (anomalies.json)
Each anomaly is a small object:
[
{
"index": 120,
"timestamp": "2025-01-01T12:00:10+00:00",
"column": "batt_voltage_v",
"value": 15.9,
"reason": "hampel",
"residual": -0.8
},
{
"index": 300,
"timestamp": "2025-01-01T12:05:00+00:00",
"column": "gps",
"value": 185.3,
"reason": "gps_jump",
"distance_m": 185.3,
"allowed_m": 70.1
}
]
Fields
index— row index in your CSVtimestamp— ISO time from--time-colcolumn— source column (gpsfor jumps, otherwise your numeric column)reason—hampelorgps_jumpvalue— original value at that row (for Hampel)residual— present when STL was applied to that columndistance_m,allowed_m— present forgps_jump
What it catches (examples)
- Battery voltage spikes/dips: loose connector, bad pack cell, power transient
- GPS jumps: poor lock, multipath, sudden coordinate glitch
- IMU outliers: vibration bursts, impacts, sudden bias shifts
It’s triage, not a verdict. Review in your log viewer and consider context.
Integration ideas
- CI check for flight logs in a repo; fail builds if anomalies > N
- Webhook: push
anomalies.jsonto a dashboard or Slack channel - CSV annotator: join flags back onto the CSV for quick visualization in charts
Validation & calibration
- Run on a few clean flights to establish baseline false positive rate
- Keep a labelled set of known issues to sanity-check recall
- For seasonal/periodic behavior (e.g., patterned speed), try STL residuals
Roadmap
- Optional annotated CSV writer (
.csvwith per-row flags) - Tiny HTML plot to visualize spikes and jumps
- Per-column thresholds via config file (YAML/JSON)
- Simple REST microservice wrapper for batch jobs
License
MIT — free to use, modify, and embed in your pipelines.
Questions?
Open an issue/PR or ping us — and if you ship something cool with it, tell us! 🚀