openGym训练中实时检测PR:个人新纪录是怎么被抓到的
【免费下载链接】openGymSelf-hosted gym & body-weight tracker — plan routines, log workouts (supersets, warm-ups, cardio), see which muscles are trained, fatigued or detrained, import from FitNotes/Strong/Hevy, passkey login. Your data, your server.项目地址: https://gitcode.com/GitHub_Trending/op/openGym
openGym 是一款自托管的健身房与自重训练追踪器:你可以规划训练计划、记录训练(超级组、热身、有氧)、查看哪些肌肉被练到、疲劳或生疏,还能从 FitNotes/Strong/Hevy 导入数据。很多人关心一个很燃的细节——PR(个人新纪录)是怎么被自动抓到的?这篇文章带你完整拆解 openGym 的 PR 判定机制:哪些组数算数、辅助器械为什么"越低越好"、改日期后 PR 徽章为什么会重新计算。
什么才算"新纪录":先看判定规则
openGym 的 PR 逻辑核心就一条:完成组中"最好"的那组,超过了该动作历史最高,才算 PR。关键在于"最好"是怎么定义的,它跟随动作的计量模式:
| 动作模式 | PR 比较对象 | 例子 |
|---|---|---|
| 负重(weight) | 最重的完成组 | 深蹲 100kg → 102.5kg 是新纪录 |
| 次数(reps) | 最多完成次数 | 引体向上 8 次 → 9 次是新纪录 |
| 计时(time) | 最长保持 | 平板支撑 60s → 75s 是新纪录 |
| 有氧(cardio) | 训练时长 | 跑步 20min → 25min |
三条硬规则值得注意:
- 热身组一律排除,不参与任何比较;
- 没记录重量不算纪录——
prev为 0 或新值为 0 时都不会触发 PR; - 平纪录不追加徽章:只有"首次达到历史最高"的那一次训练会被标记,之后再举同样重量不会多出一堆奖杯。这条规则写在 exercise-history.js 的注释里:"PR 标在首次达到全时最佳的那次训练上,而不是每次追平它的训练上"。
PR 检测三步骤:记录、结算、标注
1. 记录时不做判断
训练进行中的每一组都只被如实存入日志。判定逻辑被刻意设计成纯函数,与 UI 解耦,方便单独测试。
2. 结束训练时一次性结算
结束训练时,openGym 会对每个动作取出"该次训练中的最佳完成组"(bestWeightForEntry),与该动作的历史最高比较,命中的动作 id 写入该次训练的prs字段——这就是你训练卡片上的 PR 徽章来源:
- 结算入口:finish-workout.js
- "比谁强"的核心函数
beatsWeight:exercises.js
3. 历史页与卡片上的展示
- 动作历史页(issue #43)会把过去 10 次该动作的训练列成曲线,并给
prId(首次破纪录的那次训练)打上 PR 标记,见 exercise-history.js; - 训练卡上的"Best set"(issue #173):回答"上次状态不好,我到底能上多重",它跨所有计划查找该动作的历史最佳组,见 exercise-history.js;
- AI 教练小结里也会统计 "N new personal records",文案见 coach-demo.js。
辅助器械:为什么"重量更低"反而是破纪录
这是 openGym 里最巧妙的一条规则。在坐姿推胸机这类辅助器械上,你输入的不是"扛了多重",而是"机器帮你顶起多重"——帮助越少 = 实力越强。
所以比较方向整个反过来:普通动作是"新值 > 旧值"才破纪录,辅助器械是"新值 < 旧值"(assistance 更小)才算。统一封装在beatsWeight里(exercises.js),行为由配套测试保证:
beatsWeight(推胸机, 20, 30)→ ✅ 新纪录(帮助从 30kg 减到 20kg)beatsWeight(推胸机, 40, 30)→ ❌ 帮助变多,不算beatsWeight(推胸机, 0, 30)→ ❌ 没记录重量不算纪录
完整用例见 assisted.test.js,issue #232 正是这条规则的直接产出。
改了日期,PR 徽章会被"重写"
PR 是关于"之前发生了什么"的声明,所以时间顺序一变,徽章就可能失效。openGym 为此写了专门的rebuildPrHistory(workout-date.js):
- 移动一次训练到新的日期/时间后,所有相关动作的徽章按新时间线重新推导;
- 规则刻意不对称:移动可以取消别人已被推翻的徽章(这是"纠正"),但只有被移动的那次训练能"新获得"徽章(发新徽章是"发明");
- 从 FitNotes/Strong/Hevy 导入的历史数据统一以空徽章入库,这样哪怕你随手挪了一个日期,一年前的导入记录也不会突然冒出一堆奖杯。
这正是 openGym 数据同步模型中"纯函数可测试"思路的体现——同样的机制也保证多设备同步时徽章一致:
小结:PR 机制的四个要点
- 只有完成组参与比较,热身组被排除;
- 按模式选指标:负重比重量、自重比次数、计时比秒数、有氧比分钟;
- 辅助器械反向判定:机器帮助更少才是破纪录(issue #232);
- PR 徽章可重算:移动训练日期会触发全量重推导,平纪录不追加徽章。
如果你想在自己的服务器上跑一套,可以参考自托管指南 docs/SELF_HOSTING.md 与 docker-compose.yml,数据完全掌握在自己手里——你的每一次 PR 也如此。
【免费下载链接】openGymSelf-hosted gym & body-weight tracker — plan routines, log workouts (supersets, warm-ups, cardio), see which muscles are trained, fatigued or detrained, import from FitNotes/Strong/Hevy, passkey login. Your data, your server.项目地址: https://gitcode.com/GitHub_Trending/op/openGym
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考