ADR 009: Engine or sail from the track, as a suggestion the skipper corrects¶
- Status: Proposed (built on branch
spike/motor-sail-detection, not merged) - Date: 2026-10-21
- Deciders: Owner
- Technical Context:
apps/servertrack editor; behaviour in track-editor.md § Timeline and calculations.md § Engine detection. Evidence below; the spike scripts were removed after the merge (see Reproduce).
Context¶
Tracks imported from other apps (Garmin FIT, GPX) carry no vessel state: every point arrives as sail, so engine time is 0 and sailing time too high. Skippers know roughly when they motored but nothing let them say so. The question for the spike: can the server tell engine from sail from the track alone, and how far can that be trusted?
Decision¶
- A detector from one feature: the speed variation over the 10 minutes around each minute (below about 4 % leans engine), a sticky two-state smoother, and a prior towards engine in the first and last 10 minutes underway. Coefficients fitted on a real logbook (below).
- Only a suggestion. "Analyze track" in the track editor fills the sail-and-engine changes; nothing is saved until the skipper has checked and saved. The reliability (expected share of right minutes) is shown with it.
- The editor is the main tool: zoomable timeline with playhead, SOG, wind barbs, draggable changes, sail / engine / motorsail from the playhead. Saving rewrites the underway states on the points; stops stay.
- Model wind is shown, never used to decide. Open-Meteo (historical forecast from 2022, ERA5 before), 0.25° cells and dates only, no ID; added to the privacy page. Not a meaning change of the policy, so its version stays 1 (owner to confirm).
- Considered and rejected: more features (jitter, trip-relative variation, cruising speed, course steadiness) and wind features, both worse on held-out logbook days; filling engine time automatically on import (about 70–85 % right is too little for a logbook number).
Answer of the spike¶
Well enough for a suggestion, not to fill Engine time silently. Against real ground truth (handwritten logbook, 6 days, fitted on 5 and tested on the sixth, each in turn): 85 % balanced accuracy, AUC 0.92, the reliability matching the observed accuracy (0.83 vs 0.85). On 13 other trips (other boats, devices, labels derived from wind and tacks) about 70 %.
Data¶
| Source | Trips | Ground truth |
|---|---|---|
| Cyclades 2023 (Lavrio–Kea–Serifos–Milos–Sifnos–Syros–Kythnos): 6 Garmin FIT files, a point every ~20 s, plus the boat's handwritten logbook (scanned PDF) | 6 days, 27 h underway | yes: the time of every S/M switch ("Fetzen Groß raus", "Segel bergen, Motor an"), local time UTC+3. The minutes ±3 min around a switch are left out. |
| Other real tracks: Istria 2023, Split 2023, Mallorca 2025, Greece 2026, Sardinia/Corsica 2026 (FIT + GPX) | 18, ~280 h underway | weak labels only (below) |
SailEver FIT with vessel state (developer field 6), session.fit |
6 | recorded on land (near Vienna, Kansas): unusable |
tracks/001–003 (tracksim) |
3 | simulated; engine only in harbour, so a weak test |
Weak labels. Before the logbook arrived, minutes were labelled from ERA5 wind and track geometry: - Engine: within 30° of the true wind at ≥ 3 kn in ≥ 6 kn of wind, or ≥ 5 kn in < 2.5 kn of wind. - Sail: a zigzag of steady boards whose turns' bisector points into or away from the wind.
That gave 751 engine and 2,765 sail minutes. The logbook showed these labels to be misleading: - Their accuracy estimate (76 %) was far above the truth for the model they selected (60 %). - Model wind near the Cyclades was often far off: the boat was sailing at 5–6 kn while ERA5 reported 2–4 kn, and on one day ERA5 put the boat 9° off the wind while it was under sail.
Findings¶
- Speed varies more under sail, and that is the signal. Median detrended variation over 10 min: engine 3.5 %, sail 6.8 %. The fitted threshold is about 4 %.
- Simple beats clever. With the logbook days held out one at a time:
- variation alone: 0.84–0.87 balanced accuracy;
- variation plus jitter: 0.74–0.79;
- adding variation relative to the trip: 0.70–0.72;
- all 8 features (including distance from cruising speed and course steadiness): 0.63–0.67.
The extra features fitted differences between days (calm days are engine days), not within a day. A perfectly steady engine stretch in a gusty trip then scored as sail. 3. Model wind makes it worse: adding true wind angle and strength as features gave 0.62. Wind is shown to the skipper as context, never used to decide. 4. Weak labels make it worse too: training on logbook days plus weak labels gave 0.53–0.57. 5. Waves and strong wind blur the signal. Motoring into the Meltemi varied 6–7 % (like sailing); fast downwind sailing at 8–9 kn varied only 3–4 % (like engine). These are the cases the skipper corrects. 6. "Starts and ends under engine" is a prior, not a signal. Manoeuvring in harbour makes speed vary a lot. The first and last 10 minutes underway therefore get P(engine) = 0.8. 7. Timing of the suggested switches on the logbook days (handwritten time → detected), typically within 10 min, sometimes 30–70 min late:
| Day | Switch | Logbook | Detected |
|---|---|---|---|
| 25 Sep | sail | 11:58 | 11:53 |
| 25 Sep | engine | 12:16 | 12:15 |
| 25 Sep | sail | 14:53 | 14:42 |
| 25 Sep | engine | 15:25 | 16:12 |
| 24 Sep | sail | 10:30 | 10:39 |
| 24 Sep | engine | 12:31 | 13:01 |
| 27 Sep | sail | 11:36 | 11:38 |
| 27 Sep | engine | 16:12 | 15:25 (then a short sail blip until 16:21) |
| 28 Sep | sail | 14:25 | 14:02 (but engine again 15:05–16:00) |
| 28 Sep | engine | 17:28 | 17:35 |
Reliability score¶
reliability = mean of max(P, 1 − P) over the moving minutes: the expected share of right minutes.
- Smoothing: stickiness 0.95 per minute and emission temperature 0.2 keep the score honest (0.83 claimed, 0.85 observed on held-out days). Stickier settings claimed more than they delivered: 0.93 claimed vs 0.88 observed.
- Per trip it ranged from 0.77 to 0.95 on the logbook days.
- Limits: with 6 days of truth, one skipper, one boat and one device, the 85 % is optimistic for other boats. The weak-label check on 13 other trips suggests about 70 %.
Consequences and next steps¶
- More ground truth: more logbooks with S/M times, or tracks recorded with the SailEver watch apps, where the skipper sets the state. Using production tracks for this is a new use of user data: it needs a decision and a privacy-page entry first (
privacy.md). - Measure corrections: count how often skippers change the suggestion in the editor. That gives real accuracy across boats, without reading anyone's tracks.
Reproduce¶
The spike scripts (tools/motor-sail-spike/: Python analysis and Ruby dumps) were removed from the repository on 2026-10-21, once the detector was built. They are in the git history of PR #49 (last commit b140853). The track data and the logbook times they used are personal and were never in git.
Addendum 2026-10-21: detector v2 (speed steps) and the fullscreen editor¶
Why. On the owner's Mallorca day (27 April 2025, 1 s points) the first detector was wrong: the engine block until 12:34 (5.6–6.1 kn, dead even) and a later stretch under sail at the same speed (wind building, from 14:45) both varied only 2–3 % over 10 minutes. A skipper tells them apart by the shape over hours: the engine block is flat and ends with a sharp drop (5.6 → 2.1 kn, engine off); under sail the speed builds slowly with the wind.
Change. 1. The smoother may switch state almost only at a speed step: the mean speed of the 5 minutes before and after differs by 37.5 % or more. Elsewhere switching costs 0.001 per minute instead of 0.05. 2. The minute score is unchanged: speed variation alone, about 4 % as the threshold.
Evidence. 7 days (the six logbook days plus the owner's reading of the Mallorca day), each left out of the fit in turn:
| Detector | Balanced accuracy | Reliability claimed vs observed |
|---|---|---|
| v1 | 0.85 | — |
| v2 | 0.97 | 0.96 vs 0.965 |
- Mallorca: 0.79 → 1.00.
- Worst day: 25 Sep at 0.86. Its last switch is found 48 minutes late, because the speed doesn't step there.
- Tuning: the threshold 0.375 lies in the middle of a stable range (0.35–0.40). Lower values let gusts count as steps.
- Rejected: applying the start/end prior once instead of per minute gave 0.93. Harbour manoeuvring varies like sailing, and the per-minute prior is what calls it engine.
- Caveat: the step threshold, stickiness and temperature were chosen on the same 7 days, so expect less on other boats.
Editor. It became one fullscreen screen: - an action bar with Cancel, Delete, Analyze and Save; - the map with plotter boxes (Time, SOG, COG, State, TWD/TWA/TWS, kept totals) at the playhead; - one timeline with grab handles for IN, OUT and every change, and resize/grab cursors; - a selection panel for the departure and destination names and the change notes, pre-filled from our OSM places.
Moving a track to another trip left the editor: it is a "Move" dialog on the trip page. Notes are stored in tracks.state_notes and shown on the trip map's state-change markers.
Addendum 2026-10-21 (2): wind stored with every track¶
The model wind is now fetched once per track and stored with it (tracks.wind), for every track, not only when the editor opens.
- How: TrackWindJob runs when a track is processed. A migration backfills existing tracks, spaced 2 s apart.
- Privacy: Open-Meteo still gets only 0.25° cells and dates. The privacy page says it now covers every track.
- Editor: the IN handle is the first state change. Clicking the timeline opens the change form at the playhead. Deleting a track moved into its Move dialog on the trip page.