Discretization And Linearization¶
Linearize nonlinear dynamics at an operating point, then discretize the local model for discrete-time controller design. JAX derivatives support model construction and batching over operating points.
Where They Fit¶
The discrete Riccati path through dare() has the broadest benchmark coverage.
Linearization¶
linearize() computes A, B, C, and D Jacobians around an operating
point and returns them as a ContLTI. linearize_ss is an alias for
linearize.
JAX differentiation computes the model Jacobians, so compiled local-model construction and vmapped operating-point sweeps use the same code path.
Use:
linearize(f, x0, u0)for plain dynamics(t, x, u) → x_dot; defaults to full-state outputlinearize(f, x0, u0, output=h)when you also have an output maph(x, u) → ylinearize(sys, x0, u0)when you have a reusableNonlinearSystemorPHSSystem
The local approximation is the usual first-order model around an operating
point (x_0, u_0):
with
Discretization¶
c2d() converts a ContLTI to a DiscLTI.
The public methods are:
zoh: zero-order hold, recommended for differentiable and reference-checked workflowstustin: bilinear transform for applications that call for that mapping
The zoh path has broader derivative and reference coverage.
Zero-Order Hold Path¶
Zero-order-hold discretization uses JAX's native matrix exponential and its
forward/reverse derivatives. It supports jacfwd, jacrev and higher-order
workflows without a reverse-only custom rule. Stiff nonnormal regression cases
compare both derivative directions with independent SciPy Frechet derivatives;
scalar ZOH Jacobians and Hessians have closed-form reference checks.
Like any scaling-and-squaring computation, numerical range and conditioning limit usable inputs. Large matrix norms can exceed the exponential's squaring budget; a badly conditioned exponential or derivative remains sensitive to roundoff. Enable float64 before constructing precision-sensitive design data.
For zero-order hold, the continuous-to-discrete map is
$$ \begin{bmatrix} \Phi & \Gamma \ 0 & I \end{bmatrix}
= \exp\left( \begin{bmatrix} A & B \ 0 & 0 \end{bmatrix} \Delta t \right) $$
so that the discrete model becomes
Caveats¶
linearize()(and its aliaslinearize_ss()) approximates behavior near the chosen operating pointc2d()is precision-sensitive and requiresjax_enable_x64=Truezohis the path to prefer for serious workflows todaytustinprovides the bilinear frequency mapping
Practical Checks¶
On unfamiliar workflows, the useful checks are:
- linearized shapes match what the downstream control design expects
- vmapped operating-point pipelines stay finite
- discrete closed-loop poles look reasonable after
c2d() -> lqr() - gradients through representative
c2d()objectives stay finite