Function vmd_select_k
pub fn vmd_select_k(
signal: &Signal<f64>,
config: &VmdSelectKConfig,
) -> Result<VmdSelectKResult>Expand description
Sweep K over config.k_range and return the recommended K. Two
detectors run in order: the K = start boundary check fires if
E[start] ≤ [boundary_fidelity](VmdSelectKConfig::boundary_fidelity);
otherwise the ratio-of-drops elbow detector fires at the smallest
K ≥ start + 1 where Δ_{K+1}/Δ_K < [improvement_threshold](VmdSelectKConfig::improvement_threshold).
Falls back to *k_range.end() when neither detector trips.
config.base_config.tau must be exactly 0.0. Positive dual ascent
enforces reconstruction equality, so residual energy stops measuring
missing modes and can make under-specified K look correct. The check
is tau != 0.0, so even a microscopic non-zero τ (e.g. 1e-300) is
rejected — there’s no “small enough” τ that’s safely ignored, because
dual ascent’s effect is structural, not magnitude-dependent. If you
genuinely want zero, pass 0.0. The check fires at call time rather
than at config-construction time (no compile-time enforcement), since
VmdSelectKConfig reuses the general-purpose VMDConfig — build your
base_config without calling with_tau and the default 0.0 will
satisfy this constraint.
Note this runs vmd once per sweep point — O(|range|) cost. For long
signals, narrow the range or warm-start the base config’s iteration cap.