Usage
For the full theoretical description, refer to the njerk() technical explanation.
Inputs
A:A sensor data structure or annx3acceleration matrix with columns[ax ay az].Acan be in any consistent unit, e.g., g or m/s^2.Acan be in any frame as the norm-jerk is rotation independent.Amust have at least 2 rows (i.e.,n>=2) and must be regularly sampled.fs:The sampling rate of the sensor data in Hz (samples per second). This is only needed ifAis 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 inputAwas 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 ofAis m/s^2, the norm-jerk has unit m/s^3. If the unit ofAis g, the norm-jerk has unit g/s. Asjis the norm of the jerk, it is always positive or zero (if the acceleration is constant). The final value injis 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 were gleaned from the file and added to the data. Other metadata were 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 5 s, i.e., we expect that the shortest time between prey captures is 5 s, 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 have 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()