Model#

class Model(model_type=None, symvar_type='SX')[source]#

Bases: object

The do-mpc model class. This class holds the full model description and is at the core of do_mpc.simulator.Simulator, do_mpc.controller.MPC and do_mpc.estimator.Estimator. The Model class is created with setting the model_type (continuous or discrete). A continous model 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 discrete model 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 SX or MX variable type. We refer to the CasADi documentation on the difference of these two types.

Note

SX vs. MX in a nutshell: In general use SX variables (default). If your model consists of scalar operations SX variables will be beneficial. Your implementation will most likely only benefit from MX variables if you use large(r)-scale matrix-vector multiplications.

Note

The option symvar_type will be inherited to all derived classes (e.g. do_mpc.simulator.Simulator, do_mpc.controller.MPC and do_mpc.estimator.Estimator). All symbolic variables in these classes will be chosen respectively.

Configuration and setup:

Configuring and setting up the Model involves the following steps:

  1. Use set_variable() to introduce new variables to the model.

  2. 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.

  3. Optionally introduce measurement equations with set_meas(). The syntax is identical to set_expression(). By default state-feedback is assumed.

  4. 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.

  5. Call setup() to finalize the Model. 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 is discrete or continuous.

  • symvar_type (str) – Set if the model is configured with CasADi SX or MX variables.

Raises:
  • assertion – model_type must be string

  • assertion – model_type must be either discrete or continuous

__getitem__(ind)[source]#

The Model class 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 state

  • uss (ndarray) – Steady state input

  • z (ndarray) – Steady state algebraic states

  • tvp (ndarray) – time varying parameters set point

  • p (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 discrete model:

\[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 expression

  • expr (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 x1x2 is then available in all do-mpc modules utilizing this model instance. It can be set, e.g. as the cost function in do_mpc.controller.MPC or 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_noise to False. Note that measurement noise is only meaningful for state-estimation and will not affect the controller. Furthermore, it can be set with each do_mpc.simulator.Simulator call 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 = True to introduce an additive process noise variable. This is meaningful for the do_mpc.estimator.MHE (See do_mpc.estimator.MHE.set_default_objective() for more details). Furthermore, it can be set with each do_mpc.simulator.Simulator call to obtain imperfect (realistic) simulation results.

Parameters:
  • var_name (str) – Reference to previously introduced state names (with Model.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))#

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_type allows a shorthand notation e.g. _x which is equivalent to states.

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 to 1.

The following types of var_type are valid (long or short name is possible):

Long name

short name

Remark

states

_x

Required

inputs

_u

optional

algebraic

_z

Optional

parameter

_p

Optional

timevarying_parameter

_tvp

Optional

Raises:
  • assertionvar_type must be string

  • assertionvar_name must be string

  • assertionshape must be tuple or int

  • 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 _x must have been set with set_rhs().

Sets default measurement function (state feedback) if set_meas() was not called. :rtype: None

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

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 argument meas_noise = True.

Note

The measurement noise is used for the do_mpc.estimator.MHE and can be used to simulate a disturbed system in the do_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 argument process_noise = True.

Note

The process noise is used for the do_mpc.estimator.MHE and can be used to simulate a disturbed system in the do_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.