KrOstir
KrOstir

Reputation: 94

Calculate speed (first derivative in time) of time series

I would like to compute the speed from data in xts time series. My data looks like this (command bellow generates sample, actual data is much larger).

measurement <- xts(c(7.9, 8.6, 12.7, 13.3), 
                   as.POSIXct(c("2016-02-24 06:00:00",
                                "2016-02-24 07:30:00",
                                "2016-02-24 09:15:00",
                                "2016-02-24 11:15:00")))
names(measurement) <- "pos"

head(measurement)
                     pos
2016-02-24 06:00:00  7.9
2016-02-24 07:30:00  8.6
2016-02-24 09:15:00 12.7
2016-02-24 11:15:00 13.3

If I use diff I am getting the changes between successive values.

diff(measurement)
                    pos
2016-02-24 06:00:00  NA
2016-02-24 07:30:00 0.7
2016-02-24 09:15:00 4.1
2016-02-24 11:15:00 0.6

However, I would like to take time into account and compute speed (e.g. change in time period). I have tried using the following dirty road.

measurement$time  <- as.numeric(index(measurement))
measurement$speed  <- diff(measurement$pos) / diff(measurement$time) * 3600

head(measurement)
                    pos  time       speed
2016-02-24 06:00:00  7.9 1456290000        NA
2016-02-24 07:30:00  8.6 1456295400 0.4666667
2016-02-24 09:15:00 12.7 1456301700 2.3428571
2016-02-24 11:15:00 13.3 1456308900 0.3000000

There must be a simpler and more elegant way to do this. Have in mind that I am still new to R and might be missing something.

Upvotes: 2

Views: 2495

Answers (1)

WaltS
WaltS

Reputation: 5530

I'm not aware that either base R or the xts package provides a way to directly calculate a physical rate in the way you're doing. A bit more straightforward way to do the speed calculation in hours might be

# alternative time conversion 
  del_t <- diff(index(measurement))
  units(del_t) <- "hours"
  measurement$speed_hr <- diff(measurement$pos, na.pad=FALSE)/as.numeric(del_t)

The units of time returned by diff can be specified so in this case can be set to hours.

More generally, your speed calculation has discontinuities at the data points. In some situations, there would also be a requirement for continuity of speed across the data points. speed could then be calculated using R's splinefun routine which can return not only the spline interpolation for position but also the first derivative giving an approximation of speed which is both continuous and depends upon more than two of neighboring data points. Code could look like

# provides continuity of speed at data points
# perform cubic spline fit
  spline_fit <- splinefun(x=index(measurement), y=measurement$pos, method="natural")

# add spline speeds to measurements
  measurement$spline_spd <- spline_fit(index(measurement), deriv=1)*3600

The spline speeds disagree with the speeds from the original calculation but this seems to be a result of the constraint on continuity at the data points. A plot may help to clarify this.

# make a sequence of plot times for spline fits
  spline_times <- seq(start(measurement), end(measurement), length.out=40)
# plot positions
  par(mfcol=c(2,1))
  plot(spline_times, spline_fit(spline_times, deriv=0), col="red", type="b", 
       main="Positions", xlab = "Time", ylab="Pos")
  points(index(measurement), measurement$pos, type="p", pch=19, cex=1.1)
  legend("topleft", legend = c("-- pos data","-- spline pos interpolations"), 
         text.col = c("black","red"), y.intersp=.2, yjust=3., bty="n", cex=1.3)
# plot speeds
  plot(spline_times, spline_fit(spline_times, deriv=1)*3600, col="red", type="b",
       main="Speeds", xlab="Time", ylab="Speed")
  lines(index(measurement), measurement$speed, type="b", pch=19, cex=1.1)
  legend("topleft", legend = c("-- speed calculation","-- spline speed interpolations"), 
       text.col = c("black","red"), y.intersp=.2, yjust=3., bty="n", cex=1.3)

enter image description here

Four data points is really too few for a good spline fit but perhaps this conveys the general idea.

Upvotes: 3

Related Questions