From 1cb6efbee318139c091fee45641130a44355e7d0 Mon Sep 17 00:00:00 2001 From: 4aiman Date: Wed, 21 Oct 2026 11:22:46 +0300 Subject: [PATCH] Track detail: reference calibrated-HR kcal figure (Keytel x personal factor) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HR methods over-read vs physics (ride) and weight (sedentary day); a rough single factor ~0.65 reconciles both. Add config.hrCalibFactor (0.65) and show a 'ЧСС откалибр. (грубо)' figure next to the Keytel one in the calories block, clearly labelled as a rough reference. Activity balance still uses physics. --- .../2026-10-21_hr-base-and-calib.md | 35 +++++++++++++++++++ frontend/js/gps.js | 1 + frontend/js/main.js | 6 ++-- 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 docs/session-logs/2026-10-21_hr-base-and-calib.md diff --git a/docs/session-logs/2026-10-21_hr-base-and-calib.md b/docs/session-logs/2026-10-21_hr-base-and-calib.md new file mode 100644 index 0000000..b011e14 --- /dev/null +++ b/docs/session-logs/2026-10-21_hr-base-and-calib.md @@ -0,0 +1,35 @@ +# Сессия 2026-10-21 - база покоя из ночной записи + справочная калибровка ЧСС + +## Ночь записалась чисто (нативный лог сработал) +Воркаут `1792529811087` (20.10 23:56 -> 21.10 09:20): 9.4ч непрерывно, 0 дыр. Нативный лог +ЧСС (foreground-сервис, ble_hr_log.jsonl) переживает гаснущий экран - прошлый 21ч-прогон имел +11.6ч дыр из-за заморозки JS-поллинга, теперь починено. + +## База покоя +Истинный пульс сна **~48 (46-50)**, устойчивый 10-мин минимум 50 в 05:46, общий минимум 46. +Всплеск 112 в 05:00 = подъём в туалет. Прежняя прикидка 65-85 завышена. + +## Прикидка моделей (разбор, объяснено пользователю словами) +Поездка 90км по-всякому: физика 2756, Keytel-net 4283, резерв-ЧСС/Карвонен (от покоя 48, +VO2max 56 по Uth) ~4841. Пульсовые ~1.5-1.8x физики. Якорь на покой поездку не уменьшил. +Сутки (сон этой ночью + работа 10-17 вчера, 16ч бодрств.): по пульсу ~2300 против веса +BMR1670 x1.2=2005 (x1.3=2172). Пульс завышает и день (+10-15%), и поездку. Чисто НЕ сходятся; +грубый множитель ~0.65 мирит обе точки (поездка 2756/4283=0.64; день 335/632=0.53..0.79). +Физика у велосипеда занижает (неэффективный односкоростной складной - реально жжёшь больше +идеала); пульс завышает (жара/обезвоживание/еда + неспособность отделить их от усилия). + +## Сделано (reference-only, баланс не трогаем) +- Память `project_hr_calibration_experiment.md` дополнена результатами ночи; статус - база + получена. Напоминалка снята (state.json status=done). +- `gps.js`: `config.hrCalibFactor = 0.65` (грубый персональный множитель, правится вручную). +- `main.js` showSessionDetail блок "Калории": добавлена строка "ЧСС откалибр. (грубо)" = + Keytel x hrCalibFactor, рядом с "По ЧСС (Keytel)"; подпись "грубая прикидка". В баланс + по-прежнему идёт физика. + +## Остатки (не срочно) +Собрать ещё 1-2 чистых дня для устаканивания множителя; скидка на переваривание (TEF); +батарея ремня - ждём первого шага вниз (9.4ч @ 100%, ноль шагов). + +## Проверка +Синтаксис JS ок. На телефоне: открыть трек с ЧСС -> в "Калории" три числа (физика, +По ЧСС Keytel, ЧСС откалибр.); баланс дня не изменился. Живую проверку делает пользователь. diff --git a/frontend/js/gps.js b/frontend/js/gps.js index 6480192..dbf8ea6 100644 --- a/frontend/js/gps.js +++ b/frontend/js/gps.js @@ -14,6 +14,7 @@ GPS.config = { airDrag: 0.6, // аэродинамическое сопротивление (CdA, м2). Город=0.6, спорт=0.4 airDensity: 1.225, // плотность воздуха (кг/м3). Уровень моря=1.225, горы=1.0 pedalEfficiency: 25, // КПД педалирования (%). Человек ~25% + hrCalibFactor: 0.65, // грубый персональный множитель для справочной "ЧСС откалибр." (Keytel x этого). Пульс завышает ~в 1.5x vs физика/вес; 0.65 мирит по 2 точкам (поездка 90км + сидячий день). НЕ истина, для справки. altSmoothHalf: 2, // полуокно сглаживания высоты (точек). 2 = 5pt, 5 = 11pt, 7 = 15pt walkMaxSpeedKmh: 12, // макс. скорость ходьбы/бега (выше = глитч GPS) walkMinSpeedMs: 0.3, // мин. скорость ходьбы (ниже = стоит). 0.3 м/с = 1 км/ч diff --git a/frontend/js/main.js b/frontend/js/main.js index 463cad6..2c9e41e 100644 --- a/frontend/js/main.js +++ b/frontend/js/main.js @@ -5483,6 +5483,7 @@ async function showSessionDetail(sessionId) { heightCm: parseFloat(state.profile?.height_cm) || 178, }; let hrKcal = hasHr ? GPS.hrKcalNet(hrSamples, hrProfile) : null; + let hrKcalCalib = hasHr ? Math.round(hrKcal * (GPS.config.hrCalibFactor ?? 0.65)) : null; // грубая справочная прикидка let hrAvg = hasHr ? Math.round(hrSamples.reduce((a, s) => a + s[1], 0) / hrSamples.length) : null; let hrMax = hasHr ? Math.max(...hrSamples.map(s => s[1])) : null; @@ -5527,8 +5528,9 @@ async function showSessionDetail(sessionId) {
${session.total_kcal ?? stats.kcal} ккал${hasHr ? "Физика (в баланс)" : "Всего"}
${kcalMin} ккал/минРасход
- ${hasHr ? `
${hrKcal} ккалПо ЧСС (сравнение)
-
В баланс идёт «физика»; цифра по ЧСС (Keytel) - для сравнения.
` : ""} + ${hasHr ? `
${hrKcal} ккалПо ЧСС (Keytel)
+
${hrKcalCalib} ккалЧСС откалибр. (грубо)
+
В баланс идёт «физика». По ЧСС (Keytel) завышает; «откалибр.» = Keytel x ${(GPS.config.hrCalibFactor ?? 0.65)} - грубая прикидка для сравнения.
` : ""} ${elevations.length > 0 ? `