calcpace 1.8.2 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/Gemfile.lock +1 -1
- data/README.md +42 -2
- data/lib/calcpace/cameron_predictor.rb +108 -0
- data/lib/calcpace/version.rb +1 -1
- data/lib/calcpace.rb +2 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 510953dda84be6757bd902b5dbb76752b362241abd69e47f1f321f0eaaa0c7e4
|
|
4
|
+
data.tar.gz: 3c8487adbd99edc3e5588b2c220f199a07a016d447cf768b9a1cc1474aec6b9e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 24f353d01da23bca0cb84a12070b7db967499fde606dfc247afcfc071dd7f791e42c9c746f1adb5a1beee1e0b1031b52721ae4739b7928824489fb63d957b0d8
|
|
7
|
+
data.tar.gz: eca2e3ea93439300bd9253832db99e6e1aad1b4008ec8dc0ef50881e73b5cc00587c38549a13cd5e795793e1f84afd76b23ee010afe10f9dfea7d47eb4adbf58
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.9.0] - 2026-03-24
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Cameron race predictor (`CameronPredictor` module) — alternative to Riegel for predicting race times
|
|
12
|
+
- `predict_time_cameron` — predicts race time in seconds using the Cameron formula
|
|
13
|
+
- `predict_time_cameron_clock` — same, returned as `HH:MM:SS` string
|
|
14
|
+
- `predict_pace_cameron` — predicted pace in seconds per kilometer
|
|
15
|
+
- `predict_pace_cameron_clock` — same, returned as `HH:MM:SS` string
|
|
16
|
+
- Formula: `T2 = T1 × (D2/D1) × [f(D1) / f(D2)]` where `f(d) = a + b × e^(-d/c)`, constants calibrated for km
|
|
17
|
+
- The exponential correction is larger when predicting from shorter distances, reflecting the greater anaerobic contribution at shorter race distances
|
|
18
|
+
- Accepts the same input formats as `RacePredictor`: string (`HH:MM:SS`, `MM:SS`) or numeric seconds
|
|
19
|
+
- 18 test cases covering standard predictions, round-trip consistency, clock format outputs, and error handling
|
|
20
|
+
|
|
8
21
|
## [1.8.2] - 2026-03-07
|
|
9
22
|
|
|
10
23
|
### Added
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Calcpace [](https://badge.fury.io/rb/calcpace)
|
|
2
2
|
|
|
3
3
|
Calcpace is a Ruby gem designed for calculations and conversions related to distance and time. It can calculate velocity, pace, total time, and distance, accepting time in various formats, including HH:MM:SS. The gem supports conversion to 42 different units, including kilometers, miles, meters, and feet. It also provides methods to validate input.
|
|
4
4
|
|
|
@@ -7,7 +7,7 @@ Calcpace is a Ruby gem designed for calculations and conversions related to dist
|
|
|
7
7
|
### Add to your Gemfile
|
|
8
8
|
|
|
9
9
|
```ruby
|
|
10
|
-
gem 'calcpace', '~> 1.
|
|
10
|
+
gem 'calcpace', '~> 1.9'
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Then run:
|
|
@@ -308,6 +308,46 @@ The formula works best for:
|
|
|
308
308
|
- Results are estimates - actual performance varies by individual fitness, training focus, and race conditions
|
|
309
309
|
- The formula is most accurate when predicting between similar distance ranges (e.g., 10K to half marathon)
|
|
310
310
|
|
|
311
|
+
### Race Time Predictions — Cameron Formula
|
|
312
|
+
|
|
313
|
+
An alternative predictor using the **Cameron formula**, which applies an exponential correction based on the known distance. Unlike Riegel's fixed power-law exponent, Cameron's correction is larger when predicting from shorter races (where anaerobic capacity plays a bigger role) and diminishes as the known distance increases.
|
|
314
|
+
|
|
315
|
+
```ruby
|
|
316
|
+
calc = Calcpace.new
|
|
317
|
+
|
|
318
|
+
# Predict marathon time from 10K
|
|
319
|
+
calc.predict_time_cameron_clock('10k', '00:42:00', 'marathon')
|
|
320
|
+
# => "02:57:46"
|
|
321
|
+
|
|
322
|
+
# Predict 10K from 5K
|
|
323
|
+
calc.predict_time_cameron_clock('5k', '00:20:00', '10k')
|
|
324
|
+
# => "00:42:24"
|
|
325
|
+
|
|
326
|
+
# Get predicted pace per km
|
|
327
|
+
calc.predict_pace_cameron_clock('10k', '00:42:00', 'marathon')
|
|
328
|
+
# => "00:04:13"
|
|
329
|
+
|
|
330
|
+
# Raw seconds (useful for further calculations)
|
|
331
|
+
calc.predict_time_cameron('5k', '00:20:00', 'half_marathon')
|
|
332
|
+
# => 5382.7 (approximately 1:29:42)
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
#### How the Cameron Formula Works
|
|
336
|
+
|
|
337
|
+
**Formula:** `T2 = T1 × (D2/D1) × [(a + b × e^(-D1/c)) / (a + b × e^(-D2/c))]`
|
|
338
|
+
|
|
339
|
+
Where:
|
|
340
|
+
- **T1** = known time, **D1** = known distance (km)
|
|
341
|
+
- **T2** = predicted time, **D2** = target distance (km)
|
|
342
|
+
- **a = 0.000495**, **b = 0.000985**, **c = 1.4485** (empirical constants)
|
|
343
|
+
|
|
344
|
+
The exponential correction factor `f(d) = a + b × e^(-d/c)` decreases as distance grows. When predicting from a short race to a long one, `f(D1) > f(D2)`, making `T2` grow slightly faster than a pure linear extrapolation — accounting for the greater fatigue at longer distances.
|
|
345
|
+
|
|
346
|
+
**Compared to Riegel:**
|
|
347
|
+
- Predicting from short distances (5K): Cameron tends to be more conservative (slower prediction) — acknowledges that 5K speed has a larger anaerobic component
|
|
348
|
+
- Predicting from moderate distances (10K): Cameron tends to be slightly more optimistic — 10K is already a strong predictor of marathon aerobic capacity
|
|
349
|
+
- Both formulas are estimates; real performance depends on training specificity, conditions, and individual physiology
|
|
350
|
+
|
|
311
351
|
### Other Useful Methods
|
|
312
352
|
|
|
313
353
|
Calcpace also provides other useful methods:
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Module for predicting race times using the Cameron formula
|
|
4
|
+
#
|
|
5
|
+
# An alternative to the Riegel formula (RacePredictor module) that uses an
|
|
6
|
+
# exponential correction to better account for physiological differences across
|
|
7
|
+
# distances. The correction is larger when predicting from shorter races, where
|
|
8
|
+
# anaerobic contribution is greater, and diminishes as the known distance approaches
|
|
9
|
+
# the target distance.
|
|
10
|
+
#
|
|
11
|
+
# Formula: T2 = T1 × (D2/D1) × [(a + b × e^(-D1/c)) / (a + b × e^(-D2/c))]
|
|
12
|
+
#
|
|
13
|
+
# Constants (calibrated for distances in km):
|
|
14
|
+
# a = 0.000495
|
|
15
|
+
# b = 0.000985
|
|
16
|
+
# c = 1.4485
|
|
17
|
+
#
|
|
18
|
+
# Reference: Dave Cameron, "A Critical Examination of Racing Predictions" (1997)
|
|
19
|
+
module CameronPredictor
|
|
20
|
+
# Cameron formula constants (calibrated for distances in km)
|
|
21
|
+
CAMERON_A = 0.000495
|
|
22
|
+
CAMERON_B = 0.000985
|
|
23
|
+
CAMERON_C = 1.4485
|
|
24
|
+
|
|
25
|
+
# Predicts race time using the Cameron formula
|
|
26
|
+
#
|
|
27
|
+
# @param from_race [String, Symbol] known race distance ('5k', '10k', 'half_marathon', 'marathon', etc.)
|
|
28
|
+
# @param from_time [String, Numeric] time achieved at known distance (HH:MM:SS or seconds)
|
|
29
|
+
# @param to_race [String, Symbol] target race distance to predict
|
|
30
|
+
# @return [Float] predicted time in seconds
|
|
31
|
+
# @raise [ArgumentError] if races are invalid or distances are the same
|
|
32
|
+
#
|
|
33
|
+
# @example Predict marathon time from 10K
|
|
34
|
+
# predict_time_cameron('10k', '00:42:00', 'marathon')
|
|
35
|
+
# #=> ~10,666 seconds (approximately 2:57:46)
|
|
36
|
+
#
|
|
37
|
+
# @example Predict 10K time from 5K
|
|
38
|
+
# predict_time_cameron('5k', '00:20:00', '10k')
|
|
39
|
+
# #=> ~2,544 seconds (approximately 42:24)
|
|
40
|
+
def predict_time_cameron(from_race, from_time, to_race)
|
|
41
|
+
from_distance = race_distance(from_race)
|
|
42
|
+
to_distance = race_distance(to_race)
|
|
43
|
+
|
|
44
|
+
if from_distance == to_distance
|
|
45
|
+
raise ArgumentError,
|
|
46
|
+
"From and to races must be different distances (both are #{from_distance}km)"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
time_seconds = from_time.is_a?(String) ? convert_to_seconds(from_time) : from_time
|
|
50
|
+
check_positive(time_seconds, 'Time')
|
|
51
|
+
|
|
52
|
+
# Cameron formula: T2 = T1 × (D2/D1) × [cameron_factor(D1) / cameron_factor(D2)]
|
|
53
|
+
time_seconds * (to_distance / from_distance) *
|
|
54
|
+
(cameron_factor(from_distance) / cameron_factor(to_distance))
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Predicts race time using the Cameron formula, returned as a clock time string
|
|
58
|
+
#
|
|
59
|
+
# @param from_race [String, Symbol] known race distance
|
|
60
|
+
# @param from_time [String, Numeric] time achieved at known distance
|
|
61
|
+
# @param to_race [String, Symbol] target race distance to predict
|
|
62
|
+
# @return [String] predicted time in HH:MM:SS format
|
|
63
|
+
#
|
|
64
|
+
# @example
|
|
65
|
+
# predict_time_cameron_clock('10k', '00:42:00', 'marathon')
|
|
66
|
+
# #=> '02:57:46'
|
|
67
|
+
def predict_time_cameron_clock(from_race, from_time, to_race)
|
|
68
|
+
convert_to_clocktime(predict_time_cameron(from_race, from_time, to_race))
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Predicts pace per kilometer using the Cameron formula
|
|
72
|
+
#
|
|
73
|
+
# @param from_race [String, Symbol] known race distance
|
|
74
|
+
# @param from_time [String, Numeric] time achieved at known distance
|
|
75
|
+
# @param to_race [String, Symbol] target race distance to predict
|
|
76
|
+
# @return [Float] predicted pace in seconds per kilometer
|
|
77
|
+
#
|
|
78
|
+
# @example
|
|
79
|
+
# predict_pace_cameron('5k', '00:20:00', 'marathon')
|
|
80
|
+
# #=> ~255.1 (approximately 4:15/km)
|
|
81
|
+
def predict_pace_cameron(from_race, from_time, to_race)
|
|
82
|
+
predict_time_cameron(from_race, from_time, to_race) / race_distance(to_race)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Predicts pace per kilometer using the Cameron formula, returned as a clock time string
|
|
86
|
+
#
|
|
87
|
+
# @param from_race [String, Symbol] known race distance
|
|
88
|
+
# @param from_time [String, Numeric] time achieved at known distance
|
|
89
|
+
# @param to_race [String, Symbol] target race distance to predict
|
|
90
|
+
# @return [String] predicted pace in HH:MM:SS format
|
|
91
|
+
#
|
|
92
|
+
# @example
|
|
93
|
+
# predict_pace_cameron_clock('5k', '00:20:00', 'marathon')
|
|
94
|
+
# #=> '00:02:32'
|
|
95
|
+
def predict_pace_cameron_clock(from_race, from_time, to_race)
|
|
96
|
+
convert_to_clocktime(predict_pace_cameron(from_race, from_time, to_race))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
# Computes the Cameron exponential correction factor for a given distance
|
|
102
|
+
#
|
|
103
|
+
# @param distance_km [Float] distance in kilometers
|
|
104
|
+
# @return [Float] correction factor value
|
|
105
|
+
def cameron_factor(distance_km)
|
|
106
|
+
CAMERON_A + (CAMERON_B * Math.exp(-distance_km / CAMERON_C))
|
|
107
|
+
end
|
|
108
|
+
end
|
data/lib/calcpace/version.rb
CHANGED
data/lib/calcpace.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'calcpace/calculator'
|
|
4
|
+
require_relative 'calcpace/cameron_predictor'
|
|
4
5
|
require_relative 'calcpace/checker'
|
|
5
6
|
require_relative 'calcpace/converter'
|
|
6
7
|
require_relative 'calcpace/converter_chain'
|
|
@@ -33,6 +34,7 @@ require_relative 'calcpace/race_splits'
|
|
|
33
34
|
# @see https://github.com/0jonjo/calcpace
|
|
34
35
|
class Calcpace
|
|
35
36
|
include Calculator
|
|
37
|
+
include CameronPredictor
|
|
36
38
|
include Checker
|
|
37
39
|
include Converter
|
|
38
40
|
include ConverterChain
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: calcpace
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- João Gilberto Saraiva
|
|
@@ -31,6 +31,7 @@ files:
|
|
|
31
31
|
- calcpace.gemspec
|
|
32
32
|
- lib/calcpace.rb
|
|
33
33
|
- lib/calcpace/calculator.rb
|
|
34
|
+
- lib/calcpace/cameron_predictor.rb
|
|
34
35
|
- lib/calcpace/checker.rb
|
|
35
36
|
- lib/calcpace/converter.rb
|
|
36
37
|
- lib/calcpace/converter_chain.rb
|
|
@@ -61,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
61
62
|
- !ruby/object:Gem::Version
|
|
62
63
|
version: '0'
|
|
63
64
|
requirements: []
|
|
64
|
-
rubygems_version: 4.0.
|
|
65
|
+
rubygems_version: 4.0.6
|
|
65
66
|
specification_version: 4
|
|
66
67
|
summary: A Ruby gem for pace, distance, and time calculations.
|
|
67
68
|
test_files: []
|