# How to calculate turn rate from a GPS log?

I'd like to calculate a rate of turn from a GPS log (GPX file).

Each trackpoint in a GPX track has location and time, and in addition to speed (a common calculation and sometimes embedded in a tracklog) I'd like to calculate the rate at which the aircraft or vehicle is turning, for each trackpoint. That said, I suspect the 'rate of turn' is more accurately reflected by a moving average over several points, and would be interested to see if anyone has examined that.

Sample GPX file here.

Open-source solutions in R or QGIS preferred!

• I think you should be more precise about what do you mean with 'turn rate' and what do you expect to find. degree/km? What is the (guessed) 'turn rate' from your figure? 180°/5km? Is it to calculate from the starting point to the last point or between each point i.e the difference between two segments? – nebi Sep 1 '16 at 20:03
• As stated: "... for each trackpoint." i.e. each point should have an associated rate of turn. Turn rate should be in degrees per minute. In the example, the 180° turn happens over 59 seconds. – Simbamangu Sep 3 '16 at 4:18

Set up a function for calculating the course (angle between points):

``````angle <- function(pt1, pt2) {
conv = 180 / pi # conversion radians / degrees
diff <- pt2 - pt1
left <- sign(diff[1]) # is X diff < 0?
left[left == 0] <- -1 # sign(0) = 0, need to keep as nonzero
angle <- left * (diff[2] * pi + atan(diff[1] / diff[2]))
angle[angle < 0] <- angle[angle < 0] + 2 * pi
return(angle * conv)
}
``````

``````require(rgdal)
setwd(".") # set to the directory where the sample GPX is located.
gpx.trackpoints <- readOGR(dsn = "tracksample.gpx", layer = "track_points", stringsAsFactors = F)
``````

We're interested in rates by time, so convert GPX time to POSIXlt:

``````gpx.trackpoints\$time <- strptime(gpx.trackpoints\$time, "%Y/%m/%d %H:%M:%S", tz = "GMT")
``````

Extract the coordinates as a matrix:

``````gpx.tp <- coordinates(gpx.trackpoints)
``````

Loop through the GPX points and add distance, time interval and speed for each point, using the previous point as reference.

``````require(raster) # interestingly, this has pointDistance for vectors
for (tp in 2:nrow(gpx.tp)) {
gpx.trackpoints\$dist[tp] <- pointDistance(gpx.tp[tp,], gpx.tp[tp-1,], lonlat=T)
gpx.trackpoints\$interval[tp] <- as.numeric((gpx.trackpoints\$time[tp] - gpx.trackpoints\$time[tp-1]))
gpx.trackpoints\$speed[tp] <-  gpx.trackpoints\$dist[tp] / gpx.trackpoints\$interval[tp] # m/s
}
``````

Loop through and add course - the difference between the of the current point and the following one:

``````for (tp in 1:(nrow(gpx.tp)-1)) {
gpx.trackpoints\$course[tp] <- angle(gpx.tp[tp + 1,], gpx.tp[tp,])
}
``````

Loop through again and look at turn angle and calc rate. Turn angle is the difference between the current point's course and the following point's course:

``````for (tp in 2:nrow(gpx.tp)) {
gpx.trackpoints\$turn[tp] <- gpx.trackpoints\$course[tp] - gpx.trackpoints\$course[tp -1]
gpx.trackpoints\$turn_rate[tp] <- gpx.trackpoints\$turn[tp] / gpx.trackpoints\$interval[tp]
}
``````

Let's have a look ... adding the points to QGIS, but styling with a rotation dependent on the "course" field:

Changing the size of the marker depending on the turn rate: