Skip to content
Jens Engel edited this page Feb 18, 2021 · 5 revisions

Models

A model is a symbolic representation of the state trajectory over the horizon, together with a symbolic representation of the input u and the disturbances d. A model is defined by a set of ordinary difference equations for the states that yield $x_s(n+1|k) = f_n(x_s(n|k), u(n|k), d_s(n|k))$, to build the symbolic expressions for the state trajectory in multiple scenarios. Since PARODIS defines a prediction horizon by the time steps within the horizon, each time step has it's own associated ODE $f_n(\cdot)$.

Hence, in PARODIS, a model is described by a function, that returns these ODEs in terms of a given sample time along with the number of states, inputs and disturbances

[ode, n_x, n_u, n_d] = my_model_fun(T_s)

The ODE that is returned must be a function handle, which takes three inputs

  1. The state $x(k)$
  2. The input $u(k)$
  3. The disturbance $d(k)$

and returns the resulting state $x(k+1)$:

x_kp = @(x_k, u_k, d_k)( .. )

The following code shows an examplary nonlinear model:

function [ode, n_x, n_u, n_d] = my_model_fun(T_s)
    ode = @(x, u, d)( [ x(1)^2 + u(1) + sin(d(1)); ...
                        x(2) + u(2) + cos(d(2)) ] );
    n_x = 2;
    n_u = 2;
    n_d = 2;
end

Parameter-Variant Systems

PARODIS also supports parameter-variant (nonlinear) models. For a parameter-variant system, the ODEs can take a fourth and fifth argument, namely the time step within the horizon n and the struct of available parameters params

x_kp = @(x_k, u_k, d_k, n, params)( .. )
function [ode, n_x, n_u, n_d] = my_model_fun(T_s)
    ode = @(x, u, d, n, params)( ...
            [ params.friction(n) * x(1)^2 + u(1) + sin(d(1));   ...
              x(2) + u(2) + cos(d(2)) ]                         ...
          );
    n_x = 2;
    n_u = 2;
    n_d = 2;
end

Fast Linear Representation

These ODEs are used for building constraints, as well as calculating the predicted state trajectory over a given prediction horizon. For larger, linear systems this representation is rather inefficient, as the calculation of the predicted trajectory can be contracted into equivalent matrix-vector multiplications. Also, in some special cases, it may be possible to express the entire state trajectory efficiently, instead of splitting it into single ODEs. Therefore, PARODIS supports two special cases: Linear systems of the form $x(n+1|k) = A_n x(n|k) + B_n u(n|k) + S_n d(n|k)$ can provide their matrices $A_n$, $B_n$, $S_n$ and return them as a fourth output argument:

function [ode, n_x, n_u, n_d, linearRepresentation] = test_model(T_s)
    A = diag([ 0.1   0.05   1.01 ]);
    B = [1 0; 0 1; 1 1];
    S = diag([2 2 2]);

    % always required!
    ode = @(x, u, d)( A*x + B*u + S*d );
    n_x = 3;
    n_u = 2;
    n_d = 3;

    % additional linear representation
    linearRepresentation = struct;
    linearRepresentation.A = A;
    linearRepresentation.B = B;
    linearRepresentation.S = S;
end

PARODIS will use these matrices to built a fast linear representation (FLR) of the system dynamics which is then used whenever the state trajectory over the horizon is calculated.

Parameter-variant

If the linear system is parameter variant, the matrices $A$, $B$ or $S$ shall be function handles which take 2 input arguments, the time step within the horizon n and the struct of available parameters params

function [ode, n_x, n_u, n_d, linearRepresentation] = test_model(T_s)

    % parameter-variant system description
    A = @(n, params)( diag([ params.friction(n) 0.05 1.01 ]) );
    B = [1 0; 0 1; 1 1];
    S = diag([2 2 2]);

    % always required!
    ode = @(x, u, d, n, params)( A(n, params)*x + B*u + S*d );
    n_x = 3;
    n_u = 2;
    n_d = 3;

    % additional linear representation
    linearRepresentation = struct;
    linearRepresentation.A = A;
    linearRepresentation.B = B;
    linearRepresentation.S = S;
end

Fast representation for nonlinear (parameter-variant) systems

In some cases, it may be possible to calculate the state trajectory over the prediction horizon compactly and efficiently, similar to the fast linear representation. PARODIS therefore supports returning a function(handle)

x_flat = @(x0, u_flat, d_flat, params)( .. )

that returns a $n_x \cdot (N_{pred}+1) \times 1$ vector, containing the state trajectory predicted over the horizon, given the initial state x0 and $n_u \cdot N_{pred} \times 1$ input vector and $n_d \cdot N_{pred} \times 1$ disturbance vector. This function is returned as a fifth argument of the model function.

Since in general knowledge of all sample times within the horizon is necessary, the model function must take a second input argument, $T_s_all$ which is a vector containing all sample times in the horizon.

function [ode, n_x, n_u, n_d, x_flat] = my_model_fun(T_s, T_s_all)
    % always required, ODE for given sample time
    ode = @(x, u, d)( some ODE );

    n_x = 2;
    n_u = 2;
    n_d = 2;

    % compact system representation
    x_flat = @(x0, u_flat, d_flat, params)( some compact represenation );
end

Using a Model

After having defined a model function, models can be used/created using the createModel function. This will generate a struct containing a symbolic model representation and information about the ODEs and the model, see internal model representation.

model = createModel( @my_model_fun, T_s, numScenarios, implicitPrediction );

If the argument implicitPrediction is set to false, the state trajectory $x_s(n|k)$ will be expressed directly in terms of $x_s(n+1|k) = f_n(x_s(n|k), u(n|k), d_s(n|k))$, so it will be a symbolic expression of $u(n|k)$ and $d_s(n|k)$. If it is set to true, the prediction will be expressed implicitly, meaning that the prediction dynamics will be represented by equality constraints $x_s(n+1|k) == f_n(x_s(n|k), u(n|k), d_s(n|k))$. Depending on your model, it may make sense to use the implicit prediction form, as it can help with problem conditioning.

Parameter-variant models

Note: If you are using a parameter-variant model description, you must call createModel only after you have defined your controller and parameters and provide a 5th input argument to createModel, namely the controller instance you are using:

controller = SymbolicController( numScenarios ); % or ExplicitController, ParetoController
controller.addParam( ... );
...
model = createModel( @my_model_fun, T_s, numScenarios, implicitPrediction, controller );

This is necessary, because the controller manages the symbolic variables for the parameters, on which the symbolic model description depends in a parameter-variant system.

Internal Model Representation

Internally, in PARODIS a model is stored in a struct of the following structure:

Field Description
x0 Symbolic expression for the initial state, sdpvar of size $n_x \times 1$
x Cell array of length numScenarios, where each cell contains a $n_x \times N_{pred}+1$ sdpvar that describes the symbolic state trajectory in terms of model.x0, model.u and model.dPred
u Symbolic expression representing the predict input, sdpvar of size $n_u \times N_{pred}$
d Cell array of length numScenarios, where each cell contains a $n_d \times N_{pred}$ sdpvar representing the predicted disturbance in each scenari
n_x Number of states $n_x$
n_u Number of inputs $n_u$
n_d Number of disturbances $n_d$
ode0 The ODE for performing $x(k+1) = f_0( x(k), u(k), d(k) )$
odes Cell array, containing the ODEs for each time step in the horizon
model_fun The function handle of the model function used to create the model
implicitPrediction If false, x is expressed in terms of u and d. Otherwise they will be connected using equality constraints $x(n+1|k) == f_n( x(n|k), u(n|k), d(n|k) )$
flrMatrices Matrices for fast linear representation, set only if FLR is supported but matrices are parameter variant
x_flat Function @(x0, u_flat, d_flat, n, params)( .. ) that returns entire (flattend) state trajectory over prediction horizon based on x0, the input vector and disturbance vector, set if either your model returns it's own x_flat or if FLR is time invariant