I'm working with our local cycling group to anonymise GPX files on two criteria (primarily for security). I've never come across a standard way of anonymising data but this satisfies two concerns of our members, while preserving accuracy along roads and speed information:
- Personal locations, removing 'private' areas for individuals;
- Obscuring timestamps so that travel data could not be used to identify individual movements.
GPSBabel can do both of these from the command line - for example, to shift the times in a GPX file by +123450 seconds, and remove all trackpoints 0.5 km away from a landmark in northern Tanzania:
gpsbabel -t -i gpx -f infile.gpx \
-x transform,wpt=trk,del -x track,move=123450s \
-x radius,distance=0.5K,lat=-3.368,lon=36.624,nosort,exclude \
-x transform,trk=wpt,del \
-o gpx -F infile_rand.gpx
-t: process tracks only;
-i, -f: input file type (gpx) and filename;
-x: two sequential (-x) filter arguments for timeshift (move) and removal (radius,exclude) around a point;
-o, -F: output file type and filename.
This command chains together several filters - first transforming the trackpoints into waypoints, then filtering, then transforming back to trackpoints.
Note that reducing the decimal places around the landmark / privacy area is VERY important as it obscures the exact centre of the privacy area. 3 decimal places = ~ 110m accuracy in this case.
I usually call GPSBabel from R, writing a new GPX file with filters applied, including a random timeshift +/- 2 weeks. This would be better as a bash or python script but a lot of the other work I do is in R and I'm lazy ...
# Get the correct location for GPSBabel:
GB <- Sys.which("gpsbabel")
# Set up the filters
shift <- round((runif(1, 0, 2600000) - 1300000), 0) # +/- 2 weeks in secs
filter <- " -x transform,wpt=trk,del"
filter <- paste(" -x track,move=", shift, "s", sep = "")
filter <- paste(filter, " -x radius,distance=", dist, "K,", "lat=", lat, ",long=", lon, sep = "")
filter <- paste(filter, " -x transform,wpt=trk,del", sep="")
# Pass the complete command to the system
system(paste(GB, " -t -i gpx -f ", gpx_file, filter, " -o gpx -F ",
gsub(".gpx", replacement = "_rand.gpx", x = gpx_file, fixed = T),
sep = ""), intern = TRUE)