open_oura评分复现:如何用线性校准拟合Oura的0-100睡眠、准备度与活动分数

发布时间:2026/11/5 6:35:00
open_oura评分复现:如何用线性校准拟合Oura的0-100睡眠、准备度与活动分数

【免费下载链接】open_oura

A Rust toolkit for the Oura Ring (Gen 3/4/5): reverse-engineered BLE protocol, event decoders, and reimplemented>项目地址:https://gitcode.com/gh_mirrors/op/open_oura

点击查看免费下载

open_oura 是一个面向 Oura Ring(Gen 3/4/5)的 Rust 工具包,本项目用线性校准方法,从一份 Oura 账户的 Trends 导出 CSV 中,反推出 0–100 分制 Sleep Score、Readiness Score 与 Activity Score 的组合权重与子分数曲线,并能在本地无云环境实时复算你的睡眠分数。整个过程不需要阅读反编译代码,只要一条回归。

为什么 Oura 的分数可以离线复现?

一个关键发现:Oura 的三个 0–100 分数不是在云端算的。它们由手机里的原生ecore引擎(libappecore.so)在本地计算后上传,云端只负责存储与同步。这意味着只要拿到分数公式,就可以完全离线复算(见 docs/algorithms/README.md)。

但权重表无法直接从反编译产物中干净读出,于是项目采用了更稳妥的路径——校准(calibration):

Trends 导出 CSV 里,每一天同时包含「最终分数」和「各贡献因子子分数」,这正是回归分析需要的成对样本。

整体思路分两层:

层内容拟合方法
第一层:组合权重最终分 =round(Σ wᵢ·子分ᵢ / 100),权重和为 100无截距 OLS 线性回归
第二层:贡献因子曲线每个子分 = fᵢ(原始指标)单调用 isotonic 回归,非单调用分箱经验曲线,多输入用线性拟合

准备数据:导出 Oura Trends CSV

线性校准对样本量有要求,建议300 天以上的完整导出(项目验证用了 336–348 天):

  1. 登录 Oura 网页账户 → 设置 → 数据导出,选择 Trends 趋势导出;
  2. 得到的 CSV 放到仓库的local/trends.csv,或直接用--csv参数指定路径;
  3. 安装依赖:
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt

如果需要拉取代码,克隆地址为https://gitcode.com/gh_mirrors/op/open_oura。

第一步:线性回归恢复组合权重

运行权重恢复脚本 tools/fit_scores.py:

python tools/fit_scores.py local/trends.csv

它把每个最终分数对它的贡献因子子分数做无截距回归(np.linalg.lstsq),回归系数和 ≈1.0 恰好证实了「加权平均」的结构。实测结果:

分数R²最大误差结论
Sleep Score0.99870.8 分✅ 几乎精确
Readiness Score0.96912.6 分◐ 线性 + 少量非线性
Activity Score0.90411 分◐ 分段组合,线性近似

恢复出的睡眠分数权重:Total Sleep 35%、Restfulness 15%、其余 5 项(Efficiency / REM / Deep / Latency / Timing)各 10%。完整的三张权重表见 docs/algorithms/score-weights.md。

第二步:拟合子分数曲线,端到端复现睡眠分

权重只是第一层——Trends 里的子分数本身也是原始指标(睡眠时长、HRV、温度偏差等)的确定性函数。tools/fit_sleep_score.py 为每个贡献因子挑选合适的曲线类型:

  • 单调指标(总睡眠时长、效率、REM、深睡)→isotonic 回归(Pool-Adjacent-Violators 算法),留出集 R² 达 0.98–1.00;
  • 非单调指标(入睡潜伏期)→ 分箱经验曲线,它实际上是一条U 型曲线:太短和太长都被扣分;
  • 多输入指标(Restfulness、Sleep Timing)→ 线性拟合,其中睡眠时相是一个昼夜节律峰值曲线,中点落在 ~03:00 时得分最高,另叠加 7 天节律稳定性项。

留出 20% 天数的端到端验证结果:

Sleep Score 端到端 R²=0.964,RMSE 1.38,84% 的天数误差不超过 ±1 分,94% 不超过 ±3 分。

残差集中在两个贡献因子上:Restfulness(15% 权重,真实输入是 Oura 内部基于运动信号的 restful 时段计数,CSV 中只有聚合值)和 Sleep Timing 的个人节律理想点。这是数据粒度墙,不是方法问题。

三项分数总览与「基线墙」

tools/fit_scores_all.py 把同一套方法扩展到全部三个分数,并为基线相对型贡献因子(HRV Balance、Resting HR、Sleep/Activity Balance)构造「今日值 vs 近 14 天均值」的滞后特征:

分数ceiling(权重×真实子分)achieved(权重×我方子分)差距原因
Sleep0.9980.969两个微观输入缺失
Readiness0.9410.49~50% 权重依赖 14 天个人基线轨迹
Activity0.8380.0624% 权重绑定个性化每日目标,训练量是多日累积

结论很清晰:权重全部恢复正确(ceiling 证明),端到端差距几乎全部来自需要「累积历史」的贡献因子,而非缺失的逻辑。

校准一次,持久本地:实时评分流程

校准只做一次,结果持久化,运行时不再依赖 CSV:

# 一次性校准:trends 导出 → local/score_params.json python tools/calibrate_scores.py --csv local/trends.csv # 每晚:原始事件 → 每日摘要 + 滚动基线(写入 oura.db 的 daily_summary) python tools/build_daily.py # 实时评分(无需云端) python tools/score_sleep.py # 或 oura sleep-score python tools/score_readiness.py # 或 oura readiness-score
  • tools/calibrate_scores.py 只保留「戒指可推导」的驱动列(LIVE_DRIVERS),把权重 + 每条曲线序列化为local/score_params.json(个人校准文件,gitignore 在本地);
  • tools/score_sleep.py 用 SleepNet 生成睡眠图,再走「曲线 → 子分 → 加权求和」三步,例如最近一晚 471 分钟睡眠、91% 效率 →Sleep Score 82;
  • tools/score_readiness.py 从daily_summary读数;历史不足 14 天时会自动标注「⚠ baselines still maturing — provisional」,基线成熟后 Readiness 就和 Sleep 一样实时可用。

管道细节见 docs/algorithms/daily-summaries-and-baselines.md。

新手常见坑与排查清单 📋

现象原因处理
提示找不到 CSV未导出或路径不对放到local/trends.csv或传--csv
拟合样本太少导出天数不足、有缺失行用 300+ 天的完整导出,脚本会跳过不完整行
列名对不上Oura 官方列名自带拼写错误Sleep Timin Score保持 CSV 原样,不要「修正」表头
Readiness 偏低不稳基线冷启动(<14 天)每晚同步 + 重跑build_daily.py,等基线成熟
想换更长导出校准是个人生理参数重新运行calibrate_scores.py覆盖即可

小结:这条路径能走多远

  1. 权重层:三个分数全部恢复,Sleep R²=0.9987 近乎位级精确;
  2. 曲线层:Sleep 端到端 R²=0.969、84% 天数 ±1 分内,日常使用完全够用;
  3. 实时层:Sleep 今日即可实时复算,Readiness 在 14 天基线成熟后同样实时,Activity 因个性化目标与多日训练量仍属「权重已解、暂不实时」。

对新手来说,最大的收获是方法论:当公式读不出来时,用真实数据回归出它——一份 Trends 导出 + 两条回归命令,就能得到你专属的 0–100 分模型。

延伸阅读

  • 权重与曲线全表:docs/algorithms/score-weights.md
  • 算法移植状态总览:docs/algorithms/README.md
  • 每日摘要与基线机制:docs/algorithms/daily-summaries-and-baselines.md
  • Rust 客户端入口:crates/README.md

【免费下载链接】open_oura

A Rust toolkit for the Oura Ring (Gen 3/4/5): reverse-engineered BLE protocol, event decoders, and reimplemented>项目地址:https://gitcode.com/gh_mirrors/op/open_oura

点击查看免费下载

相关推荐

上一篇:不用网格,10 分钟出图:Brush 高斯泼溅 3D 重建完整指南
下一篇:免费自托管的可视化数据库:NocoDB 快速上手指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考