Time to revisit a familiar topic: since a few months we’re using a different algorithm to extract elevation data from uploaded GPS tracks. Without going into too much mathematical detail (which can be quite entertaining though), it consists of a discrete exponential smoothing filter followed by simple thresholding. There are more refined and better filters possible (trigonometric bandpass filters etc), but it is simple, and with only two parameters (RC constant and threshold), it seems to work pretty well for the typical data that gets uploaded to the site.
This data is generally recorded by GPS devices, and usually of decent quality already in its raw form. The best devices combine barometric sensor readings with the trilatered elevation (z-coordinate) from the GPS satellites, the latter typically being used to compensate any slow drift of the barometric sensor (for instance due to weather changes). Nevertheless, even for raw data of such relatively high quality, calculated totals for altitude gain and loss during rides have been a source of doubt and confusion for many people. And this goes both ways: it’s being felt as being either inflated, or underestimated (though mostly the former).
Something people generally do tend to trust, are the totals the device itself displays at the end of the ride – perhaps because of the more tangible nature of the process? But that number is of course also the result of some internal (and unknown) filtering algorithm. Now the issue is mostly for mountain bike rides on rather chunky terrain (technical, many short ups-and-downs), or for very long mountain bike rides (100 milers e.g.), where small errors may accumulate to very large ones – for road rides and other ‘smooth’ tracks there was never much deviation with the old algorithms or ground for discussion.
So back to filtering, which I’ll now try to explain using simple, non-engineering terms. You basically want to get rid of two things: spiky noise in the elevation signal – say points in the datastream that look like they jump up and down for no good reason (but do so because some tiny atmospheric disturbance is messing up the signal of the GPS satellite a bit, or a cosmic ray that happens to impact a chip in your device, etc) – and secondly, slow drift in the signal. To understand where the latter may come from: imagine you’re riding on perfectly flat terrain, which means your total elevation gain should be zero – the sensor data may however still show small changes in elevation from point to point (because of subtle changes in air pressure due to weather conditions that confuse the barometric sensor, or because the circuit in your device is rounding off the numerical values and does so with small errors, etc), and when you add this all up, it gives a non-zero total.
An electrical engineer will say he has both high frequent (the spiky stuff) and low frequent noise (the slow drift) in the signal and he’ll want to get rid of it using a ‘bandpass filter’. The ‘band’ is the part of the signal that is of interest, which can be considered a meaningful measure for elevation changes, and all the rest is noise that needs to be filtered away. Our current algorithm (the exponential smoothing, basically a low-pass filter, followed by thresholding, which is a simple form of high-pass filter) is an implementation of this idea – by no means the best or most refined – but it seems to work well enough: in my experience from the last months (many tracks from a Garmin Edge 305 and 705), the totals calculated by the site match up with the ‘trusted’ totals displayed on the unit itself, mostly within a few percent.
Of course, for units that generate lower quality data (older, less accurate GPS receivers, no barometric sensors, etc) the simple filtering will not magically crank out the right answer, but I figure those who really care about things like how much altitude they’ve gained will get a better device eventually!
Here is a link to the script we use to process the GPX files – if you can run Ruby on your system, you can try it out for your self. The two parameters in our filter (RC constant = 40ft and threshold = 3ft) received values we found to work well but they can of course be played with…