How Edge calculate current heart zone decimal value

Hi all, 

I don't understand how Garmin calculate current Heart Zone value in it's system default DataField.

I tried to develop the same "algorithm" based on my current Heart Zones but I can't get the same results...
See below an example:

Instant HR value is 62bpm. 
The simple algorithm I've made gives me I am in Zone 0.7 
Default device (I am using an Edge 840) calculation gives me Zone 0.5

My Heart Zones are the following:

Zone 0: 0 - 91
Zone 1: 92 - 109
Zone 2: 110 - 127
Zone 3: 128 - 145
Zone 4: 146 - 164
Zone 5: 165 - 183

Based on those values, my algorithm looks more precise... but I really do not understand how Garmin gives me 0.5 for the same bpm value (62).

Any idea? 

Top Replies

All Replies

  • Clearly I was talking about the graph that you get if you connect the points.

    But then IMHO you get the same graph using your [Z1min, Z1max], [Z1max, Z2max]  or my (Z1min, Z1max],  (Z1max, Z2max] - if we're only talking about the original difference that you proposed regarding the touching of the zones.

    I think that my graph will have 1 bend at the border between each zone, while yours will have 2 bends at each border

    Again not sure what are you talking about. I understand your 1 bend theory (but I don't think it's true, if you consider that in my imaginary "graph" the width of the zone would be proportional to the Znmax-Znmin and thus the graph would be linear.

    But I don't know why you think that my model would have 2 bends? If Z1: (120, 140], Z2: (140, 160], then the 2 lines would meet in 140.5 and there could be 1 bend. it's not that there would be a bend at 140 and another bend at 141.

    your method of adjusting the configured ranges so they are "not touching" is different than Garmin's method

    I noted that, and I'll think about it. It's odd to me, because when the user sets the Z2max to 134, then he (ok, at least me, but I doubt that I would be the minority) would expect that if the HR is 134 then it would count as Z2 and not Z3. For this reason I'm hesitant to adjust my algorithm.

    In my app I calculate the HR zone based on the HR and I use the result to both display the number (in the format choosen by the user, either integer or decimal), display the graphical gauge, and to record the integer value to FIT (though I'm not sure what value it has, it served more as a debugging tool to me)

    It's unclear if Garmin is different only in the way the data is displayed in Garmin Connect, or if also the displayed data is different. To me it's a strange decision either way to "distort" the meaning of the clearly labelled Z2max.

    the touching ranges algorithm would work without modification if the input HR could actually be a real number

    I noted that too, and I am playing with the thought to endeavour into that. This will need some more serious development than to change where I have a +1 or -1, but might result in interesting things. I'll try to do some debugging with logging the HR(int) reported by the band and the RR-interval(ms) and the computed HR(float) based on the RR-interval.

    What decimal zone values should the user expect

    I think that's a good question, but to answer that I wouldn't continue with what you wrote in the next sentence, because the real question is not mathematical, but what the average Garmin user [of my data field] would expect (without looking at my code or think mathematical, only based on his experience with Garmin and the understanding of HR zones in Garmin)

  • and the other half we don't understand ;)

  • the touching ranges algorithm would work without modification if the input HR could actually be a real number

    I noted that too, and I am playing with the thought to endeavour into tha

    Yeah, this is where the thing about mathematical elegance comes in [just as far as my poor intuition goes, and keeping in mind I'm not a mathematician]

    My algorithm can also be used for real numbers [without modification]

    And again, my algorithm would produce the same numbers [after appropriate scaling] if adjacent zones of equal width were combined, or if one zone was further subdivided into smaller zones of equal width. So if someone arbitrarily decided to create a 10 zone system by dividing each of the 5 zones in two, hypothetically my algorithm would produce similar numbers [after scaling] for either the 5 or 10 zone system [except maybe for zone 0, since it wouldn't be cut in half, presumably]. Why does that matter? It doesn't really matter, but I think it's kind of a neat property [almost like how a fractal looks the same no matter how far you zoom in or out.]

  • Clearly I was talking about the graph that you get if you connect the points.

    But then IMHO you get the same graph using your [Z1min, Z1max], [Z1max, Z2max]  or my (Z1min, Z1max],  (Z1max, Z2max] - if we're only talking about the original difference that you proposed regarding the touching of the zones.

    This is clearly not the case, whether or not the points are connected.

    To show this, all I have to do is find a single x-value which produces a different y-value for each algorithm, for a given set of zones.

  • Consider the following configured zones: Z0 = 30-120, Z1 = 120-140, Z2 = 140-160

    And the following HR value (x-value): 140

    - My algorithm gives the following fractional HR zone (y-value): 2.0 (this should be well established by now)

    --

    --

    If an input (x-value) of 140 produces an output (y-value) of 2.0 for my algorithm, and 1.95 for yours, it should be 100% clear to everyone that the graphs will be different, regardless of whether the points are connected or not.

    So are you starting to see why I'm certain your algorithm produces different results than mine?

  • I think that my graph will have 1 bend at the border between each zone, while yours will have 2 bends at each border

    Again not sure what are you talking about. I understand your 1 bend theory (but I don't think it's true, if you consider that in my imaginary "graph" the width of the zone would be proportional to the Znmax-Znmin and thus the graph would be linear.

    But I don't know why you think that my model would have 2 bends? If Z1: (120, 140], Z2: (140, 160], then the 2 lines would meet in 140.5 and there could be 1 bend. it's not that there would be a bend at 140 and another bend at 141.

    To clarify what I think (this is just off the top of my head, I'm not trying to rigorously prove anything)

    For the touching zones algorithm:

    - the slope of the line segment connecting zone N and zone N+1 depends on how wide the zone is. The wider the zone, the less steep it is. (The extreme case is a 0-width zone, which would have an infinite slope)

    - the graph would only be linear if all zones are the same width

    - if two adjacent zone have different widths, then the corresponding line segments would have different slopes (although they would touch), which is why I think there should be 1 bend at each border, or to be more precise: 0 to 1 bends

    For the non-touching zones algorithm:

    - I think there would be still be at least 0 to 1 bends at each border, for the same reason as above

    - But (just going off intuition), since the zones no longer touch, I think there could also be an additional 0 to 1 bends at each border, for a total of 0 to 2 bends. Yeah, this part is something that I'm not 100% sure about.


    To make my intuition clear here:

    My (touching) algorithm...

    - ...would produce a line segment L1 of slope s1 connecting 120 to 140 (inclusive)

    - ...would produce a line segment L2 of slope s2 connecting 140 to 160 (inclusive)

    - There is no problem with 140 belonging to both L1 and L2, as we've established that the y-value at the bordering x-value of two zones is the same no matter which zone you consider the x-value to belong to

    - Since there are two line segments with two slopes which could possibly be different (but could also be the same), I claim there could be up to one bend at each zone border

    Your (non-touching) algorithm...

    - ...would produce a line segment L1 of slope s1 connecting 121 to 140 (inclusive)

    - ...would produce a line segment L2 of slope s2 connecting 141 to 160 (inclusive)

    - Given that all the points are connected, there would be a 3rd line segment L3 of slope s3 connecting 140 to 141

    - Given that there are three line segments, unless you can prove that s3 is always equal to either s1 or s2, I claim there could be up to two bends at each zone border.

    I would probably have to graph a few examples in both algorithms to try to defend or disprove these ideas. In both algorithms, it's conceivable that the entire graph would be a straight line in some cases, but I don't think that is true in general.

    Not like any of it matters anyway, except for trying to get the same numbers as Garmin (which also doesn't matter that much, probably)

  • and the other half we don't understand ;)

    Speaking of things that are hard to understand

    Why does your implementation refer to a constant/variable called one (I sure hope this is equal to 1), but you also have the literal number 1 in two other places?

    If the point is to somehow optimize the code, I'd expect all instances of 1 to be replaced with one.

  • and the other half we don't understand ;)

    In all seriousness, I always try to start out explaining things as simply as I can, but if that doesn't work, I end up saying more and it rarely ends well.

    I def need to work on my communication skills.

    I will say that the opposite often happens on these forums, especially when discussing technical issues (whether it's related to development or not).

    Imo people often dumb down concepts a *bit* too much, for the sake of clarity and brevity, so certain things get lost in translation and people end getting the wrong impression about things. Like people's understanding might be 95% right (to pick an arbitrary number) on a given topic, but when it comes to the additional 5%, their understanding will be completely wrong. And sometimes that 5% is crucial (e.g. when trying to troubleshoot certain kinds of problems; just trying to understand how something works; or trying to code a solution that works in general, not just in *most* cases.)

    You can actually see this a lot when non-devs talk about Connect IQ or Stryd in the other forums. People sort of have a very vague idea of how this stuff works which is usually good enough for their purposes. But if you dig a bit deeper, their understanding is often very shallow, and sometimes completely wrong in some ways.

    So yeah, I hate dumbing things down, and that can lead to being overly verbose or hard to understand. If I can make a short reply which isn't misleading or incomplete, I'll do so, though.

  • because in my real code I use local variables zero, one when I use the same number literal at least 3 times (this shrinks code size) and I tried to remove them for clarity, but I missed some. The same was true for the mHeartRateZones vs heartRateZones.