Tuesday, May 19, 2015

using a modified Fiets formula to tune climb detection

Last time I described that the recursive algorithm I proposed for finding climbs in a profile was:

  1. identify all non-overlapping rateable climbs in a profile:
    1. If there's no rateable climbs of some minimum climb rating, then we're done.
    2. identify the highest-rated climb in a profile.
    3. identify all rateable climbs preceding this climb (recursive)
    4. identify all rateable climbs following this climb (recursive)

I implemented this in Perl, which went a lot faster than it had taken to implement my previous, unsuccessful iterative approach. I tested this on randomly generated "profiles". I put "profiles" in quotes because they're not very realistic.

I had to define a "minimal" climb, so this I decided was 5 meters gained in 0.1 km. This is a 5% (approximate) grade for only 100 meters. So to be identified as a "climb" the simulated road would need to be steeper and/or gain more altitude.

Initially I used the conventional Fiets formula which is : altitude squared / distance. Note a variation on this is average gradient times altitude gained. These are essentially equivalent. Here'a a typical result, where the total profile is red and identified climbs follow. Identified climbs occlude the red profile curve where they are present, so the red curve, if you see it, only exists where no qualifying climb exists.

image
n = 2 (Fiets)

Note that in many cases regions of contiguous altitude gain are broken up into pieces. This is because a steeper subset of the total region of altitude gain has a higher rating by virtue of a higher average grade despite the penalty of less altitude gained. This highlights the importance of considering profile subsets in apply a Fiets-like formula to climb data.

However, one can generalize thd Fiets-type formula as follows:

rating = |altitude gained|n / distance

where n is a power (2 for Fiets). This is virtually equivalent to using |grade| multiplied by |altitude difference| raised to the n-1 power, where the "||" denote absolute value. The higher n, the more importance placed on altitude. If n = 1, then altitude gained doesn't matter, just grade. That's silly because the climb of maximal rating would be the segment of maximal grade, and that segment can be arbitrarily short. On the other extreme, if n is large, altitude difference dominates, and grade becomes relatively insignificant.

Here's an example of using n = 4:

image
n = 4

With this it's less prone to breaking up continous climbs.

And here's an example using n=8:

image
n = 8

Now it tends to take points of altitude extremes, even if there's extended descents between the two.

image
n = 16

I could do this with real profile data, for example the Terrible Two which has a very nice mix of climbs, but unfortunately right now this code is confined to the random profile generation code.

No comments: