-
Notifications
You must be signed in to change notification settings - Fork 0
/
magnetometer-filtering.Rmd
184 lines (132 loc) · 10.1 KB
/
magnetometer-filtering.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
---
title: "More complementary filtering: magnetometer & dynamic acceleration"
author: "tagtools project team"
date: "`r Sys.Date()`"
output:
html_document:
code_folding: hide
vignette: >
%\VignetteIndexEntry{magnetometer-filtering}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r setup, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
require(tagtools)
```
Welcome to the `magnetometer-filtering` vignette! Thanks for getting some time to know our package---we hope it's, thus far, all you've dreamed it would be.
This vignette will probably be more insightful if you complete it after `complementary-filtering` and/or `jerk-transients`, but you are welcome to try it regardless. In this vignette, you will use a complementary filter to separate magnetometer data into low and high frequencies. This is similar to what we do in `complementary-filtering` with acceleration data.
*Estimated time for this vignette: 25 minutes.*
These practicals 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
If you've done `acceleration-filtering` *or* `jerk-transients` **within the same R session**, skip down to [Spoilers]. If, within the same R session, you've done *both*, skip to [Complementary Filter for Magnetometer]. If not, you'll want to do this section to load the necessary data, and take a look at it.
For these vignettes we will use data from a suction cup tag attached to the back of a beaked whale. The data is in `testset1`. 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
Use `load_nc()` to read it in---write `testset1.nc` to the object `bw`, for "beaked whale". Then use `plott()` to get a look at it.
```{r, echo = TRUE, eval = FALSE}
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))
```
<button class="btn btn-primary" data-toggle="collapse" data-target="#plott_bw"> Show/Hide Results </button>
<div id="plott_bw" class="collapse">
```{r, echo = FALSE, eval = TRUE}
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))
```
</div>
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.
# Spoilers
If you've done both `acceleration-filtering` AND `jerk-transients` in the same R session, skip down to [Complementary Filter for Magnetometer]. If not, you'll want to do this section. We'll do a bunch of spoilers from these two vignettes so that we have the objects we need. Paste all this code in, and it shouldn't mess with what you already had, whether you've done one or the other.
```{r, echo = TRUE, eval = TRUE}
# stuff from acceleration-filtering
fc = 0.267032715030423 # filter cut-off frequency
Af <- comp_filt(bw$A, fc = fc) # filtering acceleration data
Alow <- Af[[1]] # low-frequency acceleration
Ahigh <- Af[[2]] # high-frequency acceleration
sampling_rate <- bw$A$sampling_rate # sampling rate for this data
intvl1 <- c(36*60, 38*60)
intvl2 <- c(56*60, 58*60) # two interesting time intervals: 36-38 and 56-58 minutes
Ah1 <- crop_to(Ahigh, sampling_rate = sampling_rate, tcues = intvl1) # high-frequency acceleration data in the first interval
Ah2 <- crop_to(Ahigh, sampling_rate = sampling_rate, tcues = intvl2) # high-frequency acceleration data in the first interval
# stuff from jerk-transients (might depend on stuff from complementary-filtering, just paste it all)
J <- njerk(bw$A) # get jerk
Ad <- decdc(bw$A, 5) # decimate accel data by a factor of 5
Jd <- njerk(Ad) # decimated jerk
```
# Complementary Filter for Magnetometer
Let's get started! Try applying the complementary filter to the magnetometer data, `bw$M`, and then plot the high frequency magnetometer data for the two intervals of swimming that you might have looked at in the Locomotion style section of `acceleration-filtering`.
```{r, echo = TRUE, eval = TRUE}
Mf <- comp_filt(bw$M, fc = fc)
Mhigh <- Mf[[2]] # high frequency M data
Mh1 <- crop_to(Mhigh, sampling_rate = sampling_rate, tcues = intvl1)
Mh2 = crop_to(Mhigh, sampling_rate = sampling_rate, tcues = intvl2)
```
Make a new figure and plot these for comparison.
```{r, echo = TRUE, eval = FALSE}
plott(X = list(`Mh Interval 1` = Mh1, `Mh interval 2` = Mh2), fsx = sampling_rate)
```
<button class="btn btn-primary" data-toggle="collapse" data-target="#plott_Mh1Mh2"> Show/Hide Results </button>
<div id="plott_Mh1Mh2" class="collapse">
```{r, echo = FALSE, eval = TRUE}
plott(X = list(`Mh Interval 1` = Mh1, `Mh interval 2` = Mh2), fsx = sampling_rate)
```
</div>
How do the magnetometer signals compare to the same intervals in the accelerometer (`Ah1` and `Ah2`)? Either hearken back to `acceleration-filtering` or open the following:
```{r, echo = TRUE, eval = FALSE}
# Spoilers from acceleration-filtering. If you want to see how the accelerometer signals in these time intervals look, here's the code.
plott(X = list(`Ah Interval 1` = Ah1, `Ah interval 2` = Ah2), fsx = sampling_rate)
```
<button class="btn btn-primary" data-toggle="collapse" data-target="#plott_Ah1Ah2"> Show/Hide Results </button>
<div id="plott_Ah1Ah2" class="collapse">
```{r, echo = FALSE, eval = TRUE}
# Spoilers from acceleration-filtering. If you want to see how the accelerometer signals in these time intervals look, here's the code.
plott(X = list(`Ah Interval 1` = Ah1, `Ah interval 2` = Ah2), fsx = sampling_rate)
```
</div>
Do you see a similar increase in magnitude in the magnetometer data in interval 2 as you did with acceleration?
<button class="btn btn-primary" data-toggle="collapse" data-target="#ans_similar_mag_increase_mag"> _Show/Hide Answers_ </button>
<div id="ans_similar_mag_increase_mag" class="collapse">
*Actually, no. In the case of acceleration, in first interval the magnitude of the peaks is usually between* $-1$ *and* $+1.5$ $m/s^2$ *, whereas in the second interval the magnitude of the peaks is between* $-3$ and $+4$ $m/s^2$*. By contrast, in the case of the magnetometer data, the magnitude of the peaks is between *$-4$ *and* $+4$ $\mu T$*in both interval 1 and interval 2.*
</div>
Remember that the magnetometer is sensitive to postural dynamics but not specific acceleration. Can you conclude whether the difference between the swimming styles is a result of larger amplitude swimming strokes (i.e., a larger orientation dynamic due to body undulations) or a larger specific acceleration, or a bit of both?
<button class="btn btn-primary" data-toggle="collapse" data-target="#ans_why_swim_diff"> _Show/Hide Answers_ </button>
<div id="ans_why_swim_diff" class="collapse">
*The magnetometer is not reporting a difference, but the accelerometer is. So the difference between swimming styles must be due to a larger specific acceleration, not postural dynamics.*
</div>
# Jerk vs. Dynamic Acceleration
As you may know, any high-pass filter will emphasize rapid changes in acceleration.
Jerk is effectively a filter that emphasises higher frequencies progressively more. You could also use a filter that is flat above a cut-off frequency, like the complementary filter you used to make `Ahigh`.
To get the magnitude of the three axes together like with `njerk()`, use `norm2()`. This gives what is sometimes called the *dynamic acceleration*:
```{r, eval = TRUE, echo = TRUE}
DA <- norm2(Ahigh)
```
Plot `DA` and `J` to compare them:
```{r, echo = TRUE, eval = FALSE}
plott(X = list(`Dyn. Acc` = DA, Jerk = J), fsx = sampling_rate)
```
<button class="btn btn-primary" data-toggle="collapse" data-target="#plott_DAJ"> Show/Hide Results </button>
<div id="plott_DAJ" class="collapse">
```{r, echo = FALSE, eval = TRUE}
plott(X = list(`Dyn. Acc` = DA, Jerk = J), fsx = sampling_rate)
```
</div>
Check out the obvious peaks around minute 20 to minute 30 to see how clear they look in `DA` and `J`. Which signal gives the lowest noise between the peaks, i.e., the best signal-to-noise ratio? What does that suggest about the frequency content in the acceleration transients? Give some thought to your answers--you're so close.
<button class="btn btn-primary" data-toggle="collapse" data-target="#ans_freq_content_accel_transients"> _Show/Hide Answers_ </button>
<div id="ans_freq_content_accel_transients" class="collapse">
*Jerk gives a better signal-to-noise ratio than dynamic acceleration. This suggests that the acceleration transients happen so quickly, so it is important to have high-resolution data.* **Is this right?**
</div>
# Review
You've learned how to separate low- and high-frequency magnetometer data with a complementary filter, and done some interpretation of these two sets of data.
Fabulous work! You pranced all the way through this vignette.
*If you'd like to continue working through these vignettes, `fine-scale-tracking` is a fairly logical option. In it, you'll consider dead-reckoned paths as a way to visualize how an animal might move, why this can lead to large errors, and how to correct for some of those errors.*
```{r, echo = TRUE, eval = FALSE}
vignette('fine-scale-tracking')
```
***
Animaltags home pages: http://animaltags.org/ (old), https://animaltags.netlify.app/ (new), https://github.com/stacyderuiter/TagTools (for latest beta source code), https://stacyderuiter.github.io/TagTools/articles/TagTools (vignettes overview)