Extract magnetometer data from a move2 or data.frame and convert to a
mag vector.
Data are extracted from the object's active_mag_colsets().
Usage
as_mag(x, ...)
# Default S3 method
as_mag(x, ...)
# S3 method for class 'move2'
as_mag(
x,
colset = NULL,
min_freq = 0,
freq_tol = 0.01,
gap_tol = 1e-06,
merge_continuous = TRUE,
drop = FALSE,
...
)
# S3 method for class 'data.frame'
as_mag(
x,
timestamp,
track_id,
colset = NULL,
min_freq = 0,
freq_tol = 0.01,
gap_tol = 1e-06,
merge_continuous = TRUE,
drop = FALSE,
...
)Arguments
- x
A
move2ordata.framecontaining magnetometer data. Amove2will typically be loaded from disk withmove2::mt_read()or downloaded usingmove2::movebank_download_study().- ...
These dots are for future extensions and must be empty.
- colset
An
imu_colsetobject or list ofimu_colsetobjects specifying the columns ofxthat contain magnetometer data. By default, constructs bursts for all column sets that are detected inxthat also contain data (seeactive_mag_colsets()).Several common colsets are listed under
movebank_mag_colsets(). To specify a custom set of columns, useimu_colset().- min_freq
For expanded-format data, the minimum allowable burst frequency in the output. Any burst whose derived frequency falls below this value is instead split into individual (length-1) bursts. Increase this value to avoid producing slow-frequency bursts. By default, all samples recorded at consistent intervals will be combined into bursts, regardless of their sampling frequency.
Inputs with compatible units are converted to Hz internally. If no units are specified,
min_freqis assumed to be in Hz.- freq_tol
Bare numeric value specifying the relative tolerance to use when detecting differences in sampling frequency when building or merging bursts. This determines how much two sampling frequencies may differ before they're treated as belonging to separate sampling regimes. Two frequencies belong to the same burst when the faster is at most
(1 + freq_tol)times the slower. For example,freq_tol = 0.01keeps frequencies that are within 1% of each other in the same burst.Increase this value to prevent small deviations in sample timing from initiating the creation of new bursts. See details.
- gap_tol
Absolute tolerance (in seconds) to use when determining whether two bursts are adjacent in time and can be merged. Two bursts are adjacent when the gap between the first burst's end and the second burst's start is within
gap_tol.For example, setting
gap_tol = 0.02would allow a burst that starts up to 0.02 seconds after the end of the previous burst to be merged. See details.- merge_continuous
Logical value indicating whether to merge adjacent bursts. Two adjacent bursts can be merged if the end of the first burst coincides with the start of the second burst (within
gap_tol) and their frequencies agree (withinfreq_tol). This is useful for processing continuous data that have been stored in chunks split at regular intervals (e.g. e-obs data). Seemerge_imu().- drop
Logical indicating whether empty bursts should be dropped from the output. If
drop = FALSE, then the length of the output will match the number of rows in the input dataxand bursts will be stored at the index location corresponding to the start time of the burst.- timestamp
When
xis adata.frame, a vector of timestamps corresponding to the recording time of each row ofx.Accepts
POSIXct,POSIXlt,Date, or numeric values.Dateobjects are treated as being recorded at midnight, UTC. Numeric values are interpreted as the number of seconds since1970-01-01 00:00:00 UTC. Inputs are all converted toPOSIXct.- track_id
When
xis adata.frame, a vector of IDs identifying the track (or other grouping variable) for each row inx. Bursts are never built across tracks, and adjacent bursts are only merged within a track.Provide
NULLto indicate that all rows belong to the same track.
Details
By default (drop = FALSE), the output vector will be the same length
as the input. This facilitates the use of an IMU burst vector as a column
in a data.frame. For expanded data formats, multiple rows of input data will
be represented in a single row in the output (corresponding to the start
timestamp of the burst).
Input requirements
as_*() functions require that the input be sorted by track and strictly
increasing in time. Duplicate timestamps within a single track must be
resolved before calling as_*(). For move2 inputs, see
move2::mt_is_track_id_cleaved(), move2::mt_is_time_ordered(), and
move2::mt_filter_unique() for help diagnosing issues with data
organization.
Dealing with noise in recorded timestamps
Noise in the recorded timestamps of the input data can disrupt the
correct identification of the IMU bursts identified by as_*().
For data stored in expanded format,
as_*()must derive the implied sampling frequency from the individual timestamps recorded in the data. Within each burst, all samples must be collected at a fixed frequency. However, timestamp errors may make it appear as if the sampling frequency has changed, artificially splitting a run of samples into multiple bursts.For data stored in compact format, sampling frequencies are recorded explicitly. However, when data are collected continuously, adjacent bursts need to be merged together. Here again, timestamp noise can prevent bursts from merging properly if gaps between bursts differ from the sampling period implied by the frequency of those two bursts.
You can fine-tune the burst parsing and merging process with the freq_tol
and gap_tol arguments.
freq_toldetermines how much sampling frequency noise is tolerated when identifying changes in sampling frequency over the course of a series of recorded samples. For example, atfreq_tol = 0.01, a new burst is initiated only when two consecutive sampling frequencies differ by more than 1%.Thus, at low values of
freq_tol, small deviations in the sampling frequency will trigger a new burst. Largerfreq_tolvalues will smooth these inconsistencies, combining samples into single bursts. However, at high values,freq_tolmay mask true changes in the sampling frequency, producing bursts with spurious sampling frequencies. For example,freq_tol = 0.5risks combining samples from a 30Hz signal with those from a 20Hz signal. Similarly, gradual timestamp drift within thefreq_tolcan produce misleading output frequencies for a burst.freq_tolalso governs the similarity tolerance between two burst sampling frequencies when merging bursts (ifmerge_continuous = TRUE). Note that bursts that do not clear themin_freqthreshold are automatically recorded in individual samples withNAfrequency, meaning these cannot later be merged.gap_toldetermines how much deviation in the time gap between bursts is tolerated when merging two bursts together, in seconds (ifmerge_continuous = TRUE). Two adjacent bursts can be merged when the gap between the two matches the sampling period (the reciprocal of the frequency) of each burst, and each burst has the same sampling frequency (withinfreq_tol). This implies that the two bursts represent one continuous stream of data. Small values ofgap_tolrequire that the gap be a near-exact match to the period implied by the sampling frequency of the bursts. Larger values ofgap_tolwill ignore larger deviations in gap timing.Note that a burst's frequency is recalculated after merging using the number of samples and the recorded start and end of the burst. Thus, setting a large
gap_tolmay produce bursts that have non-standard frequencies, as the gap between the bursts (which deviates from the expected sampling frequency) will be incorporated into the samples of a single burst.
In general, it is best to keep the tolerance parameters as low as possible while still accommodating the noise inherent in the timestamp recordings in your data.
Because of floating-point timestamp noise, some values of freq_tol and
gap_tol may not always admit the frequencies or gaps that you expect. To
reliably allow frequencies and gaps within a given tolerance, you may want to
set the values slightly above your desired output tolerance.
See also
movebank_mag_colsets() for supported magnetometer column sets
in Movebank.
Examples
# Example magnetometer data, with each burst stored as a single string
m <- data.frame(
magnetic_field_axes = "XYZ",
magnetic_field_sampling_frequency_per_axis = 10,
magnetic_fields_raw = c(
"1 5 9 2 6 10 3 7 11 4 8 12",
"2 6 10 3 7 11 4 8 12 5 9 13"
),
timestamp = as.POSIXct("2024-01-01", tz = "UTC") + c(0, 60),
id = "tag_1"
)
mag <- as_mag(m, timestamp = m$timestamp, track_id = m$id)
mag
#> <magnetometer[2]>
#> [1] (2.5 6.5 10.5) (3.5 7.5 11.5)
#> # frequency: 10 [Hz]
# Each burst holds a column of samples per recorded axis
bursts(mag)[[1]]
#> X Y Z
#> [1,] 1 5 9
#> [2,] 2 6 10
#> [3,] 3 7 11
#> [4,] 4 8 12
# Output is index-matched to the input so the result can be easily attached:
m$mag <- mag
# Data can also be provided with one sample per row:
m_expanded <- data.frame(
mag_x = c(1, 2, 3, 4),
mag_y = c(5, 6, 7, 8),
mag_z = c(9, 10, 11, 12),
timestamp = as.POSIXct("2024-01-01", tz = "UTC") + seq(0, 0.3, by = 0.1),
id = "tag_1"
)
# If column names are not identified automatically, specify your
# own column set:
as_mag(
m_expanded,
colset = imu_colset(x = "mag_x", y = "mag_y", z = "mag_z"),
timestamp = m_expanded$timestamp,
track_id = m_expanded$id
)
#> <magnetometer[4]>
#> [1] (2.5 6.5 10.5) <NA> <NA> <NA>
#> # frequency: 10 [Hz]
# For a `move2`, timestamps and track IDs come from the object's metadata.
# Build a sample move2 with empty geometries:
m2 <- move2::mt_as_move2(
sf::st_sf(m, geometry = sf::st_sfc(rep(list(sf::st_point()), nrow(m)))),
time_column = "timestamp",
track_id_column = "id"
)
as_mag(m2)
#> <magnetometer[2]>
#> [1] (2.5 6.5 10.5) (3.5 7.5 11.5)
#> # frequency: 10 [Hz]