const LOW_PCT = 0.5; const HIGH_PCT = 0.85; module.exports = { slug: "target-heart-rate-zones", title: "Target heart rate zones", deck_category: "health", description: "Estimates a moderate-to-vigorous target heart rate zone using the percentage-of-max method, and also the Karvonen (heart rate reserve) method when resting heart rate is given.", inputs: [ { name: "age_years", type: "number", unit: "years", required: true, description: "Age in years", min: 0 }, { name: "resting_hr", type: "number", unit: "bpm", required: false, description: "Resting heart rate, enables the Karvonen method", min: 0 } ], outputs: [ { name: "hr_max", unit: "bpm", description: "Estimated maximum heart rate (220 minus age)" }, { name: "pctmax_low", unit: "bpm", description: "Lower bound of the percentage-of-max zone (50%)" }, { name: "pctmax_high", unit: "bpm", description: "Upper bound of the percentage-of-max zone (85%)" }, { name: "karvonen_low", unit: "bpm", description: "Lower bound of the Karvonen zone (50% of heart rate reserve), only when resting_hr given" }, { name: "karvonen_high", unit: "bpm", description: "Upper bound of the Karvonen zone (85% of heart rate reserve), only when resting_hr given" } ], steps: [ "hr_max = 220 - age_years.", "Percentage-of-max method: pctmax_low = 0.50 * hr_max, pctmax_high = 0.85 * hr_max.", "If resting_hr is given, Karvonen method: heart_rate_reserve = hr_max - resting_hr; karvonen_low = resting_hr + 0.50 * heart_rate_reserve; karvonen_high = resting_hr + 0.85 * heart_rate_reserve.", "Round every bpm value to the nearest whole number." ], constants: [ { name: "age_coefficient_hrmax", value: 220, unit: "bpm", source: 0 }, { name: "moderate_low_pct", value: 0.5, unit: "fraction", source: 1 }, { name: "vigorous_high_pct", value: 0.85, unit: "fraction", source: 1 } ], sources: [ { kind: "edition_page", value: "Fox SM, Naughton JP, Haskell WL. Physical activity and the prevention of coronary heart disease. Ann Clin Res. 1971;3(6):404-432.", title: "Origin of the 220-minus-age maximum heart rate estimate", publisher: "Annals of Clinical Research", retrieved_utc: "2026-09-30T19:35:00Z", note: "Widely used estimate for hr_max; also see Karvonen M, Kentala E, Mustala O. The effects of training on heart rate. Ann Med Exp Biol Fenn. 1957;35:307-315 for the heart-rate-reserve method." }, { kind: "url", value: "https://www.heart.org/en/healthy-living/exercise-and-physical-activity/fitness-basics/target-heart-rates", title: "Target Heart Rates Chart", publisher: "American Heart Association", retrieved_utc: "2026-09-30T22:29:13Z", note: "Confirmed live at this final URL (the site redirected the older /fitness/fitness-basics/ path here); moderate intensity is about 50-70% of hr_max and vigorous intensity is about 70-85%; this card reports the full 50% to 85% band as the general target zone." } ], disclaimer: "General formula only. Not medical advice. Dosing decisions belong to a licensed clinician and the product's label.", questionText(inputs) { const restPart = (inputs.resting_hr !== undefined && inputs.resting_hr !== null) ? ` with a resting heart rate of ${inputs.resting_hr} bpm` : ""; return `What are the target heart rate zones for a ${inputs.age_years}-year-old${restPart}?`; }, run(inputs) { const { age_years, resting_hr } = inputs; if (typeof age_years !== "number" || age_years <= 0) throw new Error("age_years must be a positive number"); const hrMaxRaw = 220 - age_years; const hrMax = Math.round(hrMaxRaw); const pctLow = Math.round(LOW_PCT * hrMaxRaw); const pctHigh = Math.round(HIGH_PCT * hrMaxRaw); const values = { hr_max: hrMax, pctmax_low: pctLow, pctmax_high: pctHigh }; let answer = `HRmax ${hrMax} bpm; percent-of-max zone ${pctLow}-${pctHigh} bpm`; if (resting_hr !== undefined && resting_hr !== null) { if (typeof resting_hr !== "number" || resting_hr < 0) throw new Error("resting_hr must be a non-negative number if provided"); const hrr = hrMaxRaw - resting_hr; const karLow = Math.round(resting_hr + LOW_PCT * hrr); const karHigh = Math.round(resting_hr + HIGH_PCT * hrr); values.karvonen_low = karLow; values.karvonen_high = karHigh; answer += `; Karvonen zone ${karLow}-${karHigh} bpm`; } return { answer, values }; }, examples: [ { name: "worked example", inputs: { age_years: 40, resting_hr: 65 }, expected: { answer: "HRmax 180 bpm; percent-of-max zone 90-153 bpm; Karvonen zone 123-163 bpm" }, check: "hr_max = 220-40 = 180. pctmax: 0.5*180=90, 0.85*180=153. HRR = 180-65=115. Karvonen low = 65+0.5*115=65+57.5=122.5, JS Math.round rounds half up to 123. Karvonen high = 65+0.85*115=65+97.75=162.75 rounds to 163." }, { name: "test vector: no resting heart rate", inputs: { age_years: 25 }, expected: { answer: "HRmax 195 bpm; percent-of-max zone 98-166 bpm" }, check: "hr_max = 220-25=195. 0.5*195=97.5 rounds to 98. 0.85*195=165.75 rounds to 166." } ] };