Training Load & Recovery Calculator

ANALife Services AuthorityNational Calculator Authority›Training Load & Recovery Calculator

.calc-container { max-width: 640px; margin: 2rem 0; padding: 1.5rem; background: #fff; border: 1px solid #ddd; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); font-family: system-ui, -apple-system, sans-serif; } .calc-container h3 { font-family: Georgia, serif; font-size: 1.15rem; color: #1a1a1a; margin-bottom: 1rem; padding-bottom: 0.5rem; border-bottom: 2px solid var(--ac, #3d5a80); } .calc-row { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.75rem; flex-wrap: wrap; } .calc-row label { min-width: 160px; font-size: 0.9rem; color: #333; font-weight: 500; } .calc-row input[type="number"], .calc-row select { flex: 1; min-width: 120px; max-width: 200px; padding: 0.5rem 0.6rem; border: 1px solid #ccc; border-radius: 4px; font-size: 0.9rem; font-family: system-ui, sans-serif; color: #1a1a1a; background: #fafaf8; } .calc-row input:focus, .calc-row select:focus { outline: none; border-color: var(--ac, #3d5a80); box-shadow: 0 0 0 2px rgba(26,74,138,0.12); } .calc-row .unit { font-size: 0.82rem; color: #888; min-width: 30px; } .calc-btn { display: inline-block; margin-top: 0.5rem; padding: 0.55rem 1.5rem; background: var(--ac, #3d5a80); color: #fff; border: none; border-radius: 4px; font-size: 0.9rem; font-weight: 600; cursor: pointer; font-family: system-ui, sans-serif; } .calc-btn:hover { opacity: 0.9; } .calc-result { margin-top: 1.25rem; padding: 1rem 1.25rem; background: #f0f6fc; border-left: 3px solid var(--ac, #3d5a80); border-radius: 0 6px 6px 0; display: none; } .calc-result.visible { display: block; } .calc-result-label { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; color: #666; margin-bottom: 0.25rem; } .calc-result-value { font-size: 1.6rem; font-weight: 700; color: var(--ac, #3d5a80); } .calc-result-detail { font-size: 0.85rem; color: #555; margin-top: 0.5rem; line-height: 1.5; } .calc-note { margin-top: 1rem; font-size: 0.8rem; color: #888; font-style: italic; } .calc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; margin-top: 0.75rem; } .calc-grid-item { padding: 0.6rem 0.8rem; background: #f8f9fa; border-radius: 4px; border: 1px solid #eee; } .calc-grid-item .label { font-size: 0.75rem; color: #888; text-transform: uppercase; letter-spacing: 0.04em; } .calc-grid-item .value { font-size: 1.1rem; font-weight: 600; color: #1a1a1a; } @media (max-width: 720px) { .calc-row { flex-direction: column; align-items: flex-start; gap: 0.3rem; } .calc-row label { min-width: auto; } .calc-row input[type="number"], .calc-row select { max-width: 100%; width: 100%; } .calc-grid { grid-template-columns: 1fr; } } .calc-chart { margin: 1rem 0; text-align: center; } .calc-chart svg { max-width: 100%; height: auto; } .calc-chart-legend { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.6rem 1.2rem; margin-top: 0.6rem; font-size: 0.8rem; color: #555; } .calc-chart-legend span { display: inline-flex; align-items: center; gap: 0.3rem; } .calc-chart-legend i { display: inline-block; width: 10px; height: 10px; border-radius: 2px; font-style: normal; } .calc-related { max-width: 640px; margin: 2rem 0 1rem; padding: 1.25rem 1.5rem; background: #f8f9fa; border: 1px solid #e8e8e8; border-radius: 8px; } .calc-related h3 { font-family: Georgia, serif; font-size: 1rem; color: #1a1a1a; margin: 0 0 0.75rem; padding-bottom: 0.4rem; border-bottom: 2px solid var(--ac, #3d5a80); } .calc-related-list { list-style: none; padding: 0; margin: 0 0 0.75rem; display: grid; grid-template-columns: 1fr 1fr; gap: 0.4rem 1.5rem; } .calc-related-list li a { font-size: 0.88rem; color: var(--ac, #3d5a80); text-decoration: none; } .calc-related-list li a:hover { text-decoration: underline; } .calc-browse-all { margin: 0.5rem 0 0; font-size: 0.9rem; font-weight: 600; } .calc-browse-all a { color: var(--ac, #3d5a80); text-decoration: none; } .calc-browse-all a:hover { text-decoration: underline; } @media (max-width: 720px) { .calc-related-list { grid-template-columns: 1fr; } }

Training Load & Recovery Calculator

Calculate your Acute Training Load (ATL), Chronic Training Load (CTL), Training Stress Balance (TSB), and estimated recovery time using the Banister impulse-response model.

Session RPE (1–10 scale)

Rate of Perceived Exertion for today's session

Session Duration (minutes)

Total training time in minutes

Previous ATL (Acute Training Load)

Your ATL from yesterday (0 if starting fresh)

Previous CTL (Chronic Training Load)

Your CTL from yesterday (0 if starting fresh)

ATL Time Constant (days)

Typically 7 days (short-term fatigue window)

CTL Time Constant (days)

Typically 42 days (long-term fitness window)

Resting Heart Rate (bpm)

Measured this morning before getting up

Baseline Resting HR (bpm)

Your normal well-rested resting heart rate

Sleep Quality (1–10)

1 = very poor, 10 = excellent

Muscle Soreness (1–10)

1 = none, 10 = severe DOMS

Calculate Training Load & Recovery

function traCalc() { // --- Gather inputs --- const rpe = parseFloat(document.getElementById('tra-session-rpe').value); const duration = parseFloat(document.getElementById('tra-duration').value); const atlPrev = parseFloat(document.getElementById('tra-atl-prev').value); const ctlPrev = parseFloat(document.getElementById('tra-ctl-prev').value); const atlTau = parseFloat(document.getElementById('tra-atl-days').value); const ctlTau = parseFloat(document.getElementById('tra-ctl-days').value); const rhr = parseFloat(document.getElementById('tra-rhr').value); const rhrBaseline = parseFloat(document.getElementById('tra-rhr-baseline').value); const sleep = parseFloat(document.getElementById('tra-sleep').value); const soreness = parseFloat(document.getElementById('tra-soreness').value);

const resultDiv = document.getElementById('tra-result');

// --- Validation --- const errors = []; if (isNaN(rpe) || rpe 10) errors.push("Session RPE must be between 1 and 10."); if (isNaN(duration) || duration 600) errors.push("Duration must be between 1 and 600 minutes."); if (isNaN(atlPrev) || atlPrev 14) errors.push("ATL time constant must be between 1 and 14 days."); if (isNaN(ctlTau) || ctlTau 60) errors.push("CTL time constant must be between 14 and 60 days."); if (isNaN(rhr) || rhr 100) errors.push("Resting heart rate must be between 30 and 100 bpm."); if (isNaN(rhrBaseline) || rhrBaseline 100) errors.push("Baseline resting HR must be between 30 and 100 bpm."); if (isNaN(sleep) || sleep 10) errors.push("Sleep quality must be between 1 and 10."); if (isNaN(soreness) || soreness 10) errors.push("Muscle soreness must be between 1 and 10."); if (!isNaN(atlTau) && !isNaN(ctlTau) && atlTau >= ctlTau) errors.push("ATL time constant must be less than CTL time constant.");

if (errors.length > 0) { resultDiv.style.display = 'block'; resultDiv.innerHTML = 'Please fix the following:' + errors.map(e => '').join('') + ''; return; }

// ============================================================ // CORE FORMULAS — Banister Impulse-Response Model // ============================================================

// 1. Training Stress Score (session load) — sRPE method // TRIMP_sRPE = RPE × Duration (arbitrary units, AU) const trimp = rpe * duration;

// 2. ATL (Acute Training Load) — exponentially weighted moving average // ATL_today = ATL_prev × e^(-1/τ_ATL) + TRIMP × (1 − e^(-1/τ_ATL)) const atlDecay = Math.exp(-1 / atlTau); const atl = atlPrev * atlDecay + trimp * (1 - atlDecay);

// 3. CTL (Chronic Training Load) — exponentially weighted moving average // CTL_today = CTL_prev × e^(-1/τ_CTL) + TRIMP × (1 − e^(-1/τ_CTL)) const ctlDecay = Math.exp(-1 / ctlTau); const ctl = ctlPrev * ctlDecay + trimp * (1 - ctlDecay);

// 4. Training Stress Balance (TSB) = CTL − ATL (positive = fresh, negative = fatigued) const tsb = ctl - atl;

// 5. ATL:CTL Ratio (monotony / overreaching risk indicator) const atlCtlRatio = ctl > 0 ? atl / ctl : null;

// 6. Heart Rate Variability proxy — HR elevation above baseline // HRV_delta = RHR_today − RHR_baseline const hrDelta = rhr - rhrBaseline;

// 7. Recovery Score (composite, 0–100) // Weighted combination of: // - TSB normalised (40% weight) // - Sleep quality (30% weight) // - Soreness (20% weight) // - HR elevation (10% weight) // // TSB component: map TSB to 0–100 // TSB ≥ +20 → 100, TSB ≤ −40 → 0, linear between const tsbScore = Math.min(100, Math.max(0, ((tsb + 40) / 60) * 100)); const sleepScore = ((sleep - 1) / 9) * 100; const sorenessScore = ((10 - soreness) / 9) * 100; // HR elevation: 0 bpm above baseline → 100, ≥10 bpm above → 0 const hrScore = Math.min(100, Math.max(0, ((10 - hrDelta) / 10) * 100));

const recoveryScore = (tsbScore * 0.40) + (sleepScore * 0.30) + (sorenessScore * 0.20) + (hrScore * 0.10);

// 8. Estimated recovery time (hours) // Base: 24 h × (1 − recoveryScore/100) × scaling factor // Minimum 4 h, maximum 96 h const recoveryHours = Math.min(96, Math.max(4, 24 * (1 - recoveryScore / 100) * 4));

// 9. Recommended next session intensity (% of max effort) // Based on recovery score let recommendedIntensity, intensityLabel; if (recoveryScore >= 80) { recommendedIntensity = "85–100%"; intensityLabel = "High intensity / competition"; } else if (recoveryScore >= 60) { recommendedIntensity = "65–84%"; intensityLabel = "Moderate–high intensity"; } else if (recoveryScore >= 40) { recommendedIntensity = "45–64%"; intensityLabel = "Low–moderate (aerobic base)"; } else { recommendedIntensity = "Rest or 1.5) { overreachRisk = "HIGH — Significant overreaching risk"; overreachColor = "#e74c3c"; } else if (atlCtlRatio > 1.3) { overreachRisk = "MODERATE — Monitor closely"; overreachColor = "#e67e22"; } else if (atlCtlRatio > 1.0) { overreachRisk = "LOW-MODERATE — Productive overload"; overreachColor = "#f1c40f"; } else { overreachRisk = "LOW — Well within capacity"; overreachColor = "#27ae60"; } }

// 11. TSB zone classification let tsbZone, tsbColor; if (tsb > 25) { tsbZone = "Transition / Detraining risk"; tsbColor = "#3498db"; } else if (tsb >= 5) { tsbZone = "Optimal Performance / Race Ready"; tsbColor = "#27ae60"; } else if (tsb >= -10) { tsbZone = "Productive Training Zone"; tsbColor = "#f1c40f"; } else if (tsb >= -30) { tsbZone = "Overreaching / High Fatigue"; tsbColor = "#e67e22"; } else { tsbZone = "Overtraining Risk"; tsbColor = "#e74c3c"; }

// Recovery score colour const recColor = recoveryScore >= 70 ? "#27ae60" : recoveryScore >= 45 ? "#e67e22" : "#e74c3c";

// ============================================================ // OUTPUT // ============================================================ resultDiv.style.display = 'block'; resultDiv.innerHTML = ` ### Training Load & Recovery Results

Session Load (sRPE TRIMP) ${trimp.toFixed(0)} AU RPE ${rpe} × ${duration} min

Acute Training Load (ATL) ${atl.toFixed(1)} AU 7-day fatigue window (τ = ${atlTau}d)

Chronic Training Load (CTL) ${ctl.toFixed(1)} AU 42-day fitness window (τ = ${ctlTau}d)

Training Stress Balance (TSB) ${tsb >= 0 ? '+' : ''}${tsb.toFixed(1)} ${tsbZone}

${atlCtlRatio !== null ? `

ATL:CTL Ratio ${atlCtlRatio.toFixed(2)} ${overreachRisk} ` : ''}

HR Elevation Above Baseline ${hrDelta >= 0 ? '+' : ''}${hrDelta} bpm ${hrDelta > 7 ? '⚠ Significant — consider rest' : hrDelta > 3 ? 'Mild elevation — monitor' : 'Normal range'}

Recovery Score ${recoveryScore.toFixed(0)} / 100

TSB 40% · Sleep 30% · Soreness 20% · HR 10%

Estimated Recovery Time ${recoveryHours.toFixed(0)} hours ≈ ${(recoveryHours / 24).toFixed(1)} days

Recommended Next Session ${recommendedIntensity} ${intensityLabel}

Score Breakdown: TSB component: ${tsbScore.toFixed(0)}/100  |  Sleep: ${sleepScore.toFixed(0)}/100  |  Soreness: ${sorenessScore.toFixed(0)}/100  |  HR: ${hrScore.toFixed(0)}/100

`; }

#### Formulas Used

1. Session Load (sRPE TRIMP): TRIMP = RPE × Duration (min) — Foster et al. (2001) session-RPE method.

2. Acute Training Load (ATL) — short-term fatigue: ATLtoday = ATLprev × e−1/τATL + TRIMP × (1 − e−1/τATL) Default τATL = 7 days.

3. Chronic Training Load (CTL) — long-term fitness: CTLtoday = CTLprev × e−1/τCTL + TRIMP × (1 − e−1/τCTL) Default τCTL = 42 days.

4. Training Stress Balance (TSB): TSB = CTL − ATL Positive = fresh/recovered; Negative = fatigued.

5. ATL:CTL Ratio: Ratio = ATL / CTL — Values >1.5 indicate high overreaching risk.

6. Recovery Score (composite 0–100): Score = (TSB_score × 0.40) + (Sleep_score × 0.30) + (Soreness_score × 0.20) + (HR_score × 0.10) TSB mapped: TSB ≥ +20 → 100, TSB ≤ −40 → 0.

7. Estimated Recovery Time: Hours = clamp(24 × (1 − Score/100) × 4, 4, 96)

#### Assumptions & References

More Calculators

Read Next

Building Vs Contents Coverage Allocator ANA › Life Services Authority › National Calculator Authority › Building vs Contents Coverage Allocator .calc-container {...

Study Time Planner ANA › Life Services Authority › National Calculator Authority › Study Time Planner .calc-container { max-width: 640px; margin:...

References