baldav/docs/session-logs/2026-09-07_gps-model-findings-impl.md
4aiman 9f8ab0eeb1 GPS model: accel-based Crr scale, auto walk-the-bike split; document climb/elevation limits
Acted on docs/gps-model-findings.md (independent analysis of 156 rides).

Implemented:
- crrFromAccel extended past the old 0.008 ceiling: 7-11 -> 0.008,
  11-15 -> 0.012 (packed dirt), >15 -> 0.020 (grass/rut/gravel). Rough
  surfaces were undercounted ~3x. Applied to session median and per-point Crr.
- Auto walk-the-bike detection (single-speed only, gear_count 1/unset):
  a normal-fix segment slower than the 30-rpm-cadence speed is the rider
  pushing, not riding. Excluded from ride distance/speed/elevation (elevRef
  reset so a pushed climb doesn't merge with the ridden one); effort counted
  as walking, not bike physics. Every sub-threshold point excluded regardless
  of duration; only runs >=30s reported as walked (walkBikeSec/walkBikeMeters).
  gearCount threaded through every computeStats/finish caller.

Documented as known limitations (left as-is by decision, need calibration/DEM):
- kcal max(physics, MET) never sums the biological overhead, so climbs are
  slightly undercounted (comment + README + PROJECT_MAP).
- absolute elevation gain is bounded by the raw GPS altimeter (tens of
  percent; needs a terrain model / wired DEM preload).
2026-09-07 15:50:19 +03:00

4.3 KiB
Raw Blame History

Сессия 2026-09-07: реализация находок по расчётной модели GPS

Контекст

Разобрали docs/gps-model-findings.md (вывод независимого инструмента tools/track/track.py по 156 поездкам). Пользователь принял решения по каждой находке. Плана в plan-mode не было — работали по прямым решениям пользователя, зафиксированным ниже.

Решения пользователя и что сделано

  • #1 Crr-потолок 0.008 занижен → внедряем. crrFromAccel в gps.js расширен: 7-11=0.008, 11-15=0.012 (плотный грунт), >15=0.020 (трава/колея). Мапится и медиана сессии, и per-point ptCrr.
  • #2 max(физика,MET) не складывает, подъёмы недосчитаны → только пометить. Не меняем формулу: добавлен комментарий у Math.max(physicsKcal, metNetKcal) (ИЗВЕСТНОЕ ОГРАНИЧЕНИЕ, нужна калибровка), записано в README и PROJECT_MAP.
  • #3+#7 ходьба с велосипедом как езда → внедряем. computeStats: для односкоростного (gearCount 1/пусто + звезда/трещотка/колесо) порог walkBikeMs = 30 об/мин; сегмент медленнее порога (нормальный фикс) исключается из ездовой дистанции/скорости/высоты (elevRef=null), усилие = walk-MET нетто. #7: исключается каждая точка без гейта по длительности, в отчёт «пешком» только пробеги ≥30с. Возврат: walkBikeSec/walkBikeMeters. gearCount прокинут во все вызовы (live-stop, recalculateSession, recovery, bulk, main.js старт записи + detail). Время пуша ≥30с вычитается из duration (средняя скорость остаётся чисто ездовой).
  • #4 набор высоты расходится в обе стороны → только пометить. Не код: записано в README и PROJECT_MAP (предел сырого GPS-альтиметра, реальный фикс — предзагрузка DEM по проводу).
  • #5/#6 — к сведению (пульс потерян браслет; ветер в track.py, не в приложении).

Ветер (часть 2 доки)

Пользователь: калории от неточного ветра не считать. Хочет простые отслеживаемые вещи — голосовые метки («ветер в лицо») и/или кнопки в UI (нажал когда дует в лицо, отжал когда перестал), писать данные и делать выводы после набора километража. Это вариант 5 в роли РАЗМЕТКИ, не измерения. Трубка Пито (вариант 3) — точно нет. Вариант 2 (предзагрузка прогноза) — пользователь не понял, нужно объяснить. Реализация ветер-фичи — отдельным шагом (нужны решения по UX: триггер-слова, место кнопки, схема хранения событий).

Результат

Модельные правки #1/#3/#7 внедрены, #2/#4 задокументированы. node --check чист по всем файлам. Собрано и поставлено ранее build 436 (только правки пауз/высоты); эти правки требуют новой сборки.

Следующие шаги

  • Собрать/поставить новую сборку, проверить: на грунтах ккал выше; пеший подъём на односкоростном не в ездовой статистике и не склеивается с ездовым подъёмом.
  • Ветер: спроектировать и внедрить разметку событий (голос/кнопки).