Objective function

The basic objective for computing a control action in the MPC controller is of the form

\[\sum_{k=0}^{N-1} {\left((Cx_{k}-r)^T Q (C x_{k}-r) + u_{k}^T R u_{k} + \Delta u_{k}^T R_r \Delta u_k\right)},\]

where $N$ is the prediction horizon of the controller.

For an MPC controller mpc, the weighting matrices $Q$, $R$, and $R_r$ that defines the objective can be set with

set_objective!(mpc;Q,R,Rr)
mpc.set_objective(Q=Q, R=R, Rr=Rr)

If a vector value of $Q$,$R$, or $R_r$ are inputted to set_objective, it will be interpreted as a diagonal matrix with the vector on diagonal. Similarly, if a scalar is inputted, it will be interpreted as a diagonal matrix with this value on the diagonal.

The default values are $Q=I$, $R=I$, and $R_r = 0$.

Reference tracking

The first term $(Cx_{k}-r)^T Q (C x_{k}-r)$ is for reference tracking, which means that it aims to make $Cx = r$, where the matrix $C$ is set by the user when initializing the model. Typically, the weighting matrix $Q$ is a diagonal matrix, where higher weights are selected for the rows of $C x$ that should be prioritized.

Control energy

The second term $u_k^T R u_k$ penalizes larger values of the control action. Typically, the weighting matrix $R$ is a diagonal matrix, where higher weights are selected for the control signals that are more "expensive".

Control change

The third term $\Delta u_k^T R \Delta u_k$ penalizes changes to the control action. Typically, the weighting matrix $R_r$ is a diagonal matrix, where higher weights are selected for the control signals that are more "expensive".

Terminal constraint

A term of the form $(Cx_N-r)^T Q_f (C x_N -r)^T$ can also be added to the objective. This adds an additional terminal cost, which can be useful to ensure stability[Mayne00]. The terminal weight $Q_f$ is set with set_objective!, and is by default the same as $Q$.

Cross term

It is also possible to include a cross term $x_k^T S u_k$ in the objective. This term can also be set with the set_objective! function. By default, $S=0$.

Reference Preview

By default, the reference tracking term uses a constant reference $r$ across the prediction horizon: $(Cx_{k}-r)^T Q (C x_{k}-r)$ for all $k$.

Reference preview allows time-varying references $r_k$ in the objective:

\[\sum_{k=0}^{N-1} (Cx_{k}-r_k)^T Q (C x_{k}-r_k)\]

Enable reference preview with:

mpc.settings.reference_preview = true
setup!(mpc)
mpc.settings({"reference_preview": True})
mpc.setup()

Then provide a reference trajectory matrix of size (ny, Np) to compute_control:

r_trajectory = [1.0 1.5 2.0 2.0 2.0;   # Reference for output 1
                0.0 0.0 0.5 1.0 1.0]   # Reference for output 2
u = compute_control(mpc, x; r=r_trajectory)
import numpy as np
r_trajectory = np.array([[1.0, 1.5, 2.0, 2.0, 2.0],   # Reference for output 1
                          [0.0, 0.0, 0.5, 1.0, 1.0]])  # Reference for output 2
u = mpc.compute_control(x, r=r_trajectory)

Generalized parameters in objective and constraints

LinearMPC also supports a stagewise generalized parameter trajectory $p_k$ entering the problem as

\[(Ex p_k + ex)^T x_k + (Eu p_k + eu)^T u_k\]

in the objective, and through additional constraint terms such as

\[\underline{b} \le A_x x_k + A_u u_k + A_p p_k \le \overline{b}.\]

The matrices Ex, Eu, and Ap are stagewise coefficients. By default, the generalized parameter p is constant across the horizon, so only np new parameters are added. If you want a time-varying generalized-parameter trajectory, enable parameter_preview and provide an (np, Np) matrix.

This replaces the older dedicated linear control-cost feature. Economic terms such as time-varying electricity prices can now be modeled directly with Eu, eu, and p.

set_objective!(mpc; Q=[1.0], R=[0.1], Ex=[0.5 0.0], ex=[0.1], Eu=[1.0 0.0], eu=[0.2])
add_constraint!(mpc; Au=[1.0;;], Ap=[0.5 1.0], ub=[1.0], ks=1:mpc.Np)

u = compute_control(mpc, x; p=[0.3, -0.1])

# Time-varying parameter preview
mpc.settings.parameter_preview = true
setup!(mpc)
p_preview = [0.3 0.2 0.1 0.1;
             -0.1 -0.1 0.0 0.1]
u = compute_control(mpc, x; p=p_preview)
mpc.set_objective(Q=[1.0], R=[0.1], Ex=[[0.5, 0.0]], ex=[0.1], Eu=[[1.0, 0.0]], eu=[0.2])
mpc.add_constraint(Au=[[1.0]], Ap=[[0.5, 1.0]], ub=[1.0], ks=range(1, mpc.Np + 1))

u = mpc.compute_control(x, p=[0.3, -0.1])

# Time-varying parameter preview
mpc.settings({"parameter_preview": True})
mpc.setup()
p_preview = np.array([[0.3, 0.2, 0.1, 0.1],
                      [-0.1, -0.1, 0.0, 0.1]])
u = mpc.compute_control(x, p=p_preview)
  • Mayne00Mayne, David Q., et al. "Constrained model predictive control: Stability and optimality." Automatica 36.6 (2000): 789-814.