R: Calibrate Depth and Generate a "TDRcalibrate" object

calibrateDepth {diveMove} | R Documentation

## Calibrate Depth and Generate a "TDRcalibrate" object

### Description

Detect periods of major activities in a TDR record, calibrate depth readings, and generate a `TDRcalibrate` object essential for subsequent summaries of diving behaviour.

### Usage

    calibrateDepth(
      x,
      dry.thr = 70,
      wet.cond,
      wet.thr = 3610,
      dive.thr = 4,
      zoc.method = c("visual", "offset", "filter"),
      ...,
      interp.wet = FALSE,
      dive.model = c("unimodal", "smooth.spline"),
      smooth.par = 0.1,
      knot.factor = 3,
      descent.crit.q = 0,
      ascent.crit.q = 0
    )

### Arguments

`x` | An object of class `TDR` for `calibrateDepth` or an object of class `TDRcalibrate` for `calibrateSpeed`.
`dry.thr` | numeric: dry error threshold in seconds. Dry phases shorter than this threshold will be considered as wet.
`wet.cond` | logical: indicates which observations should be considered wet. If it is not provided, records with non-missing depth are assumed to correspond to wet conditions (see ‘Details’ and ‘Note’ below).
`wet.thr` | numeric: wet threshold in seconds. At-sea phases shorter than this threshold will be considered as trivial wet.
`dive.thr` | numeric: threshold depth below which an underwater phase should be considered a dive.
`zoc.method` | character string to indicate the method to use for zero offset correction. One of “visual”, “offset”, or “filter” (see ‘Details’).
`...` | Arguments required for ZOC methods `filter` (`k`, `probs`, `depth.bounds` (defaults to range), `na.rm` (defaults to TRUE)) and `offset` (`offset`).
`interp.wet` | logical: if TRUE (default is FALSE), 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.
`dive.model` | character string specifying what 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 (see ‘Details’). For dives with less than five observations, smoothing spline regression is used regardless (see ‘Details’).
`smooth.par` | numeric scalar representing amount of smoothing (argument `spar` in `smooth.spline`) when `dive.model="smooth.spline"`. If it is NULL, then the smoothing parameter is determined by Generalized Cross-validation (GCV). Ignored with default `dive.model="unimodal"`.
`knot.factor` | numeric scalar that multiplies the number of samples in the dive. This is used to construct the time predictor for the derivative.
`descent.crit.q` | numeric: critical quantile of rates of descent below which descent is deemed to have ended.
`ascent.crit.q` | numeric: critical quantile of rates of ascent above which ascent is deemed to have started.

### Details

This function is really a wrapper around `.detPhase`, `.detDive`, and `.zoc` which perform the work on simplified objects. It performs wet/dry phase detection, zero-offset correction of depth, and detection of dives, as well as proper labelling of the latter.

The procedure starts by zero-offset correcting depth (see ‘ZOC’ below), and then a factor is created with value “L” (dry) for rows with NAs for `depth` 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 logical vector as long as the time series should be supplied as argument `wet.cond` to indicate which observations should be considered wet. This argument is directly analogous to the `subset` argument in `subset.data.frame`, so it can refer to any variable in the `TDR` object (see ‘Note’ section below). The duration of each of these phases of activity is subsequently calculated. If the duration of a dry phase (“L”) is less than `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 `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.

The next step is to detect dives whenever the zero-offset corrected depth in an underwater phase is below the specified dive threshold. A new factor with finer levels of activity is thus generated, including “U” (underwater), and “D” (diving) in addition to the ones described above.

Once dives have been detected and assigned to a period of wet activity, phases within dives are identified using the descent, ascent and wiggle criteria (see ‘Detection of dive phases’ below). This procedure generates a factor with levels “D”, “DB”, “B”, “BA”, “DA”, “A”, and “X”, breaking the input into descent, descent/bottom, bottom, bottom/ascent, ascent, descent/ascent (ocurring when no bottom phase can be detected) and non-dive (surface), respectively.

## ZOC

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 “visual” calls `plotTDR`, which plots depth and, optionally, speed vs. time with the ability of zooming in and out on time, changing maximum depths displayed, and panning through time. The button to zero-offset correct sections of the record allows for the collection of ‘x’ and ‘y’ coordinates for two points, obtained by clicking on the plot region. The first point clicked represents the offset and beginning time of section to correct, and the second one represents the ending time of the section to correct. Multiple sections of the record can be corrected in this manner, by panning through the time and repeating the procedure. In case there's overlap between zero offset corrected windows, the last one prevails.

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 (Luque and Fried 2011), using `.depth.filter`. The method calculates the first running quantile defined by `probs[1]` on a moving window of size `k[1]`. The next running quantile, defined by `probs[2]` and `k[2]`, 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 NAs when non-NA phases can be regarded as a continuum, so splicing non-NA phases makes sense. Conversely, if there are level shifts between non-NA phases, then it is better to retain NA 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 whole record has been zero-offset corrected, remaining depths below zero, are set to zero, as these are assumed to indicate values at the surface.

## Detection of dive phases

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’.

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.

### ‘unimodal’

In this default model, the spline is constrained to be unimodal (Koellmann et al. 2014), assuming the diver must return to the surface to breathe. The model is fitted using the uniReg package (see `unireg`). This model and constraint are consistent with the definition of dives in air-breathers, so is certainly 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.

However, note that dives with less than five samples are fit using smoothing splines (see section below) 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.

### ‘smooth.spline’

In this model, specified via `dive.model="smooth.spline"`, a smoothing spline is used to model each dive (see `smooth.spline`), 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.

A comparison of these methods is shown in the Examples section of `diveModel`.

The first derivate 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 * \code{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.

### Value

An object of class `TDRcalibrate`.

### Note

Note that the condition implied with argument `wet.cond` is evaluated after the ZOC procedure, so it can refer to corrected depth. In many cases, not all variables in the `TDR` object are sampled with the same frequency, so they may need to be interpolated before using them for this purpose. Note also that any of these variables may contain similar problems as those dealth with during ZOC, so programming instruments to record depth only when wet is likely the best way to ensure proper detection of wet/dry conditions.

### Author(s)

Sebastian P. Luque spluque@gmail.com

### References

Koellmann, C., Ickstadt, K. and Fried, R. (2014) Beyond unimodal regression: modelling multimodality with piecewise unimodal, mixture or additive regression. Technical Report 8. https://sfb876.tu-dortmund.de/FORSCHUNG/techreports.html, SFB 876, TU Dortmund

Luque, S.P. and Fried, R. (2011) Recursive filtering for zero offset correction of diving depth time series. PLoS ONE 6:e15850

### See Also

`TDRcalibrate`, `.zoc`, `.depthFilter`, `.detPhase`, `.detDive`, `plotTDR`, and `plotZOC` to visually assess ZOC procedure. See `diveModel`, `smooth.spline`, `unireg` for dive models.

### Examples

    data(divesTDR)
    divesTDR

    ## Too long for checks
    ## Consider a 3 m offset, a dive threshold of 3 m, the 1% quantile for
    ## critical vertical rates, and a set of knots 20 times as long as the
    ## observed time steps. Default smoothing spline model for dive phase
    ## detection, using default smoothing parameter.
    (dcalib <- calibrateDepth(divesTDR, dive.thr=3, zoc.method="offset",
                              offset=3, descent.crit.q=0.01, ascent.crit.q=0,
                              knot.factor=20))

    ## Or ZOC algorithmically with method="filter":
    ## dcalib <- calibrateDepth(divesTDR, dive.thr=3, zoc.method="filter",
    ##                          k=c(3, 5760), probs=c(0.5, 0.02), na.rm=TRUE,
    ##                          descent.crit.q=0.01, ascent.crit.q=0,
    ##                          knot.factor=20))

    ## If no ZOC required:
    data(divesTDRzoc)
    (dcalib <- calibrateDepth(divesTDRzoc, dive.thr=3, zoc.method="offset",
                              offset=0, descent.crit.q=0.01, ascent.crit.q=0,
                              knot.factor=20))

[Package diveMove version 1.6.0 Index]