Running 5:00/km on flat ground is not the same effort as running 5:00/km up a 10% grade. The aerobic cost per meter is dramatically different. Grade-Adjusted Pace (GAP) converts your actual pace on hilly terrain into the flat-ground pace that would require the same metabolic cost. It's the foundation of meaningful running performance analysis.

Why flat pace comparison fails

Consider two athletes who both run 1 hour on courses with significant elevation. Athlete A runs a flat loop and averages 4:45/km. Athlete B runs a hilly route and also averages 4:45/km. Athlete B worked dramatically harder. Comparing average paces makes them look equivalent.

rTSS, NGP, and any meaningful training load calculation needs to account for the actual aerobic cost of each kilometer, not just the elapsed time per kilometer. That requires a model of how energy expenditure changes with grade.

The Minetti 2002 model

Alberto Minetti and colleagues published a 2002 paper in the Journal of Applied Physiology that measured the metabolic cost of running at various grades. They fit a fifth-degree polynomial to the data:

Cr(i) = 155.4i⁵ - 30.4i⁴ - 43.3i³ + 46.3i² + 19.5i + 3.6

Where i is the grade (slope, not percentage — so 10% grade = 0.10), and Cr(i) is the metabolic cost in J/kg/m (joules per kilogram per meter of horizontal distance traveled).

At flat grade (i = 0): Cr(0) = 3.6 J/kg/m. This is the baseline metabolic cost of running on flat ground.

Computing GAP

GAP converts actual pace to flat-equivalent pace by adjusting for the ratio of current metabolic cost to flat metabolic cost:

function minetti(grade: number): number {
  const i = Math.max(-0.45, Math.min(0.45, grade));
  return (
    155.4 * i ** 5 -
    30.4 * i ** 4 -
    43.3 * i ** 3 +
    46.3 * i ** 2 +
    19.5 * i +
    3.6
  );
}

const CR_FLAT = minetti(0); // 3.6

function gradeAdjustedPace(paceMPerSec: number, grade: number): number {
  const costRatio = minetti(grade) / CR_FLAT;
  return paceMPerSec / costRatio;
}

If you're running at 3.0 m/s (5:33/km) up a 10% grade:

minetti(0.10) ≈ 7.38 J/kg/m
costRatio = 7.38 / 3.6 ≈ 2.05
GAP = 3.0 / 2.05 ≈ 1.46 m/s (≈ 11:25/km flat equivalent)

That 5:33/km uphill effort is metabolically equivalent to running 11:25/km on flat ground. Intuitively correct — climbing 10% is roughly twice the aerobic cost of running flat.

Practical effect on pace adjustments

Common grade adjustments using the Minetti model:

GradeCost ratioPace adjustment (approx)
+4%1.36×+~90 sec/km equivalent
+8%1.83×+~215 sec/km equivalent
-4%0.84×-~50 sec/km equivalent (slightly easier)
-10%0.89×-~33 sec/km equivalent (downhill costs nearly as much)

The asymmetry of uphill vs. downhill is the key insight from Minetti's data. Steep downhill running is not proportionally easier — the eccentric muscle loading (quads resisting gravity) keeps the metabolic cost high. At grades steeper than about -20%, the metabolic cost starts rising again.

Implementation in pacelore

GAP is computed per sample in the activity's 1Hz stream. Each sample has an instantaneous grade derived from the elevation change between adjacent GPS points. The Minetti function is applied per sample, producing a GAP value for each second of the run.

The per-sample GAP values feed into two downstream computations:

  • NGP (Normalized Graded Pace): a 30-second rolling average of GAP, raised to the 4th power, averaged, and 4th-rooted. Same algorithm as Normalized Power, applied to GAP values. NGP is the input to rTSS.
  • Average GAP: the simple mean of per-sample GAP values, shown on the activity detail page alongside actual average pace. Useful for comparing trail runs against road runs.

Grade clamping

The Minetti polynomial was fit to data collected on grades between -0.45 and +0.45 (i.e., ±45%). GPS elevation noise can produce instantaneous grade spikes well beyond this range. pacelore clamps grade to [-0.45, 0.45] before applying the Minetti function. Spikes beyond this range are likely GPS artifacts, not actual terrain. The elevation stream is also low-pass filtered before grade computation.