Перейти к содержимому

Формулы метрик

Версия: 0.3 Дата: 2026-09-28 Аудитория: внутренний документ команды (продукт + разработка). Не предназначен для пользователя.

Этот документ — единая точка входа в логику расчётов Lumo. Сами формулы живут в screens/ рядом со своими экранами; здесь — рамка, которая их связывает: какие данные у нас уже есть, что требует персонального baseline, а что работает с первого дня, и откуда взяты веса.


1. Главный принцип — ярусы персонализации

Заголовок раздела «1. Главный принцип — ярусы персонализации»

В wearable-алгоритмах нет «правильного абсолютного значения HRV». RMSSD у разных людей отличается в 10 раз (20–200 мс — обе нормы), и интерпретация без личного baseline бессмысленна. Поэтому каждая метрика принадлежит к одному из трёх ярусов:

ЯрусКогда работаетЧто туда попадаетЧто показываем до
0. Абсолютные нормыДень 1HR-зоны (220 − возраст), SpO2 < 90% тревожно, сон 7–9ч adult, цель 8000 шаговРаботает сразу
1. Персональный baseline14 дней ношенияHRV (RMSSD), RHR, кожная температура (отклонение), фоновый стресс, время отхода ко сну (хронотип)Плашка «Накапливаем данные» + абсолютная норма как fallback (см. §3)
2. Долгосрочный тренд30–90 днейЗдоровье, Lumo Age, кардио-трендыСкрыто полностью

Правило: каждая метрика в screens/ должна явно указывать свой ярус. Если ярус 1 или 2, обязателен cold-start UX — что показываем, пока baseline не сформирован.


Окна:

  • Recent window — 7 дней (свежее состояние)
  • Baseline window — 14 дней (личная норма)
  • Long-term window — 60 дней (для медленных метрик: Здоровье, Lumo Age)

Большинство «балансовых» метрик (HRV Balance, RHR vs baseline) сравнивают recent с baseline.

Минимум данных для запуска:

  • Ярус 1 (Energy, Stress, Battery): 14 ночей ношения с покрытием ≥ 70% времени сна
  • Ярус 2 (Здоровье): 10 полных дней для индикатора, 30 дней для Lumo Age

Что делаем при перерывах ношения:

  • < 3 дня без данных — продолжаем считать на старом baseline
  • ≥ 3 дня без данных — фризим обновление baseline до накопления свежих 7 дней
  • Полный сброс кольца / новый пользователь — пересчёт с нуля, плашка «Накапливаем данные, точность улучшится через N дней»

Fallback на ярус 0 для ярусов 1/2 в cold-start: используем популяционные нормы по возрасту/полу. Например, RHR ожидаемый = 60–80 для 25–45 лет; HRV-нормы по age-band. Это прокси-baseline на первые 14 дней — точность ниже, но лучше пустого экрана.


Что кольцо отдаёт и где это в продукте — product-spec §5. Здесь — что из этого уже читает наш код. Источник реальности — LinktopDataService в iOS-приложении.

ДанныеИсточник SR28DВ коде
Пульс, HRV (RMSSD), межударный интервал, дыхание, SpO2, температура, движение, надето, зарядИстория, фид 2✅
На зарядкеИстория, фид 1✅
Стресс кольцаИстория (поле устаревшее с прошивки V0.9.4), живой замер⚠️ только в лог — для сверки «кольцо или свой»
Засыпание / пробуждение / время в постелиСобытия сна✅
Температура во сне поминутноОтдельный фид✅
Фазы сна, латентность, пульс покояSleepV4 на телефоне✅
Шаги, дистанция, калории, интенсивность за 5 минАктивность✅ читается, в формулы не подключено
Автоопределение активности, VO2maxАктивность❌
ТренировкиРежим тренировки❌
Живой пульс + HRV + IBI, живой SpO2Живой замер✅
Разовая температураКоманда✅
Сырой PPG + акселерометрПоток при подключении❌

Следствие для v1: Activity-компоненты в Energy / Battery и «вы много сидите» упираются в интенсивность за 5 минут — данные уже читаются, но в формулы не подключены. Пока компонент недоступен, в доке метрики стоит ⚠️ компонент недоступен — пересчитываем веса оставшихся к 1.0.


Все формулы держим у соответствующих экранов, чтобы не было двух источников правды. Здесь — обзор: ярус, источник весов, ссылка.

МетрикаГде формулаЯрусБазовая модель
Sleep Score06-sleep-detail.md0 + 1 (timing — 1)Oura Sleep Score (см. §8)
Energy07-energy-detail.md1 (требует HRV/RHR baseline)Oura Readiness contributors
Stress (фоновый)08-stress-detail.md1Garmin Body Battery / Polar Stress — или метрика кольца, решаем по данным
Stress (замер «сейчас»)08-stress-detail.md1 или 0Та же шкала, что фон (ярус 1), либо Baevsky SI (ярус 0) — после валидации A4
Battery (Lumo)04-battery-detail.md1 (через Energy + Stress)Garmin Body Battery
Здоровье05-health-detail.md2Oura Resilience
Lumo Age05-health-detail.md2Композит, см. §8

Что отдаём на экране 11-raw-metrics.md и какие пороги используем для алертов / окрашивания.

МетрикаЯрусАбсолютный порог (ярус 0)Персональный baseline (ярус 1)
HR (день)0< 40 brady, > 100 покой — алерт—
HR (тренировка)0HR-зоны от max HR = 220 − возрастУточняем измеренным max за 60 дней
RHR (ночной)0 + 1< 40 / > 90 — алертΔ vs personal baseline (±5 bpm заметно)
HRV (RMSSD)1— (нет универсального порога)Δ vs personal 14-day baseline в %
SpO20< 90% тревожно, < 95% во сне — насторожитьсяΔ vs personal ночной baseline
Температура (кожа)1— (кожная температура на пальце 33–36°C, абсолютного порога нет)Δ ночного среднего vs personal night baseline (±0.5°C — паттерн)

Правило подачи raw: для ярус-0 показываем абсолютное значение + цвет по порогу. Для ярус-1 показываем абсолютное значение, но интерпретация («норма / выше / ниже») — только после baseline.

Исключение — температура. Абсолютное значение не показываем вообще: только отклонение ночного среднего от личной нормы (+0.3°C), как Oura, и статус «в вашем диапазоне / выше / ниже», как Whoop. До 14 ночей — без числа.


Пользователь может вручную измерить через детальные экраны. Вопрос: использовать ли эти точки в композитных формулах или они только для самоощущения?

ИзмерениеИсточникИспользование в формулахИспользование в UI
Живой пульсЖивой замер пульса❌ нет (формулы используют расписание и ночь)Точечный snapshot
Живой SpO2Живой замер SpO2❌ нет (Sleep Score использует ночной)Snapshot + история ручных замеров
«Стресс сейчас»Живой замер пульса: RMSSD, IBI, стресс кольца❌ не входит в фоновый Stress scoreОтдельный snapshot на экране Стресса, сравнение с последним часом — если шкала та же
HRV живого замераЖивой замер пульса⚠️ кандидат: заменить им дневную HRV этого дняSnapshot
Разовая температураКоманда кольцу❌ нет❌ не показываем: дневная кожная температура несравнима с ночной нормой

Решение для v1: ручные измерения — отдельный канал, не вмешиваются в композитные скоры. Иначе один невозможный замер посреди дня сломает Energy/Battery.

Открыто: HRV живого замера — единственный кандидат на интеграцию в формулы: минута неподвижного замера точнее 15-секундного по расписанию. Решаем после валидации A4 и первых пользователей.


Что видит пользователь на разных стадиях накопления данных:

ДеньЧто доступноЧто скрыто / fallback
1Sleep Score (если поспал в кольце), HR, SpO2 с абсолютными порогамиEnergy / Stress / Battery / Здоровье — плашка «Накапливаем данные». Температура — без числа до 14 ночей
3+ первые тренды HR / SpO2 / SleepТе же
7+ ранний Sleep Score уверенный, ранний proxy Energy на population baselineStress / Battery — всё ещё плашка
14✅ Полный набор: Energy, Stress, Battery, baseline-зависимые rawЗдоровье — ещё нет
30✅ ЗдоровьеLumo Age — ещё нет
90✅ Lumo Age—

Это в т.ч. ответ на вопрос продаж: «А когда уже будет польза от кольца?» — конкретные ответы по дням.


8. Веса формул — обоснование на референсах

Заголовок раздела «8. Веса формул — обоснование на референсах»

Текущие веса в формулах (Energy, Sleep Score, Здоровье, Lumo Age) — округлённые, требуют валидации на ≥100 пользователях после запуска. Базируются на следующих публичных решениях:

Sleep Score (наша формула — 7 компонентов). Опирается на Oura Sleep Score: те же 7 компонентов (Total / Efficiency / REM / Deep / Restfulness / Latency / Timing). Точные веса Oura не публикует, но в их whitepaper и help-центре указано, что Total Sleep и Efficiency — доминирующие. Наши 0.25 / 0.15 для них консистентны. WASO выделили отдельным компонентом (0.10) — клинический маркер фрагментации, отсутствует у Oura, но есть у медицинских стандартов (AASM).

Energy (наша формула — 5 компонентов: Sleep / HRV / RHR / Temp / Activity). Аналог Oura Readiness. Oura использует 8 contributors, мы свернули в 5 (объединили sleep score / sleep balance, выкинули recovery index, требующий ночных RR). Наш вес Sleep 0.40 близок к доминирующему вкладу сна у Oura (по их breakdown — крупнейший контрибьютор). HRV 0.30 + RHR 0.15 = 0.45 на сердечные сигналы — близко к Whoop Recovery, где HRV — основной фактор (~50%+).

Stress (фоновый). Путь Garmin Body Battery / Polar Stress: эвристика на HRV vs personal baseline + HR + исключение активного движения. Точные формулы Garmin/Polar закрыты (Firstbeat — проприетарный алгоритм), но принцип «HRV ниже baseline → стресс выше» документирован в их whitepapers. Наша реализация = тот же принцип.

Stress on-demand (Baevsky SI) — кандидат. Академическая формула из российской/советской космической медицины (Баевский Р.М., 1979–2000е). Используется в Polar OwnRelax, упоминается в современных исследованиях по HRV. Норма 80–150, рост ×1.5–10 при стрессе. Главное отличие от фонового: даёт точечный snapshot за 2–3 минуты, а не балансное значение. Требует ряда интервалов по каждому удару — возможен, только если живой замер SR28D его отдаёт (валидация A4). Иначе замер считаем той же формулой, что фон.

Battery (Lumo). Аналог Garmin Body Battery: стартовое значение = утренний Energy, в течение дня drain от стресса/нагрузки, charge от отдыха. Наша формула проще (нет Firstbeat-математики), но архитектура совпадает.

Тренировку считаем по модели Welltory: она тратит заряд как нагрузка, но снимает накопленный сидячий стресс и даёт буфер от следующего. У Garmin похоже: заряд уходит в активности, стресс меряется только в покое. Два канала не пересекаются: нагрузка считается только на активных отрезках, стресс — только на сидячих.

Здоровье (14 дней). Аналог Oura Resilience, Whoop Recovery Trend, Polar Sleep Plus 7-day trend. Все строятся на 14–28-дневной агрегации тех же базовых сигналов. Наши веса (0.40 / 0.30 / 0.20 / 0.10) — приоритет Восстановления (HRV+RHR) > Стресса > Сна > Активности — соответствует логике Oura: устойчивость = в первую очередь автономная нервная система.

Lumo Age. Композит без прямого аналога. Reverse-fit к паспортному возрасту по 5 сигналам (см. 05-health-detail.md). Веса доминируют RHR (0.40) — научно обоснованно: RHR — самый сильный одиночный предиктор сердечно-сосудистого возраста (см. Cooper Clinic Longitudinal Study). HRV-trend (0.20) — второй валидированный сигнал. Остальные веса — рабочие, требуют калибровки на референсной когорте.


Батарейку тратят два канала: drain_стресс на сидячих отрезках и drain_нагрузка на активных. Чтобы избежать рекурсии, фиксируем направление потока:

Вариант А — свой расчёт: Вариант Б — метрика кольца:
RMSSD истории (раз в 5 мин) stress кольца 0–1 (история)
vs личная база 14 дней × 100
+ пульс
+ интенсивность активности
(активные отрезки исключаются) + интенсивность активности
↓ ↓
Stress score (0–100, карточка) — только сидячие отрезки
↓
Накопленный сидячий стресс S (2 часа, Stress > 50)
− обнуление тренировкой − буфер после неё
↓
drain_стресс ─────┐
├──→ Battery (0–100)
drain_нагрузка ───┘
↑
Интенсивность кольца за 5 минут
или зона пульса в тренировке — только активные отрезки

Активный это отрезок или сидячий — решает интенсивность кольца за 5 минут, режим тренировки кольца и тренировки из Apple Здоровья. Механика S и буфера — в 08-stress-detail.md, стартовые значения нагрузки — в 04-battery-detail.md.

Какой вариант — решаем по сверке на сэмпле (валидация A4: кольцо, свой, Oura daily_stress). Вход в Батарейку в обоих случаях — готовый Stress score. Stress score не использует Battery — петли нет.

Порог накопления S — Stress score > 50 (граница «Повышенный» из 08-stress-detail.md).


Сводка TBD из всех экранов, чтобы не искать по 7 файлам:

  • Веса формул — все текущие веса (0.40 / 0.30 / …) требуют калибровки на ≥100 пользователях после запуска. До этого — round-numbers по аналогии с Oura/Whoop.
  • Перевод значений в 0–100 перед взвешиванием — итог каждой метрики (Энергия, Sleep Score, Activity Score) — взвешенное среднее её составляющих, веса заданы. Не задано, как сырое значение превращается в балл 0–100 до умножения на вес: «HRV +5% к норме», «пульс покоя −1», «температура −0,1°» в одних единицах не складываются. Стартуем с линейных функций вокруг личной нормы и калибруем на данных в процессе использования (решение 2026-09-27).
  • Cold-start fallback на популяционные нормы — нужна таблица RHR/HRV ожидаемых по возрасту/полу. Источник: NHANES / Garmin user data tables / академические работы. Не сделано.
  • Пульс покоя — берём у SleepV4 (пульс покоя за ночь). Сверить с Oura lowest_heart_rate на сэмпле; если расходится — свой расчёт по минимуму устойчивого окна.
  • HRV живого замера → замена дневной HRV — оставлено на v1.1 после первых пользователей.
  • Стресс: кольцо или свой — см. §9, решаем по данным.
  • PPG sample rate — закрыто: у SR28D сырой PPG 25 / 50 / 100 Гц, только при подключении. Cardio Age возможен только как ручной замер, v2.
  • Dynamic порог «высокого стресса» для Battery — сейчас S копится выше фиксированных 50 (граница «Повышенный»). Возможно стоит делать персональным (75-й перцентиль личного распределения за 14 дней).
  • Коэффициенты Батарейки — все каналы (бодрствование, нагрузка, накопленный стресс, сидение, отдых) в таблице 04, снятие стресса и буфер — в 08. Стартовые значения, калибруем на сэмпле против Garmin Body Battery и Welltory. Сама модель решена 2026-09-28: тренировка тратит заряд и снимает накопленный стресс. Моки приложения считаются этой же формулой (BatteryModel).

Версия: 0.3 Последнее обновление: 2026-09-28