8.1.1. Basic Example

Consider the following linear MPC problem with lower and upper bounds on state and inputs, and a terminal cost term:

\begin{align*} \text{minimize} \quad & x_N^\top P x_N + \sum_{i=0}^{N-1} x_i^\top Q x_i + u_i^\top R u_i \\ \text{subject to} \quad & x_0 = {\color{red} x} \\ & x_{i+1} = A x_i + B u_i \\ & \underline{x} \leq x_i \leq \bar{x} \\ & \underline{u} \leq u_i \leq \bar{u} \end{align*}

This problem is parametric in the initial state \(\color{red} x\) and the first input \(u_0\) is typically applied to the system after a solution has been obtained. The following code generates a function that takes \(-Ax\) as a calling argument and returns \(u_0\), which can then be applied to the system.

Here is the Matlab code:

%% FORCES multistage form
% assume variable ordering zi = [ui, xi+1] for i=1...N-1

stages = MultistageProblem(N); % get stages struct of length N

for i = 1:N

        % dimension
        stages(i).dims.n = nx+nu; % number of stage variables
        stages(i).dims.r = nx;    % number of equality constraints
        stages(i).dims.l = nx+nu; % number of lower bounds
        stages(i).dims.u = nx+nu; % number of upper bounds

        % cost
        if( i == N )
                stages(i).cost.H = blkdiag(R,P); % terminal cost (Hessian)
        else
                stages(i).cost.H = blkdiag(R,Q);
        end
        stages(i).cost.f = zeros(nx+nu,1); % linear cost terms

        % lower bounds
        stages(i).ineq.b.lbidx = 1:(nu+nx); % lower bound acts on these indices
        stages(i).ineq.b.lb = [umin; xmin]; % lower bound for this stage variable

        % upper bounds
        stages(i).ineq.b.ubidx = 1:(nu+nx); % upper bound acts on these indices
        stages(i).ineq.b.ub = [umax; xmax]; % upper bound for this stage variable

        % equality constraints
        if( i < N )
                 stages(i).eq.C = [zeros(nx,nu), A];
        end
        if( i>1 )
                 stages(i).eq.c = zeros(nx,1);
        end
        stages(i).eq.D = [B, -eye(nx)];
end

% RHS of first eq. constr. is a parameter: stages(1).eq.c = -A*x0
params(1) = newParam('minusA_times_x0',1,'eq.c');

You can download the Matlab code of this example to try it out for yourself by clicking here.

And here’s the Python code:

# FORCES multistage form
# assume variable ordering zi = [ui, xi+1] for i=1...N-1

stages = MultistageProblem(N) # get stages struct of length N

for i in range(N):

         # dimension
        stages.dims[ i ]['n'] = nx+nu # number of stage variables
        stages.dims[ i ]['r'] = nx    # number of equality constraints
        stages.dims[ i ]['l'] = nx+nu # number of lower bounds
        stages.dims[ i ]['u'] = nx+nu # number of upper bounds

        # cost
        if ( i == N-1 ):
                stages.cost[ i ]['H'] = np.vstack((np.hstack((R,np.zeros((nu,nx)))),np.hstack((np.zeros((nx,nu)),P))))
        else:
                stages.cost[ i ]['H'] = np.vstack((np.hstack((R,np.zeros((nu,nx)))),np.hstack((np.zeros((nx,nu)),Q))))
        stages.cost[ i ]['f'] = np.zeros((nx+nu,1)) # linear cost terms

        # lower bounds
        stages.ineq[ i ]['b']['lbidx'] = range(1,nu+nx+1) # lower bound acts on these indices
        stages.ineq[ i ]['b']['lb'] = np.concatenate((umin,xmin),0) # lower bound for this stage variable

        # upper bounds
        stages.ineq[ i ]['b']['ubidx'] = range(1,nu+nx+1)  # upper bound acts on these indices
        stages.ineq[ i ]['b']['ub'] = np.concatenate((umax,xmax),0) # upper bound for this stage variable

        # equality constraints
        if ( i < N-1 ):
                 stages.eq[i]['C'] = np.hstack((np.zeros((nx,nu)),A))
        if ( i>0 ):
                 stages.eq[i]['c'] = np.zeros((nx,1))
        stages.eq[i]['D'] = np.hstack((B,-np.eye(nx)))


# RHS of first eq. constr. is a parameter: stages(1).eq.c = -A*x0
stages.newParam('minusA_times_x0', [1], 'eq.c')
# define output of the solver
stages.newOutput('u0', 1, range(1,nu+1))

You can download the Python code of this example to try it out for yourself by clicking here.