Adaptive engine (Orca Stage 1)¶
This tool follows a signal that drifts slowly, keeps updating what it considers normal and pulls the signal gently toward it, so that a slow drift is not mistaken for a glitch.
A signal that drifts slowly is not a spike. It is a sequence of samples, each of them
plausible on its own, that together move the average. A purely local detector misses
this by construction: each sample is within the local window's amplitude, so nothing
fires. Orca's Stage 1 is the module that handles this case: it does not judge each
sample against a fixed baseline, it continuously re-estimates the baseline and
damps toward it with a smooth curve.
The module is AdaptiveSignalStabilizer, a causal recursive filter written as a
jax.lax.scan so it can run inside a JAX pipeline without leaving the JIT.
The examples use a 100 Hz channel with a spike at sample 1500 and a slow ramp from 0.5 to 0.7 starting at sample 2000.
1. Filter the series¶
import jax
jax.config.update("jax_enable_x64", True)
import numpy as np
from dense_armor.core.engine import AdaptiveSignalStabilizer
x = 0.5 + 0.1 * np.random.default_rng(42).standard_normal(3000)
x[1500] = 2.5
x[2000:] += 0.2 * (np.arange(1000) / 1000)
stabilizer = AdaptiveSignalStabilizer()
clean = stabilizer.filter_data_stream(np.asarray(x))
print(clean.shape, float(clean[1500]))
clean is the same series with the spike removed and the ramp followed but slightly
smoothed — the filter does not fight a sustained change, it damps the transient part of
it. At the spike position the value 2.5 comes out as 0.76: the filter damps the spike strongly
but does not replace it with the baseline.
2. What "adaptive" means here¶
The filter measures the local noise of the signal (a rolling volatility) and turns it into a damping gain with a sigmoid:
$$k(n) = k_{min} + \frac{k_{max} - k_{min}}{1 + e^{-(n - 2)}}, \qquad n = \mathrm{clip}(\text{local noise},\, 0,\, 5).$$
- Low local noise: the gain stays near $k_{min}$ and the signal passes almost untouched.
- High local noise: the gain goes towards $k_{max}$ (about 8.78 by default) and the filter purifies strongly.
- Samples beyond a dynamic threshold (
anomaly_sigma_multtimes the rolling volatility) are damped selectively, preserving the L2 norm of the series so the damping cannot create local explosions.
The sigmoid is why the filter is smooth: there is no single value at which it switches from "pass" to "reject".
3. Presets¶
Four calibrated parameter sets ship with the library:
| preset | when to use |
|---|---|
balanced_v2 |
default, good across signals |
cifar10_best_v1 |
tuned for image-grid-like inputs |
pure_1d_time_v1 |
reactive; follows fast changes more closely |
cifar10_hardened_lyapunov |
hardened; damps more aggressively |
import numpy as np
from dense_armor.core.preset import SIGNAL_STABILIZER_PRESETS
from dense_armor.core.engine import AdaptiveSignalStabilizer
x = 0.5 + 0.1 * np.random.default_rng(42).standard_normal(3000)
x[1500] = 2.5
stabilizer = AdaptiveSignalStabilizer(**SIGNAL_STABILIZER_PRESETS["pure_1d_time_v1"])
clean = stabilizer.filter_data_stream(np.asarray(x))
print(round(float(np.var(np.asarray(x) - clean)), 6))
The presets behave differently on the same series: pure_1d_time_v1 leaves a residual variance
of 0.0031 against 0.0061 for balanced_v2 — it changes the signal about half as much, following
it more closely.
4. Where Orca uses it¶
Orca.protect_and_forward calls the stabilizer twice: once on the input tensor before
the model, once on the response after. The four-phase shield described on the
Orca page is exactly this: purify, forward, purify, report trust scores.
Stage 2 (Orca's Collatz-based gate) sits on top and decides how much of the damped
value to use versus how much of the raw value to trust on the input side; on the output
side the check is against the model's own response to the clean reference.
If you use AdaptiveSignalStabilizer on its own, you get the same soft damping without
the input/output distinction: a single cleaned stream.
5. Batch and multi-scenario use¶
When you have a whole batch of signals (or several scenarios side by side), the stabilizer exposes batch methods that vmap over rows:
import numpy as np
from dense_armor.core.engine import AdaptiveSignalStabilizer
batch = np.random.default_rng(0).standard_normal((4, 500))
s = AdaptiveSignalStabilizer()
clean_batch = s.filter_batch_scenarios(np.asarray(batch))
print(clean_batch.shape)
filter_batch_scenarios uses a shared calibration for the whole batch.
filter_batch_scenarios_independent gives each row its own thresholds — useful when
the rows come from different sensors with different amplitudes.
API reference¶
engine ¶
Adaptive signal stabilizer for time series and AI gradients.
Features
- Anomaly detection through a dynamic threshold based on rolling volatility.
- Selective damping with L2-norm preservation to avoid local blow-ups.
- Macro-context calibration on 2D batches
(N_scenarios, T_steps)with dynamic parameters. - Fully JAX-compatible, with precompiled
vmap+scankernels.
The numeric constants below are fixed hyper-parameters of the damping curve. They have no physical or mathematical meaning beyond shaping the gain.
AdaptiveSignalStabilizer ¶
AdaptiveSignalStabilizer(
static_threshold: float = 1e-05,
initial_damping: float = 0.1,
alpha: float = _SIGMA,
anomaly_sigma_mult: float = 2.0,
k_anom_min: float = _ALPHA,
k_anom_max: float = _K_MAX_ZETA,
window_radius: int = 1,
smooth_l2_blend: float = 0.5,
)
Adaptive anti-panic filter for chaotic AI signals.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
static_threshold
|
float
|
base detection threshold. |
1e-05
|
initial_damping
|
float
|
initial damping coefficient. |
0.1
|
alpha
|
float
|
EMA coefficient for the rolling volatility. |
_SIGMA
|
anomaly_sigma_mult
|
float
|
multiplier on the rolling volatility used to build the dynamic threshold. |
2.0
|
k_anom_min
|
float
|
minimum gain on the anomalous branch. |
_ALPHA
|
k_anom_max
|
float
|
maximum gain on the anomalous branch. |
_K_MAX_ZETA
|
window_radius
|
int
|
radius of the local mean window. |
1
|
smooth_l2_blend
|
float
|
blend between the raw smoothed value and its
L2-rescaled version, in |
0.5
|
Configure the thresholds and precompile the JAX kernels.
Source code in dense_armor/core/engine.py
calibrate_macro_context ¶
Calibrate the dynamic thresholds on the global context of the batch.
Analyses the distribution of jumps between samples to tell an
extremely turbulent environment (a shock) from physiological noise.
The parameters are stored on the instance (dyn_thr, dyn_dmp,
dyn_alp, noise_scalar); the method is not pure by design and
leaves existing callers unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw_batch
|
ndarray
|
the batch of raw signals. |
required |
Source code in dense_armor/core/engine.py
calibrate_macro_context_independent ¶
calibrate_macro_context_independent(
raw_batch: ndarray,
) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]
Same formulas as :meth:calibrate_macro_context, computed per row.
The parameters are computed along axis=-1 instead of on the whole
flattened batch. The method is pure and does not mutate self, so
it is safe to use inside vmap downstream. The existing
batch-shared :meth:calibrate_macro_context is kept unchanged for
its callers (test_boundA.py and the adversarial suite use the
shared calibration on purpose: correlated scenarios share one
context).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw_batch
|
ndarray
|
shape |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
A tuple |
ndarray
|
shape |
Source code in dense_armor/core/engine.py
filter_batch_scenarios_independent ¶
filter_batch_scenarios_independent(
raw_batch: ndarray,
hard_clamp_mask: ndarray | None = None,
) -> np.ndarray
Like :meth:filter_batch_scenarios with per-scenario calibration.
Every scenario receives its own calibration from
:meth:calibrate_macro_context_independent instead of one shared on
the whole batch. Numerically equivalent to calling
:meth:filter_batch_scenarios once per scenario
(n_scenarios=1 each), but in a single vmap call instead of N
separate JAX dispatches. Added for
:meth:Orca.protect_and_forward: the library has never exercised
n_scenarios > 1 on independent scenarios before (the only
existing multi-scenario caller, the adversarial suite in
test_boundA.py, wants the shared calibration on purpose).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw_batch
|
ndarray
|
the batch of raw signals, shape |
required |
hard_clamp_mask
|
ndarray | None
|
optional boolean mask, same shape as
|
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
The filtered batch, same shape as |
Source code in dense_armor/core/engine.py
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | |
filter_data_stream ¶
Filter a single 1D time series.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw_data
|
ndarray
|
the input series. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
The filtered series, same length as |
Source code in dense_armor/core/engine.py
filter_batch_scenarios ¶
Filter a batch of structured scenarios in parallel (vmap).
Accepts native 2D tensors or multidimensional arrays (3D/4D).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw_batch
|
ndarray
|
the batch of raw signals, shape |
required |
hard_clamp_mask
|
ndarray | None
|
optional boolean mask, same shape as
|
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
The filtered batch, same shape as |
Source code in dense_armor/core/engine.py
dynamic_damping_gain ¶
dynamic_damping_gain(
local_noise: ndarray,
k_min: float = 0.0,
k_max: float = _K_MAX_ZETA,
) -> jnp.ndarray
Sigmoid damping curve as a function of the local noise.
A low local_noise gives a gain close to k_min (maximum
transparency); a high local_noise gives a gain close to k_max
(maximum purification).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
local_noise
|
ndarray
|
the local noise estimate. |
required |
k_min
|
float
|
minimum gain (maximum transparency). |
0.0
|
k_max
|
float
|
maximum gain (maximum purification). |
_K_MAX_ZETA
|
Returns:
| Type | Description |
|---|---|
ndarray
|
The gain value in |
Source code in dense_armor/core/engine.py
Details¶
See also: Orca, which uses AdaptiveSignalStabilizer as Stage 1,
followed by a Collatz-based gate (Stage 2) deciding how much to damp toward the clean
reference. This is also the engine exercised directly by the adversarial test suite
(test/test_boundA-E.py) behind the
robustness numbers on the home page.