Advanced control (MPC)¶
Model predictive control end to end: a differentiable QP solver, linear and nonlinear MPC, state estimation (Kalman, extended/unscented Kalman, and moving horizon estimation), and closed-loop simulation and tuning.
See the advanced control guide for worked examples.
mpc
¶
Differentiable model predictive control and state estimation for Fugacio.
Advanced process control is where a differentiable engine earns its keep: every controller here is built from the same autodiff primitives as the rest of Fugacio, so a closed-loop performance index has exact gradients with respect to the controller's own tuning, and the controllers compose with the dynamic flowsheet they regulate. The subpackage is layered bottom-up:
riccati: differentiable Riccati solvers (DARE/CARE), the infinite-horizon LQR gain (dlqr,lqr) and the steady-state Kalman gain (kalman_gain), via fixed-iteration structured-doubling / matrix-sign recursions that backprop cleanly.qp: a small dense convex QP solver (solve_qp) in the OSQP/ADMM style with an active-set polish and an implicit-function-theoremcustom_vjp, the differentiable core of linear MPC.linear: condensed-QP linear and offset-free MPC (linear_mpc) with an LQR terminal cost, a disturbance-observer for zero steady-state offset, and hard input / soft output constraints.estimation: the Kalman filter, the extended and unscented Kalman filters, and optimization-based moving-horizon estimation (moving_horizon_estimate), all differentiable.nonlinear: nonlinear and economic MPC (nonlinear_mpc) by direct single-shooting over the true nonlinear model, optimized withfugacio.sim.argmin(differentiating through the optimum).simulate: a one-scanclosed-loop harness (simulate_closed_loop) and gradient-based weight tuning (tune_mpc).
Modules:
| Name | Description |
|---|---|
estimation |
Differentiable state estimation: Kalman, EKF, UKF, and moving-horizon estimation. |
linear |
Linear and offset-free model predictive control. |
nonlinear |
Nonlinear and economic model predictive control. |
qp |
A small, differentiable convex quadratic-program solver for MPC. |
riccati |
Riccati equations, LQR, and the steady-state Kalman gain: differentiably. |
simulate |
Closed-loop simulation and gradient-based controller tuning. |
Classes:
| Name | Description |
|---|---|
ExtendedKalmanFilter |
Kalman filter on the exact autodiff linearization of a nonlinear model. |
GaussianState |
A Gaussian belief over the state. |
KalmanFilter |
Recursive linear-Gaussian Kalman filter for |
MHEResult |
Outcome of |
UnscentedKalmanFilter |
Sigma-point (unscented) Kalman filter for a nonlinear model. |
LinearMPC |
A condensed-QP linear MPC with offset-free tracking and constraints. |
MPCResult |
Outcome of a single |
MPCState |
Estimator + memory carried between controller steps. |
NMPCResult |
Outcome of a single |
NonlinearMPC |
Receding-horizon nonlinear MPC over a discrete prediction model. |
QPSettings |
Algorithmic settings for the ADMM forward solve (all static, never differentiated). |
QPSolution |
Outcome of a QP solve. |
ClosedLoop |
Trajectories returned by |
Functions:
| Name | Description |
|---|---|
moving_horizon_estimate |
Estimate the current state by fitting the model to a window of measurements. |
c2d |
Discretize a continuous |
linear_mpc |
Assemble a |
discretize |
Turn a continuous right-hand side into a discrete one-step transition. |
nonlinear_mpc |
Assemble a |
quadratic_tracking |
Build quadratic tracking stage/terminal costs around a setpoint carried in |
solve_qp |
Solve |
solve_qp_canonical |
Differentiable minimizer of |
care |
Stabilizing solution |
dare |
Stabilizing solution |
dlqr |
Discrete infinite-horizon LQR gain and cost-to-go. |
kalman_gain |
Steady-state discrete Kalman filter gain and prior covariance. |
lqr |
Continuous infinite-horizon LQR gain and cost-to-go. |
riccati_residual_continuous |
Residual |
riccati_residual_discrete |
Residual |
closed_loop_cost |
A differentiable quadratic closed-loop performance index. |
constant_setpoint |
A constant output setpoint trajectory |
linear_feedback |
Adapt a |
nonlinear_feedback |
Adapt a |
simulate_closed_loop |
Run a discrete closed loop and return its trajectories. |
tune_mpc |
Tune controller parameters by descending a closed-loop performance index. |
ExtendedKalmanFilter
dataclass
¶
ExtendedKalmanFilter(
f: Callable[[Array, Array], Array],
h: Callable[[Array], Array],
q: Array,
r: Array,
)
Kalman filter on the exact autodiff linearization of a nonlinear model.
The discrete transition f(x, u) -> x+ and measurement h(x) -> y are
arbitrary differentiable callables; the filter linearizes them on the fly with
jax.jacobian (A = df/dx, C = dh/dx). For a continuous plant,
pass a one-step integrator as f (e.g. a wrapped
fugacio.sim.dynamics.odeint_final).
Methods:
| Name | Description |
|---|---|
predict |
Time update: push the belief through |
update |
Measurement update: fold in |
step |
One predict-then-update cycle for input |
filter |
Run the EKF over input/measurement sequences; return the belief trajectory. |
predict
¶
predict(
state: GaussianState, u: ArrayLike = 0.0
) -> GaussianState
Time update: push the belief through f and propagate covariance via df/dx.
update
¶
update(state: GaussianState, y: ArrayLike) -> GaussianState
Measurement update: fold in y through the linearized dh/dx (Joseph form).
step
¶
step(
state: GaussianState, u: ArrayLike, y: ArrayLike
) -> GaussianState
One predict-then-update cycle for input u and measurement y.
filter
¶
filter(
state0: GaussianState, us: Array, ys: Array
) -> GaussianState
Run the EKF over input/measurement sequences; return the belief trajectory.
GaussianState
¶
Bases: NamedTuple
A Gaussian belief over the state.
Attributes:
| Name | Type | Description |
|---|---|---|
mean |
Array
|
State estimate |
cov |
Array
|
Estimate error covariance |
KalmanFilter
dataclass
¶
Recursive linear-Gaussian Kalman filter for x+ = A x + B u + w, y = C x + D u + v.
Construct directly with the model and noise covariances (q process, r
measurement; scalars/diagonals broadcast). A filter step corrects the prior
with a prediction: step predicts from the previous posterior through
the input and then updates with the new measurement.
Methods:
| Name | Description |
|---|---|
predict |
Time update: propagate the belief one step through the dynamics. |
update |
Measurement update: correct the belief with an observation |
step |
One predict-then-update cycle (previous posterior, input, new measurement). |
filter |
Run the filter over input/measurement sequences; return the belief trajectory. |
steady_state_gain |
The steady-state Kalman update gain (the dual-DARE solution). |
predict
¶
predict(
state: GaussianState, u: ArrayLike = 0.0
) -> GaussianState
Time update: propagate the belief one step through the dynamics.
update
¶
update(
state: GaussianState, y: ArrayLike, u: ArrayLike = 0.0
) -> GaussianState
Measurement update: correct the belief with an observation y.
step
¶
step(
state: GaussianState, u: ArrayLike, y: ArrayLike
) -> GaussianState
One predict-then-update cycle (previous posterior, input, new measurement).
filter
¶
filter(
state0: GaussianState, us: Array, ys: Array
) -> GaussianState
Run the filter over input/measurement sequences; return the belief trajectory.
us and ys have a leading time axis of equal length T; the
returned GaussianState has a leading time axis of length T on
mean and cov.
steady_state_gain
¶
The steady-state Kalman update gain (the dual-DARE solution).
MHEResult
¶
Bases: NamedTuple
Outcome of moving_horizon_estimate.
Attributes:
| Name | Type | Description |
|---|---|---|
x |
Array
|
Estimate of the state at the end of the window (the current state). |
trajectory |
Array
|
The full estimated state trajectory over the window |
x0 |
Array
|
The estimated state at the start of the window. |
noise |
Array
|
The estimated process-noise sequence |
UnscentedKalmanFilter
dataclass
¶
UnscentedKalmanFilter(
f: Callable[[Array, Array], Array],
h: Callable[[Array], Array],
q: Array,
r: Array,
alpha: float = 0.001,
beta: float = 2.0,
kappa: float = 0.0,
)
Sigma-point (unscented) Kalman filter for a nonlinear model.
Propagates 2n + 1 deterministic sigma points through the true nonlinear
transition f(x, u) and measurement h(x) and reconstructs the Gaussian
by weighted moments: no Jacobians, and accurate to higher order than the EKF
for strongly nonlinear maps. alpha/beta/kappa are the standard
spread parameters.
Methods:
| Name | Description |
|---|---|
predict |
Time update: propagate the sigma points through |
update |
Measurement update: fold in |
step |
One predict-then-update cycle for input |
filter |
Run the UKF over input/measurement sequences; return the belief trajectory. |
predict
¶
predict(
state: GaussianState, u: ArrayLike = 0.0
) -> GaussianState
Time update: propagate the sigma points through f and rebuild the Gaussian.
update
¶
update(state: GaussianState, y: ArrayLike) -> GaussianState
Measurement update: fold in y via the sigma-point output cross-covariance.
step
¶
step(
state: GaussianState, u: ArrayLike, y: ArrayLike
) -> GaussianState
One predict-then-update cycle for input u and measurement y.
filter
¶
filter(
state0: GaussianState, us: Array, ys: Array
) -> GaussianState
Run the UKF over input/measurement sequences; return the belief trajectory.
LinearMPC
dataclass
¶
LinearMPC(
a: Array,
b: Array,
c: Array,
q: Array,
r: Array,
s_du: Array,
p_terminal: Array,
u_min: Array,
u_max: Array,
du_max: Array,
y_min: Array,
y_max: Array,
soft_weight: float,
obs_gain: Array,
n_pred: int,
n_ctrl: int,
dt: float,
n_dist: int,
has_rate_limit: bool,
has_output_limit: bool,
)
A condensed-QP linear MPC with offset-free tracking and constraints.
Construct with linear_mpc, which discretizes (if needed), computes the
LQR terminal cost and the disturbance-observer gain, and fills the bounds. The
controller is discrete-time with sample period dt; drive a closed loop
with step (estimate, optimize, advance) or query a one-shot optimal
move with solve.
Methods:
| Name | Description |
|---|---|
target |
Steady-state target |
solve |
Solve the MPC QP for the current estimate; return the optimal first move. |
init_state |
Initial controller state (prior estimate and last input). |
estimate |
Correct the augmented |
step |
One discrete controller iteration: estimate, optimize, advance the prior. |
Attributes:
| Name | Type | Description |
|---|---|---|
n_state |
int
|
Number of plant states. |
n_input |
int
|
Number of manipulated inputs. |
n_output |
int
|
Number of controlled outputs. |
target
¶
target(r: Array, d_hat: Array) -> tuple[Array, Array]
Steady-state target (x_ss, u_ss) giving C x_ss + d_hat = r at steady state.
Solves [[I - A, -B], [C, 0]] [x_ss; u_ss] = [0; r - d_hat] (least squares
when the actuator/output counts differ), the standard MPC target problem.
solve
¶
solve(
x_hat: Array,
r: Array,
u_prev: Array,
d_hat: Array | None = None,
*,
settings: QPSettings | None = None,
) -> MPCResult
Solve the MPC QP for the current estimate; return the optimal first move.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x_hat
|
Array
|
Current state estimate |
required |
r
|
Array
|
Output setpoint |
required |
u_prev
|
Array
|
Previously applied input |
required |
d_hat
|
Array | None
|
Output-disturbance estimate |
None
|
settings
|
QPSettings | None
|
Optional QP solver settings. |
None
|
init_state
¶
init_state(
x0: ArrayLike,
u0: ArrayLike | None = None,
d0: ArrayLike | None = None,
) -> MPCState
Initial controller state (prior estimate and last input).
estimate
¶
Correct the augmented [x; d] estimate from a new measurement (Kalman update).
step
¶
step(
state: MPCState,
y_meas: Array,
r: Array,
*,
settings: QPSettings | None = None,
) -> tuple[Array, MPCState]
One discrete controller iteration: estimate, optimize, advance the prior.
Mirrors fugacio.sim.control.PID.step: returns (u, new_state)
where new_state carries the predicted prior estimate for the next
sample. Drop into a closed-loop simulation (see
fugacio.sim.mpc.simulate_closed_loop).
MPCResult
¶
Bases: NamedTuple
Outcome of a single LinearMPC.solve.
Attributes:
| Name | Type | Description |
|---|---|---|
u |
Array
|
The first input move to apply |
u_sequence |
Array
|
The full optimal move sequence |
x_target |
Array
|
The steady-state target state |
u_target |
Array
|
The steady-state target input |
objective |
Array
|
Optimal QP objective value. |
feasible |
Array
|
Whether the QP converged within tolerance. |
MPCState
¶
Bases: NamedTuple
Estimator + memory carried between controller steps.
Attributes:
| Name | Type | Description |
|---|---|---|
x_hat |
Array
|
Current state estimate |
d_hat |
Array
|
Output-disturbance estimate |
u_prev |
Array
|
Last applied input |
NMPCResult
¶
Bases: NamedTuple
Outcome of a single NonlinearMPC.solve.
Attributes:
| Name | Type | Description |
|---|---|---|
u |
Array
|
The first input move to apply |
u_sequence |
Array
|
The optimal move sequence |
trajectory |
Array
|
Predicted state trajectory under the optimum |
cost |
Array
|
Optimal open-loop cost. |
result |
OptimizeResult
|
The underlying |
NonlinearMPC
dataclass
¶
NonlinearMPC(
transition: Transition,
stage_cost: StageCost,
terminal_cost: TerminalCost | None,
n_input: int,
n_pred: int,
n_ctrl: int,
u_min: Array,
u_max: Array,
du_max: Array,
has_rate_limit: bool,
method: str,
max_iter: int,
)
Receding-horizon nonlinear MPC over a discrete prediction model.
Construct with nonlinear_mpc. The controller optimizes the move
sequence each call to solve; step runs one receding-horizon
iteration and returns a shifted warm start for the next sample.
Methods:
| Name | Description |
|---|---|
rollout |
Predicted state trajectory |
solve |
Solve the open-loop optimal-control problem for the current state. |
step |
One receding-horizon iteration; returns |
rollout
¶
rollout(
x0: Array, u_seq: Array, theta: Any = None
) -> Array
Predicted state trajectory (Np + 1, n) under a move sequence.
solve
¶
solve(
x0: Array,
theta: Any = None,
*,
u_init: Array | None = None,
u_prev: Array | None = None,
) -> NMPCResult
Solve the open-loop optimal-control problem for the current state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x0
|
Array
|
Current state |
required |
theta
|
Any
|
Parameters forwarded to the model and cost (e.g. the setpoint). |
None
|
u_init
|
Array | None
|
Optional warm-start move sequence |
None
|
u_prev
|
Array | None
|
Previous applied input, enabling the move-rate limit on the first move. |
None
|
QPSettings
¶
Bases: NamedTuple
Algorithmic settings for the ADMM forward solve (all static, never differentiated).
Attributes:
| Name | Type | Description |
|---|---|---|
rho |
float
|
ADMM penalty on the consistency constraint (step size). |
sigma |
float
|
Tiny proximal regularization that makes the KKT matrix nonsingular
even when |
alpha |
float
|
Over-relaxation factor in |
iters |
int
|
Number of ADMM iterations (fixed, for a differentiable scan). |
active_tol |
float
|
Distance below which a constraint counts as active in the polish. |
QPSolution
¶
Bases: NamedTuple
Outcome of a QP solve.
Attributes:
| Name | Type | Description |
|---|---|---|
x |
Array
|
The optimal decision vector |
obj |
Array
|
Objective value |
primal_residual |
Array
|
Max constraint violation |
dual_residual |
Array
|
Max-norm stationarity residual |
converged |
Array
|
Whether both residuals are below tolerance. |
ClosedLoop
¶
Bases: NamedTuple
Trajectories returned by simulate_closed_loop.
With T control steps, n states, m inputs and p outputs:
Attributes:
| Name | Type | Description |
|---|---|---|
t |
Array
|
Sample times |
states |
Array
|
Plant states |
outputs |
Array
|
Clean outputs |
measurements |
Array
|
Noisy outputs fed to the controller |
inputs |
Array
|
Applied inputs |
setpoints |
Array
|
Output setpoints used at each step |
moving_horizon_estimate
¶
moving_horizon_estimate(
f: Callable[[Array, Array], Array],
h: Callable[[Array], Array],
us: Array,
ys: Array,
x_prior: Array,
*,
q: ArrayLike,
r: ArrayLike,
p0: ArrayLike,
state_bounds: tuple[Any, Any] | None = None,
max_iter: int = 200,
) -> MHEResult
Estimate the current state by fitting the model to a window of measurements.
Minimizes the arrival cost plus the stage costs over a window of N
measurements::
||x0 - x_prior||^2_{P0^{-1}}
+ sum_k ||w_k||^2_{Q^{-1}} + sum_k ||y_k - h(x_k)||^2_{R^{-1}}
subject to x_{k+1} = f(x_k, u_k) + w_k, over the decision variables x0
and the process-noise sequence w. The optimum is found with
fugacio.sim.argmin, so the estimate is differentiable (and optional
box state_bounds are enforced). For a linear-Gaussian model with no bounds
this reproduces the Kalman filter's posterior mean.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
f
|
Callable[[Array, Array], Array]
|
Discrete transition |
required |
h
|
Callable[[Array], Array]
|
Measurement map |
required |
us
|
Array
|
Window inputs |
required |
ys
|
Array
|
Window measurements |
required |
x_prior
|
Array
|
Prior mean of the window's first state |
required |
q
|
ArrayLike
|
Process-noise covariance |
required |
r
|
ArrayLike
|
Measurement-noise covariance |
required |
p0
|
ArrayLike
|
Arrival-cost covariance |
required |
state_bounds
|
tuple[Any, Any] | None
|
Optional |
None
|
max_iter
|
int
|
Optimizer iteration cap. |
200
|
Returns:
| Type | Description |
|---|---|
MHEResult
|
An |
c2d
¶
c2d(
ss: StateSpace, dt: ArrayLike, *, method: str = "zoh"
) -> StateSpace
Discretize a continuous StateSpace at sample time dt.
Zero-order-hold exactly via the matrix exponential of the augmented block
[[A, B], [0, 0]]: expm(.. * dt) = [[Ad, Bd], [0, I]]. The output map
(C, D) is unchanged. Differentiable in dt and the model matrices.
linear_mpc
¶
linear_mpc(
model: StateSpace,
*,
q: ArrayLike,
r: ArrayLike,
horizon: int,
control_horizon: int | None = None,
s_du: ArrayLike = 0.0,
dt: ArrayLike | None = None,
discretize: bool = False,
u_min: ArrayLike = -inf,
u_max: ArrayLike = inf,
du_max: ArrayLike = inf,
y_min: ArrayLike = -inf,
y_max: ArrayLike = inf,
soft_weight: float = 10000.0,
terminal: str = "lqr",
disturbance: str = "output",
proc_noise: float = 0.01,
dist_noise: float = 1.0,
meas_noise: float = 0.01,
) -> LinearMPC
Assemble a LinearMPC from a state-space model and weights.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
StateSpace
|
The plant |
required |
q
|
ArrayLike
|
Output tracking weight |
required |
r
|
ArrayLike
|
Input weight |
required |
horizon
|
int
|
Prediction horizon |
required |
control_horizon
|
int | None
|
Move (control) horizon |
None
|
s_du
|
ArrayLike
|
Input-move (rate) weight |
0.0
|
dt
|
ArrayLike | None
|
Sample time; required if |
None
|
discretize
|
bool
|
Whether |
False
|
u_min
|
ArrayLike
|
Lower input-magnitude limit (vector). |
-inf
|
u_max
|
ArrayLike
|
Upper input-magnitude limit (vector). |
inf
|
du_max
|
ArrayLike
|
Per-step input-rate limit (vector). |
inf
|
y_min
|
ArrayLike
|
Lower output limit, imposed as a soft (slack) constraint. |
-inf
|
y_max
|
ArrayLike
|
Upper output limit, imposed as a soft (slack) constraint. |
inf
|
soft_weight
|
float
|
Linear penalty on output-constraint slacks. |
10000.0
|
terminal
|
str
|
Terminal cost, |
'lqr'
|
disturbance
|
str
|
|
'output'
|
proc_noise
|
float
|
Process-noise weight for the observer Kalman gain. |
0.01
|
dist_noise
|
float
|
Disturbance-state noise weight for the observer Kalman gain. |
1.0
|
meas_noise
|
float
|
Measurement-noise weight for the observer Kalman gain. |
0.01
|
Returns:
| Type | Description |
|---|---|
LinearMPC
|
A ready |
discretize
¶
discretize(
rhs: Callable[[Array, Array, Array, Any], Array],
dt: ArrayLike,
*,
method: str = "rk4",
substeps: int = 4,
) -> Transition
Turn a continuous right-hand side into a discrete one-step transition.
Wraps fugacio.sim.dynamics.odeint_final to integrate
dx/dt = rhs(t, x, u, theta) over one sample dt holding u constant,
yielding f(x, u, theta) -> x(dt) for use as an NMPC prediction model.
nonlinear_mpc
¶
nonlinear_mpc(
transition: Transition,
*,
stage_cost: StageCost,
horizon: int,
n_input: int,
control_horizon: int | None = None,
terminal_cost: TerminalCost | None = None,
u_min: ArrayLike = -inf,
u_max: ArrayLike = inf,
du_max: ArrayLike = inf,
method: str = "bfgs",
max_iter: int = 100,
) -> NonlinearMPC
Assemble a NonlinearMPC.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
transition
|
Transition
|
Discrete prediction model |
required |
stage_cost
|
StageCost
|
Stage cost |
required |
horizon
|
int
|
Prediction horizon |
required |
n_input
|
int
|
Number of manipulated inputs |
required |
control_horizon
|
int | None
|
Move horizon |
None
|
terminal_cost
|
TerminalCost | None
|
Optional terminal cost |
None
|
u_min
|
ArrayLike
|
Lower input-magnitude limit. |
-inf
|
u_max
|
ArrayLike
|
Upper input-magnitude limit. |
inf
|
du_max
|
ArrayLike
|
Per-step input-rate limit. |
inf
|
method
|
str
|
Inner optimizer for the box-constrained solve ( |
'bfgs'
|
max_iter
|
int
|
Optimizer iteration cap. |
100
|
quadratic_tracking
¶
quadratic_tracking(
q: ArrayLike,
r: ArrayLike,
*,
output: Callable[[Array], Array] | None = None,
) -> tuple[StageCost, TerminalCost]
Build quadratic tracking stage/terminal costs around a setpoint carried in theta.
The returned costs read the setpoint and reference input from theta (a dict
with keys "r" and optional "u_ss"); the stage cost is
||y - r||^2_Q + ||u - u_ss||^2_R (with y = output(x), default y = x)
and the terminal cost is ||y_N - r||^2_Q. Pair with NonlinearMPC.
solve_qp
¶
solve_qp(
p: ArrayLike,
q: ArrayLike,
*,
a_eq: ArrayLike | None = None,
b_eq: ArrayLike | None = None,
g_ineq: ArrayLike | None = None,
h_ineq: ArrayLike | None = None,
lb: ArrayLike | None = None,
ub: ArrayLike | None = None,
settings: QPSettings = _DEFAULT_SETTINGS,
) -> QPSolution
Solve min 0.5 z^T P z + q^T z with optional equality/inequality/box constraints.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
p
|
ArrayLike
|
Symmetric positive-semidefinite Hessian |
required |
q
|
ArrayLike
|
Linear term |
required |
a_eq
|
ArrayLike | None
|
Optional equality-constraint matrix |
None
|
b_eq
|
ArrayLike | None
|
Optional equality-constraint vector |
None
|
g_ineq
|
ArrayLike | None
|
Optional inequality-constraint matrix |
None
|
h_ineq
|
ArrayLike | None
|
Optional inequality-constraint vector |
None
|
lb
|
ArrayLike | None
|
Optional lower box bound |
None
|
ub
|
ArrayLike | None
|
Optional upper box bound |
None
|
settings
|
QPSettings
|
ADMM |
_DEFAULT_SETTINGS
|
Returns:
| Type | Description |
|---|---|
QPSolution
|
A |
QPSolution
|
respect to every datum ( |
QPSolution
|
active-set implicit function theorem. |
solve_qp_canonical
¶
solve_qp_canonical(
p: ArrayLike,
q: ArrayLike,
a: ArrayLike,
low: ArrayLike,
up: ArrayLike,
*,
settings: QPSettings = _DEFAULT_SETTINGS,
) -> Array
Differentiable minimizer of 0.5 z^T P z + q^T z s.t. low <= A z <= up.
The bare canonical form the MPC layer assembles directly. Returns just the
optimal z (a la fugacio.sim.argmin), carrying exact implicit-diff
gradients with respect to P, q, A, low, up.
care
¶
care(
a: Array,
b: Array,
q: Array,
r: Array,
*,
iters: int = 40,
) -> Array
Stabilizing solution X of the continuous algebraic Riccati equation.
Solves A^T X + X A - X B R^{-1} B^T X + Q = 0 for the symmetric
positive-semidefinite stabilizing solution via the matrix sign function of the
Hamiltonian Z = [[A, -G], [-Q, -A^T]] (with G = B R^{-1} B^T), followed
by Roberts' least-squares extraction. Differentiable in every input matrix.
dare
¶
dare(
a: Array,
b: Array,
q: Array,
r: Array,
*,
iters: int = _DEFAULT_ITERS,
) -> Array
Stabilizing solution X of the discrete algebraic Riccati equation.
Solves A^T X A - X - A^T X B (R + B^T X B)^{-1} B^T X A + Q = 0 for the
unique symmetric positive-semidefinite stabilizing solution by the
structure-preserving doubling algorithm. The iteration is a fixed-length
jax.lax.scan, so X is differentiable with respect to every input
matrix.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a
|
Array
|
State matrix |
required |
b
|
Array
|
Input matrix |
required |
q
|
Array
|
State weight |
required |
r
|
Array
|
Input weight |
required |
iters
|
int
|
Number of doubling steps (each squares the horizon; the default is comfortably into the converged regime). |
_DEFAULT_ITERS
|
Returns:
| Type | Description |
|---|---|
Array
|
The symmetric stabilizing solution |
dlqr
¶
dlqr(
a: Array,
b: Array,
q: Array,
r: Array,
*,
iters: int = _DEFAULT_ITERS,
) -> tuple[Array, Array]
Discrete infinite-horizon LQR gain and cost-to-go.
Returns (K, X) for the optimal state feedback u = -K x that minimizes
sum_k x_k^T Q x_k + u_k^T R u_k subject to x_{k+1} = A x_k + B u_k,
with X the dare solution (the cost-to-go x_0^T X x_0) and
K = (R + B^T X B)^{-1} B^T X A.
kalman_gain
¶
kalman_gain(
a: Array,
c: Array,
qn: Array,
rn: Array,
*,
iters: int = _DEFAULT_ITERS,
) -> tuple[Array, Array]
Steady-state discrete Kalman filter gain and prior covariance.
For x_{k+1} = A x_k + w_k with process covariance Qn and measurement
y_k = C x_k + v_k with covariance Rn, returns (L, P) where P is
the stabilizing solution of the filtering Riccati equation (the steady-state
prior error covariance) and L = P C^T (C P C^T + Rn)^{-1} is the
a-posteriori update gain (x_hat <- x_prior + L (y - C x_prior)).
Estimation is control run backwards: P is dare applied to the dual
pair (A^T, C^T, Qn, Rn), so this shares the doubling solver and its
differentiability.
lqr
¶
Continuous infinite-horizon LQR gain and cost-to-go.
Returns (K, X) for the optimal feedback u = -K x minimizing
\int x^T Q x + u^T R u subject to x' = A x + B u, with X the
care solution and K = R^{-1} B^T X.
riccati_residual_continuous
¶
Residual A^T X + X A - X B R^{-1} B^T X + Q of the continuous ARE (zero at solution).
riccati_residual_discrete
¶
Residual A^T X A - X - A^T X B (R + B^T X B)^{-1} B^T X A + Q (zero at the solution).
Useful as a self-contained correctness oracle: a valid DARE solution drives this matrix to zero with no external reference.
closed_loop_cost
¶
closed_loop_cost(
loop: ClosedLoop,
*,
error_weight: ArrayLike = 1.0,
effort_weight: ArrayLike = 0.0,
move_weight: ArrayLike = 0.0,
u_ref: ArrayLike = 0.0,
) -> Array
A differentiable quadratic closed-loop performance index.
Sums the tracking error of the resulting outputs against the setpoints, plus optional input-effort and input-move penalties:
``sum_k ||y_{k+1} - r_k||^2_We + ||u_k - u_ref||^2_Wu + ||u_k - u_{k-1}||^2_Wd``
Each weight may be a scalar, a per-channel vector, or a full matrix. This is the
natural objective for tune_mpc.
constant_setpoint
¶
constant_setpoint(r: ArrayLike, n_steps: int) -> Array
A constant output setpoint trajectory (n_steps, p).
linear_feedback
¶
linear_feedback(
mpc: Any,
x0: ArrayLike,
*,
u0: ArrayLike | None = None,
d0: ArrayLike | None = None,
) -> tuple[ControllerStep, Any]
Adapt a LinearMPC to the closed-loop step protocol.
Returns (step, ctrl0) ready for simulate_closed_loop; step is the
controller's own estimate-optimize-advance iteration and ctrl0 its initial
estimator state.
nonlinear_feedback
¶
nonlinear_feedback(
mpc: Any,
*,
u0: ArrayLike | None = None,
theta: Any = None,
) -> tuple[ControllerStep, Any]
Adapt a NonlinearMPC to the closed-loop step protocol.
Assumes full-state feedback (the measurement is the state). The setpoint passed
by the harness is written into theta["r"] each step; any other entries of
theta (e.g. "u_ss" or model parameters) are carried through unchanged. The
controller state is (u_prev, warm_start).
simulate_closed_loop
¶
simulate_closed_loop(
plant: Plant,
controller: ControllerStep,
x0: ArrayLike,
ctrl0: Any,
setpoints: ArrayLike,
*,
dt: ArrayLike = 1.0,
measure: Measure | None = None,
process_noise: ArrayLike | None = None,
meas_noise: ArrayLike | None = None,
) -> ClosedLoop
Run a discrete closed loop and return its trajectories.
At each step k the measurement y_k = measure(x_k) + v_k is formed, the
controller produces u_k (advancing its own state), and the plant steps to
x_{k+1} = plant(x_k, u_k) + w_k. The whole march is a single
jax.lax.scan, hence differentiable and jit-able.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
plant
|
Plant
|
Discrete plant map |
required |
controller
|
ControllerStep
|
Step |
required |
x0
|
ArrayLike
|
Initial plant state |
required |
ctrl0
|
Any
|
Initial controller state. |
required |
setpoints
|
ArrayLike
|
Output setpoints |
required |
dt
|
ArrayLike
|
Sample time (for the reported time axis only). |
1.0
|
measure
|
Measure | None
|
Output map |
None
|
process_noise
|
ArrayLike | None
|
Optional additive state noise |
None
|
meas_noise
|
ArrayLike | None
|
Optional additive measurement noise |
None
|
Returns:
| Type | Description |
|---|---|
ClosedLoop
|
A |
ClosedLoop
|
setpoint trajectories. |
tune_mpc
¶
tune_mpc(
simulate: Callable[[Any], ClosedLoop],
params0: Any,
*,
performance: Callable[[ClosedLoop], Array]
| None = None,
bounds: tuple[Any, Any] | None = None,
method: str = "bfgs",
max_iter: int = 60,
) -> OptimizeResult
Tune controller parameters by descending a closed-loop performance index.
simulate(params) must build the controller from the params pytree, run the
closed loop, and return the ClosedLoop; performance scores it
(defaults to closed_loop_cost, i.e. tracking ISE). The gradient flows
through the simulation and the MPC's own QP, so the tune is exact first-order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
simulate
|
Callable[[Any], ClosedLoop]
|
|
required |
params0
|
Any
|
Initial parameter pytree (e.g. |
required |
performance
|
Callable[[ClosedLoop], Array] | None
|
Scalar score |
None
|
bounds
|
tuple[Any, Any] | None
|
Optional |
None
|
method
|
str
|
Unconstrained optimizer forwarded to |
'bfgs'
|
max_iter
|
int
|
Maximum optimizer iterations forwarded to |
60
|
Returns:
| Type | Description |
|---|---|
OptimizeResult
|
The |