Grade Calc - Community Project

I'm still not happy with CIQ Grade calcs. I live in Florida (mostly flat) so I really don't have a lot of real world opportunities to test Grade. On the other hand, these subtle rollers are some of the most challenging use cases to test the algorithm. The problem seems to be that barometric values aren't updated quickly - and then they tend to jump in a step function when they do change.

Even up steeper grades like Colorado passes that I got to ride last weekend, barometric data isn't smooth. A balance is needed between grade being noisey (due to barometric jumps) or slow to respond (due to smoothing out those jumps). I've tried to make the balance factor adaptive. So it detects a slope inversion or a transition to/from flat roads faster.

Even the native grade values are slow to respond. However, Garmin apparently did a lot of work on this problem in the new Garmin EDGE 1050 (according to DC Rainmaker's beta evals) and now the native grade is dramatically better. As soon as you hit a steep grade from a flat road, for example, grade will reflect a legit value, not slowly adjust over 10-15 seconds. Maybe using the accelerometer sensor to assist?

Anyway, Garmin still refuses to expose native Grade to CIQ. So we have to figure this out on our own.

I am thinking about a Community Effort to optimize the CIQ Grade calcs. I'll create a DF that only generates grade, and that writes to the FIT file, with some User Settings for various variables. I'll display the current grade as well as a line graph of grade to show how our algorithm adapts to slope changes, slope inversion, and transitions to/from flat roads. And I can display this and the EDGE's native grade on the same screen to compare.

I'll post the CIQ Code in GIT Hub and allow contributors to check out, and update. I bet we can come up with a barrel pretty quick that does a great job.

This image shows a pretty steep sustained grade (grey is the elevation profile, blue is my current GRADE calc). Now that I write a FIT graph I have more visibility into the dynamics and I clearly need to smooth it a bit more. I had tried a Kalman Filter at one point that also seemed ok, but not good enough.

If you are interested in joining the project, let me know.

  • (I'm japanese. This is a machine translation.)
    I think this is because the results will be noisy if several pieces of data are not averaged.
    In fact, with my FR165, there was noisy when there was only data from two points.
    However, with the formula proposed, the slope may shift when the speed changes.
    For example, if you go up a 10% slope and your speed gradually decreases,

    s(1to 8) : 10, 9, 8, 7, 6, 5, 4, 3 (m/s)
    d(0 to 8) : 0, 10, 19, 27, 34, 40, 45, 49, 52
    a(0 to 8) : 0, 1.0,1.9,2.7,3.4,4.0,4.5,4.9,5.2
    all point grade :10% , least squares :10% , data per second

    ((a8+a7+a6+a5)/4-(a4+a3+a2+a1)/4)/(s6+s5+s4+s3)
    =((5.2+4.9+4.5+4.0)/4-(3.4+2.7+1.9+1.0)/4)/(5+6+7+8) = 9.2%
    2*((a8+a7+a6+a5)/4-(a4+a3+a2+a1)/4)/(s8+s7+s6+s5+s4+s3+s2+s1) = 9.2%

    I think it will be easier to understand if you transform the above formula as follows.
    ((a8+a7+a6+a5)/4-(a4+a3+a2+a1)/4) = ((a8-a4)+(a7-a3)+(a6-a2)+(a5-a1)) / 4
    (s6+s5+s4+s3) = d6-d5 + d5-d4 + d4-d3 + d3-d2 = d6-d2
    -> ( (a8-a4)/(d6-d2) + (a7-a3)/(d6-d2) + (a6-a2)/(d6-d2) + (a5-a1)/(d6-d2) )/4
    =( 6.9% + 8.5% + 10.0% + 11.5% )/4 = 9.2%

    If s(1to 8) : 9.5(s1=(d2-d0)/2), 8.5,,, In this case it would be 10%, but the problem remains.
    I use the least squares method because the arithmetic mean of the slope values ​​cannot account for velocity changes. Since the least squares method is used to calculate all second data, the Kalman filter, which performs double altitude correction, is not used.

    With my FR165, I feel that the speed data lags more than the altitude data, so I use distance data.
    If you can get real-time speed data from your bike, I think speed data is better than GPS distance.

  • Not convinced. In fact you just convinced me about the opposite: calculating with only 2 values is a) easier, b) more precise (see: you get 10% which is the correct grade, instead of 9.5%)

  •   I think you are after a different metric than what we are after. If you want to look for the average gradient of let's say the current lap, you would save the altitude and elapsedDistance when the lap timer is pressed and then take the simple change in altitude divided by the change in distance over the lap so far. But we are after a momentary slope that you are on right now. Altitude data from one second to another is very imprecise (it looks more precise in FIT files than the data handed to your app, that's why it is called "improvedAltitude" in the FIT file). So if you take altitude(now)-altitude(1 sec ago), there is a lot of error. Your grade estimation will jump up and down even on a stable gradient.

    Thank you for the explanation. Indeed, averaging gradients is not right. However, I am not averaging gradients, I am first averaging the altitude from 8 to 4 seconds ago and the altitude from 4 seconds ago to now. The difference is the average altitude gain from about 2 to 6 seconds ago. I then take the average speed from 2 to 6 seconds ago. I will try to replace the speed data by the distance data, sounds like a good idea. The main problem with my approach is that it 1) does not account for curvature of the slope, 2) estimates the slope from 4 to 5 seconds ago, and 3) requires the lag of the altitude and the lag of the distance/speed to be identical.

    In general, if we create a barrel, we may need to account for different devices/sensors. On a Garmin Edge it seems that speed data and altitude data has a lag of 1 second according to the correction Garmin applies to the data at FIT creation.
    Phew, that was a long post, so many issues to think about!

  • But you don't use alt(now) and alt(1 sec ago) :) You use alt(-8) and alt(-4) (and all the others in between) so even though each altitude reading second after second might be jumping because of the wind or quantum fluctuations in the barometer, when you are interested in how much the altitude changed over 4 seconds, then the inpreciseness is relatively small (not bigger than for second by second, while the rider climbed 4 times the height)

  • If you want to look for the average gradient of let's say the current lap, you would save the altitude and elapsedDistance when the lap timer is pressed and then take the simple change in altitude divided by the change in distance over the lap so far.

    But you have stated before:

    Another use case is the average climbing gradient of the ride so far. That would be well estimated by summing over all the positive values in the proposed algorithm.

    That‘s what  referred to…

  • Whether this is better or not depends on the error. If there is noise with high frequency variation (let's say a gust of wind lasting 2 seconds changes air pressure), you can improve the estimate by averaging over nearby data points. If the error is more persistent (let's say 4 seconds), then averaging makes it worse. Error frequency components larger than 8 seconds don't matter. We could figure out the frequency components with a proper Fourier analysis....

  • I poorly chose my words, what I meant was a "different" use case from what I was focusing on. I fully agree that for average gradients over longer durations Delta altitude / Delta distance is the right approach. Again, for the local gradient, curve fitting as in turkey-run's package or applying rise over run to averaged data might be better.

  • When running with my FR165, I concerned noise at two points: 20 seconds before and now.
    20 seconds is about 60m.(my running)
    
    
  • Has anyone compared fit file data, as pushed by garmin, with fit file data pushed by CIQ, from data handled to it in real time, to verify actual lags?  Ideally with some synchronizing event to 'real world'?

    I see how pressure data alone can be 'jumpy' over time, but doing just temporal calculations, samples at fixed time intervals, compounds the error by the variation in speed, sometimes. as you go slower and slower on a climb (by nature of limited leg power or to test algorithms), the small distance in 1s becomes an amplifier of the errors.   A smart algorithm would take that in account as well, perhaps calculating bounds each time, considering observed errors in pressure and in distance, and reporting the 'most likely' not an eventual extreme because speed is small and we happened to get a pressure update that second.

    Does anyone know if when you have a 'speed sensor' on the wheel, does that provide actual rotational speed, calculated internally on the sensor near continuously by accelerometer attitude, or simply # of rotations since last transmit, or rotational speed from this quantized data?   Or does garmin use it for distance and some mix of gps and distance sensor for speed?

  • btw it has been confirmed - flexure on the case or even pressing the screen (say to swipe to next page) generates large disturbances in the 1040 pressure sensor, havoc to grade calculations.  The edge 1000 doesn't suffer from this.