Simplifying walk tracks

I have a bunch of GPX tracks generated by iSmoothRun, a GPS tracker for the iPhone that tries to correct for location error by using the accelerometer as a pedometer. The tracks it produces are pretty lumpy too, so I’m trying to use ST_Simplify afterwards to clean them up.

ST_Simplify takes as a second parameter the “tolerance”, how much to smooth. This parameter is not well documented but it seems to be measured in the units of the geometry you are simplifying. For my walking tracks 0.00005 seems to be about right. If that were degrees, that’d correspond to about 15 – 20′ in San Francisco.

Here’s a quicky chart of the average percentage difference between the original track length and the simplified track length, for different tolerances.

0.00001   0.1%
0.00003   0.7%
0.00005   1.8%
0.00007   2.8%
0.0001    4.4%
0.001    19.9%

0.00005 seems to be a reasonable compromise. It produces tracks with about 1/3 the number of points as the original. Below is a picture of the original track and the simplified drawn on top of it, to show the geometry change.

I wish I understood SRIDs more intuitively, I feel like I’m bashing about. Half my data is WGS84 and half is Google Mercator, and then below I’m using SRID 2163 to do the distance calculation. That’s a bit of cargo cult coding, I think it’s NAD83 which is close enough to WGS84 to get away with.


-- Create a simplified view of an ogr2ogr imported track
create or replace view simple_tracks as
select
ogc_fid,
ST_Simplify(wkb_geometry,0.0001) as wkb_geometry,
name
from tracks;

-- Display the difference between original and simplified
select
  miles-smiles as difference,
  round((miles-smiles)/miles*100) as pctlength,
  round(spoints*100/points) as pctpoints,
  * from
(select
tracks.name,
ST_Length(ST_Transform(simple_tracks.wkb_geometry, 2163)) /1609 as smiles,
ST_Length(ST_Transform(tracks.wkb_geometry, 2163)) /1609 as miles,
ST_NPoints(simple_tracks.wkb_geometry) as spoints,
ST_NPoints(tracks.wkb_geometry) as points
from simple_tracks inner join tracks
on simple_tracks.name = tracks.name order by name) as m;

-- Calculate just the average difference
select avg((miles-smiles)/miles*100) from
(select
  tracks.name,
  ST_Length(ST_Transform(simple_tracks.wkb_geometry, 2163)) /1609 as smiles,
  ST_Length(ST_Transform(tracks.wkb_geometry, 2163)) /1609 as miles
from simple_tracks inner join tracks
on simple_tracks.name = tracks.name order by name) as m
where miles > 1;