openrowingmonitor/docs/README_concept2_predictions.md

11 KiB
Raw Blame History

Wattage predictions

See:

Zones

See:

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 s.min-1 %HRR %2k (W) range
Oxygen Utilisation 2 (UT2) 16-20 65-70 45-60 15%
Oxygen Utilisation 1 (UT1) 20-24 70-80 60-70 10%
Anaerobic Threshold (AT) 24-28 80-85 70-80 10%
VO2 Max/Transport (TR) 28-32 85-95 80-105 25%
Peak Power/Anaerobic (AN) 32+ 95-100 105-115 10%

*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

Example 2

Take the result of example 1 and a zone and provide a suitable training session

Given zone: UT2 is midpoint of range: 0.5*(45+60) = 52.5% of 192W = 101.3W

Given zone: AT: 0.5*(70+80) = 75% of 193W = 144.7W

Examples 3

Return a training zone from a training table

See: parse_ITP_spreadsheet.py for a pandas dataframe parsing and querying the spreadsheet.

Given a level 1-5, a session number and a week number return the associated session eg 3x16'UT1

Available Levels

Level 1 | 3 Sessions | 26 Weeks Level 2 | 3 Sessions | 26 Weeks Level 2 | 4 Sessions | 26 Weeks Level 3 | 4 Sessions | 26 Weeks Level 4 | 4 Sessions | 26 Weeks Level 4 | 5 Sessions | 26 Weeks Level 4 | 6 Sessions | 26 Weeks Level 5 | 6 Sessions | 26 Weeks Level 5 | 7 Sessions | 26 Weeks Level 5 | 8 Sessions | 26 Weeks

cat level-1_3-session_26-weeks.csv

"Interactive 2,000m Programme",,,
2000m 26 Week Training Programme,,,
"Athlete Level 1, 3 Sessions a Week",,,
Week,Session 1,Session 2,Session 3
1,TEST,12'UT2,15'UT2
2,14'UT2,16'UT2,18'UT2
3,17'UT2,19'UT2,20'UT2
4,10'UT1,25'UT2,30'UT2
5,12'UT1,18'UT1,8'AT
6,30'UT2,2x10'UT1,2x7'AT
7,15'UT1,20'UT2,7'AT
8,18'UT1,25UT2,9'AT
9,4x2'TR,30'UT2,2X12'UT1
10,2x2'TR,15'UT1,20'UT2
11,4x2'TR,18'UT1,25'UT2
12,6x2'TR,2X12'UT1,30'UT2
13,TEST,2x3'TR,2x7'AT
14,4x2'TR,16'UT1,25'UT2
15,2x4'TR,2x12'UT1,3x7'AT
16,6x2'TR,2x8'UT1,20'UT2
17,2x9'AT,18'UT1,30'UT2
18,2x10'AT,3x2'TR,20'UT1
19,4x1.5'AN,2x12UT1,2x8'AT
20,3x2'TR,25'UT1,2x9'AT
21,2x4'TR,30'UT2,2x10'AT
22,2x4'TR,15'UT1,2x7'AT
23,30'UT2,18'UT1,2x9'AT
24,3x2'TR,30'UT2,2x12'UT1
25,5x2'TR,6x1.5'AN,3x3'TR
26,2x1.5'AN,3x45s AN,RACE

Interactive 2,000m Programme 2000m 26 Week Training Programme Athlete Level 5, 8 Sessions a Week

Week Session 1 Session 2 Session 3 Session 4 Session 5 Session 6 Session 7 Session 8
1 TEST 2x15'UT1 55'UT2 2x18'UT1 68'UT2 3x15'UT1 55'UT2 2x15'UT1
2 65'UT2 2x21'UT1 72'UT2 3x16'UT1 80'UT2 4x13'UT1 72'UT2 3x12'UT1
3 76'UT2 3x17'UT1 85'UT2 3x19'UT1 90'UT2 3x20'UT1 85'UT2 2x25'UT1
4 45'UT2 2x15'UT1 2x6'AT 3x12'UT1 2x7'AT 3x15'UT1 2x10'AT 3x12'UT2
5 65'UT2 2x24'UT1 4x5'AT 3x16'UT1 3x8'AT 3x18'UT1 2x12'AT 3x16'UT1
6 76'UT2 2x25'UT1 3x7'AT 3x19'UT1 3x10'AT 5x12'UT1 3x8'AT 3x18'UT1
7 45'UT2 2x15'UT1 2x8'AT 3x12'UT1 2x10'AT 3x15'UT1 2x9'AT 2x3'TR
8 65'UT2 3x14'UT1 2x9'AT 75'UT2 2x8' AT 4x14'UT1 2x7'AT 3x4'TR
9 76'UT2 3x17'UT1 3x7'AT 90'UT2 4x5'TR 4X15'UT1 3x8'AT 4x4'TR
10 45'UT2 2x15'UT1 2x8'AT 60'UT2 4x2'TR 3x12'UT1 2x9'AT 3x3'TR
11 65'UT2 3x15'UT1 2x10'AT 75'UT2 4x3'TR 3x15'UT1 2x10'AT 4x3'TR
12 75'UT2 4x15'UT1 3x8'AT 90'UT2 4x4'TR 4x12'UT1 3x10'AT 5x4'TR
13 TEST 2X15'UT1 2x8'AT 60'UT2 3x1'AN 3x15'UT1 2x8'AT 4x2'TR
14 65'UT2 3X15'UT1 2x10'AT 75'UT2 4x1.5'AN 4x12'UT1 3x7'AT 6x2'TR
15 75'UT2 5x12'UT1 3x10'AT 90'UT2 6x1'AN 5x12'UT1 3x10'AT 6x4'TR
16 45'UT2 2X15'UT1 2x9'AT 60'UT2 8x45sAN 4x14'UT1 2x10'AT 5x2'TR
17 65'UT2 3X15'UT1 3x10'AT 75'UT2 6x1.5'AN 3x12'UT1 3x8'AT 6x3'TR
18 75'UT2 4x15'UT1 4x8'AT 90'UT2 8x1'AN 2x15'UT1 4x9'AT 7x4'TR
19 45'UT2 2X15'UT1 2x10'AT 60'UT2 4x1.5'AN 3x12'UT1 3x8'AT 6x2'TR
20 65'UT2 3X15'UT1 3x12'AT 75'UT2 6x1'AN 3x15'UT1 3x10'AT 7x3'TR
21 75'UT2 5x12'UT1 5x8'AT 90'UT2 8x45sAN 5x12'UT1 4x10'AT 8x4'TR
22 45'UT2 2x15'UT1 2x10'AT 60'UT2 8x1.5'AN 3x12'UT1 2x7'AT 4x2'TR
23 65'UT2 3x15'UT1 3x8'AT 75'UT2 10x45sAN 3x15'UT1 3x7'AT 4x3'TR
24 76'UT2 4x15'UT1 4x8'AT 90'UT2 2(6x1')AN 4x15'UT1 2x10'AT 4x4'TR
25 50'UT2 2x12'UT1 6' AT 40'UT2 2x1.5'AN 20'UT2 2x2'TR 3x45sAN
26 OFF 1x15'UT1 5'AT 1x3'TR 20'UT2 2x2'TR 3x45sAN RACE

cat level-5_8-session_26-weeks.csv

"Interactive 2,000m Programme",,,,,,,,
2000m 26 Week Training Programme,,,,,,,,
"Athlete Level 5, 8 Sessions a Week",,,,,,,,
Week,Session 1,Session 2,Session 3,Session 4,Session 5,Session 6,Session 7,Session 8
1,TEST,2x15'UT1,55'UT2,2x18'UT1,68'UT2,3x15'UT1,55'UT2,2x15'UT1
2,65'UT2,2x21'UT1,72'UT2,3x16'UT1,80'UT2,4x13'UT1,72'UT2,3x12'UT1
3,76'UT2,3x17'UT1,85'UT2,3x19'UT1,90'UT2,3x20'UT1,85'UT2,2x25'UT1
4,45'UT2,2x15'UT1,2x6'AT,3x12'UT1,2x7'AT,3x15'UT1,2x10'AT,3x12'UT2
5,65'UT2,2x24'UT1,4x5'AT,3x16'UT1,3x8'AT,3x18'UT1,2x12'AT,3x16'UT1
6,76'UT2,2x25'UT1,3x7'AT,3x19'UT1,3x10'AT,5x12'UT1,3x8'AT,3x18'UT1
7,45'UT2,2x15'UT1,2x8'AT,3x12'UT1,2x10'AT,3x15'UT1,2x9'AT,2x3'TR
8,65'UT2,3x14'UT1,2x9'AT,75'UT2,2x8' AT,4x14'UT1,2x7'AT,3x4'TR
9,76'UT2,3x17'UT1,3x7'AT,90'UT2,4x5'TR,4X15'UT1,3x8'AT,4x4'TR
10,45'UT2,2x15'UT1,2x8'AT,60'UT2,4x2'TR,3x12'UT1,2x9'AT,3x3'TR
11,65'UT2,3x15'UT1,2x10'AT,75'UT2,4x3'TR,3x15'UT1,2x10'AT,4x3'TR
12,75'UT2,4x15'UT1,3x8'AT,90'UT2,4x4'TR,4x12'UT1,3x10'AT,5x4'TR
13,TEST,2X15'UT1,2x8'AT,60'UT2,3x1'AN,3x15'UT1,2x8'AT,4x2'TR
14,65'UT2,3X15'UT1,2x10'AT,75'UT2,4x1.5'AN,4x12'UT1,3x7'AT,6x2'TR
15,75'UT2,5x12'UT1,3x10'AT,90'UT2,6x1'AN,5x12'UT1,3x10'AT,6x4'TR
16,45'UT2,2X15'UT1,2x9'AT,60'UT2,8x45sAN,4x14'UT1,2x10'AT,5x2'TR
17,65'UT2,3X15'UT1,3x10'AT,75'UT2,6x1.5'AN,3x12'UT1,3x8'AT,6x3'TR
18,75'UT2,4x15'UT1,4x8'AT,90'UT2,8x1'AN,2x15'UT1,4x9'AT,7x4'TR
19,45'UT2,2X15'UT1,2x10'AT,60'UT2,4x1.5'AN,3x12'UT1,3x8'AT,6x2'TR
20,65'UT2,3X15'UT1,3x12'AT,75'UT2,6x1'AN,3x15'UT1,3x10'AT,7x3'TR
21,75'UT2,5x12'UT1,5x8'AT,90'UT2,8x45sAN,5x12'UT1,4x10'AT,8X4'TR
22,45'UT2,2x15'UT1,2x10'AT,60'UT2,8x1.5'AN,3x12'UT1,2x7'AT,4x2'TR
23,65'UT2,3x15'UT1,3x8'AT,75'UT2,10x45sAN,3x15'UT1,3x7'AT,4x3'TR
24,76'UT2,4x15'UT1,4x8'AT,90'UT2,2(6x1')AN,4x15'UT1,2x10'AT,4x4'TR
25,50'UT2,2x12'UT1,6' AT,40'UT2,2x1.5'AN,2x15'UT1,4'TR,2x12'UT1
26,OFF,1x15'UT1,5'AT,1x3'TR,20'UT2,2x2'TR,3x45sAN,RACE

cat concept2_prediction.py

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")