GPS validation
Validation is a pure function of the GPS table and the parameter set. It never deletes rows: it sets a bit mask of quality flags on every sample and derives a per-sample validity flag from it. Downstream stages use only valid samples and carry the flags through to the profiles.
Flags
| bit | name | rule | invalidates |
|---|---|---|---|
| 1 | NO_FIX |
fix quality < 3 (i.e. no 3-D fix), or latitude and longitude both exactly 0 | yes |
| 2 | HIGH_DOP |
dilution of precision > 3.0; confidence is halved above 2.0 | yes |
| 4 | DUPLICATE_STATIONARY |
identical position to the previous sample while speed < 0.5 m/s: the receiver is holding, treated as stationary | no |
| 8 | POSITION_JUMP |
identical position while moving (≥ 3 m/s), or a step from the last good sample larger than : twice the distance covered in one sample interval at the current speed, plus a 3 m noise allowance, with a 60 m/s floor speed | yes |
| 16 | SPEED_SPIKE |
reported speed > 80 m/s; or a speed step whose acceleration exceeds 15 m/s² and reverses within 3 samples; or a Hampel outlier (window of 7 samples, threshold 3 × 1.4826 MAD, and at least 2 m/s away) | yes |
| 32 | ACCEL_IMPLAUSIBLE |
sustained |dv/dt| > 12 m/s² for longer than 0.5 s: confidence lowered to 0.3 | no |
| 64 | TIME_NONMONOTONIC |
sample time not increasing | yes |
| 128 | INTERPOLATED |
speed filled by linear interpolation inside a gap ≤ 0.5 s | no |
| 256 | PRELOCK |
every sample before the first 2 s run of fixed, low-DOP samples | yes |
| 512 | EDGE |
first and last 0.5 s of each contiguous run (filter warm-up); excluded from peak statistics | no |
| 1024 | PROJ_LOST |
reserved for samples whose track projection was lost; the projection stage reports this per lap (as a count of lost samples) rather than in the GPS flags | no |
A sample is valid when none of the invalidating bits is set.
Session-level checks
- Valid fraction = valid samples / all samples, reported as
gps.valid_fraction. The session check uses the fraction from the camera's first fix on (gps.valid_fraction_after_lock:PRELOCKsamples left out): below 0.8 the quality report records a blocking error ("not enough valid GPS"), which the interface shows as a problem. A camera switched on in the pits finds its satellites minutes later, and that wait says nothing about the laps timed after it (production, Oct 2026: 27 % of the whole recording, 99 % from the first fix on, three laps timed). A first fix too late to time anything fails the longest-run check below. Reports stored before this rule are decided again from their sample and flag counts when they are read. - Longest valid run: below 60 s the quality report records a blocking error ("never gave usable readings for 60 seconds in a row").
- What a blocking error does: it is shown (above the analysis, and as the problem badge); no stage reads it. Lap detection still runs on the valid runs, and each lap is judged on its own GPS (invalid below 0.9 valid or with a gap > 1 s, see Lap detection).
- Gaps: a gap is any interval longer than 3 sample periods; gaps > 1.0 s split the data into separate runs for lap detection.
- Effective rate = (valid samples − 1) / (time span of valid samples), reported in Hz.
- Speed consistency (independent witness): over 2 s windows the position-derived speed and the receiver's reported speed must agree within 1.5 m/s in at least 95 % of moving windows; otherwise a warning is raised and confidence is downgraded. Calibrated during development on the 18 Hz HERO9 recording.
Projection to metres
Positions are converted to a local east-north plane about the track origin: , with m. Track extents are under 1 km, so the flat-earth error is below 1 mm.
What was verified on real data
- HERO9 (18 Hz, GPS5): 7 speed spikes with |dv/dt| > 15 m/s² in one heat, all caught; 958 duplicate positions, all while stationary.
- HERO9 chaptered file: the first 18 samples have fix = 0 and DOP 99.99 (
PRELOCK). - Valid fraction on the reference recordings 99.8–100 %; effective rates 10.0 Hz (HERO11) and 17.7 Hz (HERO9).
Tests: every rule is triggered and not triggered in unit tests; synthetic recordings carry an injected spike, pre-lock zeros, duplicates, a jump and a gap; the flag counts on both reference recordings are pinned by regression tests.