So, this is in part a serious look at how we could improve upon TSS as a way to record training load and use it to inform us of the way we should train on a day to day basis.
The other part of this is that I wanted to start programming in Python after years of tinkering about in spreadsheets. So bear with me, this is all a work in progress:
To do this I’ve broken the system down into four main parts:
- Power Duration modelling
- Ride classification
- Athlete load modelling
- Training advice
If all of this sounds familiar it should come as no surprise that this is the model used by Xert, of which I’m a user and advocate. As I say, I’m just doing this for my own interest, but it may be of use to others, so here goes:
1. The power duration model
No point in reinventing the wheel here as there are some great models out there. The best, as far as I can see is the one by Peronnet and Thibault, which you can read about in this article on Veloclinic:
The model is fairly straight-forward mathematically being broken down into 2 components:
P(awc) = AWC / t * (1-exp(-t / tau))
P(map) = MAP * (1 - exp(-t / tau2)); when t <= Tmap
P(map) = MAP * (1 - exp(-t / tau2)) – a * Ln(t / Tmap): when t > Tmap
The inputs for the model are as follows:
Pmax = maximum power (Watts)
AWC = Anearobic work capacity (Joules)
tau = Pmax / AWC
MAP = maximum aerobic power or FTP (Watts)
Tmap = time to exhaustion for MAP (seconds)
a = factor to determine the slope of P(map) after Tmap
tau2 = factor to determine the shape of P(map) before Tmap
I have taken a slightly different approach (just because I can) for P(awc) at the extreme right hand end of the model: Originally P(awc) would continue to be a non-zero value to t = infinity. In my model I wanted to make the contribution zero beyond a power equal to LT1. Fot this I’ve pinched a model for LT1:
LT1 = MAP * (1 - (5 / 2) * (( AWC / 1000) / MAP))
For every power it’s now possible to calculate the Aerobic contribution and the Anaerobic contribution.
Here’s the power model with a sample Mean Maximal Power curve:
2. Ride classification
By having a power duration model that allows us to workout contributions from the anaerobic and aerobic systems we can start to think about how these two systems contribute to overall system load.
At this stage, I’m not looking to reinvent the wheel completely, just to investigate if what we have already can be improved upon, so I’m sticking with TSS!
NP = (average (30 second rolling average **4)) **0.25
IF = NP / MAP
TSS = (t * NP **2) / (36 * MAP **2)
My first thought was that although TSS is usually just calculated at the end of a ride and is related to your FTP and the normalized power of the ride, it occurred to me that you can calculate TSS after every second, in exactly the same way that it’s displayed on your bike computer.
From that you can calculate the rate at which TSS is built up on a second by second basis and then apportion that to either TSSr(awc) or TSSr(map). Add these back together at the end and you get TSS(awc) and TSS(map)
Here’s how a workout looks (based on perfect data):
And here’s a ride:
I’m happy with the way that this working based on the model I developed - there’s a small bug but I’ll catch that soon.
In the examples above you can see that for any output under LTP (225 Watts in this case) there is no TSSr(awc) and if I’d tried a bit harder, the TSSr(map) drops off as you push higher and high wattages.
What it does highlight is that TSS is far from perfect and that it accrues much quicker at the start of a workout than at the end, however, so long as the proportions are correct between TSSr(awc) and TSSr(map) it still gets.
3. Athlete load modelling
No point breaking a good model - just split it in two…
Now that we’ve calculated TSS(awc) and TSS(map) we can track them both separately and combined.
It’s long been a complaint of the Performance Management chart that all load is lumped together and tracked with the same decay rates. Now that these are separated we can track them independently and with different decay values.
The graphs below use made up data with the following decay rates:
MAP Load: 60
MAP Recovery: 7
AWC Load: 20
AWC Recovery: 5
MAP Performance management chart:
AWC Performance management chart:
Total Performance management chart:
4. Training advice
The idea here is to develop a way of advising what types of workouts or rides you should do next:
Depending on where your Low form sits you might be advised not to train (if it’s less than -30% of you training load).
Similarly, for AWC you’d only be advised to do higher intensity workouts if you AWC form was high enough.
That’s really as far as I’ve got - things need to be worked out and my programming needs to improve from the basic level it’s at right now. I can create workouts, import fit files and manipulate the data based on these, but it’s a long way from being a system.
I hope this is of interest to some of you out there.
Mike