Python library that implements DeePC: Data-Enabled Predictive Control.
Original paper: Data-Enabled Predictive Control: In the Shallows of the DeePC
Library Author: Alessio Russo (arusso2@bu.edu)
License: MIT
Other contributors:
- Many thanks to Edgar W. for spotting out a bug that
let the slack variables slack_u
and slack_y
assume any value when the value of the
corresponding regularizer was 0
.
DeePC applied to a 3-pulley system with transfer function
with sampling time Ts=0.05 [s]. Check the file in examples\example_siso_pulley.py
for more information.
- Python 3.7
- Numpy, Scipy, CVXPY, Matplotlib, Ecos, Jupyter (to run the examples)
You can find a list of libraries in requirements.txt
Use the setup.py
file to install the library (execute the command pip install .
).
The library makes extensive use of the CVXPY library. If you are unfamiliar with CVXPY, we strongly recommend you to first learn about CVXPY.
The algorithm can be instantiated by creating a DeePC
object (see example below). Use
the DeePC.build_problem
to build the optimization problem and DeePC.solve
to solve the problem.
To learn how to use the library, check the examples located in the examples/
folder.
In general the code has the following structure
import numpy as np
import cvxpy as cp
from typing import List
from cvxpy.expressions.expression import Expression
from cvxpy.constraints.constraint import Constraint
from pydeepc import DeePC
from pydeepc.utils import Data
# Define the loss function for DeePC. The callback should accept
# 2 input/output variables, each of type Variable (see CVXPY library)
# The callback must return the objective function
def loss_callback(u: cp.Variable, y: cp.Variable) -> Expression:
horizon, M, P = u.shape[0], u.shape[1], y.shape[1]
# Sum_t ||y_t - 1||^2
return cp.norm(y - 1, 'fro') + 0.1 * cp.norm(u, 'fro)
# Define the constraints for DeePC. See also how constraints are defined
# in CVXPY. The callback should accept # 2 input/output variables, each
# of type Variable (see CVXPY library). The callback must return a list of
# constraints
def constraints_callback(u: cp.Variable, y: cp.Variable) -> List[Constraint]:
horizon, M, P = u.shape[0], u.shape[1], y.shape[1]
# Define a list of input/output constraints
return [y <= 10, y >= -10, u >= -20, u <= 20]
# DeePC paramters
s = 3 # How many steps before we solve again the DeePC problem
T_INI = 5 # Size of the initial set of data
T = 200 # Number of data points used to estimate the system
HORIZON = 30 # Horizon length
LAMBDA_G_REGULARIZER = 0 # g regularizer (see DeePC paper, eq. 8)
LAMBDA_Y_REGULARIZER = 0 # y regularizer (see DeePC paper, eq. 8)
# Define plant
sys = ...
# Generate initial data and initialize DeePC
u = ... # define input data of length T
y = ... # apply input to system and measure output
data = Data(u, y)
deepc = DeePC(data, Tini = T_INI, horizon = HORIZON)
# Build the deepc problem
deepc.build_problem(
build_loss = loss_callback,
build_constraints = constraints_callback,
lambda_g = LAMBDA_G_REGULARIZER,
lambda_y = LAMBDA_Y_REGULARIZER)
# Simulate for a number of steps
for idx in range(300):
# Update initial data and solve DeepC
u_optimal, info = deepc.solve(data_ini = data_ini)
output = ... # Apply optimal control input of size s to the system and measure output
data_ini = Data(..., ...) # Use last T_INI samples to build a new initial condition
- When using the projection regularizer you may encounter some problems while using the ECOS solver. We suggest setting the regularizer to 0, or using another solver (e.g., MOSEK)
Our code is released under the MIT license