tests/testthat/test_vel.R

library(trajr)

context("Velocity and acceleration tests")

test_that("Basic velocity", {
  # Crude test that it doesn't crash and returns the expected number of values
  set.seed(1)
  n <- 10
  # Argument to TrajGenerate is number of steps, whereas we want n to be number
  # of points, i.e. 1 more than number of steps
  trj <- TrajGenerate(n = n - 1)
  vel <- TrajVelocity(trj)
  expect_equal(length(vel), n)
  expect_true(inherits(vel, "complex"))
  expect_equal(attr(vel, "trj"), trj)
  # Expect 1st and last to be NA, no others
  expect_true(is.na(vel[1]))
  expect_true(is.na(vel[n]))
  expect_equal(sum(is.na(vel)), 2)
})

test_that("velocity", {
  # Test returned values are as expected.
  # Simple trajectory, constant velocity in x, exponentially increasing in y
  x <- 1:10
  y <- x ^ 2
  trj <- TrajFromCoords(data.frame(x, y), fps = 1)
  vel <- TrajVelocity(trj)
  # Discard first and last elements - we know they are NA (tested above)
  vel <- vel[2:(length(vel) - 1)]
  # X velocities should all be 1
  expect_true(all(Re(vel) == 1))
  # Y velocities should be increasing linearly
  expect_true(all(Im(vel) == seq(4, length.out = length(vel), by = 2)))
})

test_that("Basic acceleration", {
  set.seed(1)
  n <- 10
  # Argument to TrajGenerate is number of steps, whereas we want n to be number
  # of points, i.e. 1 more than number of steps
  trj <- TrajGenerate(n = n - 1)
  acc <- TrajAcceleration(trj)
  expect_equal(length(acc), n)
  expect_true(inherits(acc, "complex"))
  expect_equal(attr(acc, "trj"), trj)
  # Expect 1st and last to be NA, no others
  expect_true(is.na(acc[1]))
  expect_true(is.na(acc[n]))
  expect_equal(sum(is.na(acc)), 2)
})

test_that("Acceleration", {
  # Test returned values are as expected.
  # Simple trajectory, constant velocity in x, exponentially increasing in y
  x <- 1:10
  y <- x ^ 2
  trj <- TrajFromCoords(data.frame(x, y), fps = 1)
  acc <- TrajAcceleration(trj)
  # Discard first and last elements - we know they are NA (tested above)
  acc <- acc[2:(length(acc) - 1)]
  # X acceleration should all be 0 (constant velocity)
  expect_true(all(Re(acc) == 0))
  # Y acceleration should all be 2 (constant but non-zero acceleration)
  expect_true(all(Im(acc) == 2))
})

test_that("Variable step times", {
  # Simple trajectory, constant step length of 5, speed oscillates between 1 & 5
  x <- 1:10 * 3
  y <- 1:10 * 4
  times <- cumsum(rep(c(1, 5), times = 5))
  trj <- TrajFromCoords(data.frame(x, y, times), timeCol = 3)
  # Calculate velocity using forward differences
  fvel <- TrajVelocity(trj, diff = "forward")
  expect_true(is.na(fvel[length(fvel)]))
  # Discard last element
  vel <- fvel[1:(length(fvel) - 1)]
  # Speeds should match those from TrajDerivates since the trajectory is 1-dimensional and we've used forward differences
  expect_true(all(Mod(vel) == TrajDerivatives(trj)$speed))

  # Backward should be the same as forward except NA is first rather than last element
  bvel <- TrajVelocity(trj, diff = "backward")
  expect_true(is.na(bvel[1]))
  expect_true(all(bvel[2:length(bvel)] == vel))
})

test_that("acc sanity", {
  # Perform a sanity check: simple implementation of acceleration by central
  # differences from fixed step times should yield the same result as
  # TrajAcceleration applied to fixed step times

  set.seed(2)
  n <- 100
  trj <- TrajGenerate(n = n - 1)
  acc <- TrajAcceleration(trj)

  # Recalculate using central diffs
  dt <- mean(diff(trj$time))
  ax <- stats::filter(trj$x, c(1, -2, 1)) / dt ^ 2
  ay <- stats::filter(trj$y, c(1, -2, 1)) / dt ^ 2

  expect_equal(as.numeric(Re(acc)), as.numeric(ax))
  expect_equal(as.numeric(Im(acc)), as.numeric(ay))
})

test_that("Variable steps acc", {
  # Step lengths are equal, but time decreases so trajectory is accelerating
  x <- c(1, 1, 1, 1, 1)
  y <- 1:5 * 8
  times <- cumsum(c(0, 8, 4, 2, 1))
  trj <- TrajFromCoords(data.frame(x, y, times), timeCol = 3)

  # Integrating velocity should give us distance travelled at each step
  vel <- TrajVelocity(trj, diff = "forward")
  vel <- head(vel, -1) # Remove trailing NA
  dx <- Re(vel) * diff(times)
  expect_equal(dx, diff(x))
  dy <- Im(vel) * diff(times)
  expect_equal(dy, diff(y))

  # Compare acceleration to hand-calculated acceleration
  acc <- TrajAcceleration(trj)
  acc <- na.omit(acc)
  expect_equal(as.numeric(Re(acc)), rep(0, 3))
  # Speeds should be 1, 2, 4, 8
  expect_equal(Im(vel), c(1, 2, 4, 8))
  # Acceleration should be (diffs in speed) / (diffs in times of step centres)
  expect_equal(as.numeric(Im(acc)), c(1, 2, 4) / c(6, 3, 1.5))
})

test_that("velocity & speed", {
  set.seed(5)
  trj <- TrajGenerate()
  # Compare speed from TrajDerivatives & TrajVelocity
  drv <- TrajDerivatives(trj)
  vel <- TrajVelocity(trj, diff = "backward")
  vspeed <- data.frame(speed = Mod(vel), speedTimes = trj$time)
  vspeed <- na.omit(vspeed)
  expect_equal(drv$speed, vspeed$speed)
  expect_equal(drv$speedTimes, vspeed$speedTimes)

  # Try a different, log trajectory
  trj <- TrajGenerate(n = 10000, linearErrorDist = rcauchy)
  drv <- TrajDerivatives(trj)
  vel <- TrajVelocity(trj, diff = "backward")
  vspeed <- na.omit(data.frame(speed = Mod(vel), speedTimes = trj$time))
  expect_equal(drv$speed, vspeed$speed)
  expect_equal(drv$speedTimes, vspeed$speedTimes)

  trj <- TrajGenerate(50000, angularErrorDist = function(n) runif(n, -pi, pi))
  drv <- TrajDerivatives(trj)
  vel <- TrajVelocity(trj, diff = "backward")
  vspeed <- na.omit(data.frame(speed = Mod(vel), speedTimes = trj$time))
  expect_equal(drv$speed, vspeed$speed)
  expect_equal(drv$speedTimes, vspeed$speedTimes)

})
JimMcL/trajr documentation built on Jan. 31, 2024, 12:57 a.m.