Usage
For the full theoretical description, refer to the njerk() technical explanation.
Inputs
A:
A sensor data structure or annx3
acceleration matrix with columns[ax ay az]
.A
can be in any consistent unit, e.g., g or m/s^2.A
can be in any frame as the norm-jerk is rotation independent.A
must have at least 2 rows (i.e.,n>=2
) and be regularly sampled.fs:
The sampling rate of the sensor data in Hz (samples per second). This is only needed ifA
is not a sensor structure.
Outputs
j:
is the norm jerk, a column vector with the same number of rows as inA
, or a tag sensor data structure (if the inputA
was one). The norm-jerk is ||dA/dt||, where ||x|| is the 2-norm ofx
, i.e., the square-root of the sum of the squares of each axis. If the unit ofA
is m/s^2, the norm-jerk has unit m/s^3. If the unit ofA
is g, the norm-jerk has unit g/s. Asj
is the norm of the jerk, it is always positive or zero (if the acceleration is constant). The final value inj
is always 0 because the last finite difference cannot be calculated.
Theoretical Description
Rapid muscle movements which could be associated with strikes at prey, ingestion, predator detection and avoidance, sound production, breathing, heart-beat and many other important activities that we would like to detect reliably could be detected calculating the jerk. For the full theoretical description, refer to the njerk() technical explanation.
Technical Description
The jerk is the differential (i.e., the rate of change) of acceleration and has units m/s3. Taking the differential emphasises the fast-changing parts of a signal and de-emphasises the slow-changing parts. Thus, jerk is a great way to emphasise smaller-but-sharper components in the accelerometer data possibly associated with rapid muscle movements.
Caveats
Jerk is not generally a good measure of activity because it de-emphasises steady powerful movements such as locomotion. For the full caveats description, refer to the njerk() technical explanation.
Load and Visualize the Test Data Set
For this practical we will use data from a suction cup tag attached to the back of a beaked whale [Note]This dataset has already been converted from a source file that was offloaded from the tag into a NetCDF file. In doing so, some metadata was gleaned from the file and added to the data. Other metadata was added by hand.. The same one as in dsf tutorial. This dataset is built into the tagtools
package, so you can access it using system.file
bw_file_path = xxx
bw = load_nc(bw_file_path)
bw_file_path <- system.file("extdata", "testset1.nc", package = 'tagtools', mustWork = TRUE)
bw <- load_nc(bw_file_path)
Then use plott()
to inspect it:
figure
plott(bw.P, bw.A, bw.M)
subplot(311)
ylabel('Depth')
subplot(312)
ylabel('Acc')
subplot(313)
ylabel('Mag')
legend({'x-axis','y-axis','z-axis'})
plott(X = list(Depth = bw$P, Acc = bw$A, Mag = bw$M))
Expand to show figure …


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
Acceleration transients, jerk and dynamic acceleration
We want to look for indications of foraging during the two dives. Sudden changes (transients) in acceleration are often associated with prey capture attempts. One way to emphasise rapid changes in acceleration is by differentiating it to produce the jerk.
This is effectively high-pass filtering acceleration with a constantly-sloping filter—the higher the frequency, the more it is emphasised. Because we don’t know what kind of movement is involved in a prey capture attempt, we don’t know which axis of acceleration will be most relevant. It is safer then to just compute the magnitude of the jerk in all three axes to get a single vector (also called “norm-jerk”). That way, a peak in any or all axes will show up. njerk()
function computes this from acceleration. Try running
on our acceleration data and writing the result to njerk()
J
. Then, once you also grab the sampling rate, you can plot this jerk data.
J = njerk(bw.A)
fs = bw.A.sampling_rate
figure
plott(bw.P.data, fs, J, fs)
subplot(211)
ylabel('Depth')
axis ij
subplot(212)
ylabel('Jerk')
J <- njerk(bw$A)
fs <- bw$A$sampling_rate
plott(X = list(Depth = bw$P$data, Jerk = J), fsx = fs)
Expand to show figure …


Where in the dive profile do the largest jerk transients (peaks) appear?
The largest jerk transients appear mostly at the bottom of the deeper dive.
Check out some of the biggest peaks to see how short they are.
Effects of Sampling Rate on jerk
The size and clarity of the jerk peaks depends on the sampling rate. We are using 25 Hz data. To see what you would get with 5 Hz data, try decimating the acceleration before computing the jerk:
bw.A % look at the data before decimation
Ad = decdc(bw.A, 5) % decimate by 5 times. New sampling rate is 25/5 Hz
bw.Ad % look at the data after decimation
str(bw$A, max.level = 1) # look at the data before decimation
Ad <- decdc(bw$A, 5) # decimate by 5 times. New sampling rate is 25/5 Hz
str(Ad, max.level = 1) # and after decimation
Compute the decimated jerk from the decimated acceleration, and plot it with the jerk computed from the full bandwidth acceleration:
Jd = njerk(Ad)
fsd = bw.Ad.sampling_rate
figure
plott(bw.P.data, fs, J, fs, Jd, fsd)
subplot(311)
ylabel('Depth')
axis ij
subplot(312)
ylabel('Jerk')
subplot(313)
ylabel('Jerk dec')
Jd <- njerk(Ad)
plott(X = list(Depth = bw$P$data, `25 Hz Jerk` = J, `5Hz Jerk` = Jd),
fsx = c(fs, fs, fs/5))
Expand to show figure …


Check out some of the obvious peaks around minute 20 to minute 30 to have a look at the ‘signal-to-noise’ in the jerk transients.
How clear are the jerk transients in the decimated signal compared to the original data rate? What does this tell you about the frequency content in the transients?
Jerk transients are clearer in the original data rate. This is an indication that the frequency content in the transients is higher than 5Hz.
Detecting Jerk Peaks
To find potential prey capture attempts, we need to run a detector on the norm-jerk signal. Although it is easy to see peaks by eye in the data, detectors require some information to do a good job: they need to know the threshold above which a peak is really a peak and the blanking time, i.e., the minimum time that must elapse after a detection before another detection can happen.
The tagtools toolbox includes interactive peak detectors, detect_peaks()
function, that allow you to choose a threshold and see the effect this has on which transients are detected. We will use a blanking time of 5s, i.e., we expect that the shortest time between prey captures is 5s, the rest of the inputs will be set as default, i.e., []
:
peaks = detect_peaks(J, fs,[], [], 5, [], [])
xlabel('Time (1/sampling rate)')
ylabel('Signal Power')
pks <- detect_peaks(J, fs, bktime = 5) # 5s blanking time, threshold is interactive
Expand to show figure …


Follow the instructions in the console to change the threshold. You need to pick a threshold that excludes most of the jerk transients during the strong propulsion locomotion in the ascent but that still detects most of the jerk transients during the bottom part of the deep dive. (Balancing false detections and missed detections is often not easy in a detector and is a matter of finding a trade-off that works for your application.) In the figure given, we’ve set the threshold to 100.
This function returns a list of information about the detected peaks. For each detection, the start and end times are reported (in seconds), along with the time at which the peak occurred and the height of the peak. Finally, the selected threshold and blanking time are reported. You can plot the height and time of each detection along with the dive profile as follows:
figure
plott(bw.P)
plot(peaks.peak_time/fs/60,bw.P.data(round(peaks.peak_time)),'go')
ylabel('Depth, m')
plott(X = list(Depth = bw$P))
# note: the code below assumes your plott x-axis is in hours.
# if it were in minutes use /60 instead of /3600, etc.
points(pks$peak_time/fs/3600, bw$P$data[round(pks$peak_time)], pch = 8)
Expand to show figure …


Common Questions
Bearing in mind that some of the jerk peaks might come from strong locomotory strokes, is there strong evidence for foraging in the deep dive? Is there strong evidence for foraging in the shallow dive?
Yes during the deep dive, but not during the shallow dive.
Now, if you have done complementary-filtering
recently, here is one more question for you. Adding your inference from complementary-filtering
about locomotion in the shallow dive, what can you conclude about the general behaviour of the animal in the shallow dive? Namely, is it resting, traveling or foraging? Write down your marvelous thoughts.
We know now that the whale is likely not foraging in the shallow dive, since the sudden movements (jerk peaks) are happening only in the earlier dive. Additionally, though the animal is not accelerating quickly (striking/flinching), it is still moving (locomotion). So it seems more likely to be traveling than resting.
Further Resources
You’ve learned how to accentuate quick movements of an animal using jerk, and used the accentuated picture to gain understanding about the animal’s behaviour.
For a more in-depth explanation of the usage and inner workings of the
tool, refer to the Technical Explanation of jerk. njerk()