Simulator#
- class Simulator(model)[source]#
Bases:
IteratedVariables
A class for simulating systems. Discrete-time and continuous systems can be considered.
New in version >v4.5.1: New interface to settings. The class has an attribute
settings
which is an instance ofSimulatorSettings
orContinousSimulatorSettings
(please see this documentation for a list of available settings). Settings are now chosen as:simulator.settings.t_step = 0.5
Previously, settings were passed to
set_param()
. This method is still available and wraps the new interface. The new method has important advantages:The
simulator.settings
attribute can be printed to see the current configuration.Context help is available in most IDEs (e.g. VS Code) to see the available settings, the type and a description.
do-mpc uses the CasADi interface to popular state-of-the-art tools such as Sundials CVODES for the integration of ODE/DAE equations.
Configuration and setup:
Configuring and setting up the simulator involves the following steps:
Configure the simulator with
SimulatorSettings
orContinousSimulatorSettings
. The simulator instance has the attributesettings
which is an instance ofSimulatorSettings
orContinousSimulatorSettings
.Set parameter function with
get_p_template()
andset_p_fun()
.Set time-varying parameter function with
get_tvp_template()
andset_tvp_fun()
.Setup simulator with
setup()
.
During runtime, call the simulator
make_step()
method with current input (u
). This computes the next state of the system and the respective measurement. Optionally, pass (sampled) random variables for the processw
and measurement noisev
(if they were defined in :py:class`do_mpc.model.Model`)- Parameters:
model (
Model
) – A configured and setupdo_mpc.model.Model
Methods#
get_p_template#
- get_p_template(self)#
Obtain output template for
set_p_fun()
. Use this method in conjunction withset_p_fun()
to define the function for retrieving the parameters at each sampling time.See
set_p_fun()
for more details.- Returns:
Union
[SXStruct
,MXStruct
] – numerical CasADi structure
get_tvp_template#
- get_tvp_template(self)#
Obtain the output template for
set_tvp_fun()
. Use this method in conjunction withset_tvp_fun()
to define the function for retrieving the time-varying parameters at each sampling time.- Returns:
Union
[SXStruct
,MXStruct
] – numerical CasADi structure
init_algebraic_variables#
- init_algebraic_variables(self)#
Initializes the algebraic variables. Solve the algebraic equations for the initial values of
x0
,u0
,p0
,tvp0
. Sets the results toz0
and returns them.Note
The method internally calls
set_initial_guess()
to set the initial guess for the algebraic variables.The initialization is computed by solving the algebraic model equations under consideration of the initial guess supplied in
z0
.Example:
simulator = do_mpc.simulator.Simulator(model) # Set initial value for the state: simulator.x0 = np.array([0.1, 0.1]).reshape(-1,1) # Obtain initial guess for the algebraic variables: z0 = simulator.init_algebraic_variables() # Initial guess is stored in simulator.z0 and simulator.set_initial_guess() was called internally.
- Returns:
ndarray
– Initial guess for the algebraic variables.
make_step#
- make_step(self, u0=None, v0=None, w0=None)#
Main method of the simulator class during control runtime. This method is called at each timestep and computes the next state or the current control input
u0
. The method returns the resulting measurement, as defined indo_mpc.model.Model.set_meas
.The initial state
x0
is stored as a class attribute. Use this attributex0
to change the initial state. It is also possible to supply an initial guess for the algebraic states through the attributez0
and by callingset_initial_guess()
.Finally, the method can be called with values for the process noise
w0
and the measurement noisev0
that were (optionally) defined in thedo_mpc.model.Model
. Typically, these values should be sampled from a random distribution, e.g.np.random.randn
for a random normal distribution.The method prepares the simulator by setting the current parameters, calls
simulator.simulate()
and updates thedo_mpc.data
object.- Parameters:
u0 (
ndarray
) – Current input to the system. Optional parameter for autonomous systems.v0 (
ndarray
) – Additive measurement noisew0 (
ndarray
) – Additive process noise
- Returns:
ndarray
– y_next
reset_history#
- reset_history(self)#
Reset the history of the simulator.
- Return type:
None
set_initial_guess#
- set_initial_guess(self)#
Initial guess for DAE variables. Use the current class attribute
z0
to create the initial guess for the DAE algebraic equations.The simulator uses “warmstarting” to solve the continous/discrete DAE system by using the previously computed algebraic states as an initial guess. Thus, this method is typically only invoked once. :rtype:
None
Warning
If no initial values for
z0
were supplied during setup, they default to zero.
set_p_fun#
- set_p_fun(self, p_fun)#
Method to set the function which gives the values of the parameters. This function must return a CasADi structure which can be obtained with
get_p_template()
.Example:
In the
do_mpc.model.Model
we have defined the following parameters:Theta_1 = model.set_variable('parameter', 'Theta_1') Theta_2 = model.set_variable('parameter', 'Theta_2') Theta_3 = model.set_variable('parameter', 'Theta_3')
To integrate the ODE or evaluate the discrete dynamics, the simulator needs to obtain the numerical values of these parameters at each timestep. In the most general case, these values can change, which is why a function must be supplied that can be evaluted at each timestep to obtain the current values.
do-mpc requires this function to have a specific return structure which we obtain first by calling:
p_template = simulator.get_p_template()
The parameter function can look something like this:
p_template['Theta_1'] = 2.25e-4 p_template['Theta_2'] = 2.25e-4 p_template['Theta_3'] = 2.25e-4 def p_fun(t_now): return p_template simulator.set_p_fun(p_fun)
which results in constant parameters.
A more “interesting” variant could be this random-walk:
p_template['Theta_1'] = 2.25e-4 p_template['Theta_2'] = 2.25e-4 p_template['Theta_3'] = 2.25e-4 def p_fun(t_now): p_template['Theta_1'] += 1e-6*np.random.randn() p_template['Theta_2'] += 1e-6*np.random.randn() p_template['Theta_3'] += 1e-6*np.random.randn() return p_template
- Parameters:
p_fun (
Callable
[[float
],Union
[SXStruct
,MXStruct
]]) – A function which gives the values of the parameters- Raises:
assert – p must have the right structure
- Return type:
None
set_param#
- set_param(self, **kwargs)#
Warning
This method will be depreciated in a future version. Settings are available via the
settings
attribute which is an instance ofContinousSimulatorSettings
orSimulatorSettings
.Note
A comprehensive list of all available parameters can be found in
ContinousSimulatorSettings
orSimulatorSettings
.For example:
simulator.settings.t_step = 0.5
The old interface, as shown in the example below, can still be accessed until further notice.
simulator.set_param(t_step=0.5)
Note
The only required parameters are
t_step
. All other parameters are optional.- Return type:
None
set_tvp_fun#
- set_tvp_fun(self, tvp_fun)#
Method to set the function which returns the values of the time-varying parameters. This function must return a CasADi structure which can be obtained with
get_tvp_template()
.In the
do_mpc.model.Model
we have defined the following parameters:a = model.set_variable('_tvp', 'a')
The integrate the ODE or evaluate the discrete dynamics, the simulator needs to obtain the numerical values of these parameters at each timestep. In the most general case, these values can change, which is why a function must be supplied that can be evaluted at each timestep to obtain the current values.
do-mpc requires this function to have a specific return structure which we obtain first by calling:
tvp_template = simulator.get_tvp_template()
The time-varying parameter function can look something like this:
def tvp_fun(t_now): tvp_template['a'] = 3 return tvp_template simulator.set_tvp_fun(tvp_fun)
which results in constant parameters.
Note
From the perspective of the simulator there is no difference between time-varying parameters and regular parameters. The difference is important only for the MPC controller and MHE estimator. These methods consider a finite sequence of future / past information, e.g. the weather, which can change over time. Parameters, on the other hand, are constant over the entire horizon.
- Parameters:
tvp_fun (
Callable
[[float
],Union
[SXStruct
,MXStruct
]]) – Function which gives the values of the time-varying parameters- Raises:
assertion – tvp_fun has incorrect return type.
assertion – Incorrect output of tvp_fun. Use get_tvp_template to obtain the required structure.
- Return type:
None
setup#
- setup(self)#
Sets up the simulator and finalizes the simulator configuration. Only after the setup, the
make_step()
method becomes available.- Raises:
assertion – t_step must be set
- Return type:
None
simulate#
- simulate(self)#
Call the CasADi simulator.
Warning
simulate()
can be used as part of the public API but is typically called from withinmake_step()
which wraps this method and sets the required values to thesim_x_num
andsim_p_num
structures automatically.Numerical values for
sim_x_num
andsim_p_num
need to be provided beforehand in order to simulate the system for one time step:states
sim_c_num['_x']
algebraic states
sim_z_num['_z']
inputs
sim_p_num['_u']
parameter
sim_p_num['_p']
time-varying parameters
sim_p_num['_tvp']
The function returns the new state of the system.
- Returns:
ndarray
– x_new
Attributes#
settings#
- Simulator.settings#
All necessary parameters for the simulator.
This is a core attribute of the Simulator class. It is used to set and change parameters when setting up the simulator by accessing an instance of
SimulatorSettings
orContinousSimulatorSettings
.Example to change settings:
simulator.settings.t_step = 0.5
Note
Settings cannot be updated after calling
do_mpc.simulator.setup()
.For a detailed list of all available parameters see
SimulatorSettings
orContinousSimulatorSettings
.
t0#
- Simulator.t0#
Current time marker of the class. Use this property to set of query the time.
Set with
int
,float
,numpy.ndarray
orcasadi.DM
type.
u0#
- Simulator.u0#
Initial input and current iterate. This is the numerical structure holding the information about the current input in the class. The property can be indexed according to the model definition.
Example:
model = do_mpc.model.Model('continuous') model.set_variable('_u','heating', shape=(4,1)) ... mhe = do_mpc.estimator.MHE(model) # or mpc = do_mpc.estimator.MPC(model) # Get or set current value of variable: mpc.u0['heating', 0] # 0th element of variable mpc.u0['heating'] # all elements of variable mpc.u0['heating', 0:2] # 0th and 1st element
Useful CasADi symbolic structure methods:
.shape
.keys()
.labels()
x0#
- Simulator.x0#
Initial state and current iterate. This is the numerical structure holding the information about the current states in the class. The property can be indexed according to the model definition.
Example:
model = do_mpc.model.Model('continuous') model.set_variable('_x','temperature', shape=(4,1)) ... mhe = do_mpc.estimator.MHE(model) # or mpc = do_mpc.estimator.MPC(model) # Get or set current value of variable: mpc.x0['temperature', 0] # 0th element of variable mpc.x0['temperature'] # all elements of variable mpc.x0['temperature', 0:2] # 0th and 1st element
Useful CasADi symbolic structure methods:
.shape
.keys()
.labels()
z0#
- Simulator.z0#
Initial algebraic state and current iterate. This is the numerical structure holding the information about the current algebraic states in the class. The property can be indexed according to the model definition.
Example:
model = do_mpc.model.Model('continuous') model.set_variable('_z','temperature', shape=(4,1)) ... mhe = do_mpc.estimator.MHE(model) # or mpc = do_mpc.estimator.MPC(model) # Get or set current value of variable: mpc.z0['temperature', 0] # 0th element of variable mpc.z0['temperature'] # all elements of variable mpc.z0['temperature', 0:2] # 0th and 1st element
Useful CasADi symbolic structure methods:
.shape
.keys()
.labels()