/** * Shake detector with frequency-band energy analysis. * * Maintains circular buffers of per-axis acceleration samples. Shake * intensity is computed via RMS of the acceleration magnitude deviation * from its mean (high-pass to remove gravity). The dominant shake * frequency is identified using the Goertzel algorithm — a single-bin * DFT that's far cheaper than a full FFT — applied to the first- * difference of individual axis signals: * * - Per-axis preserves the fundamental frequency (magnitude would * full-wave-rectify the signal, doubling the apparent frequency). * - First-difference acts as a high-pass filter, removing DC (gravity) * and low-frequency drift from arm movement. Its gain is proportional * to frequency, so the Goertzel output naturally favors oscillatory * shake signals over slow drift — no ad-hoc weighting needed. * * A 1/freq compensation is applied so the net effective weighting is * proportional to freq (diff-filter gain² ∝ freq², divided by freq), * giving moderate preference to actual shake frequencies without * completely suppressing sub-1 Hz rocking. * * `.frequency` reports the **reversal rate** (2× fundamental) — how many * direction changes per second. This matches the intuitive "how fast am * I shaking it?" mental model. `.fundamental` reports the true oscillation * frequency (one full back-and-forth cycle). * * The active flag uses a sustain counter to require several consecutive * frames above threshold before triggering, preventing transient jolts * from registering as shakes. */ /** A single frequency bin with its associated power level. */ export interface FrequencyBin { /** Frequency in Hz. */ freq: number; /** Weighted power (arbitrary units, relative within the array). */ power: number; } /** Configuration for the shake detector. */ export interface ShakeDetectorParams { /** Intensity (0–1) above which `.active` becomes true. Default 0.15. */ threshold?: number; /** Number of samples in the analysis window. Default 256 (~1s at 250 Hz, ~3s at 84 Hz in browser). */ windowSize?: number; /** * Number of consecutive above-threshold frames required before `.active` * becomes true. Also the number of below-threshold frames required to * deactivate. Default 15 (~60 ms at 250 Hz). */ sustain?: number; /** Frequency bin resolution in Hz. Default 0.25. Smaller = finer but more bins to compute. */ freqStep?: number; /** Minimum detectable frequency in Hz. Default 0.25. */ freqMin?: number; /** Maximum detectable frequency in Hz. Default 15. */ freqMax?: number; } export declare class ShakeDetector { /** Whether the controller is currently being shaken (sustained). */ active: boolean; /** Shake intensity from 0 (still) to 1 (violent shake). */ intensity: number; /** * Dominant shake frequency in Hz as a **reversal rate** — how many * direction changes per second (2× the fundamental oscillation * frequency). 0 when not shaking. */ frequency: number; /** * Fundamental oscillation frequency in Hz — one complete back-and-forth * cycle. Equal to `frequency / 2`. 0 when not shaking. */ fundamental: number; /** Intensity threshold for `active`. */ threshold: number; /** Estimated sample rate in Hz (derived from dt). Useful for diagnostics. */ get inputRate(): number; /** Number of samples in the analysis window. Can be changed at runtime (resets state). */ get windowSize(): number; set windowSize(n: number); /** * Current frequency spectrum — weighted power at each probed bin. * Updated every frame when intensity is above half the threshold. * Useful for visualization/diagnostics. */ get spectrum(): readonly FrequencyBin[]; private bufX; private bufY; private bufZ; private head; private filled; private _sampleRate; /** Sustain counter for debounce — counts up when above threshold, down when below. */ private sustainCounter; private readonly sustainRequired; /** EMA-smoothed frequency for stable readout. */ private smoothedFreq; /** Frequency bins to probe, built from constructor params. */ private readonly freqBins; /** Bin step size, used for snapping the EMA output. */ private readonly freqStep; /** Latest computed bin powers. */ private _bins; /** * Scale factor: maps RMS of our [-1, 1] calibrated accel deviation * to a 0–1 intensity. A vigorous shake produces magnitude-RMS of * ~0.3–0.5 in our units; this maps that to ~0.6–1.0 intensity. */ private static readonly INTENSITY_SCALE; constructor(params?: ShakeDetectorParams); /** Reset all state (call on disconnect). */ reset(): void; /** * Feed one accelerometer sample. * * @param ax Calibrated accel X ([-1, 1]) * @param ay Calibrated accel Y ([-1, 1]) * @param az Calibrated accel Z ([-1, 1]) * @param dt Time delta in seconds since last sample */ update(ax: number, ay: number, az: number, dt: number): void; /** * Goertzel algorithm: compute power at a single target frequency. * * Operates on the first-difference of the filled portion of a circular * buffer. The first-difference (x[n] - x[n-1]) acts as a high-pass * filter that removes DC (gravity) and low-frequency arm drift, with * gain proportional to frequency. */ private goertzel; } //# sourceMappingURL=shake.d.ts.map