Model#
- class Model(model_type=None, symvar_type='SX')[source]#
Bases:
objectThe do-mpc model class. This class holds the full model description and is at the core of
do_mpc.simulator.Simulator,do_mpc.controller.MPCanddo_mpc.estimator.Estimator. TheModelclass is created with setting themodel_type(continuous or discrete). Acontinousmodel consists of an underlying ordinary differential equation (ODE) or differential algebraic equation (DAE):\[\begin{split}\dot{x}(t) &= f(x(t),u(t),z(t),p(t),p_{\text{tv}}(t)) + w(t),\\ 0 &= g(x(t),u(t),z(t),p(t),p_{\text{tv}}(t))\\ y &= h(x(t),u(t),z(t),p(t),p_{\text{tv}}(t)) + v(t)\end{split}\]whereas a
discretemodel consists of a difference equation:\[\begin{split}x_{k+1} &= f(x_k,u_k,z_k,p_k,p_{\text{tv},k}) + w_k,\\ 0 &= g(x_k,u_k,z_k,p_k,p_{\text{tv},k})\\ y_k &= h(x_k,u_k,z_k,p_k,p_{\text{tv},k}) + v_k\end{split}\]The do-mpc model can be initiated with either
SXorMXvariable type. We refer to the CasADi documentation on the difference of these two types.Note
SXvs.MXin a nutshell: In general useSXvariables (default). If your model consists of scalar operationsSXvariables will be beneficial. Your implementation will most likely only benefit fromMXvariables if you use large(r)-scale matrix-vector multiplications.Note
The option
symvar_typewill be inherited to all derived classes (e.g.do_mpc.simulator.Simulator,do_mpc.controller.MPCanddo_mpc.estimator.Estimator). All symbolic variables in these classes will be chosen respectively.Configuration and setup:
Configuring and setting up the
Modelinvolves the following steps:Use
set_variable()to introduce new variables to the model.Optionally introduce “auxiliary” expressions as functions of the previously defined variables with
set_expression(). The expressions can be used for monitoring or be reused as constraints, the cost function etc.Optionally introduce measurement equations with
set_meas(). The syntax is identical toset_expression(). By default state-feedback is assumed.Define the right-hand-side of the discrete or continuous model as a function of the previously defined variables with
set_rhs(). This method must be called once for each introduced state.Call
setup()to finalize theModel. No further changes are possible afterwards.
Note
All introduced model variables are accessible as Attributes of the
Model. Use these attributes to query to variables, e.g. to form the cost function in a seperate file for the MPC configuration.- Parameters:
model_type (
str) – Set if the model isdiscreteorcontinuous.symvar_type (
str) – Set if the model is configured with CasADiSXorMXvariables.
- Raises:
assertion – model_type must be string
assertion – model_type must be either discrete or continuous
- __getitem__(ind)[source]#
The
Modelclass supports the__getitem__method, which can be used to retrieve the model variables (see attribute list).# Query the states like this: x = model.x # or like this: x = model['x']
This also allows to retrieve multiple variables simultaneously:
x, u, z = model['x','u','z']
Methods#
get_linear_system_matrices#
- get_linear_system_matrices(self, xss=None, uss=None, z=None, tvp=None, p=None)#
Returns the matrix quadrupel \((A,B,C,D)\) of the linearized system around the operating point (
xss,uss,z,tvp,p,w,v). All arguments are optional in which case the matrices might still be symbolic. If the matrices are not symbolic, they are returned as numpy arrays.- Parameters:
xss (
ndarray) – Steady state stateuss (
ndarray) – Steady state inputz (
ndarray) – Steady state algebraic statestvp (
ndarray) – time varying parameters set pointp (
ndarray) – parameters set point
- Returns:
Union[Tuple[SX,SX,SX,SX],Tuple[ndarray,ndarray,ndarray,ndarray]] – State matrix, Input matrix, Output matrix, Feedforward matrix
set_alg#
- set_alg(self, expr_name, expr)#
Introduce new algebraic equation to model.
For the continous time model, the expression must be formulated as
\[0 = g(x(t),u(t),z(t),p(t),p_{\text{tv}}(t))\]or for a
discretemodel:\[0 = g(x_k,u_k,z_k,p_k,p_{\text{tv},k})\]Note
For the introduced algebraic variables \(z \in \mathbb{R}^{n_z}\) it is required to introduce exactly \(n_z\) algebraic equations. Otherwise
setup()will throw an error message.- Parameters:
expr_name (
str) – Name of the introduced expressionexpr (
Union[SX,MX]) – CasADi SX or MX function depending on_x,_u,_z,_tvp,_p.
- Return type:
None
set_expression#
- set_expression(self, expr_name, expr)#
Introduce new expression to the model class. Expressions are not required but can be used to extract further information from the model. Expressions must be formulated with respect to
_x,_u,_z,_tvp,_p.Example:
Maybe you are interested in monitoring the product of two states?
Introduce two scalar states: x_1 = model.set_variable('_x', 'x_1') x_2 = model.set_variable('_x', 'x_2') # Introduce expression: model.set_expression('x1x2', x_1*x_2)
This new expression
x1x2is then available in all do-mpc modules utilizing this model instance. It can be set, e.g. as the cost function indo_mpc.controller.MPCor simply used in a graphical representation of the simulated / controlled system.- Parameters:
expr_name (
str) – Arbitrary name for the given expression. Names are used for key word indexing.expr (
Union[SX,MX]) – CasADi SX or MX function depending on_x,_u,_z,_tvp,_p.
- Raises:
assertion – expr_name must be str
assertion – expr must be a casadi SX or MX type
assertion – Cannot call after
setup().
- Returns:
Union[SX,MX] – Returns the newly created expression. Expression can be used e.g. for the RHS.
set_meas#
- set_meas(self, meas_name, expr, meas_noise=True)#
Introduce new measurable output to the model class.
\[y = h(x(t),u(t),z(t),p(t),p_{\text{tv}}(t)) + v(t)\]or in case of discrete dynamics:
\[y_k = h(x_k,u_k,z_k,p_k,p_{\text{tv},k}) + v_k\]By default, the model assumes state-feedback (all states are measured outputs). Expressions must be formulated with respect to
_x,_u,_z,_tvp,_p.Be default, it is assumed that the measurements experience additive noise \(v_k\). This can be deactivated for individual measured variables by changing the boolean variable
meas_noisetoFalse. Note that measurement noise is only meaningful for state-estimation and will not affect the controller. Furthermore, it can be set with eachdo_mpc.simulator.Simulatorcall to obtain imperfect outputs.Note
For moving horizon estimation it is suggested to declare all inputs (
_u) and e.g. a subset of states (_x) as measurable output. Some other MHE formulations treat inputs separately.Note
It is often suggested to deactivate measurement noise for “measured” inputs (
_u). These can typically seen as certain variables.Example:
# Introduce states: x_meas = model.set_variable('_x', 'x', 3) # 3 measured states (vector) x_est = model.set_variable('_x', 'x', 3) # 3 estimated states (vector) # and inputs: u = model.set_variable('_u', 'u', 2) # 2 inputs (vector) # define measurements: model.set_meas('x_meas', x_meas) model.set_meas('u', u)
- Parameters:
meas_name (
str) – Arbitrary name for the given expression. Names are used for key word indexing.expr (
Union[SX,MX]) – CasADi SX or MX function depending on_x,_u,_z,_tvp,_p.meas_noise (
bool) – Set if the measurement equation is disturbed by additive noise.
- Raises:
assertion – expr_name must be str
assertion – expr must be a casadi SX or MX type
assertion – Cannot call after
setup().
- Returns:
Union[SX,MX] – Returns the newly created measurement expression.
set_rhs#
- set_rhs(self, var_name, expr, process_noise=False)#
Formulate the right hand side (rhs) of the ODE:
\[\dot{x}(t) = f(x(t),u(t),z(t),p(t),p_{\text{tv}}(t)) + w(t),\]or the update equation in case of discrete dynamics:
\[x_{k+1} = f(x_k,u_k,z_k,p_k,p_{\text{tv},k}) + w_k,\]Each defined state variable must have a respective equation (of matching dimension) for the rhs. Match the rhs with the state by choosing the corresponding names. rhs must be formulated with respect to
_x,_u,_z,_tvp,_p.Example:
tank_level = model.set_variable('states', 'tank_level') tank_temp = model.set_variable('states', 'tank_temp') tank_level_next = 0.5*tank_level tank_temp_next = ... model.set_rhs('tank_level', tank_level_next) model.set_rhs('tank_temp', tank_temp_next)
Optionally, set
process_noise = Trueto introduce an additive process noise variable. This is meaningful for thedo_mpc.estimator.MHE(Seedo_mpc.estimator.MHE.set_default_objective()for more details). Furthermore, it can be set with eachdo_mpc.simulator.Simulatorcall to obtain imperfect (realistic) simulation results.- Parameters:
var_name (
str) – Reference to previously introduced state names (withModel.set_variable())expr (
Union[SX,MX]) – CasADi SX or MX function depending on_x,_u,_z,_tvp,_p.process_noise (
bool) – Make the respective state variable non-deterministic.
- Raises:
assertion – var_name must be str
assertion – expr must be a casadi SX or MX type
assertion – var_name must refer to the previously defined states
assertion – Cannot call after :py:func`setup`.
- Return type:
None
set_variable#
- set_variable(self, var_type, var_name, shape=(1, 1), input_type_integer=False)#
Introduce new variables to the model class. Define variable type, name and shape (optional).
Example:
# States struct (optimization variables): C_a = model.set_variable(var_type='_x', var_name='C_a', shape=(1,1)) T_K = model.set_variable(var_type='_x', var_name='T_K', shape=(1,1)) # Input struct (optimization variables): Q_dot = model.set_variable(var_type='_u', var_name='Q_dot') # Fixed parameters: alpha = model.set_variable(var_type='_p', var_name='alpha')
Note
var_typeallows a shorthand notation e.g._xwhich is equivalent tostates.input_type_integercan be set to True for inputs that are treated as integer decision variables.- Parameters:
var_type (
str) – Declare the type of the variable.var_name (
str) – Set a user-defined name for the parameter. The names are reused throughout do_mpc.shape (
Union[int,Tuple]) – Shape of the current variable (optional), defaults to1.input_type_integer (
bool) – define an integer input variable, defaults toFalse.
The following types of var_type are valid (long or short name is possible):
Long name
short name
Remark
states_xRequired
inputs_uOptional
algebraic_zOptional
parameter_pOptional
timevarying_parameter_tvpOptional
- Raises:
assertion – var_type must be string
assertion – var_name must be string
assertion – shape must be tuple or int
assertion – input_type_integer must be boolean
assertion – Cannot call after
setup().
- Returns:
Union[SX,MX] – Returns the newly created symbolic variable.
setup#
- setup(self)#
Setup method must be called to finalize the modelling process. All required model variables must be declared. The right hand side expression for
_xmust have been set withset_rhs().Sets default measurement function (state feedback) if
set_meas()was not called.Warning
After calling
setup(), the model is locked and no further variables, expressions etc. can be set.- Raises:
assertion – Definition of right hand side (rhs) is incomplete
- Return type:
None
Attributes#
aux#
- Model.aux#
Auxiliary expressions. CasADi symbolic structure, can be indexed with user-defined variable names.
Note
Expressions are introduced with
Model.set_expression()Use this property only to query variables.Example:
model = do_mpc.model.Model('continuous') model.set_variable('_x','temperature', 4) # 4 states dt = model.x['temperature',0]- model.x['temperature', 1] model.set_expression('dtemp', dt) # Query: model.aux['dtemp', 0] # 0th element of variable model.aux['dtemp'] # all elements of variable
Useful CasADi symbolic structure methods:
.shape.keys().labels()
- Raises:
assertion – Cannot set aux directly Use set_expression instead.
p#
- Model.p#
Static parameters. CasADi symbolic structure, can be indexed with user-defined variable names.
Note
Variables are introduced with
Model.set_variable()Use this property only to query variables.Example:
model = do_mpc.model.Model('continuous') model.set_variable('_p','temperature', shape=(4,1)) # Query: model.p['temperature', 0] # 0th element of variable model.p['temperature'] # all elements of variable model.p['temperature', 0:2] # 0th and 1st element
Useful CasADi symbolic structure methods:
.shape.keys().labels()
- Raises:
assertion – Cannot set model variables directly Use set_variable instead.
tvp#
- Model.tvp#
Time-varying parameters. CasADi symbolic structure, can be indexed with user-defined variable names.
Note
Variables are introduced with
Model.set_variable()Use this property only to query variables.Example:
model = do_mpc.model.Model('continuous') model.set_variable('_tvp','temperature', shape=(4,1)) # Query: model.tvp['temperature', 0] # 0th element of variable model.tvp['temperature'] # all elements of variable model.tvp['temperature', 0:2] # 0th and 1st element
Useful CasADi symbolic structure methods:
.shape.keys().labels()
- Raises:
assertion – Cannot set model variables directly Use set_variable instead.
u#
- Model.u#
Inputs. CasADi symbolic structure, can be indexed with user-defined variable names.
Note
Variables are introduced with
Model.set_variable()Use this property only to query variables.Example:
model = do_mpc.model.Model('continuous') model.set_variable('_u','heating', shape=(4,1)) # Query: model.u['heating', 0] # 0th element of variable model.u['heating'] # all elements of variable model.u['heating', 0:2] # 0th and 1st element
Useful CasADi symbolic structure methods:
.shape.keys().labels()
- Raises:
assertion – Cannot set model variables directly Use set_variable instead.
v#
- Model.v#
Measurement noise. CasADi symbolic structure, can be indexed with user-defined variable names.
The measurement noise structure is created automatically, whenever the
Model.set_meas()method is called with the argumentmeas_noise = True.Note
The measurement noise is used for the
do_mpc.estimator.MHEand can be used to simulate a disturbed system in thedo_mpc.simulator.Simulator.Useful CasADi symbolic structure methods:
.shape.keys().labels()
- Raises:
assertion – Cannot set v directly
w#
- Model.w#
Process noise. CasADi symbolic structure, can be indexed with user-defined variable names.
The process noise structure is created automatically, whenever the
Model.set_rhs()method is called with the argumentprocess_noise = True.Note
The process noise is used for the
do_mpc.estimator.MHEand can be used to simulate a disturbed system in thedo_mpc.simulator.Simulator.Useful CasADi symbolic structure methods:
.shape.keys().labels()
- Raises:
assertion – Cannot set w directly
x#
- Model.x#
Dynamic states. CasADi symbolic structure, can be indexed with user-defined variable names.
Note
Variables are introduced with
Model.set_variable()Use this property only to query variables.Example:
model = do_mpc.model.Model('continuous') model.set_variable('_x','temperature', shape=(4,1)) # Query: model.x['temperature', 0] # 0th element of variable model.x['temperature'] # all elements of variable model.x['temperature', 0:2] # 0th and 1st element
Useful CasADi symbolic structure methods:
.shape.keys().labels()
- Raises:
assertion – Cannot set model variables directly Use set_variable instead.
y#
- Model.y#
Measurements. CasADi symbolic structure, can be indexed with user-defined variable names.
Note
Measured variables are introduced with
Model.set_meas()Use this property only to query variables.Example:
model = do_mpc.model.Model('continuous') model.set_variable('_x','temperature', 4) # 4 states model.set_meas('temperature', model.x['temperature',:2]) # first 2 measured # Query: model.y['temperature', 0] # 0th element of variable model.y['temperature'] # all elements of variable
Useful CasADi symbolic structure methods:
.shape.keys().labels()
- Raises:
assertion – Cannot set model variables directly Use set_meas instead.
z#
- Model.z#
Algebraic states. CasADi symbolic structure, can be indexed with user-defined variable names.
Note
Variables are introduced with
Model.set_variable()Use this property only to query variables.Example:
model = do_mpc.model.Model('continuous') model.set_variable('_z','temperature', shape=(4,1)) # Query: model.z['temperature', 0] # 0th element of variable model.z['temperature'] # all elements of variable model.z['temperature', 0:2] # 0th and 1st element
Useful CasADi symbolic structure methods:
.shape.keys().labels()
- Raises:
assertion – Cannot set model variables directly Use set_variable instead.