Theoretical Foundations: Discrete ternary phase-space attractors, Brusentsov balanced logic (
${-1, 0, +1}$ ), and multi-tier cellular apoptosis for zero-FLOP edge intelligence.
Target Audience: Microarchitecture researchers, neuromorphic systems engineers, and embedded firmware developers.
Each call to feed() executes a four-stage deterministic pipeline in O(1) time:
Raw Sample (int16_t)
│
▼
┌─────────────────────────┐
│ 1. Adaptive Baseline │ EMA tracking (α = 1/64)
│ & Variance (Q8) │ MAD tracking (α = 1/32)
└─────────┬───────────────┘
│ diff = raw_q8 - baseline
▼
┌─────────────────────────┐
│ 2. Ternary │ diff > +threshold → +1
│ Discretization │ diff < -threshold → -1
│ │ otherwise → 0
└─────────┬───────────────┘
│ t_raw ∈ {-1, 0, +1}
▼
┌─────────────────────────┐
│ 3. Cellular Apoptosis │ Tier A: Opposing chatter annihilation
│ (Noise Annihilation) │ Tier B: Ring-buffer glitch suppression
└─────────┬───────────────┘
│ t_filtered ∈ {-1, 0, +1}
▼
┌─────────────────────────┐
│ 4. Topological Attractor│ Charge accumulation
│ & Cycle Closure │ Homological invariant check
│ │ Watchdog anti-deadlock (48 samples)
└─────────┬───────────────┘
│
▼
QState output
All math is Q8 fixed-point (multiply by 256, << 8).
raw_q8 = raw_value << 8
diff = raw_q8 - baseline_ema
baseline_ema += diff >> 6 // EMA α = 1/64
variance_ema += (|diff| - variance_ema) >> 5 // MAD α = 1/32
Why Q8? Multiplying by 256 gives 8 bits of fractional precision using only integer shifts. No float, no div instruction, no FPU required. Works identically on 8-bit AVR and 32-bit ARM.
Why EMA with bit-shift? Exponential moving average with α = 1/2^n collapses to a single right-shift and addition — the cheapest possible filter on any CPU.
| Filter | α | Time constant | Tracks |
|---|---|---|---|
| Baseline | 1/64 | ~64 samples | Slow drift (temperature, DC offset) |
| Variance | 1/32 | ~32 samples | Noise floor changes (cable, EMI) |
The continuous diff signal is quantized into Brusentsov's balanced ternary set {-1, 0, +1}:
if diff > pos_threshold → QTrit::Positive (+1)
elif diff < neg_threshold → QTrit::Negative (-1)
else → QTrit::Zero (0)
This is the core Brusentsov insight: three states with natural symmetry around zero carry more information per trit than binary bits, and eliminate sign-handling overhead.
Asymmetric thresholds allow modeling signals where positive excursion (e.g., ECG R-peak) has different amplitude than negative (S-dip).
Two opt-in extensions keep the v2.0 pipeline untouched unless configured:
- Hysteresis hold bands (
configure(hysteresis_q8)): when a trit is in+1, it is remembered and held whilediffstays above the inner edgepos − hyst(mirror:−1held whilediff < neg + hyst). Only a crossing of the opposite threshold still flips the sign instantly — exactly the v2.0 fast-capture semantics. Athyst = 0the branch is bit-for-bit v2.0:
state +1: diff > (pos − hyst) → +1 (hold)
diff < neg → −1 (fast flip, v2.0 capture)
otherwise → 0
state −1: diff < (neg + hyst) → −1 (hold)
diff > pos → +1 (fast flip)
otherwise → 0
idle: diff > pos → +1
diff < neg → −1
otherwise → 0
- Live threshold self-reinforcement (
configure(live_sigma)): after the variance EMA update, both thresholds are re-derived every sample aspos = live_sigma × variance_ema. This is the 3-sigma calibration idea turned continuous — the engine keeps pace with a rising/falling noise floor instead of waiting for the nextcalibrate().
Both options add zero floating-point and zero heap; they only cost a few integer ops and 9 bytes of state.
(Untouched in v2.1 — the annihilation cascade below is bit-for-bit identical to v2.0.)
Biological inspiration: in living organisms, damaged cells self-destruct (apoptosis) to protect the organism. Q-SETUN applies the same principle to noise.
When a +1 immediately follows a -1 (or vice versa), it's likely high-frequency jitter rather than real signal. Annihilation occurs if either condition holds:
-
Amplitude is decaying:
|diff_current| ≤ |diff_previous|
→ The "bounce" is getting weaker — characteristic of ringing, not signal. -
Within noise envelope:
|diff_current| ≤ 1.5 × MAD
→ The amplitude is within the noise floor (Mean Absolute Deviation × 1.5).
If triggered: t_filtered = 0, and noise_annihilated = true.
A 32-element circular buffer stores recent trit values. Pattern detection:
trit[n-2] = 0, trit[n-1] ≠ 0, trit[n] = 0
→ Isolated 1-sample spike surrounded by baseline
If the spike's amplitude was below 2 × MAD, the middle trit is retroactively set to 0.
Why 32? Power of two allows bitwise modulo: head = (head + 1) & 31 — zero division.
The engine tracks excursion cycles — contiguous sequences of non-zero trits that begin with +1 and end when the signal returns to 0.
┌──────────────────────┐
│ IDLE │
│ (_in_wave = false) │
└──────────┬───────────┘
│ t_filtered == +1
▼
┌──────────────────────┐
│ IN WAVE │
│ charge += trit │◄─── each sample
│ width++ │
└──────────┬───────────┘
│ closure condition
▼
┌──────────────────────┐
│ CLASSIFY CYCLE │
│ check invariants │
└──────────┬───────────┘
│
▼
back to IDLE
A cycle closes when either:
-
Baseline return:
t_filtered == 0ANDwidth ≥ 4samples
→ Signal completed a physiologically meaningful excursion and returned to equilibrium. -
Watchdog timeout:
width ≥ 48samples
→ Anti-deadlock safety. Prevents permanent lock in wave-tracking if sensor disconnects or signal saturates.
On cycle closure, the engine checks:
ANOMALY if: width > 14 OR |net_charge| ≥ charge_limit OR watchdog_fired
NORMAL if: width ≤ 14 AND |net_charge| < charge_limit
Intuition: A normal cycle is compact (short duration) and balanced (equal positive and negative trits → net charge near zero). An anomalous cycle is either too long, too asymmetric, or forcibly closed by the watchdog.
While in wave, the engine additionally accumulates:
wave_energy += |diff| // raw energetic content of the excursion (int32_t, Q8)
wave_trits += (trit ≠ 0) // non-zero trit counter
On cycle closure these are exposed as QState.wave_energy (smoothed >> 8, saturated) and QState.wave_trit_density_pct (100 × wave_trits / width). They add a shape dimension to the binary normal/anomaly verdict: a narrow-strong spike and a wide-weak drift can carry the same charge yet differ sharply in energy and density — which matters for tremor/force-scale biometrics.
Total: 84 bytes (v2.1; actual, measured with avr-g++ 7.3 -Os on ATmega328P). Zero heap.
Offset Size Field
────── ──── ─────────────────────────
0x00 4 _pos_threshold (int32_t)
0x04 4 _neg_threshold (int32_t)
0x08 2 _charge_limit (int16_t)
0x0A 4 _baseline_ema (int32_t, Q8)
0x0E 4 _variance_ema (int32_t, Q8)
0x12 32 _trit_ring[32] (int8_t × 32)
0x32 1 _ring_head (uint8_t)
0x33 1 _prev_trit (QTrit / int8_t)
0x34 4 _prev_diff (int32_t)
0x38 1 _in_wave (bool)
0x39 2 _wave_width (uint16_t)
0x3B 2 _net_charge (int16_t)
0x3D 4 _cycles_count (uint32_t)
0x41 1 _is_anomaly (bool)
0x42 1 _anomaly_score_pct (uint8_t)
0x43 4 _anomaly_score (float)
0x47 2 _last_charge (int16_t)
0x49 2 _last_width (uint16_t)
─────── v2.1 additions (schematic offsets) ───────
2 _hysteresis_q8 (uint16_t)
1 _live_sigma (uint8_t)
4 _wave_energy (int32_t, Q8)
2 _wave_trits (uint16_t)
───── 84 bytes actual (v2.1) ─────
| Property | Q-SETUN | TFLite Micro CNN |
|---|---|---|
| Operations per sample | ~20 integer ops | ~50,000 MAC ops |
| Memory model | Flat static 84 B | TensorArena 24+ KB |
| Determinism | Bit-exact O(1) | Data-dependent branching |
| Noise handling | Built-in apoptosis | Must be in training data |
| Interpretability | Every trit is explainable | Black-box weights |
| Minimum hardware | ATmega328P (2 KB RAM) | Cortex-M4 (64+ KB RAM) |
Q-SETUN is not a general-purpose ML framework. It is purpose-built for 1D quasi-periodic anomaly detection where a topological invariant (charge balance) is more robust than learned weights.