How do you add this to charts?
Sorry I thought the reply would go directly to the post. Interested how I get this plot - looks really interesting
The median cadence for all the Z2 buckets is calculated. The only buckets with cadence between 92% and 115% of the median are kept.
Thanks
Is there any chance we could have a stream showing the power trend (in watts) at a specific HR value, such as at a given % of LTHR or % of max HR?
At the moment, the existing stream has a great logic (1’ splits and HR lag plus cadence filter), but it divides average power by average HR across the entire Z2 range. In my opinion and experience, this metric would become even more useful and robust if it captured a narrower effort range. Even better if more filters could be applied, excluding activities with very high VI, IF, and temperature.
I would love to try developing an external tool to produce this, but perhaps this could even be feasible internally. Any thoughts on the feasibility of something like this, either externally or within Intervals itself?
Do you mean let’s say 130bpm, and every watt around that heartrate is captured per activity, building the average of it per activity and plotting it for many activities over months?
Precisely!
Actually, there is a more complex and robust method I’ve worked with before and that I consider ideal, but what you described is indeed very close to what I have in mind to implement here.
Edit: I’ve just remembered that we already have an interesting metric being calculated within the activities:
@david any chance of being able to make this “Power at top of Z2 HR” as a plot avaliable to use in charts? Thanks!
@Gabriel_Vargas Thanks for the link to the cycling analytics post. I just came up with a similar idea to measure power/HR in different HR bins with Claude and use it to track my fitness. Since power:HR isn’t linear it seemed the best way to track progress. I also tried to correct for heat cause that massively swings it. Would love the method in cycling analytics or something similar to be implemented natively
I find it extremely useful to judge what Garmin tries to with “Training Status”. i.e. is my training productive. It means I don’t need to do ramp tests often and the heat correction stops me thinking a hot day or cool day means a loss or gain in fitness.
I don’t really ride hard so the power curve measures of fitness like eFTP don’t work for me.Most of my work is <LT1 or exactly between LT1 and LT2. I enjoy training there as it lets me do my strength/power leg work (jumps, sprints, clusters etc.) and hate all outs except for 3 second sprints!
Wow, that’s interesting. At what sampling interval does your system collect data from activities? If I remember correctly, the default in Cycling Analytics is every 4 minutes, but it can be easily adjusted within the tool itself. Is there a view that shows the data from an activity?
And why did you choose to keep power fixed as the reference, rather than HR? Is there any practical reason or advantage, or was it simply your choice?
I’m interested in learning more about your project. Thanks.
As this top of z2 field wasn’t trackable on the fitness charts, I made (another) eAeT field with the help of some athletes data. So this was created to have a plotable version of the top of z2 (or aerobic threshold).
You can try it out, maybe it’s helpful
Thanks for the questions! This has been a real passion project for me. Rather than answering directly myself I’ll paste what Claude said. Any improvements/suggestions are welcome! I’m always looking for submax testing. I believe Garmin with firstbeat has the right approach but they’ve just not kept up with the science - no orthostatic HRV, vo2max moves to slowly, heat acclimation doesn’t count humidity, solar gain basically global wet bulb and doesn’t account for weather during ride only when you set off. So I wanted to make something similar but with cutting edge science.
Bear in mind my typical ride is 50% terrible london roads and 50% single track. I ride a hard tail MTB. So power is never even. These methods have been derived off a 10 week layoff due to a crash and only my summer riding. Indoor riding in winter, with erg would obviously be very different.
Thanks @Gabriel_Vargas — good questions, and the sampling one gets at the thing that took me longest to get right.
Sampling interval
1 Hz, straight from the FIT records — no time-binning. But raw power is never binned directly, and that turned out to be essential.
Power is first low-passed with a 30-second exponential filter (roughly heart rate’s own time constant), and each second is then assigned to a band by that HR-equivalent power rather than by instantaneous power. Without this the bands are degenerate. On one ride I got 154.4 / 154.4 / 154.4 bpm across three bands spanning 32 W — a gradient of 0.08 bpm/W where physiology says 0.3–0.5. A ten-second surge into the top band is recorded carrying whatever HR the previous two minutes produced, so the bands end up measuring the same thing.
I also tried the obvious alternative — only counting samples where power had been sustained in a band. Outdoors that fails completely: requiring 30 consecutive seconds inside a band left zero qualifying samples across 16 rides. Real-world power is just too variable. The lag filter is what makes 1 Hz data usable.
So versus 4-minute averaging: a 4-minute window would blur across band boundaries and average together efforts that belong in different bands. Filtering at HR’s time constant and keeping 1 Hz classification does the opposite — it attributes each second to the load HR is actually responding to.
Is there a per-activity view?
Not really — it’s a longitudinal tool. One point per ride per band, tracking the trend over weeks. There’s no single-activity drill-down; for that I still just use intervals.icu.
The one per-activity thing I do push back to intervals.icu is the heat data — wet-bulb, dew point and solar gain as custom activity fields, plus a chart. That part came out of the same project.
Why fix power rather than HR?
Mostly statistical rather than preference: you can’t bin on your own outcome variable.
Power is the input, HR the response. Fixing the input and watching the output is the standard submaximal-HR construction. If you bin by HR and then read HR, the bin edges select for measurement noise and you get regression-to-the-mean artefacts.
You can invert it and measure power at fixed HR — that’s a legitimate metric, just a different one. The practical cost is that HR carries lag, cardiac drift and thermal noise, so your binning variable becomes the noisy one, and error in a binning variable biases the relationship. Power is measured directly and far more precisely.
Empirically it works out: binning on filtered power holds in-band mean power to sd 0.2–0.5 W across every ride. The work really is constant, so only the response can move.
Worth adding that the choice is metric-specific rather than universal. If I were tracking heart-rate recovery I’d fix HR instead, because HR at cessation is the dominant confounder there. General rule: fix whichever variable is the confounder and measure the other.
One caveat on the screenshots
They’re 16 rides over about a month, so the trend is suggestive rather than established. The heat correction is doing real work in there — my own data gives ~1.0 bpm per °C of air temperature at fixed power, which happens to reproduce the published figure for fixed-intensity cycling almost exactly. Without it a cool spell reads as a fitness gain. Happy to go into that part if it’s useful.
In heat I keep the prescribed power. HR drift is extra cardiovascular cost, not a reason to quietly drop the watts. If I can’t hold the target for the intense interval, I cut volume (stop the set) instead of softening the number. Otherwise the session turns into something else.




