Variant 5 from the findings doc, as GROUND TRUTH for validating the
from-track wind estimate — it does NOT feed kcal/power. Chosen scope
(per user): a toggle button now, binary "in the face" only, voice later.
- rec screen button "Ветер в лицо": tap opens a headwind interval, tap
closes it; the open state is highlighted and survives a screen re-render
- GPS.toggleWindMark()/_closeOpenWindMark(); recording.windMarks =
[{startTs,endTs}] ms, persisted to localStorage, written to the DB on
finish and restored on crash recovery (a dangling interval auto-closes)
- gps_sessions.wind_marks (JSON) + DB.setSessionWindMarks (separate from
finishGpsSession so recompute paths preserve marks); parsed in getGpsSession
- rec-bottom wraps now so the third button never overflows a narrow screen
Analysis (marks vs estimate) stays in tools/track once enough km accumulate.
5.2 KiB
Сессия 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: для односкоростного
(
gearCount1/пусто + звезда/трещотка/колесо) порог 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 доки)
Пользователь: калории от неточного ветра не считать. Хочет простые отслеживаемые вещи — метки «ветер в лицо», писать данные и делать выводы после набора километража. Это вариант 5 в роли РАЗМЕТКИ, не измерения. Трубка Пито (вариант 3) — точно нет. Вариант 2 (предзагрузка прогноза) — объяснил (скачать прогноз дома по проводу как подсказку-затравку для оценки по треку; изъян тот же, что у «уточнить высоты» — надо не забыть нажать перед выездом).
Решения по UX (AskUserQuestion): кнопка-тоггл, голос потом; только «в лицо» (бинарно). Реализовано:
- кнопка «Ветер в лицо» на экране записи (тап открыть интервал / тап закрыть, активная подсвечена);
- GPS.toggleWindMark()/_closeOpenWindMark(); windMarks=[{startTs,endTs}] мс, персист в localStorage, запись DB.setSessionWindMarks на финише, восстановление в recovery (недозакрытый интервал закрывается);
- колонка gps_sessions.wind_marks (JSON), парсинг в getGpsSession. На distance/kcal/power НЕ влияет.
- Анализ (сравнение меток с оценкой ветра по треку) — позже в tools/track/track.py, после километража.
Результат
Модельные правки #1/#3/#7 внедрены, #2/#4 задокументированы. node --check чист по всем файлам.
Собрано и поставлено ранее build 436 (только правки пауз/высоты); эти правки требуют новой сборки.
Следующие шаги
- Собрать/поставить новую сборку, проверить: на грунтах ккал выше; пеший подъём на односкоростном не в ездовой статистике и не склеивается с ездовым подъёмом; кнопка «Ветер в лицо» пишет интервалы в gps_sessions.wind_marks.
- Ветер: добавить голосовые метки (отдельным шагом); анализ меток vs оценка по треку в track.py.