Add wattage predictions readme and py implementation to docs.
Node.js CI / build (14.x) (push) Waiting to run Details
Node.js CI / build (16.x) (push) Waiting to run Details

This commit is contained in:
cyteen 2024-12-04 15:06:51 +00:00
parent bbef8369ef
commit a5c94a9230
3 changed files with 139 additions and 1 deletions

View File

@ -519,6 +519,7 @@ BLE service). This is displayed as an ECG trace and heart rate graph over time.
### [Quiske RowP App](https://www.rowingperformance.com/tutorial)
The Quiske pod also allows for dynamic rowing on machines such as a Concept2 on slides.
* [Quiske Manual](https://www.rowingperformance.com/blog/the-virtual-coach-evolved)
* [Quiske knows dynamic too](https://www.rowingperformance.com/blog/quiske-coach-knows-dynamic-too)
* [Making Sense of the Data](https://www.rowingperformance.com/blog/making-sense-of-the-data)
@ -546,7 +547,7 @@ is derived from the difference in speed of the seat and handle in the various
stages of the stroke.
[For example](https://www.coachbergenroth.com/improve-your-rowing-with-the-quiske-pod/),
when I approach the catch, I could see that my handle speed and deceleration
when I approach the catch, I could see that my handle speed and deceleration
was different from my seat deceleration. This data indicated to me that I was
not establishing my forward body angle early enough on the recovery.

View File

@ -0,0 +1,52 @@
# Wattage predictions
See [concept2_predictions.py](concept2_predictions.py)
## Zones
Heart rate zones are calculated based on HRR calculated from:
Resting heart rate (RHR) 58
Maximum heart rate (MHR) 165
Heart rate reserve (HRR) (MHR minus RHR) 107
| Training Band | %HRR | %2k (W) | range |
|------------------------------|--------|---------------|-------|
| Oxygen Utilisation 2 (UT2) | 65-70 | 45-60 | 15% |
| Oxygen Utilisation 1 (UT1) | 70-80 | 60-70 | 10% |
| Anaerobic Threshold (AT) | 80-85 | 70-80 | 10% |
| VO2 Max/Transport (TR) | 85-95 | 80-105 | 25% |
| Peak Power/Anaerobic (AN) | 95-100 | 105-115 | 10% |
From [Stumpy](https://thestumpyrower.wordpress.com/rowing-on-the-concept-2-ergometer/56-2/)
| Training Band | s.min1* | %2k (w)** | HRR*** |
|---------------|---------|-----------|--------|
| Oxygen Utilisation 2 | UT2 | 16-20 | 45-60 |
| Oxygen Utilisation 1 | UT1 | 20-24 | 60-70 |
| Anaerobic Threshold | AT | 24-28 | 70-80 |
| VO2 Max/Transport | TR | 28-32 | 80-105 |
| Peak Power/Anaerobic | AN | 32+ | 105-115 |
*s.min-1 is scientific notation for strokes/minute
**%2k (w) is the % of power output, measured in watts of a 2000m test from this it is possible to calculate pace (time/500m)
***HRR% is Heart Rate Reserve %. When resting and maximum heart rates are know it is possible to calculate the heart rate at which one should train to have the most appropriate effect on the bodys systems.
## Example 1
### Heart rate 132 for 110W after 10 minutes
UT2 is 65%-70%, so 128-133 bpm.
132 is 4 (132 minus 128) into UT2 range of 5 (133 minus 128)
UT2 power is 45%-60% of max 2k power.
UT2 power range is 15% (60% minus 45%)
so 132 bmp should be 4 fifths into that 15% = 12%
so expected power is 110W/(45%+12%) = 193W

View File

@ -0,0 +1,85 @@
def calculate_wattage(resting_heart_rate, maximum_heart_rate, heart_rate, base_power_output):
def get_zone_percentile(heart_rate, resting_heart_rate, maximum_heart_rate):
HRR = maximum_heart_rate - resting_heart_rate
zone = ((heart_rate - resting_heart_rate) / HRR) * 100
return round(zone, 2)
def get_hrr_range(zone):
if zone <= 65:
return (0, 65)
elif zone <= 70:
print("UT2 Zone")
return (65, 70)
elif zone <= 80:
print("UT1 Zone")
return (70, 80)
elif zone <= 85:
print("AT Zone")
return (80, 85)
elif zone <= 95:
print("TR Zone")
return (85, 95)
else:
print("AN Zone")
return (95, 100)
def get_power_range(zone):
if zone <= 65:
return (0, 45)
elif zone <= 70:
print("UT2 Zone")
return (45, 60)
elif zone <= 80:
print("UT1 Zone")
return (60, 70)
elif zone <= 85:
print("AT Zone")
return (70, 80)
elif zone <= 95:
print("TR Zone")
return (80, 105)
else:
print("AN Zone")
return (105, 115)
zone_percentage = get_zone_percentile(heart_rate, resting_heart_rate, maximum_heart_rate)
print("Zone: " + str(zone_percentage))
min_power, max_power = get_power_range(zone_percentage)
print("Min power: " + str(min_power))
print("Max power: " + str(max_power))
min_hrr, max_hrr = get_hrr_range(zone_percentage)
print("Min hrr: " + str(min_hrr))
print("Max hrr: " + str(max_hrr))
power_range = max_power - min_power
print("Power range: " + str(power_range))
hrr_range = max_hrr - min_hrr
print("HRR range: " + str(hrr_range))
print("Zone minus min hrr: " + str(zone_percentage - min_hrr))
# Calculate percentage of hrr range
hrr_percentage = ((zone_percentage - min_hrr) / hrr_range)
print("hrr %: " + str(hrr_percentage))
power_percentage = (min_power + hrr_percentage * power_range) / 100
print("Power percentage: " + str(power_percentage))
# Add base power output
# predicted_power = power_percentage + base_power_output
predicted_power = base_power_output / power_percentage
return round(predicted_power, 0)
# Example usage
resting_heart_rate = 58
maximum_heart_rate = 165
heart_rate = 132
base_power_output = 110
watts = calculate_wattage(resting_heart_rate, maximum_heart_rate, heart_rate, base_power_output)
print(f"Predicted power: {watts} watts")