From a5c11bf173b4862f03ba140bf21461900465fac9 Mon Sep 17 00:00:00 2001 From: cyteen Date: Fri, 6 Dec 2024 21:31:32 +0000 Subject: [PATCH] Small changes to docs. --- docs/README_coach.md | 34 +++- docs/README_concept2_predictions.md | 247 +++++++++++++++++++++++++--- 2 files changed, 251 insertions(+), 30 deletions(-) diff --git a/docs/README_coach.md b/docs/README_coach.md index 8873e2a..1402a85 100644 --- a/docs/README_coach.md +++ b/docs/README_coach.md @@ -375,14 +375,20 @@ data; however, this method easily introduces noise due to friction during motion ##### Holyiot nRF52840 USB Dongle +##### DIY nRF52840 implementing [Reefwing-AHRS](https://github.com/Reefwing-Software/Reefwing-AHRS) to provide reliable roll, pitch and yaw angles. + +* [LSM9DS1](https://www.st.com/en/mems-and-sensors/lsm9ds1.html) 9-axis IMU [Reefwing-LSM9DS1](https://github.com/Reefwing-Software/Reefwing-LSM9DS1) +* [MPU6050](https://invensense.tdk.com/products/motion-tracking/6-axis/mpu-6050/) 6-axis IMU [Reefwing-MPU6050](https://github.com/Reefwing-Software/Reefwing-MPU6050) +* [MPU6500](https://invensense.tdk.com/products/motion-tracking/6-axis/mpu-6500/) 6-axis IMU [Reefwing-MPU6x00](https://github.com/Reefwing-Software/MPU6x00) + ##### Beacon for handle, seat and trunk -| NRF chip | RAM | ROM | Notes | -|----------|-----|-----|-------| -| 52810 | 24k | 192k | BARELY enough RAM for "broadcast only" function | -| 52820 | 32k | 256k | Untested, should work just as the 832 does | -| 52832 | 64/32 KB | 512/256 KB | Enough RAM for additional sensors | -| 52840 | 256 KB | 1 MB | Untested; probably overkill for this application | +| NRF chip | RAM | ROM | Notes | +|----------|----------|------------|-------------------------------------------------| +| 52810 | 24k | 192k | BARELY enough RAM for "broadcast only" function | +| 52820 | 32k | 256k | Untested, should work just as the 832 does | +| 52832 | 64/32 KB | 512/256 KB | Enough RAM for additional sensors | +| 52840 | 256 KB | 1 MB | Untested; probably overkill for this application| * 3x [holyiot 21014]() nRF52810 + lis2dh12 + RGB LED + button * [holyiot 21014 zephyr project](https://github.com/danielstuart14/wlen_project/tree/master/beacon/boards/arm/holyiot_21014) @@ -410,7 +416,10 @@ using a simple camera. * Automatic Rowing Kinematic Analysis Using OpenPose and Dynamic Time Warping] * [An introduction to Dynamic Time Warping](https://rtavenar.github.io/blog/dtw.html) * [dtw-python](https://dynamictimewarping.github.io/py-api/html/index.html) -In order to apply the DTW algorithm, we first need to choose a reference or desired rowing cycle. The paper above chooses to take the rowing cycle from a known good rower, we want to take the rowing cycle from the Biomechanics of Rowing book chapter 4: Technique. + In order to apply the DTW algorithm, we first need to choose a reference or + desired rowing cycle. The paper above chooses to take the rowing cycle from a + known good rower, we want to take the rowing cycle from the Biomechanics of + Rowing book chapter 4: Technique. [Intelligent Performance Evaluation in Rowing Sport Using a Graph-Matching Network](https://pmc.ncbi.nlm.nih.gov/articles/PMC10532480/) This study aimed to develop a video-based approach to analyze the performance of @@ -419,6 +428,17 @@ poses, the OpenPose system was used to extract robust rowing pose features and convert them into a graph structure. Subsequently, the GEM and GMN models were utilized to analyze the similarities in rowing postures between each pair of rowers. +[Inaccurate Action Detection Algorithm for Rowing Machine Exercise Based on +Attention-CNN](https://ieeexplore.ieee.org/iel8/6287639/10380310/10638659.pdf) +Assessing the conformity of a rower’s actions using [OpenPose](https://github.com/CMU-Perceptual-Computing-Lab/openpose) +, [1D CNN](https://www.mdpi.com/2076-3417/14/18/8500) and +[CoT](https://www.ibm.com/topics/chain-of-thoughts) to recognize +whether the movement is standard. + +[1D Convolutional Neural Network Models for Human Activity Recognition](https://machinelearningmastery.com/cnn-models-for-human-activity-recognition-time-series-classification/) +Classifying sequences of accelerometer data recorded by specialized harnesses or +smart phones into known well-defined movements. + ### [Rowsandall](https://analytics.rowsandall.com/) Rowsandall Rowing Data Analytics For our Basic user, the website is Free. Within this package you get diff --git a/docs/README_concept2_predictions.md b/docs/README_concept2_predictions.md index a1db20e..1c620c6 100644 --- a/docs/README_concept2_predictions.md +++ b/docs/README_concept2_predictions.md @@ -1,4 +1,4 @@ -# Wattage predictions +# Wattage predictions See: @@ -7,29 +7,24 @@ See: ## Zones +See: + +* Indoor Rowing Training Guide, Version 2 by Terry O’Neill and Alex Skelton. +* [Interactive_Training_Plans.xlsx](Interact_Training_Plans.xlsx) + 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 | +| 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 @@ -56,9 +51,9 @@ so 132 bmp should be 4 fifths into that 15% = 12% so expected power is 110W/(45%+12%) = 193W -## Example 2 +## Example 2 -### Take the result of example 1 and a zone and provide a suitable training session. +### 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 @@ -66,9 +61,215 @@ Given zone: UT2 is midpoint of range: Given zone: AT: 0.5*(70+80) = 75% of 193W = 144.7W -### Examples 3 +## Examples 3 -### Return a training zone from a [training table](Interactive_Training_Plans.xlsx) Level 5 | 8 sessions | 26 weeks +### Return a training zone from a [training table](Interactive_Training_Plans.xlsx) -Given a level 1-5 and a week number and a session number return the associated +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 + +```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 + +```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 + +```python +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") +```