Flag fixes by a speed cap (data-driven or physiological)
Source:R/mt_flag_speed_cap.R
mt_flag_speed_cap.RdFlags 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
move2object. 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 whenthreshold_type = "hard"; ignored otherwise. Whenthreshold_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 whenthreshold_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 hardv_maxor the(mass, mode)allometric prior tomt_clean_track().NULLfalls 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, passingphysiological_ceiling = v_phys_estimate(mass, mode) * 1.25gives a sharper per-species check (sprint margin on the central allometric prediction). The check is warning-only; it never alters the cap. Ignored whenthreshold_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)whereouternames 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) andinnernames the operating unit (within which the pool-fitted cap is applied and flags are unioned). Length 2 requires strict nesting: every distinctinnervalue must map to exactly oneoutervalue. Length \(> 2\) is rejected. Pool flags union intois_outlier+is_speed_above_cap– additive, never un-flags what per-track caught. Per-track pool caps are exposed viaattr(out, "v_max_used_pool"), alongside the per-trackattr(out, "v_max_used").NULL(default) preserves per-track behaviour byte-identically. Ignored whenthreshold_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. DefaultFALSE.- silent
Logical. If
FALSE(default) the function prints a one-line summary of the cap chosen, gate decisions, and the count of flagged fixes. SetTRUEto suppress. Errors and warnings are always shown.
Value
The input object with added columns:
step_speedImplied outgoing step speed in m/s.
NAfor the last fix of each track.is_speed_above_capLogical.
TRUEwhere either adjacent step exceeds the cap.is_step_below_jitterLogical. Present only when
jitteris supplied.is_outlierLogical. 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": usesv_maxas a literal physiological cap. Requiresv_maxto 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)
} # }