This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Algorithm for computing the Normalized Power

I wrote some Python code to compute the Normalized Power and I noted that the
value is different from the one computed by Garmin Edge 530.

Here is the code I used (the only dependencies are garmin_fit_sdk and numpy):
gist.github.com/.../816876d348be36b7727c9cc8c96a53f7


The compute average values are correct (once rounded), but the normalized power is incorrect.

The value from my code is: 194.33244763009563
The value from Garmin Edge 530 is: 195

Is this caused by a different algorithm or is the difference caused by additional data available internally to Garmin Edge?

Thanks

Manlio Perillo

  • Hi, Garmin uses the trademarked Normalized Power from Coggan/TrainingPeaks, which is the 30-second average powers raised to the 4th power, averaged again, then 1/4th root.

    Also note Garmin's value is the NP at the end of the ride, not the peak value that may have occurred during the ride.

    You won't get exact same answer as Garmin due to rounding etc., but you should be within +/- 1 W. Your result seems fine to me.

    I calculate mine in real-time on the device using the AppBuilder5+ ConnectIQ app. They give the formula on their website as: avg(timeavg(power,30,1)^4)^0.25 (for CIQ2 devices, such as Edge 530). An advantage of this app is it displays and records the data in real-time during the ride, and plots it in Garmin Connect after the activity is saved. Here's an example from a ride with multiple sprints:

    I also calculate/record IF and TSS the same way.

  • Thanks for the response and the link to AppBuilder5+.

    In my script I ignore NaNs and include zeroes when computing NP (though this is not clearly explained when discussing the algorithm).

    Here is a difference between the metrics from my script and the original metrics from Garmin Edge 530:

    Metrics
    avg_cadence: 88.966349670812
    avg_heart_rate: 124.65592417061612
    avg_power: 189.51162239089183
    avg_speed: 7.850856635071089
    agv_temperature: 15.947630331753555
    normalized power: 202.5039877099302

    Original metrics
    avg_cadence: 88
    avg_heart_rate: 125
    avg_power: 191
    avg_speed: 7.856
    agv_temperature: 16
    normalized power: 204

    IMHO the rounding errors are too big, but by checking other activities it seems that it is not a problem with the algorithm/implementation.

    In my implementation I use float64 from the C compiler (the default for numpy arrays).

  • Yes I believe NP should include zeros, to respect its intent. 

    Brings up a question tho: what are the avg/zero settings on your Edge for power and cadence? Are both including zeros as well?

  • Cadence do not include zeros.

    Power include zeros.

  • The calculation on the Edge is likely to be using the accumulated power value reported by the power meter and not the 1 second values on the records as this handles radio outages better.

    This would typically give a higher average power and NP value over using the 1 second records.

  • Cadence do not include zeros.

    Power include zeros.

    Okay so much for that idea lol..., they're opposite the differences in your numbers, so guess that's not it.

    My opinion is still your numbers are close enough to be considered the same. Out of curiosity tho, why are you calculating these?

  • The primary reason is to calculate the decoupling "Pw:HR".  I cannot use the Normalized Power from the FIT session, since I need to remove the warm up and cool down  data.

  • Ah ok, makes sense. Have you tried Golden Cheetah by any chance? It plots an HR:Power coupling chart. Here's a sample:

  • I'm looking at the values for the accumulated power in my activities. but I'm not sure what those values represent.

    Is there some documentation?

  • It's part of the error detection/correction for power meter dropouts. The receiving device (Edge in this case) compares the difference between the current and previous accumulated power values with the current power value. They should be the same, but if they are not then it means one or more power value transmissions weren't received. It can then approximate the missing power data by simply averaging through the gap using the accumulated power difference. I recall reading on here that it'll do up to 3 seconds of missing data, otherwise it'll report lost connection.

    For us users though, accumulated power isn't of much use. The total at the end of the ride does equal the total energy expenditure though, so it's a way to calculate calories if you want, but the device is already reporting that anyway.