Skip to contents

Flags fixes that straddle an implausibly fast step. The threshold can be derived data-driven from the track's own step-speed distribution (entropy valley or dip-test-validated broken-stick break) or supplied as a hard physiological cap in m/s. This is the only primitive that scores steps as first-class objects, and therefore the only one that catches the boundary transitions of a coherent outlier block that per-fix detectors structurally cannot see.

Usage

mt_flag_speed_cap(
  x,
  v_max = NULL,
  threshold_type = c("auto", "entropy", "gap", "hard"),
  threshold = NULL,
  jitter = NULL,
  physiological_ceiling = NULL,
  pool_by = NULL,
  plot = TRUE,
  remove = FALSE,
  silent = FALSE
)

Arguments

x

A move2 object. Longitude/latitude or projected; step lengths are computed via the package's geodesic / Euclidean helper which handles both CRS types directly.

v_max

Numeric scalar in m/s or NULL (default). Required when threshold_type = "hard"; ignored otherwise. When threshold_type != "hard" the cap is computed from the data.

threshold_type

Character, one of "auto" (default), "entropy", "gap", or "hard". See details.

threshold

Numeric tuning parameter passed to the underlying threshold helper (entropy valley-depth ratio or gap multiplier). NULL (default) uses that helper's own default. Ignored when threshold_type = "hard".

jitter

Numeric scalar or NULL (default). Optional lower bound on absolute step length (metres).

physiological_ceiling

Numeric scalar in m/s, or NULL (default). Soft upper-bound used by the auto-cap path's biological-sanity warning: when the data-driven cap exceeds this value, a message is emitted suggesting the user supply a hard v_max or the (mass, mode) allometric prior to mt_clean_track(). NULL falls back to the universal mode-agnostic ceiling of 55 m/s (Hirt et al. 2017 95\ and modes). When the user has (mass, mode) information, passing physiological_ceiling = v_phys_estimate(mass, mode) * 1.25 gives a sharper per-species check (sprint margin on the central allometric prediction). The check is warning-only; it never alters the cap. Ignored when threshold_type = "hard" (the user's cap stands).

pool_by

Optional character vector of length 1 or 2 naming column(s) in mt_track_data(x). Length 1: single column used as both fit set and operating unit. Length 2: c(outer, inner) where outer names the fit-source column (the union of its events supplies the step-speed distribution that .compute_speed_cap – with its fraction-above and mode-position gates – runs over) and inner names the operating unit (within which the pool-fitted cap is applied and flags are unioned). Length 2 requires strict nesting: every distinct inner value must map to exactly one outer value. Length \(> 2\) is rejected. Pool flags union into is_outlier + is_speed_above_cap – additive, never un-flags what per-track caught. Per-track pool caps are exposed via attr(out, "v_max_used_pool"), alongside the per-track attr(out, "v_max_used"). NULL (default) preserves per-track behaviour byte-identically. Ignored when threshold_type = "hard" (the user-supplied cap is already uniform across tracks).

plot

Logical. If TRUE (default), produce a diagnostic map with flagged fixes highlighted.

remove

Logical. If TRUE, drop flagged rows from the returned object. Default FALSE.

silent

Logical. If FALSE (default) the function prints a one-line summary of the cap chosen, gate decisions, and the count of flagged fixes. Set TRUE to suppress. Errors and warnings are always shown.

Value

The input object with added columns:

step_speed

Implied outgoing step speed in m/s. NA for the last fix of each track.

is_speed_above_cap

Logical. TRUE where either adjacent step exceeds the cap.

is_step_below_jitter

Logical. Present only when jitter is supplied.

is_outlier

Logical. Union of the above flags.

The value of the cap actually used is stored as the attribute "v_max_used".

Details

For each fix \(i\), let \(v_i = d_i / \Delta t_i\) be the implied step speed, where \(d_i\) is the distance to fix \(i+1\) (via mt_distance, geodesic for lon/lat data, Euclidean for projected data) and \(\Delta t_i\) the corresponding time lag. A fix is flagged is_speed_above_cap = TRUE if either its outgoing step \(v_i\) or its incoming step \(v_{i-1}\) exceeds the cap — without more information the detector cannot tell which of the two fixes the offending geometry belongs to, so both endpoints are flagged.

The cap itself is chosen by threshold_type:

  • "auto" (default): entropy-valley on \(-\log v\); if none is found, fall back to the broken-stick / gap break, retained only if Hartigan's dip test confirms the distribution is significantly multimodal (\(p < 0.05\)). On clean unimodal speed distributions this returns no flags — the honest "no outliers" outcome. The most principled choice, and the default.

  • "entropy": entropy valley only. Most conservative.

  • "gap": broken-stick plus tail-decay inflection only. More sensitive but can over-flag on legitimate heavy tails.

  • "hard": uses v_max as a literal physiological cap. Requires v_max to be supplied. Pick species' documented biomechanical top speed plus ~25\

When jitter is supplied, an analogous lower bound is applied to step length (not speed): is_step_below_jitter = TRUE where either neighbouring step is below jitter metres. Use this only if you explicitly want to mark sub-noise floor displacements.

On multi-track input the function dispatches per individual: each track's data-driven cap is tuned to that track's own speed distribution, and attr(out, "v_max_used") is returned as a named numeric (one entry per track id). Single-track input retains the scalar attribute. Rows with empty geometries or missing timestamps yield NA step speeds and are silently not flagged but retained in the output, preserving row parity with the caller.

See also

mt_suggest_speed_cap for a diagnostic-only helper that returns the suggested value without modifying x; mt_flag_outliers_bridge and mt_flag_outliers for per-fix detectors.

Examples

if (FALSE) { # \dontrun{
library(move2)
## data-driven (default); silent on unimodal speed distributions
x <- mt_flag_speed_cap(x)

## hard physiological cap: golden eagle documented top ~50 m/s
x <- mt_flag_speed_cap(x, v_max = 50, threshold_type = "hard")

## diagnostic: inspect distribution + suggested cap without flagging
v <- mt_suggest_speed_cap(x)
} # }