Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

ODE parameter/state estimation

Part 6.4: State and Parameter Estimation for ODEs

Estimating initial conditions (state estimation) and physical parameters (parameter estimation) from noisy observations of the Lorenz63 system.

Stack: equinox (model) · diffrax (ODE solver) · optax (optimizer) · coordax (state wrapping)

Lorenz63 System

dx/dt = σ(y − x)
dy/dt = x(ρ − z) − y
dz/dt = xy − βz
True params: σ=10.0, ρ=28.0, β=2.6667
True IC:     x0=[1. 1. 1.]

Lorenz63 Model (Equinox + Diffrax)

Lorenz63 model created.

Generate Synthetic Observations

Observations: ('time', 'state'), shape: (41, 3)
True traj std: 16.25,  SNR: 32.5

Problem 1: State Estimation (Recover Initial Condition)

Loss: L(x₀) = (1/N) Σ ||x(tᵢ; x₀, θ_true) − x_obs(tᵢ)||²

Loss at x0_guess=[2. 2. 2.]: 15.265
Loss at x0_true =[1. 1. 1.]:  0.191
Gradient of loss w.r.t. x0: [12.135993  10.012697  -2.1368177]
  iter  25: loss=9.6705, x0=[1.751183  1.7511531 2.2452395]
  iter  50: loss=4.8385, x0=[1.5133518 1.5131625 2.459534 ]
  iter  75: loss=1.8110, x0=[1.3091147 1.3087074 2.6061773]
  iter 100: loss=0.7051, x0=[1.1700063 1.169633  2.652397 ]
  iter 125: loss=0.5305, x0=[1.108884  1.109028  2.6025007]
  iter 150: loss=0.4834, x0=[1.0947616 1.0957208 2.503615 ]
  iter 175: loss=0.4395, x0=[1.0904061 1.0922536 2.3961523]
  iter 200: loss=0.4003, x0=[1.0840853 1.0868418 2.2923956]
  iter 225: loss=0.3656, x0=[1.076989  1.0806665 2.1925259]
  iter 250: loss=0.3352, x0=[1.0703448 1.0749434 2.0964162]
  iter 275: loss=0.3090, x0=[1.0641315 1.0696449 2.0047286]
  iter 300: loss=0.2867, x0=[1.05827   1.0646863 1.9179724]
Optimization: 3.3s for 300 steps
True x0=[1. 1. 1.], recovered x0=[1.05827   1.0646863 1.9179724]
Error: 0.922

Problem 2: Parameter Estimation (Recover σ, ρ, β)

Loss: L(θ) = (1/N) Σ ||x(tᵢ; x0_true, θ) − x_obs(tᵢ)||²

Initial params: σ=9.0, ρ=26.5, β=2.4000
Initial parameter loss: 4.0564
  iter  25: loss=1.6989  σ=9.49  ρ=26.99  β=2.5830
  iter  50: loss=0.6217  σ=9.86  ρ=27.39  β=2.6454
  iter  75: loss=0.2901  σ=10.06  ρ=27.66  β=2.6700
  iter 100: loss=0.2163  σ=10.13  ρ=27.82  β=2.6744
  iter 125: loss=0.2004  σ=10.12  ρ=27.90  β=2.6749
  iter 150: loss=0.1948  σ=10.09  ρ=27.94  β=2.6733
  iter 175: loss=0.1923  σ=10.06  ρ=27.96  β=2.6717
  iter 200: loss=0.1911  σ=10.04  ρ=27.98  β=2.6705
  iter 225: loss=0.1907  σ=10.03  ρ=27.99  β=2.6698
  iter 250: loss=0.1906  σ=10.02  ρ=28.00  β=2.6693
  iter 275: loss=0.1905  σ=10.02  ρ=28.00  β=2.6690
  iter 300: loss=0.1905  σ=10.01  ρ=28.00  β=2.6689
  iter 325: loss=0.1905  σ=10.01  ρ=28.00  β=2.6688
  iter 350: loss=0.1905  σ=10.01  ρ=28.00  β=2.6688
  iter 375: loss=0.1905  σ=10.01  ρ=28.00  β=2.6688
  iter 400: loss=0.1905  σ=10.01  ρ=28.00  β=2.6687
  iter 425: loss=0.1905  σ=10.01  ρ=28.00  β=2.6687
  iter 450: loss=0.1905  σ=10.01  ρ=28.00  β=2.6687
  iter 475: loss=0.1905  σ=10.01  ρ=28.00  β=2.6687
  iter 500: loss=0.1905  σ=10.01  ρ=28.00  β=2.6687
Optimization: 15.0s for 500 steps
True:      σ=10.0, ρ=28.0, β=2.6667
Recovered: σ=10.0100, ρ=28.0046, β=2.6687

Coordax State Wrapping

Demonstrate wrapping model states as coordax Fields for coordinate-aware analysis.

Trajectory field: ('time', 'state'), shape: (41, 3)
Trajectory mean (x,y,z): [-3.6464005 -4.109796  24.636417 ]
Trajectory std  (x,y,z): [7.847485 9.112147 9.818682]
Residual field: ('time', 'state'), shape: (41, 3)
RMS residual: 0.5347

Key Patterns

  • Use equinox for structured, differentiable model classes
  • Use diffrax for ODE solving inside the loss function
  • Use optax for gradient-based optimization
  • Use coordax to wrap state trajectories with meaningful dimension labels
  • jax.value_and_grad / eqx.filter_value_and_grad for gradients
  • @jax.jit / @eqx.filter_jit for compilation