Module: FitnessPredictor
- Included in:
- Calcpace
- Defined in:
- lib/calcpace/fitness_predictor.rb
Overview
Module for predicting race performances from a VO2max value
This is the inverse of Vo2maxEstimator#estimate_vo2max: instead of asking "what fitness does this race result imply?", it asks "what race result does this fitness imply?".
The Daniels & Gilbert (1979) model cannot be inverted in closed form — the %VO2max term mixes two exponentials of time with a quadratic in velocity — so the finish time is found by bisection on the time axis. VO2max decreases monotonically with time for a fixed distance, which makes the search exact to within the tolerance and guarantees the round trip:
estimate_vo2max(distance, predict_time_from_vo2max(vo2max, distance)) == vo2max
Predicted times reproduce Daniels' published VDOT table within a few seconds for the shorter races and about a minute for the marathon.
Constant Summary collapse
- SUPPORTED_VO2MAX_RANGE =
Range of VO2max values the model is meaningful for. Below it the effort is slower than a walk, above it faster than any human has run — in both cases the resulting "prediction" would be arithmetic, not physiology.
(10.0..100.0)
- FASTEST_PACE_SECONDS_PER_KM =
Bisection bounds, as seconds per kilometre: from 1:00/km (well beyond world record pace) to 20:00/km (slower than walking). They bracket every VO2max in SUPPORTED_VO2MAX_RANGE at any distance.
60.0- SLOWEST_PACE_SECONDS_PER_KM =
1200.0- TIME_TOLERANCE_SECONDS =
Search stops when the bracket is tighter than this many seconds or when the VO2max at the midpoint is this close to the target
0.001- VO2MAX_TOLERANCE =
1e-6- DEFAULT_RACES =
Races reported by #race_times_from_vo2max when none are given
%w[5k 10k half_marathon marathon].freeze
Instance Method Summary collapse
-
#predict_time_from_vo2max(vo2max, race, distance_unit: nil) ⇒ Float
Predicts the finish time a given VO2max is worth over a given race.
-
#predict_time_from_vo2max_clock(vo2max, race, distance_unit: nil) ⇒ String
Predicts the finish time and returns it as a clock time string.
-
#race_times_from_vo2max(vo2max, races: nil, unit: :km) ⇒ Hash{String => Hash}
Builds a full race-time table for one VO2max — one call per dashboard.
Instance Method Details
#predict_time_from_vo2max(vo2max, race, distance_unit: nil) ⇒ Float
estimate_vo2max can report values below 10 for very slow efforts (walking pace); those estimates are outside this predictor's supported range on purpose — a race plan built on them would be meaningless
Predicts the finish time a given VO2max is worth over a given race
64 65 66 67 68 69 70 |
# File 'lib/calcpace/fitness_predictor.rb', line 64 def predict_time_from_vo2max(vo2max, race, distance_unit: nil) target = validated_vo2max(vo2max) distance_km = predicted_race_distance_km(race, distance_unit) check_positive(distance_km, 'Distance') solve_time_for_vo2max(target, distance_km) end |
#predict_time_from_vo2max_clock(vo2max, race, distance_unit: nil) ⇒ String
Predicts the finish time and returns it as a clock time string
79 80 81 |
# File 'lib/calcpace/fitness_predictor.rb', line 79 def predict_time_from_vo2max_clock(vo2max, race, distance_unit: nil) convert_to_clocktime(predict_time_from_vo2max(vo2max, race, distance_unit: distance_unit)) end |
#race_times_from_vo2max(vo2max, races: nil, unit: :km) ⇒ Hash{String => Hash}
Builds a full race-time table for one VO2max — one call per dashboard
99 100 101 102 103 104 105 106 |
# File 'lib/calcpace/fitness_predictor.rb', line 99 def race_times_from_vo2max(vo2max, races: nil, unit: :km) meters = pace_unit_meters(unit) validated_vo2max(vo2max) Array(races || DEFAULT_RACES).to_h do |race| [normalize_race_key(race), race_time_entry(vo2max, race, meters)] end end |