Python Fitanalysis Save

Python library for analysis of ANT/Garmin .fit files

Project README

fitanalysis

fitanalysis is a Python library for analysis of ANT/Garmin .fit files.

It's geared toward cycling and allows for easy extraction of data such as the following from a .fit file:

  • elapsed time
  • moving time
  • average heart rate
  • average power
  • normalized power (based on information publicly available about TrainingPeaks' NP®)
  • intensity (based on information publicly available about TrainingPeaks' IF®)
  • training stress (based on information publicly available about TrainingPeaks' TSS®)

My impetus for this project was to better understand how platforms like TrainingPeaks analyze power and heart rate data to arrive at an estimation of training stress. As such, this project attempts to match those platforms' calculations as closely as possible.

Dependencies and installation

Pandas, NumPy, and fitparse are required.

python setup.py install (or python setup.py install --user) to install.

Example

fitanalysis provides the Activity class.

import fitanalysis

activity = fitanalysis.Activity('my_activity.fit')

print activity.elapsed_time
print activity.moving_time

# Also available for heart rate and cadence
print activity.mean_power

print activity.norm_power

# Intensity and training stress calculations require
# a functional threshold power value (in Watts)
print activity.intensity(310)
print activity.training_stress(310)

Construction of an Activity parses the .fit file and detects periods of inactivity, as such periods must be removed from the data for heart rate-, cadence-, and power-based calculations.

Comparison of activity analysis platforms

Here is a comparison for a few of my rides of varying profiles across the various platforms.

fitanalysis TrainingPeaks Garmin Connect Strava
Ride 1: epic ride
126.5 mi
15207 ft climbing
Elapsed time 12:19:40 * 12:19:20 12:19:40
Moving time 9:07:14 - 9:06:12 9:09:26
Mean power 182 W 183 W 183 W 183 W
Norm. power 232 W 232 W 232 W -
Intensity 0.74 0.74 0.74 -
Training stress 504.0 505.1 503.2 -
Ride 2: interval workout
11.9 mi
1352 ft climbing
Elapsed time 1:32:34 * 1:32:34 1:32:34
Moving time 57:17 - 57:11 57:51
Mean power 172 W 168 W 168 W 172 W
Norm. power 289 W 286 W 287 W -
Intensity 0.93 0.92 0.92 -
Training stress 81.7 82.3 83.1 -
Ride 3: tempo
25.4 mi
2451 ft climbing
Elapsed time 2:09:02 2:08:58 2:08:58 2:09:02
Moving time 1:32:39 - 1:32:23 1:32:43
Mean power 201 W 201 W 201 W 202 W
Norm. power 270 W 269 W 270 W -
Intensity 0.86 0.86 0.87 -
Training stress 115.3 114.1 115.1 -
Ride 4: "coffee pace"
13.4 mi
902 ft climbing
Elapsed time 1:41:24 1:41:23 1:41:23 1:41:24
Moving time 57:15 - 57:02 57:23
Mean power 138 W 139 W 139 W 139 W
Norm. power 251 W 252 W 252 W -
Intensity 0.80 0.81 0.81 -
Training stress 61.6 61.6 61.2 -

- Data not available on this platform

* Didn't calculate. TrainingPeaks doesn't directly report elapsed time so it has to be manually summed from lap durations, and these rides have lots of laps.

Conclusions

  • Garmin Connect is the most aggressive when calculating moving time, Strava is the most lenient, and fitanalysis falls in between.
  • Mean power calculated by fitanalysis is at most 1 W different than mean power calculated by another platform.
  • Normalized power calculated by fitanalysis is at most 2 W different than normalized power calculated by another platform.
  • Training stress calculated by fitanalysis corresponds well to other platforms across a large range.

Autopause and inactivity handling

All of the activities in the table above were recorded with autopause enabled, so they don't highlight any differences in how each platform handles long periods of inactivity. To test this I recorded a ride with autopause disabled, and then used fitanalysis to analyze it in two ways: detecting and removing periods of inactivity (the default for fitanalysis), and leaving the data as-is. This activity includes a 2-minute period of inactivity, in addition to shorter stops e.g. at stop lights.

fitanalysis
(inactivity removed)
fitanalysis
(inactivity not removed)
TrainingPeaks Garmin Connect Strava
Elapsed time 34:54 34:54 34:54 34:54 34:54
Moving time 30:48 34:54 - 30:57 31:12
Mean power 247 W 219 W 220 W 220 W 248 W
Norm. power 279 W 271 W 272 W 272 W -
Intensity 0.89 0.87 0.87 0.87 -
Training stress 41.1 43.8 43.6 43.7 -

Average power with periods of inactivity removed matches Strava's average power, but not TrainingPeaks or Garmin Connect. They calculate average power from the raw data.

TrainingPeaks and Garmin Connect also calculate normalized power from the raw data.

Garmin Connect does calculate moving time but it appears not to use it for the power calculations. If inactivity isn't removed from the power data then elapsed time should indeed be used for consistency, but the choice to remove the inactivity for the purpose of moving time calculation and not do so for power is puzzling.

Because Strava removes inactivity for power calculations, both approaches seem to be accepted. It's my opinion that removing inactivity is the correct approach because, depending on the length of inactivity, not doing so can lead to an inflated or deflated estimation of the effort during periods of activity. One counter-argument I can see is for structured workouts: it may be desirable to include the rest periods in calculations of intensity and training stress because in this case the length of the rest is deliberately chosen as part of the workout. Perhaps this is the reason for TrainingPeaks' implementation?

This is only one data point, so looking at some more rides would be interesting, but one takeaway from this example is this: want to inflate your TSS? Try disabling autopause (and don't take really long breaks, but apparently moderately long breaks are fine).

References

Coggan, Andrew. (2012, June 20). Calculate Normalised Power for an Interval. [Forum comment]. Retrieved June 14, 2017, from http://www.timetriallingforum.co.uk/index.php?/topic/69738-calculate-normalised-power-for-an-interval/&do=findComment&comment=978386

Coggan, Andrew. (2016, February 10). Normalized Power, Intensity Factor and Training Stress Score. Retrieved June 14, 2017, from https://www.trainingpeaks.com/blog/normalized-power-intensity-factor-training-stress/

Coggan, Andrew. (2003, March 13). TSS and IF - at last! Retrieved June 14, 2017, from http://lists.topica.com/lists/wattage/read/message.html?mid=907028398&sort=d&start=9353

Eckner, Andreas. (2017, April 3). Algorithms for Unevenly Spaced Time Series: Moving Averages and Other Rolling Operators. Retrieved June 14, 2017, from http://eckner.com/papers/Algorithms%20for%20Unevenly%20Spaced%20Time%20Series.pdf

Friel, Joe. (2009, Sept 21). Estimating Training Stress Score (TSS). Retrieved June 22, 2017, from https://www.trainingpeaks.com/blog/estimating-training-stress-score-tss/

License

This project is licensed under the MIT License. See LICENSE file for details.

Open Source Agenda is not affiliated with "Python Fitanalysis" Project. README Source: mtraver/python-fitanalysis
Stars
63
Open Issues
3
Last Commit
6 years ago
License
MIT

Open Source Agenda Badge

Open Source Agenda Rating