Skip to content

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/server track 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

  1. 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).
  2. 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.
  3. 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.
  4. 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).
  5. 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

  1. 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 %.
  2. Simple beats clever. With the logbook days held out one at a time:
  3. variation alone: 0.84–0.87 balanced accuracy;
  4. variation plus jitter: 0.74–0.79;
  5. adding variation relative to the trip: 0.70–0.72;
  6. 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.