# Appropriate digital filter for GPS tracks?

I have an open-source software project whose purpose is to analyze a GPS track, or a similar track made by an application such as google maps, and estimate the physical exertion required to hike or run that route. Traditionally, people have gotten a gut feeling for this sort of thing by specifying the horizontal distance and the vertical gain (i.e., the amount of climbing, ignoring any descents). My software tries to do better than that, but in any case, all such measures are extraordinarily sensitive to small, spurious fluctuations in the elevation data. For instance, I could carry a GPS receiver with me on a totally flat run along a straight road in Kansas, and if the elevation is constantly fluctuation up and down by a few meters, due to GPS errors, it could show up as if I have a huge amount of vertical gain. Similar things happen with map-tracing methods, because the digital elevation models (DEMs) have fairly large errors. GPS elevations can be extremely accurate when the position of the satellites in the sky is favorable, but it can be incredibly far off in unfavorable cases (I've seen errors of thousands of meters).

Can anyone recommend a suitable method for filtering, so that I'm not reinventing the wheel, and doing it badly?

The crude method I've been doing so far is the following. I do an initial iteration of the data analysis to find the integrated horizontal distance $h$ for each point on the track. That gives me the coordinates $x(h)$, $y(h)$, and $z(h)$ as functions of distance. Then I convolve the elevation $z(h)$ with a rectangular window 500 meters wide horizontally. This gives me what appear to be accurate and reproducible estimates of the total gain. However, I also find that my initial estimate of $h$ is quite crude, because the track has a sort of fractal structure, some of which may be real and some of which is probably measurement errors. So I probably want to do some kind of low-pass filtering on $x$ and $y$ as well, maybe cutting out anything with a wavelength less than about 100 m, and then do a second iteration on the integration of $h$.

Googling turns up a lot of material on Kalman filters. Am I correct in understanding that a Kalman filter is not really the right tool for this job, since it's meant for an object like a missile or a helicopter, which has a lot of inertia? Also, my data is a track in Euclidean space, not a time series.

I'm looking for a method that is fairly robust, and can be easily implemented and played with using open-source software on linux. My code is written in ruby, but I would be OK with shelling out to something like scipy, as long as it has a fast startup time. (E.g., I don't want to use Julia because of the slow startup time.) I would like to implement this using a library that is well tested, has a large user base, and is likely to be around and well maintained for a long time.

• Generally, if you want to apply a Kalman filter, you want the raw measurements taken by the GPS receiver. Unless you have a really fancy one, that data probably isn't available. The position fixes that it's giving you have already been run through a Kalman filter or similar structure. With that said, you still may be able to improve the track if your GPS isn't aware that it's being held by a person on foot on the ground. With that constraint, you can make additional assumptions about velocity, vertical speed, etc. Ideally you could use a DEM also if it had good enough local accuracy. – Jason R Jan 25 '17 at 16:33
• @JasonR: Thanks for your comments. In practice, it will be either GPS or DEM, depending on the user's source of data. DEM in my experience has quite poor accuracy for this purpose, and requires further filtering. E.g., the SRTM dataset in my neighborhood has bogus oscillations with typical wavelengths of 500 m and amplitude of tens of meters. For GPS, typical datasets from someone hiking have a spacing of maybe 20 to 100 m, so I don't think it helps much to try to filter based on dynamics of motion. – Ben Crowell Jan 25 '17 at 16:42