Skip to contents

Welcome to the acceleration-filtering vignette! Thanks for taking some time to learn our package; we hope it’s, thus far, all you’ve dreamed it would be.

In this vignette, you will explore postural dynamics and specific acceleration in the time and frequency domains. Specifically, you’ll load in some new data and use complementary filters to separate intervals of movements into distinct frequency bands, i.e., posture (low frequency) and strikes/flinches (high frequency), in order to gain insight about the movements of a beaked whale.

Estimated time for this practical: 20 minutes.

These vignettes all assume that you have R/Rstudio installed on your machine, some basic experience working with them, and can execute provided code, making some user-specific changes along the way (e.g. to help R find a file you downloaded). We will provide you with quite a few lines. To boost your own learning, you would do well to try and write them before opening what we give, using this just to check your work.

Additionally, be careful when copy-pasting special characters such as _underscores_ and ‘quotes’. If you get an error, one thing to check is that you have just a single, simple underscore, and 'straight quotes', whether 'single' or "double" (rather than “smart quotes”).

Setup

For this vignette we will use data from a suction cup tag attached to the back of a beaked whale. If you want to run this example, download the “testset1.nc” file from https://github.com/animaltags/tagtools_data and change the file path to match where you’ve saved the files

Write testset1 to the object bw, for “beaked whale”. Then use plott() to inspect it.

library(tagtools)
bw_file_path <- "nc_files/testset1.nc"
bw <- load_nc(bw_file_path)
plott(X = list(Depth = bw$P, Acc = bw$A, Mag = bw$M))

This dataset contains a deep dive followed by a shallow dive. We want to infer the function of these by looking for locomotion effort and sudden changes in acceleration that could be indicative of prey capture attempts. We are also going to look for changes in swimming gait.

Complementary filtering

To separate slow orientation changes from postural dynamics in locomotion, we need to choose a filter cut-off frequency below the stroke frequency. We can estimate the dominant stroke frequency using dsf(). There is a bout of steady swimming between minutes 35 and 42 in the data. Use crop_to() to pick out the accelerometer data in that interval:

Aseg <- crop_to(X = bw$A, tcues = c(35*60, 42*60))

Mimic the previous code to similarly crop the pressure (depth) and magnetometer data:

Dseg <- crop_to(X = bw$P, tcues = c(35*60, 42*60))
Mseg <- crop_to(X = bw$M, tcues = c(35*60, 42*60))

Plot the three of them together to make sure you got it right.

plott(X = list(Depth = Dseg, Acc = Aseg, Mag = Mseg), interactive = TRUE)

Then, run dsf() on Aseg to get the mean stroking rate:

dsfa <- dsf(Aseg)$fpk   # estimated stroking rate in Hz

Try doing the same with the magnetometer data:

dsfm <- dsf(Mseg)$fpk # another estimate

Are the estimated stroke rates similar?

Yes, they should be. The acceleration-based estimate is .3821574, and the magnetometer-based estimate is .3807932.

The magnetometer is not sensitive to specific acceleration, so why do stroking motions show up in Mseg?

The animal is changing its position, so the magnetometer reading will change.

Refer to your plots of Mseg and Dseg to try and figure out which axis the stroking motions show up in.

A good starting choice for the filter cut-off frequency is 70% of the stroking rate (pick one of the estimates, or average the two). Call this value fc. Run a complementary filter on A to separate the slow and fast time-scales. Recall that A is stored under bw as bw$A:

fc <- 'YourValueHere'           # your value for fc in Hz, a number, without quotes
Af <- comp_filt(bw$A, fc = fc) 
str(Af, max.level = 1) 
#> List of 2
#>  $ lowpass : num [1:137976, 1:3] -1.22 -1.22 -1.21 -1.19 -1.17 ...
#>  $ highpass: num [1:137976, 1:3] -0.624 -0.558 -0.516 -0.511 -0.471 ...

The complementary filter returns a list containing two data matrices: the low-pass filtered data and the high-pass filtered data. Each of these is a three-column matrix because the filter is run on each column of the input data. So it is like you now have two accelerometers in the tag—one is only sensitive to low frequencies and the other is only sensitive to high frequencies. If you would like to get each matrix out of the cell array, do:

Alow <- Af[[1]]     # low frequency A data
Ahigh <- Af[[2]]      # high frequency A data

The sampling rate of these is the same as for the original data. For simplicity, make a variable sampling_rate equal to the sampling rate and use plott() to plot the two filtered accelerations along with the dive profile:

sampling_rate <- bw$A$sampling_rate
plott(X = list(`Depth (m)` = bw$P$data,
               `LF Accel` = Alow, 
               `HF Accel` = Ahigh),
      fsx = sampling_rate)

These two versions of acceleration are sometimes called ‘static’ and ‘dynamic’ acceleration. If the filtering worked, you should see that Alow has large, relatively slow changes in acceleration which are mostly to do with orientation. These are missing in Ahigh, which has the high frequency specific acceleration, having to do with propulsion and strikes or flinches.

If you like, zoom in to the section of steady stroking that you used for dsf—you should only see the stroking in Ahigh, not in Alow.

plott(X = list(`Depth` = bw$P$data,
               `LF Accel` = Alow, 
               `HF Accel` = Ahigh),
      fsx = sampling_rate,
      interactive = TRUE)