筋トレの疲労度を、アプリでどうモデル化したか
自社の筋トレアプリ fit-ai に「筋肉疲労スコア」を実装した記録。回復を指数関数で近似し、部位別に半減期を変え、直近7日間だけを集計する――その3つの割り切りを、開発者の立場から正直に書きます。
「今日はどの部位を鍛えるか」を、数字で答えたい。そのために自社の筋トレアプリ fit-ai へ、過去の履歴から部位ごとの疲労を 0〜100 で返す「筋肉疲労スコア」を実装しました。
でも正直に言うと、これは生理学的に正確なモデルではありません。 むしろ――正確さを、どこで諦めるか。それを決める作業でした。
fatigue_calculator という一つの計算ロジックに落とし込むまでに、 3つの割り切りを置いています。
効果を語る記事ではありません。 設計判断の記録として、開発した立場から正直に書き残します。
🎯なぜ「疲労」を数値にしたかったか
「今日は何を避けるか」に、記録アプリは答えてくれない。使い手としての、そのもどかしさが出発点でした。
筋トレを続けていると気づきます。 記録アプリはたいてい、「何をやったか」しか教えてくれません。
セット数も重量もログには残る。 なのに「じゃあ今日は何を避けるべきか」には、答えてくれない。 私自身が使い手として、ここに一番のもどかしさを感じていました。
そこで fit-ai では、過去のトレーニング履歴から部位ごとの「疲労が残っている度合い」を推定し、 0 から 100 のスコアで返すことにしました。 高ければ休ませる、低ければ鍛えてよい。ただそれだけの、単純な信号です。
難しい理論を積み上げるより、まず一つの数字にする。 そこを優先しました。
📉割り切り その1: 回復を指数関数で近似する
回復のカーブを、指数関数的な減衰で近似する。半減期ひとつで直感的に扱える割り切りを選びました。
最初の割り切りは、回復のカーブを指数関数的な減衰で表したことです。 トレーニング直後に生まれた疲労が、時間とともに一定の割合で減っていく、と仮定しました。
実際の筋損傷と修復のプロセスは、もっと複雑です。 でもアプリが扱うのは「相対的にどちらの部位が疲れているか」。 なめらかに減っていく曲線があれば、実用上はそれで足りました。
なぜ指数減衰なのか。理由はシンプルです。 パラメータが「半減期」ひとつで済み、直感的に扱えるから。
線形に減らす案も試しました。 けれど、休養が進んだ後半で回復が急に頭打ちになるのが不自然で―― 指数のほうが、実感に近い滑らかさになりました。
⏱️割り切り その2: 部位ごとに回復の半減期を変える
大きな筋群は回復が遅く、小さな筋群は早い――その順序関係を、半減期の初期値に反映させました。
次の割り切りは、回復のスピードを部位ごとに変えたことです。 大きな筋群は回復に時間がかかり、小さな筋群は比較的早く戻る。 この一般的な経験則に沿って、半減期を部位別に置きました。
実装では、脚や背中のような大筋群を長め、腕や肩のような小さめの部位を短めに。 そんな配分にしています。
運動後の筋機能の低下と回復には数十時間単位の幅があることは、筋損傷の研究でも報告されています(Exercise-Induced Muscle Damage のレビュー(PMC))。
ただ、狙いは論文値を厳密に再現することではありません。 「大筋群のほうが戻りが遅い」という順序関係を、アプリの挙動に反映させること。 数字そのものは、使いながら直していく前提の初期値です。
📅割り切り その3: 直近7日間だけを見る
指数減衰なら1週間前の疲労はほぼ無視できる。だから集計の窓を、直近7日間に絞りました。
3つ目は、集計の窓を直近7日間に区切ったことです。 理屈のうえでは、何ヶ月も前のトレーニングもわずかに影響します。
でも指数減衰なら、1週間もすれば寄与はほぼ無視できる大きさに落ちる。 それなら7日間に絞ったほうが、処理も軽く、コードも読みやすくなります。
あわせて、各エクササイズがどの部位にどれだけ効くかは、 筋電(EMG)的な関与の強さを参考にした重みで振り分けています。 ベンチプレスなら胸に多く、補助的に肩や腕にも少し、という配分です。
7日ぶんの疲労を部位ごとに重みづけして足し合わせ、最後にスコアへ正規化する。 これが fit-ai の疲労計算の骨格です。
🧭正確さより「使える割り切り」を優先した
モデルは「当たっているか」ではなく「意思決定を少し助けるか」で評価する――そう割り切りました。
この3つはいずれも、生理学的な厳密さを犠牲にして、 実装の単純さと説明のしやすさを取った判断です。
私たちは医療機器を作っているわけではありません。 次のトレーニングの助けになる目安を出したいだけ。 だからモデルは「当たっているか」ではなく、「意思決定を少し助けるか」で評価しています。
作ってみて分かったことがあります。 疲労スコアの価値は、絶対値の正しさより、日々の相対的な変化にある――そういうことでした。
昨日より脚のスコアが下がっていれば鍛えどき。 そんなふうに、自分の履歴と比べる指標として機能します。 数字を過信させないために、UI 側でも「目安」であることを繰り返し伝えるようにしました。
📝まとめ: モデルは割り切りの集合体
疲労スコアは指数減衰・部位別の半減期・7日間の累積という、3つの割り切りでできています。
筋肉疲労スコアは、この3つの割り切りでできています。 どれも「正確だから」ではなく、「そのほうが作れて、説明できて、使えるから」選びました。
個人開発に近い一人会社の規模だからこそ、完璧なモデルを目指すより、 動く目安を早く出して、自分たちで使いながら直す。 そのほうが理にかなっている、と考えています。
モデル化とは、現実のどこを捨ててよいかを決める作業でもあります。 疲労という曖昧なものを一つの数字にする過程で、 その割り切りをできるだけ正直に開示しておく。 それが、使う人への誠実さだと思っています。
あなたが何かを数値化するとき、どこを捨てますか。 一度、その割り切りを言葉にしてみてください――きっと、モデルが少し正直になります。
開発パートナーを探していますか?
AIでプロダクトを最速で形にしませんか?
最短1週間でMVPを開発。アイデアの検証から本番リリースまで、i-Willinkがフルサポートします。まずはお気軽にご相談ください。
無料で相談する