The TDR class aims to be a comprehensive class to encapsulate the
processing of TDR records from a NetCDF data file.
Processing includes detection and quantification of periods of major
activities in a TDR record, calibrating depth readings to generate
summaries of diving behaviour. These procedures include wet/dry phase
detection, zero-offset correction (ZOC) of depth, detection of dives, as
well as proper labelling of the latter, among others utilities for the
analysis of TDR records.
All core procedures are encapsulated in TDR, and are controlled by
a set of user-defined variables in a configuration file, and systematically
executed systematically by function calibrate(). This function can be
used as a template for custom processing using different
sequences. User-defined variables can also be directly specified as a
dictionary, which is a class attribute. The standard approach follows the
logical processing sequence described below:
Zero-offset correction
Detection of wet phases
Detection of dives
Detection of dive phases
Speed calibration (if required)
Calculation of statistics
Class TDR methods implement these steps. This module instantiates
an R session to interact with low-level functions and methods of package
diveMove.
Set the speed_calib_fit attribute. This method calibrates speed
readings following the procedure outlined in Blackwell et.
al. (1999) [1].
Parameters:
tau (float, optional) – Quantile on which to regress speed on rate of depth change.
contour_level (float, optional) – The mesh obtained from the bivariate kernel density estimation
corresponding to this contour will be used for the quantile
regression to define the calibration line.
z (float, optional) – Only changes in depth larger than this value will be used for
calibration.
bad (array_like, optional) – Two-element array_like indicating that only rates of depth
change and speed greater than the given values should be used
for calibration, respectively.
Complete filling the dives attribute. The process for each dive
begins by taking all observations below the dive detection
threshold, and setting the beginning and end depths to zero, at
time steps prior to the first and after the last, respectively.
The latter ensures that descent and ascent derivatives are
non-negative and non-positive, respectively, so that the end and
beginning of these phases are not truncated. The next step is to
fit a model to each dive. Two models can be chosen for this
purpose: unimodal (default) and smooth.spline (see Notes).
Both models consist of a cubic spline, and its first derivative is
evaluated to investigate changes in vertical rate. Therefore, at
least 4 observations are required for each dive, so the time series
is linearly interpolated at equally spaced time steps if this limit
is not achieved in the current dive. Wiggles at the beginning and
end of the dive are assumed to be zero offset correction errors, so
depth observations at these extremes are interpolated between zero
and the next observations when this occurs.
This procedure generates a categorical variable with levels D,
DB, B, BA, DA, A, and X, breaking the input
into descent, descent/bottom, bottom, bottom/ascent, ascent,
descent/ascent (occurring when no bottom phase can be detected) and
non-dive (surface), respectively.
Parameters:
dive_model ({"unimodal", "smooth.spline"}) – Model to use for each dive for the purpose of dive phase
identification. One of smooth.spline or unimodal, to
choose among smoothing spline or unimodal regression. For dives
with less than five observations, smoothing spline regression
is used regardless.
smooth_par (float, optional) – Amount of smoothing when dive.model="smooth.spline". If it
is None, then the smoothing parameter is determined by
Generalized Cross-validation (GCV). Ignored with default
dive.model="unimodal".
knot_factor (int, optional) – Multiplier for the number of samples in the dive. This is used
to construct the time predictor for the derivative.
descent_crit_q (float, optional) – Critical quantile of rates of descent below which descent is
deemed to have ended.
ascent_crit_q (float, optional) – Critical quantile of rates of ascent above which ascent is
deemed to have started.
Notes
1. Unimodal method: in this default model, the spline is
constrained to be unimodal [2], assuming the diver must return to
the surface to breathe. The model is fitted using R’s uniReg
package. This model and constraint are consistent with the
definition of dives in air-breathers, so is appropriate for this
group of divers. A major advantage of this approach over the next
one is that the degree of smoothing is determined via restricted
maximum likelihood, and has no influence on identifying the
transition between descent and ascent. Therefore, unimodal
regression splines make the latter transition clearer compared to
using smoothing splines. Note that dives with less than five
samples are fit using smoothing splines regardless, as they produce
the same fit as unimodal regression but much faster. Therefore,
ensure that the parameters for that model are appropriate for the
data, although defaults are reasonable.
2. Smooth spline: in this model, specified via
dive_model="smooth.spline", a smoothing spline is used to model
each dive, using the chosen smoothing parameter. Dive phases
identified via this model, however, are highly sensitive to the
degree of smoothing (smooth_par) used, thus making it difficult
to determine what amount of smoothing is adequate.
The first derivative of the spline is evaluated at a set of knots
to calculate the vertical rate throughout the dive and determine
the end of descent and beginning of ascent. This set of knots is
established using a regular time sequence with beginning and end
equal to the extremes of the input sequence, and with length equal
to \(N \times knot\_factor\). Equivalent procedures are used
for detecting descent and ascent phases.
Once one of the models above has been fitted to each dive, the
quantile corresponding to (descent_crit_q) of all the positive
derivatives (rate of descent) at the beginning of the dive is used
as threshold for determining the end of descent. Descent is deemed
to have ended at the first minimum derivative, and the nearest
input time observation is considered to indicate the end of
descent. The sign of the comparisons is reversed for detecting the
ascent. If observed depth to the left and right of the derivative
defining the ascent are the same, the right takes precedence.
The particular dive phase categories are subsequently defined using
simple set operations.
Set the dives attribute’s row_ids dictionary element, and
update the wet_act attribute’s phases dictionary
element. Whenever the zero-offset corrected depth in an underwater
phase is below the specified dive threshold. A new categorical
variable with finer levels of activity is thus generated, including
U (underwater), and D (diving) in addition to the ones
described above.
Parameters:
dive_thr (float) – Threshold depth below which an underwater phase should be
considered a dive.
A categorical variable is created with value L (dry) for rows
with null depth samples and value W (wet) otherwise. This
assumes that TDRs were programmed to turn off recording of depth
when instrument is dry (typically by means of a salt-water
switch). If this assumption cannot be made for any reason, then a
boolean vector as long as the time series can be supplied to
indicate which observations should be considered wet. The duration
of each of these phases of activity is subsequently calculated. If
the duration of a dry phase (L) is less than a threshold
(configuration variable dry_thr), then the values in the factor
for that phase are changed to W (wet). The duration of phases
is then recalculated, and if the duration of a phase of wet
activity is less than another threshold (variable wet_thr), then
the corresponding value for the factor is changed to Z (trivial
wet). The durations of all phases are recalculated a third time to
provide final phase durations.
Some instruments produce a peculiar pattern of missing data near
the surface, at the beginning and/or end of dives. The argument
interp_wet may help to rectify this problem by using an
interpolating spline function to impute the missing data,
constraining the result to a minimum depth of zero. Please note
that this optional step is performed after ZOC and before
identifying dives, so that interpolation is performed through dry
phases coded as wet because their duration was briefer than
dry_thr. Therefore, dry_thr must be chosen carefully to avoid
interpolation through legitimate dry periods.
Parameters:
dry_thr (float, optional) – Dry error threshold in seconds. Dry phases shorter than this
threshold will be considered as wet.
wet_cond (bool mask, optional) – A Pandas.Series bool mask indexed as depth. It indicates
which observations should be considered wet. If it is not
provided, records with non-missing depth are assumed to
correspond to wet conditions. Default is generated from testing
for non-missing depth.
wet_thr (float, optional) – Wet threshold in seconds. At-sea phases shorter than this
threshold will be considered as trivial wet.
interp_wet (bool, optional) – If True, then an interpolating spline function is used to
impute NA depths in wet periods (after ZOC). Use with
caution: it may only be useful in cases where the missing data
pattern in wet periods is restricted to shallow depths near the
beginning and end of dives. This pattern is common in some
satellite-linked TDRs.
Notes
Unlike diveMove, the beginning/ending times for each phase are
not stored with the class instance, as this information can be
retrieved via the time_budget() method.
depth_deriv (bool, optional) – Whether to compute depth derivative statistics.
Returns:
DataFrame indexed by dive number, having the following columns:
begdesc: time stamp for the start of each dive;
enddesc: time stamp for the descent’s end;
begasc: time stamp for the beginning of the ascent;
desctime: duration of descent;
botttim: duration of the bottom phase;
asctim: duration of ascent;
divetim: dive duration;
descdist: last descent depth;
bottdist: sum of the absolute depth differences while
at the bottom of the dive; a measure of the amount of
“wiggling” while at the bottom;
ascdist: first ascent depth;
bottdep_mean: mean bottom depth;
bottdep_median: median bottom depth;
bottdep_sd: standard deviation of bottom depths;
maxdep: maximum depth;
desc_tdist: descent total distance, estimated from speed;
desc_mean_speed: descent mean speed;
desc_angle: descent mean speed;
bott_tdist: total distance at the bottom, estimated
from speed;
bott_mean_speed: mean speed at the bottom;
asc_tdist: ascent total distance, estimated from speed;
asc_mean_speed: ascent mean speed;
asc_angle: ascent angle, relative to bottom plane;
postdive_dur: postdive duration;
postdive_tdist: postdive total distance, estimated from
speed;
postdive_mean_speed: postdive mean speed.
If depth_deriv=True (default), 21 additional columns with
the minimum, first quartile, median, mean, third quartile,
maximum, and standard deviation of the depth derivative for
each phase of the dive are included.
concur_vars (str or list, optional) – String or list of strings with names of columns in input to
select additional data to plot.
concur_var_titles (str or list, optional) – String or list of strings with y-axis labels for concur_vars.
**kwargs – Optional keyword arguments passed to plotting function,
including those listed below. Additional arguments are passed
to underlying plotting method.
xlim (tuple of (float, float)) – Minimum and maximum limits for x axis. Ignored when
concur_vars=None.
ylim (tuple of (float, float)) – Minimum and maximum limits for y axis for data other than
depth.
depth_lim (array_like of (float, float)) – Minimum and maximum limits for depth to plot.
Diagnostic double-panel plot of dive models for selected dives. The
top panel shows depth against time, the cubic spline smoother, the
identified descent and ascent phases (which form the basis for
identifying the rest of the dive phases), while the bottom panel
shows the first derivative of the smooth trace.
Parameters:
diveNo (array_like, optional) – List of dive numbers (1-based) to plot.
**kwargs – Optional keyword arguments passed to
subplots().
Compare the zero-offset corrected depth with the uncorrected
signal, or the progress attained in each of the filters during
recursive filtering for zero-offset correction, as illustrated in
Luque and Fried (2011) [3].
Parameters:
xlim (array_like, optional) – array_like with minimum and maximum limits for x- and
y-axis, respectively.
ylim (array_like, optional) – array_like with minimum and maximum limits for x- and
y-axis, respectively.
**kwargs – Optional keyword arguments passed to
subplots().
Apply zero offset correction to depth measurements
This procedure is required to correct drifts in the pressure
transducer of TDR records and noise in depth measurements. Three
methods are available to perform this correction.
Method offset can be used when the offset is known in advance,
and this value is used to correct the entire time series.
Therefore, offset=0 specifies no correction.
Method filter implements a smoothing/filtering mechanism where
running quantiles can be applied to depth measurements in a
recursive manner [3]. The method calculates the first running
quantile defined by the first probability in a given sequence on a
moving window of size specified by the first integer supplied in a
second sequence. The next running quantile, defined by the second
supplied probability and moving window size, is applied to the
smoothed/filtered depth measurements from the previous step, and so
on. The corrected depth measurements (d) are calculated as:
\[d = d_{0} - d_{n}\]
where \(d_{0}\) is original depth and \(d_{n}\) is the last
smoothed/filtered depth. This method is under development, but
reasonable results can be achieved by applying two filters (see
Examples). The default na_rm=True works well when there are no
level shifts between non-NA phases in the data, but na_rm=False
is better in the presence of such shifts. In other words, there is
no reason to pollute the moving window with null values when
non-null phases can be regarded as a continuum, so splicing
non-null phases makes sense. Conversely, if there are level shifts
between non-null phases, then it is better to retain null phases to
help the algorithm recognize the shifts while sliding the
window(s). The search for the surface can be limited to specified
bounds during smoothing/filtering, so that observations outside
these bounds are interpolated using the bounded smoothed/filtered
series.
Once the entire record has been zero-offset corrected, remaining
depths below zero, are set to zero, as these are assumed to
indicate values at the surface.
Parameters:
method ({"filter", "offset"}) – Name of method to use for zero offset correction.
**kwargs – Optional keyword arguments passed to the chosen method
(_offset_depth(), _filter_depth())
Detect periods of major activities in a TDR object, calibrate depth
readings, and speed if appropriate, in preparation for subsequent
summaries of diving behaviour.
This function is a convenience wrapper around detect_wet(),
detect_dives(), detect_dive_phases(),
zoc(), and calibrate_speed(). It performs
wet/dry phase detection, zero-offset correction of depth, detection of
dives, as well as proper labelling of the latter, and calibrates speed
data if appropriate.
Due to the complexity of this procedure, and the number of settings
required for it, a calibration configuration file (JSON) is used to
guide the operations.
Parameters:
tdr_file (str, Path or xarray.backends.*DataStore) – As first argument for xarray.load_dataset().
config_file (str) – A valid string path for TDR calibration configuration file.