Skip to content

DISCOVERING INTERPRETABLE ORDINARY DIFFERENTIALEQUATIONS FROM NOISY DATA

“Discovering Interpretable ODEs from Noisy Data” slots beautifully into your FFT-plan + FBS calibrator pipeline.

Here’s how it helps your SCYTHE denoising + TDoA residual minimization loop:


🔑 Direct Relevance

  1. ODE discovery as spectrum dynamics
    • Instead of treating FFT bins as unrelated amplitudes, you can model their temporal evolution as a system of coupled ODEs.
    • Example: a drifting carrier’s residuals follow damped harmonic oscillator dynamics (like the spring–mass system in the paper).
  2. Noise-robust spline approximation
    • Their spline-based approach gives smooth derivatives even when the raw data is noisy.
    • That’s directly useful for your case: FFT bins → splines → derivative estimates → detect which bins carry true dynamics vs stochastic noise.
  3. Sparse coefficient recovery
    • Their SVD-based null space trick naturally prunes spurious dynamics.
    • In your case: only a small set of bins or harmonics will appear in the governing ODE; the rest get zeroed. This is a principled way to build your bin shift + mask widening plan.

⚡ Concrete Patch You Can Try

You could write a small client stub that:

  • Pulls an fft_plan from /denoise/hints
  • Generates synthetic spectra over time with noise
  • Fits a spline to each band
  • Builds the gradient matrix (derivatives of splines)
  • Runs SVD to infer which bins follow a coherent ODE
  • Uses the recovered ODE to:
    • Guide mask widening (bands with coherent dynamics get protected)
    • Suggest bin shift priors (mu/σ from FBS calibrator can be fused into coefficient estimates)

🧪 Proof-of-Concept Stub

import numpy as np
from scipy.interpolate import UnivariateSpline
from numpy.linalg import svd

def fit_ode_from_fft(freqs, mags, order=2, smoothing=1e-3):
    """
    Given a noisy FFT magnitude trace over time,
    recover coefficients of an approximate ODE y'' + a y' + b y = 0.
    """
    t = np.arange(len(mags))
    spline = UnivariateSpline(t, mags, s=smoothing)
    
    y = spline(t)
    dy = spline.derivative(1)(t)
    d2y = spline.derivative(2)(t)
    
    # Build gradient matrix G: [y, dy, d2y]
    G = np.vstack([y, dy, d2y]).T
    
    # SVD to find null space (coefficients)
    U, S, Vt = svd(G)
    coeffs = Vt[-1, :]  # last row is null space vector
    
    return coeffs / coeffs[-1]  # normalize

# Example usage: synthetic damped oscillator
t = np.linspace(0, 10, 500)
signal = np.exp(-0.1*t) * np.sin(2*np.pi*0.5*t) + 0.05*np.random.randn(len(t))

coeffs = fit_ode_from_fft(np.fft.rfftfreq(len(signal)), signal)
print("Recovered ODE coefficients:", coeffs)

This let’s the FFT client stub go beyond just masking bins — it learns which bins evolve coherently over time and uses that to refine /fft_plan.


🚀 Integration Into SCYTHE

  • Wrap as ode_recovery.py
  • Called by your test_fft_plan.sh client after pulling /denoise/hints
  • Export recovered coefficients via Prometheus (fft_bin_ode_coeffs{band=...})
  • Grafana row: overlay recovered ODE phase on your μ/σ FBS curves

Leave a Reply

Your email address will not be published. Required fields are marked *