direct_data_driven_mpc.lti_data_driven_mpc_controller.LTIDataDrivenMPCController#
- class LTIDataDrivenMPCController[source]#
A class that implements a Data-Driven Model Predictive Control (MPC) controller for Linear Time-Invariant (LTI) systems. This controller can be configured as either a Nominal or a Robust controller. The implementation is based on research by J. Berberich et al., as described in [1].
- Attributes:
controller_type (
LTIDataDrivenMPCType
) – The LTI Data-Driven MPC controller type.n (
int
) – The estimated order of the system.m (
int
) – The number of control inputs.p (
int
) – The number of system outputs.u_d (
numpy.ndarray
) – A persistently exciting input sequence.y_d (
numpy.ndarray
) – The system’s output response to u_d.N (
int
) – The length of the initial input (u_d) and output (y_d) trajectories.u_past (
numpy.ndarray
) – The past n input measurements (u[t-n, t-1]).y_past (
numpy.ndarray
) – The past n output measurements (y[t-n, t-1]).L (
int
) – The prediction horizon length.Q (
numpy.ndarray
) – The output weighting matrix for the MPC formulation.R (
numpy.ndarray
) – The input weighting matrix for the MPC formulation.u_s (
numpy.ndarray
) – The setpoint for control inputs.y_s (
numpy.ndarray
) – The setpoint for system outputs.eps_max (
float | None
) – The estimated upper bound of the system measurement noise.lamb_alpha (
float | None
) – The ridge regularization base weight for alpha, scaled by eps_max.lamb_sigma (
float | None
) – The ridge regularization weight for sigma.U (
np.ndarray | None
) – An array of shape (m, 2) containing the bounds for the m predicted inputs. Each row specifies the [min, max] bounds for a single input. If None, no input bounds are applied.c (
float | None
) – A constant used to define a Convex constraint for the slack variable sigma in a Robust MPC formulation.slack_var_constraint_type (
SlackVarConstraintType
) – The constraint type for the slack variable sigma in a Robust MPC formulation.n_mpc_step (
int
) – The number of consecutive applications of the optimal input for an n-Step Data-Driven MPC Scheme (multi-step).use_terminal_constraints (
bool
) – If True, include terminal equality constraints in the Data-Driven MPC formulation. If False, the controller will not enforce these constraints.HLn_ud (
numpy.ndarray
) – The Hankel matrix constructed from the input data u_d.HLn_yd (
numpy.ndarray
) – The Hankel matrix constructed from the output data y_d.alpha (
cvxpy.expressions.variable.Variable
) – The optimization variable for a data-driven input-output trajectory characterization of the system.ubar (
cvxpy.expressions.variable.Variable
) – The predicted control input variable.ybar (
cvxpy.expressions.variable.Variable
) – The predicted system output variable.sigma (
cp.Variable | None
) – The slack variable to account for noisy measurements in a Robust Data-Driven MPC.dynamics_constraints (
list[cp.Constraint]
) – The system dynamics constraints for a Data-Driven MPC formulation.internal_state_constraints (
list[cp.Constraint]
) – The internal state constraints for a Data-Driven MPC formulation.terminal_constraints (
list[cp.Constraint]
) – The terminal state constraints for a Data-Driven MPC formulation.slack_var_constraint (
list[cp.Constraint]
) – The slack variable constraints for a Robust Data-Driven MPC formulation.constraints (
list[cp.Constraint]
) – The combined constraints for the Data-Driven MPC formulation.cost (
cvxpy.expressions.expression.Expression
) – The cost function for the Data-Driven MPC formulation.problem (
cvxpy.problems.problem.Problem
) – The quadratic programming problem for the Data-Driven MPC.optimal_u (
numpy.ndarray
) – The optimal control input derived from the Data-Driven MPC solution.
References
[1] J. Berberich, J. Köhler, M. A. Müller and F. Allgöwer, “Data-Driven Model Predictive Control With Stability and Robustness Guarantees,” in IEEE Transactions on Automatic Control, vol. 66, no. 4, pp. 1702-1717, April 2021, doi: 10.1109/TAC.2020.3000182.
- __init__(n: int, m: int, p: int, u_d: ndarray, y_d: ndarray, L: int, Q: ndarray, R: ndarray, u_s: ndarray, y_s: ndarray, eps_max: float | None = None, lamb_alpha: float | None = None, lamb_sigma: float | None = None, U: ndarray | None = None, c: float | None = None, slack_var_constraint_type: SlackVarConstraintType = SlackVarConstraintType.CONVEX, controller_type: LTIDataDrivenMPCType = LTIDataDrivenMPCType.NOMINAL, n_mpc_step: int = 1, use_terminal_constraints: bool = True)[source]#
Initialize a Direct LTI Data-Driven MPC with specified system model parameters, an initial input-output data trajectory measured from the system, and LTI Data-Driven MPC parameters.
Note
The input data u_d used to excite the system to get the initial output data must be persistently exciting of order (L + 2 * n), as defined in the Data-Driven MPC formulations in [1].
- Parameters:
n (
int
) – The estimated order of the system.m (
int
) – The number of control inputs.p (
int
) – The number of system outputs.u_d (
numpy.ndarray
) – A persistently exciting input sequence.y_d (
numpy.ndarray
) – The system’s output response to u_d.L (
int
) – The prediction horizon length.Q (
numpy.ndarray
) – The output weighting matrix for the MPC formulation.R (
numpy.ndarray
) – The input weighting matrix for the MPC formulation.u_s (
numpy.ndarray
) – The setpoint for control inputs.y_s (
numpy.ndarray
) – The setpoint for system outputs.eps_max (
float | None
) – The estimated upper bound of the system measurement noise.lamb_alpha (
float | None
) – The ridge regularization base weight for alpha. It is scaled by eps_max.lamb_sigma (
float | None
) – The ridge regularization weight for sigma.U (
np.ndarray | None
) – An array of shape (m, 2) containing the bounds for the m predicted inputs. Each row specifies the [min, max] bounds for a single input. If None, no input bounds are applied. Defaults to None.c (
float | None
) – A constant used to define a Convex constraint for the slack variable sigma in a Robust MPC formulation.slack_var_constraint_type (
SlackVarConstraintType
) – The constraint type for the slack variable sigma in a Robust MPC formulation.controller_type (
LTIDataDrivenMPCType
) – The Data-Driven MPC controller type.n_mpc_step (
int
) – The number of consecutive applications of the optimal input for an n-Step Data-Driven MPC Scheme (multi-step). Defaults to 1.use_terminal_constraints (
bool
) – If True, include terminal equality constraints in the Data-Driven MPC formulation. If False, the controller will not enforce these constraints.
References
[1] J. Berberich, J. Köhler, M. A. Müller and F. Allgöwer, “Data-Driven Model Predictive Control With Stability and Robustness Guarantees,” in IEEE Transactions on Automatic Control, vol. 66, no. 4, pp. 1702-1717, April 2021, doi: 10.1109/TAC.2020.3000182.
- evaluate_input_persistent_excitation() None [source]#
Evaluate whether the input data is persistently exciting of order (L + 2 * n).
This method first verifies that the length of the elements in the input data matches the number of inputs of the system. Then, it ensures that the length of the input sequence meets a minimum threshold, as defined in Remark 1 [1]. Finally, it evaluates the rank of the Hankel matrix induced by the input sequence to determine if the input sequence is persistently exciting, as described in Definition 1 [1].
- Raises:
ValueError – If the length of the elements in the data sequence does not match the number of inputs of the system, or if the input data is not persistently exciting of order (L + 2 * n).
References
[1]: See class-level docstring for full reference details.
- check_prediction_horizon_length() None [source]#
Check if the prediction horizon length, L, satisfies the MPC system design restriction based on the type of the Direct Data-Driven MPC controller. For a Nominal type, it must be greater than or equal to the estimated system order n. For a Robust controller, it must be greater than or equal to two times the estimated system order n.
These restrictions are defined by Assumption 3, for the Nominal MPC scheme, and Assumption 4, for the Robust one, as described in [1].
- Raises:
ValueError – If the prediction horizon L is less than the required threshold based on the controller type.
References
[1]: See class-level docstring for full reference details.
- check_weighting_matrices_dimensions() None [source]#
Check if the dimensions of the output and input weighting matrices, Q and R, are correct for an MPC formulation based on their order.
- Raises:
ValueError – If the dimensions of the Q or R matrices are incorrect.
- initialize_data_driven_mpc() None [source]#
Initialize the Data-Driven MPC controller.
This method performs the following tasks:
Constructs Hankel matrices from the initial input-output trajectory data (u_d, y_d). These matrices are used for the data-driven characterization of the unknown system, as defined by the system dynamic constraints in the Robust and Nominal Data-Driven MPC formulations of [1].
Defines the optimization variables for the Data-Driven MPC problem.
Defines the constraints for the MPC problem, which include the system dynamics, internal state, terminal state, and input constraints. For a Robust MPC controller, it also includes the slack variable constraint.
Defines the cost function for the MPC problem.
Formulates the MPC problem as a Quadratic Programming (QP) problem.
Solves the initialized MPC problem to ensure the formulation is valid and retrieve the optimal control input for the initial setup.
This initialization process ensures that all necessary components for the Data-Driven MPC are correctly defined and that the MPC problem is solvable with the provided initial data.
References
[1]: See class-level docstring for full reference details.
- update_and_solve_data_driven_mpc() None [source]#
Update the Data-Driven MPC optimization parameters, solve the problem, and store the optimal control input.
This method updates the MPC optimization parameters to incorporate the latest n input-output measurements of the system. It then solves the MPC problem and stores the resulting optimal control input.
References
[1]: See class-level docstring for full reference details.
- define_optimization_variables() None [source]#
Define the optimization variables for the Data-Driven MPC formulation based on the specified MPC controller type.
This method defines data-driven MPC optimization variables as described in the Nominal and Robust MPC formulations in [1]:
Nominal MPC: Defines the variable alpha for a data-driven input-output trajectory characterization of the system, and the predicted input (ubar) and output (ybar) variables, as described in Equation (3).
Robust MPC: In addition to the optimization variables defined for a Nominal MPC formulation, defines the sigma variable to account for noisy measurements, as described in Equation (6).
Note
This method initializes the alpha, ubar, ybar, and sigma attributes to define the MPC optimization variables based on the MPC controller type. The sigma variable is only initialized for a Robust MPC controller.
References
[1]: See class-level docstring for full reference details.
- define_optimization_parameters() None [source]#
Define MPC optimization parameters that are updated at every step iteration.
This method initializes the input setpoint (u_s_param), output setpoint (y_s_param), past inputs (u_past_param), and past outputs (y_past_param) MPC parameters.
The values of u_s_param and y_s_param are initialized to u_s and y_s.
These parameters are updated at each MPC iteration, except for u_s_param and y_s_param, which must be manually updated when setting new controller setpoint pairs.
Using CVXPY Parameter objects allows efficient updates without the need of reformulating the MPC problem at every step.
- update_optimization_parameters() None [source]#
Update MPC optimization parameters.
This method updates MPC parameters with the latest input-output measurement data.
- define_mpc_constraints() None [source]#
Define the constraints for the Data-Driven MPC formulation based on the specified MPC controller type.
This method defines the following constraints, as described in the Nominal and Robust MPC formulations in [1]:
System dynamics: Ensures input-output predictions are possible trajectories of the system based on a data-driven characterization of all its input-output trajectories. In a Robust MPC scheme, adds a slack variable to account for noisy measurements. Defined by Equations (3b) (Nominal) and (6a) (Robust).
Internal state: Ensures predictions align with the internal state of the system’s trajectory. This constrains the first n input-output predictions to match the past n input-output measurements of the system, guaranteeing that the predictions consider the initial state of the system. Defined by Equations (3c) (Nominal) and (6b) (Robust).
Terminal state: Aims to stabilize the internal state of the system so it aligns with the steady-state that corresponds to the input-output pair (u_s, y_s) in any minimal realization (last n input-output predictions, as considered in [1]). Defined by Equations (3d) (Nominal) and (6c) (Robust).
Input: Constrains the predicted input (ubar). Defined by Equation (6c).
Slack Variable: Bounds a slack variable that accounts for noisy online measurements and for noisy data used for prediction (used to construct the Hankel matrices). Defined by Equation (6d), for a Non-Convex constraint, and Remark 3, for a Convex constraint and an implicit alternative.
Note
This method initializes the dynamics_constraints, internal_state_constraints, terminal_constraints, input_constraints, slack_var_constraint, and constraints attributes to define the MPC constraints based on the MPC controller type.
References
[1]: See class-level docstring for full reference details.
- define_system_dynamic_constraints() list[Constraint] [source]#
Define the system dynamic constraints for the Data-Driven MPC formulation corresponding to the specified MPC controller type.
These constraints use a data-driven characterization of all the input-output trajectories of a system, as defined by Theorem 1 [1], to ensure predictions are possible system trajectories. This is analogous to the system dynamics constraints in a typical MPC formulation.
In a Robust MPC scheme, these constraints include a slack variable to account for noisy online measurements and for noisy data used for prediction (used to construct the Hankel matrices).
These constraints are defined according to the following equations from the Nominal and Robust MPC formulations in [1]:
Nominal MPC: Equation (3b).
Robust MPC: Equation (6a).
- Returns:
list[cp.Constraint] – A list containing the CVXPY system dynamic constraints for the Data-Driven MPC controller, corresponding to the specified MPC controller type.
References
[1]: See class-level docstring for full reference details.
- define_internal_state_constraints() list[Constraint] [source]#
Define the internal state constraints for the Data-Driven MPC formulation.
These constraints ensure predictions align with the internal state of the system’s trajectory. This way, the first n input-output predictions are constrained to match the past n input-output measurements of the system, guaranteeing that the predictions consider the initial state of the system.
These constraints are defined according to Equations (3c) (Nominal) and (6b) (Robust) from the Nominal and Robust MPC formulations in [1].
- Returns:
list[cp.Constraint] – A list containing the CVXPY internal state constraints for the Data-Driven MPC controller.
Note
It is essential to update the past n input-output measurements of the system, u_past and y_past, at each MPC iteration.
References
[1]: See class-level docstring for full reference details.
- define_terminal_state_constraints() list[Constraint] [source]#
Define the terminal state constraints for the Data-Driven MPC formulation.
These constraints aim to stabilize the internal state of the system so it aligns with the steady-state that corresponds to the input-output pair (u_s, y_s) in any minimal realization, specifically the last n input-output predictions, as considered in [1].
These constraints are defined according to Equations (3d) (Nominal) and (6c) (Robust) from the Nominal and Robust MPC formulations in [1].
- Returns:
list[cp.Constraint] – A list containing the CVXPY terminal state constraints for the Data-Driven MPC controller.
References
[1]: See class-level docstring for full reference details.
- define_input_constraints() list[Constraint] [source]#
Define the input constraints for the Data-Driven MPC formulation.
These constraints are defined according to Equation (6c) of [1].
- Returns:
list[cp.Constraint] – A list containing the CVXPY input constraints for the Data-Driven MPC controller.
- define_slack_variable_constraint() list[Constraint] [source]#
Define the slack variable constraint for a Robust Data-Driven MPC formulation based on the specified slack variable constraint type.
This constraint bounds a slack variable (sigma) that accounts for noisy online measurements and for noisy data used for prediction (used to construct the Hankel matrices for the system dynamic constraint).
As described in [1], this constraint can be defined in three different ways, achieving the same theoretical guarantees:
Non-Convex: Defines a non-convex constraint (Equation (6d)).
Convex: Defines a convex constraint using a sufficiently large coefficient c (Remark 3).
None: Omits an explicit constraint definition. The slack variable constraint is implicitly met, relying on a high lamb_sigma value (Remark 3).
- Returns:
list[cp.Constraint] – A list containing the CVXPY slack variable constraint for the Robust Data-Driven MPC controller, corresponding to the specified slack variable constraint type. The list is empty if the NONE constraint type is selected.
References
[1]: See class-level docstring for full reference details.
- define_cost_function() None [source]#
Define the cost function for the Data-Driven MPC formulation based on the specified MPC controller type.
This method defines the MPC cost function as described in the Nominal and Robust MPC formulations in [1]:
Nominal MPC: Implements a quadratic stage cost that penalizes deviations of the predicted control inputs (ubar) and outputs (ybar) from the desired equilibrium (u_s, y_s), as described in Equation (3).
Robust MPC: In addition to the quadratic stage cost, adds ridge regularization terms for alpha and sigma variables to account for noisy measurements, as described in Equation (6).
Note
This method initializes the cost attribute to define the MPC cost function based on the MPC controller type.
References
[1]: See class-level docstring for full reference details.
- define_mpc_problem() None [source]#
Define the optimization problem for the Data-Driven MPC formulation.
Note
This method initializes the problem attribute to define the MPC problem of the Data-Driven MPC controller, which is formulated as a Quadratic Programming (QP) problem. It assumes that the cost (objective function) and constraints attributes have already been defined.
- solve_mpc_problem(warm_start: bool = False) str [source]#
Solve the optimization problem for the Data-Driven MPC formulation.
- Returns:
str – The status of the optimization problem after attempting to solve it (e.g., “optimal”, “optimal_inaccurate”, “infeasible”, “unbounded”).
Note
This method assumes that the MPC problem has already been defined. It solves the problem and updates the problem attribute with the solution status.
- get_problem_solve_status() str [source]#
Get the solve status of the optimization problem of the Data-Driven MPC formulation.
- Returns:
str – The status of the optimization problem after attempting to solve it (e.g., “optimal”, “optimal_inaccurate”, “infeasible”, “unbounded”).
- get_optimal_cost_value() float [source]#
Get the cost value corresponding to the solved optimization problem of the Data-Driven MPC formulation.
- Returns:
float – The optimal cost value of the solved MPC optimization problem.
- get_optimal_control_input() ndarray [source]#
Retrieve and store the optimal control input from the MPC solution.
- Returns:
np.ndarray – The predicted optimal control input from time step 0 to (L - 1).
- Raises:
ValueError – If the MPC problem solution status was not “optimal” or “optimal_inaccurate”.
Note
This method should be called after the MPC problem has been solved. It stores the predicted optimal control input in the optimal_u attribute.
- get_optimal_control_input_at_step(n_step: int = 0) ndarray [source]#
Get the optimal control input from the MPC solution corresponding to a specified time step in the prediction horizon [0, L-1].
- Parameters:
n_step (
int
) – The time step of the optimal control input to retrieve. It must be within the range [0, L-1].- Returns:
np.ndarray – An array containing the optimal control input for the specified prediction time step.
Note
This method assumes that the optimal control input from the MPC solution has been stored in the optimal_u attribute.
- Raises:
ValueError – If n_step is not within the range [0, L-1].
- store_input_output_measurement(u_current: ndarray, y_current: ndarray) None [source]#
Store an input-output measurement pair for the current time step in the input-output storage variables.
This method updates the input-output storage variables u_past and y_past by appending the current input-output measurements and removing the oldest measurements located at the first position. This ensures these variables only store the past n measurements, as required for the internal state constraints defined by Equations (3c) (Nominal) and (6b) (Robust) of [1].
- Parameters:
u_current (
numpy.ndarray
) – The control input for the current time step, expected to match the dimensions of prior inputs.y_current (
numpy.ndarray
) – The measured system output for the current time step, expected to match the dimensions of prior outputs. This output should correspond to the system’s response to u_current, as both represent a trajectory of the system.
- Raises:
ValueError – If u_current or y_current do not match the expected dimensions.
Note
This method modifies the u_past and y_past arrays directly to ensure that only the most recent n measurements are retained.
References
[1]: See class-level docstring for full reference details.
- set_past_input_output_data(u_past: ndarray, y_past: ndarray) None [source]#
Set the storage variables for past input-output measurements.
This method assigns the provided input-output measurements to the arrays storing past input-output measurements, u_past and y_past. It is intended to be used for setting the historical data used in the MPC problem formulation.
- Parameters:
u_past (
numpy.ndarray
) – An array containing past control inputs. Expected to have a shape of (n * m, 1), where ‘n’ is the estimated system order and ‘m’ is the dimension of the input.y_past (
numpy.ndarray
) – An array containing past measured system outputs. Expected to have a shape of (n * p, 1) where ‘n’ is the estimated system order and ‘p’ is the dimension of the output.
- Raises:
ValueError – If u_past or y_past do not have correct dimensions.
Note
This method sets the values of the u_past and y_past attributes with the provided new historical data.
- set_input_output_setpoints(u_s: ndarray, y_s: ndarray) None [source]#
Set the control and system setpoints of the Data-Driven MPC controller.
- Parameters:
u_s (
numpy.ndarray
) – The setpoint for control inputs.y_s (
numpy.ndarray
) – The setpoint for system outputs.
- Raises:
ValueError – If u_s or y_s do not have the expected dimensions.
Note
This method sets the values of the u_s and y_s attributes with the provided new setpoints and updates the values of u_s_param and y_s_param to update the data-driven MPC controller setpoint.