A convex data-driven predictive control (DPC) framework for systems with unknown dynamics operating in biased conditions (e.g., wind). System dynamics are modelled online from data; bias is treated as a disturbance, estimated from prediction residuals; and cvxpy solves the resulting convex optimization at each step.
At each time step
subject to:
where
The following terms are updated online at every step:
-
Dynamics —
$\hat{A}$ ,$\hat{B}$ , and offset$\hat{c}$ are identified from a sliding window of$n$ input-output samples to minimize the following (see Data-driven Modelling):
-
Disturbance —
$\hat{d}$ is inferred from the prediction residual via the Moore-Penrose pseudoinverse$\hat{B}^\dagger$ (see Bias Rejection):
Within the optimization, dynamics are lifted over the full horizon by generating stacked state and input vectors and augmented state-space matrices as follows:
where
A data-driven model is considered viable when the following conditions are satisfied:
-
The eigenvalues of the state-transition matrix estimate are stabilizing, such that
$\max_i |\lambda_i(\hat A)| \leq 1$ -
The combination of
$\hat{A}$ and$\hat{B}$ is controllable such that$\text{rank}[\hat{B},,\hat{A}\hat{B},,\ldots,,\hat{A}^{n_x-1}\hat{B}] = n_x$ .
The plant is modelled as
The modes of the plant are excited with random, bounded inputs drawn uniformly from
Only the state increment is regressed, rather than the full next state:
This improves numeric conditioning, since
Each batch is normalized by the per-feature standard deviation before fitting:
A stacked regressor is constructed from the normalized data:
Parameter matrix
Parameters from each batch are blended into a running model with learning rate
The animation shows a brief excitation phase followed by the controlled trajectory. The control trajectory is produced only after the model passes the viability checks described above Formulation (i.e., stable and controllable).
| Control Inputs | Velocity States |
|---|---|
![]() |
![]() |
Bias (e.g., wind) is treated as an unknown slowly-varying disturbance
At each step,
| Without Disturbance Rejection | With Disturbance Rejection |
|---|---|
![]() |
![]() |
Without rejection the trajectory drifts from the origin; with rejection the estimated disturbance is cancelled in the predictions, restoring convergence.
| Control Inputs | Velocity States |
|---|---|
![]() |
![]() |
The formulation and results above demonstrate that a convex data-driven predictive control framework can be implemented without requiring a priori knowledge of the plant model. Moreover, the framework is robust to biased conditions (e.g., wind) by estimating and rejecting disturbances online.
The use of convex optimization ensures the control problem remains tractable and can be solved efficiently at each time step. This approach is applicable to a wide range of systems, provided their dynamics can be approximated as linear and the disturbances are slowly varying.
Install dependencies and run:
pip install -r requirements.txt
python main.pyParameters are configured in configs/.
- P. T. Jardine, S. N. Givigi, S. Yousefi and M. J. Korenberg, "Adaptive MPC Using a Dual Fast Orthogonal Kalman Filter: Application to Quadcopter Altitude Control," in IEEE Systems Journal, vol. 13, no. 1, pp. 973-981, March 2019
- Parts of this project were developed with the assistance of Claude Sonnet 4.6
- Solving the optimization: cvxpy
- Terminal cost via Discrete Algebraic Riccati Equation: scipy.linalg.solve_discrete_are
- Disturbance estimation via Moore-Penrose pseudoinverse: numpy.linalg.lstsq






