# Equation/s used for running training-pace calculators

There are a few popular running training-pace calculators online that all use the same underlying equations:

All underlying calculators are the same: the user enter's their best time for a given distance; and the calculators provide different recommended training paces for: 1) easy runs; tempo / lactate threshold workouts; VO2 max workouts; speed workouts; Yasso 800s; and long runs.

Given that the results are the same for all sites; I know the underlying equations are the same. But what are the equations?

--Edit--

I found the Riegel equation, used to predict the time for a given distance using the time already run for a different distance. This equation might have been used for the above calculators, but I think it is unlikely because the training distances are very short in comparison to the endurance race distances the Riegel method was designed for.

I also don't know what distances the "VO2 max" or "speed form" paces were designed for, so I do not know what distance to enter into the Reigel equation. If I go with the assumption that "VO2 max" pace is good for 800m intervals, things still don't match the calculator results. See example Python code below.

``````def riegel(t1, d1, d2):
t1_seconds = t1*60
d1_meters = d1 * 1000
d2_meters = d2 * 1000
t2_seconds = t1_seconds*(d2_meters/d1_meters)**1.06
v = d2_meters/t2_seconds
v_minutes_per_km = 1/(v*60/1000)
minutes = int(v_minutes_per_km)
seconds = (v_minutes_per_km*60) % 60
return minutes, seconds

# use the function
t1 = 40  # minutes
d1 = 10  # kilometers
d2 = 0.8 # kilometers for interval distance
interval_pace = riegel(t1, d1, d2)
``````

the output interval pace is 3min26s/km, however the calculators return a pace of 3min43s/km.

I don't know anything about running; I haven't gone on a run in 5+ years. However, when inspecting the `Calculate` button from Runner's World, the site runs a function called `runConversion()`. A quick Ctrl+F for that in the source gives us script:

``````<script language="JavaScript">
<!--

var metric;
var VO2max;

function initGlobals() {
metric = false;
VO2Max = -1;
}

function runConversion() {
var frm = document.forms.input1;
// race time in min, length in m and speed in m/min.
var time = document.forms.input1.hours.value * 60 + document.forms.input1.minutes.value * 1 + document.forms.input1.seconds.value / 60;
var rlength = document.forms.input1.length.value;
var speed;

if (time <= 0 || isNaN(time)) {
return;
}

if (rlength <= 0 || isNaN(rlength)) {
return;
}

if (frm.units.options.selected) {
rlength *= 1000;
} else {
rlength *= 1609;
}

speed = rlength / time;

VO2Max = velToVO2(speed) / timeToPercentVO2Max(time);
makeCalculations();
}

function makeCalculations() {

if (VO2Max <= 0) {
return;
}

var velEasy = VO2ToVel(VO2Max * .7);
var velTempo = VO2ToVel(VO2Max * .88);
var velMaximum = VO2ToVel(VO2Max);
var velSpeed = VO2ToVel(VO2Max * 1.1);
var velxlong = VO2ToVel(VO2Max * .6);
var velYasso = velMaximum * 1.95;

var toAppend;
if (metric) {
toAppend = ' min/km';
} else {
toAppend = ' min/mile';
}

var frm = document.forms.input1;

frm.easy.value = '' + timeConvert(velEasy) + toAppend;
frm.tempo.value = '' + timeConvert(velTempo) + toAppend;
frm.maximum.value = '' + timeConvert(velMaximum) + toAppend;
frm.speed.value = '' + timeConvert(velSpeed) + toAppend;
frm.xlong.value = '' + timeConvert(velEasy) + ' - ' + timeConvert(velxlong) + toAppend;
var oldMetric = metric;
metric = false;
frm.yasso.value = '' + timeConvert(velYasso) + ' min/800';
metric = oldMetric;
}

// Toggle output type of paces.
function toggleMetric() {
if (document.forms.input1.paceType.options.selected) {
metric = false;
} else {
metric = true;
}
makeCalculations();
}

// Takes a velocity and converts it to a VO2 level.
function velToVO2(vel) {
return (-4.60 + 0.182258 * vel + 0.000104 * vel * vel);
}

// Takes a VO2 measurement and converts it to a velocity.
function VO2ToVel(VO2) {
return (29.54 + 5.000663 * VO2 - 0.007546 * VO2 * VO2);
}

// Takes a time in minutes and uses EQ 2 to convert it to a percent of VO2 maximum.
function timeToPercentVO2Max(minutes) {
return (.8 + 0.1894393 * Math.exp(-.012778 * minutes) + 0.2989558 * Math.exp(-.1932695 * minutes));
}

// Takes a speed in metres / minute a converts it to a string representing a pace in
// minutes per mile or km.
function timeConvert(speed) {
var ans;
if (!metric) {
ans = (1 / speed) * 1609;
} else {
ans = (1 / speed) * 1000;
}
minutes = Math.floor(ans);
seconds = Math.floor((ans - minutes) * 60);
if (seconds > 9) {
return '' + minutes + ':' + seconds;
} else {
return '' + minutes + ':0' + seconds;
}
}
// -->
</script>
``````

When dissecting this a bit, it looks like every estimate is your calculated V02Max multiplied by varying coefficients. This is then calculated back into a velocity to give you a pace. The calculator found at Helpful Runner gives the same results because it's the identical code pushed into a file.

The V02Max coefficients are:

• Easy = 70% * VO2Max
• Tempo = 88% * V02Max
• Maximum = 100% * VO2Max
• Speed = 110% * VO2Max
• xlong = 60% * VO2Max
• Yasso = Maximum Velocity * 1.95

I'm having a bit more trouble dissecting Omni Calculator but they calculate `velocity_to_V02` using the exact same formula so I'd take a guesstimation that the rest is the same formulae just re-packaged:

from: training-pace.js

``````'use strict';

omni.onResult(['x'], function(ctx, x) {
ctx.hideVariables('base1', 'base2', 'percent_max',
'vo2max', 'vo2', 'easy_vo2','x','y','velocity', 'velocity_easy',
'velocity_vo2max','velocity_tempo', 'velocity_speed', 'velocity_long',
'speed_vo2','tempo_vo2', 'long_vo2' );
});
/*
omni.onInit(function(ctx) {
var countryCode = ctx.getCountryCode();
if (countryCode === 'US') {
ctx.setDefault('result_units_type', '1');
} else {
ctx.setDefault('result_units_type', '0');
}
});

omni.define('velocity_to_vo2', function(_velocity) {
var velocity = _velocity.toNumber();
return (-4.60 + 0.182258 * velocity + 0.000104 * velocity * velocity);
});

omni.define('time_convert', function(_trainingVelocity, _useImperial) {
var trainingVelocity = _trainingVelocity.toNumber();
var useImperial = _useImperial.toNumber();
var trainingPace;
if (useImperial) {
trainingPace = (1 / trainingVelocity) * 1609;
} else {
trainingPace = (1 / trainingVelocity) * 1000;
}
return trainingPace;
});
*/
``````

Unfortunately, I can't find anywhere that specifies that these are the coefficients to be used. No one has really set in stone that an easy run should be 70% of your V02Max. I find a lot of websites that list ranges (i.e. 65-75%). My guess is that this code is simply being passed from one site to the next.

• If anyone has academic sources or wants to tack something onto this I/you/we can gladly make a community wiki. Running is out of my element but I hope this helps or guides you in the right direction. Aug 30, 2020 at 18:07