pub struct TemporalDerivativeKernel<const N: usize> {
pub fast: [f32; N],
pub slow: [f32; N],
pub alpha_fast: f32,
pub alpha_slow: f32,
}Expand description
Dual fast/slow EMA temporal-derivative kernel.
fast tracks the signal with a short time constant; slow with a long
one. Their difference (fast − slow) is a signed band-pass derivative
that spikes on change and decays to zero when the signal is stationary
— the canonical neocortical prediction-error signal.
Generic over N (the signal dimension). Fixed-size array, zero
allocation, suitable for embedding inside per-NPC state structs.
§Invariants
0 < alpha_slow < alpha_fast <= 1(validated at construction).- State arrays are zero-initialized on
new; usewith_initialfor warm starts / snapshot restore. - All operations are branch-free and in-place; safe to call from hot paths at any tier (plasma → cold).
Fields§
§fast: [f32; N]Fast EMA — short time constant.
slow: [f32; N]Slow EMA — long time constant.
alpha_fast: f32Fast EMA coefficient. new_fast = (1 − α_f) · old_fast + α_f · signal.
alpha_slow: f32Slow EMA coefficient. new_slow = (1 − α_s) · old_slow + α_s · signal.
Implementations§
Source§impl<const N: usize> TemporalDerivativeKernel<N>
impl<const N: usize> TemporalDerivativeKernel<N>
Sourcepub fn new(alpha_fast: f32, alpha_slow: f32) -> Self
pub fn new(alpha_fast: f32, alpha_slow: f32) -> Self
Construct a zero-initialized kernel.
Validates 0 < alpha_slow < alpha_fast <= 1. Panics in debug,
clamps in release (paper’s ~10× ratio is the canonical default;
e.g. alpha_fast=0.3, alpha_slow=0.03).
Sourcepub fn with_initial(
fast: [f32; N],
slow: [f32; N],
alpha_fast: f32,
alpha_slow: f32,
) -> Self
pub fn with_initial( fast: [f32; N], slow: [f32; N], alpha_fast: f32, alpha_slow: f32, ) -> Self
Construct with initial EMA state — for warm starts or snapshot restore.
Sourcepub fn observe(&mut self, signal: &[f32; N]) -> [f32; N]
pub fn observe(&mut self, signal: &[f32; N]) -> [f32; N]
Observe one signal sample; update both EMAs and return the
per-dim signed surprise vector (fast − slow).
Branch-free, no allocations. Reuses simd_fused_decay_write when
the simd-implied path is available (always-on in this crate — the
kernel dispatches to NEON/AVX2/scalar inside simd).
Paper reference: O’Reilly 2026 §Implementational — the CaMKII/DAPK1
kinase cascade maps onto the (fast − slow) difference; we compute
it algebraically rather than biochemically.
Sourcepub fn observe_simd(&mut self, signal: &[f32; N]) -> [f32; N]
pub fn observe_simd(&mut self, signal: &[f32; N]) -> [f32; N]
SIMD-optimized observe (alias — the default observe
already routes through simd_fused_decay_write).
Kept as a distinct entry point so callers that want to make the SIMD path explicit in their code can do so, and so that future wider-SIMD specializations have a natural home.
Sourcepub fn surprise_norm(&self) -> f32
pub fn surprise_norm(&self) -> f32
L2 norm of the current (fast − slow) derivative.
Uses simd_dot_f32 for the inner reduction when N >= 4.
Bounded scalar in [0, ∞); typical operating range [0, 1] after
normalization.
Sourcepub fn derivative_slice(&self, out: &mut [f32; N])
pub fn derivative_slice(&self, out: &mut [f32; N])
Write (fast − slow) into a caller-provided buffer — zero-alloc
read path for consumers that already own a scratch buffer.
Trait Implementations§
Source§impl<const N: usize> Clone for TemporalDerivativeKernel<N>
impl<const N: usize> Clone for TemporalDerivativeKernel<N>
Source§fn clone(&self) -> TemporalDerivativeKernel<N>
fn clone(&self) -> TemporalDerivativeKernel<N>
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl<const N: usize> Debug for TemporalDerivativeKernel<N>
impl<const N: usize> Debug for TemporalDerivativeKernel<N>
Auto Trait Implementations§
impl<const N: usize> Freeze for TemporalDerivativeKernel<N>
impl<const N: usize> RefUnwindSafe for TemporalDerivativeKernel<N>
impl<const N: usize> Send for TemporalDerivativeKernel<N>
impl<const N: usize> Sync for TemporalDerivativeKernel<N>
impl<const N: usize> Unpin for TemporalDerivativeKernel<N>
impl<const N: usize> UnsafeUnpin for TemporalDerivativeKernel<N>
impl<const N: usize> UnwindSafe for TemporalDerivativeKernel<N>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more