Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Struktura

Predict failure before it happens.

Struktura is a zero-dependency Rust crate for universal anomaly detection. It uses Detrended Fluctuation Analysis (DFA) to measure the structural health of any time series — bearings, heartbeats, spacecraft telemetry, drone motors, DNA sequences.

One algorithm. Any signal. No training data. No domain knowledge.

Why Struktura?

Current monitoring tools watch for threshold violations: “is the temperature above 80C?” But structural degradation changes the pattern of a signal before it changes the amplitude. A bearing that’s starting to wear changes its vibration structure weeks before it exceeds any alarm threshold.

Struktura catches what threshold monitors miss.

Install

cargo add struktura

Quick Start

Analyze any signal

#![allow(unused)]
fn main() {
use struktura::{analyze, health_check, HealthVerdict};

// Load your time series data
let data: Vec<f64> = load_csv("vibration.csv");

// Analyze structural health
let law = analyze(&data);
println!("DFA alpha: {:.3}", law.dfa.alpha);
println!("R-squared: {:.4}", law.dfa.r_squared);
println!("Quality: {:?}", law.quality);

// Compare against a known healthy baseline
let verdict = health_check(&law, 0.389); // baseline from calibration
match verdict {
    HealthVerdict::Healthy => println!("System is healthy"),
    HealthVerdict::Watch => println!("Minor structural shift detected"),
    HealthVerdict::Warning => println!("Significant structural change"),
    HealthVerdict::Critical => println!("CRITICAL: Major structural departure"),
}
}

What the numbers mean

  • DFA alpha near 0.5: uncorrelated noise — no exploitable structure
  • DFA alpha 0.5-1.0: long-range correlated — healthy complex system
  • Alpha shift > 0.08 from baseline: something is changing
  • R-squared > 0.7: the measurement is reliable
  • R-squared < 0.7: ABSTAIN — not enough structure to diagnose

How DFA Works

Detrended Fluctuation Analysis measures long-range correlation in a time series.

The algorithm in 4 steps

  1. Profile: compute the cumulative sum of deviations from the mean
  2. Box: divide the profile into non-overlapping boxes of size s
  3. Detrend: fit and subtract a linear trend within each box
  4. Scale: measure the root-mean-square residual F(s) at each box size

The scaling exponent alpha is the slope of log F(s) vs log s.

What alpha means

Alpha rangeInterpretation
~0.5White noise (uncorrelated)
0.5 - 1.0Long-range correlated (healthy complexity)
~1.01/f noise (pink noise)
> 1.0Non-stationary / trend-dominated

Why it works for anomaly detection

Healthy complex systems maintain a characteristic alpha. When the system degrades, alpha shifts — often before any amplitude-based monitor fires. The structure changes first.

References

  1. Peng et al., “Mosaic organization of DNA nucleotide sequences,” Physical Review E 49(2), 1994.
  2. Peng et al., “Quantification of scaling exponents,” Chaos 5(1), 1995.
  3. Goldberger et al., “Fractal dynamics in physiology,” PNAS 99(suppl 1), 2002.

Bearing Fault Detection

Struktura detects bearing faults from raw vibration data with zero domain knowledge.

CWRU Bearing Data Center results

Using 12kHz vibration data from Case Western Reserve University:

ConditionDFA alphaShiftVerdict
Normal (97.mat)0.389Healthy
Inner race fault (105.mat)0.146-0.243Critical
Outer race fault (130.mat)0.247-0.142Critical
Ball fault (118.mat)0.275-0.114Warning

All three fault types detected. The shift magnitude correlates with fault severity.

How to use it

#![allow(unused)]
fn main() {
use struktura::{analyze, health_check};

let normal = analyze(&normal_vibration);
let baseline = normal.dfa.alpha; // establish during healthy operation

// Later, during monitoring:
let current = analyze(&current_vibration);
let verdict = health_check(&current, baseline);
// verdict == HealthVerdict::Critical if bearing is degrading
}

Why DFA catches what FFT misses

FFT detects frequency changes. But early bearing degradation changes the correlation structure of the vibration — the way peaks relate to each other over time — before it introduces new frequency components. DFA measures this correlation structure directly.

Cross-Domain Proof

The same algorithm works on completely different signal types.

DomainSignalNDFA alphaR-squared
SpacecraftQueue depth5000.5930.789
BearingsCWRU 12kHz vibration243,9380.3890.872
GenomeHuman chr1 GC%8,0000.9090.991
CardiacRR intervals2,0480.6950.985

Genome: 8 chromosomes at R-squared > 0.99

ChromosomeDFA alphaR-squared
chr10.9090.991
chr20.6990.991
chr30.6590.998
chr40.8940.997
chr50.8240.994
chr60.8220.998
chr70.8620.997
chr80.8160.995

Shuffle control

To prove the structure is real and not an artifact, we permute each signal and re-run DFA. If shuffling destroys the alpha (moves it toward 0.5), the original structure was real.

This is the empirical standard: the crate never claims structure it cannot prove.

API Reference

Core functions

dfa(values: &[f64]) -> DfaResult

Compute the DFA scaling exponent. Returns alpha and R-squared.

acr(values: &[f64]) -> DfaResult

Compute autocorrelation decay exponent.

analyze(values: &[f64]) -> StructuralLaw

Full structural analysis: DFA + ACR + statistics.

health_check(law: &StructuralLaw, baseline: f64) -> HealthVerdict

Compare current DFA alpha against a baseline.

Types

DfaResult { alpha: f64, r_squared: f64 }

StructuralLaw { hurst, dfa, acr, mean, std_dev, kurtosis, p99, max, n, quality }

LawQuality — Exact, Strong, Good, Approx, Abstain, Insufficient

HealthVerdict — Healthy, Watch, Warning, Critical

Thresholds

Shift from baselineVerdict
< 0.03Healthy
0.03 - 0.08Watch
0.08 - 0.15Warning
> 0.15Critical