MPT 2.5 Changelog


Hybrid Identification Toolbox included (pre release 0.95)


The Hybrid Identification Toolbox (HIT) by Giancarlo Ferrari-Trecate can solve two types of problems: The Hybrid Identification Toolbox can be found in the mpt/hit directory of your MPT installation.

Required software: MATLAB 6.5 (or higher).

Ellipsoidal Toolbox included

The Ellipsoidal Toolbox by Alex Kurzhanskiy is a standalone set of easy-to-use configurable MATLAB routines to perform operations with ellipsoids and hyperplanes of arbitrary dimensions. It computes the external and internal ellipsoidal approximations of geometric (Minkowski) sums and differences of ellipsoids, intersections of ellipsoids and intersections of ellipsoids with halfspaces and polytopes; distances between ellipsoids, between ellipsoids and hyperplanes, between ellipsoids and polytopes; and projections onto given subspaces.

Ellipsoidal methods are used to compute forward and backward reach sets of continuous- and discrete-time piecewise affine systems. Forward and backward reach sets can be also computed for continuous-time piece-wise linear systems with disturbances. It can be verified if computed reach sets intersect with given ellipsoids, hyperplanes, or polytopes.

The toolbox provides efficient plotting routines for ellipsoids, hyperplanes and reach sets.

You will find the Ellipsoidal Toolbox in the mpt/ellipsoids directory of your MPT installation. To start, have a look at ell_demo1, ell_demo2 and ell_demo3 demos.

Required software: MATLAB 6.5 (or higher).

Latest release of YALMIP included

YALMIP by Johan Löfberg is a MATLAB toolbox for rapid prototyping of optimization problems. The package initially focused on semi-definite programming, but the latest release extends this scope significantly. YALMIP can now be used for: The latest relase of YALMIP has improved integration between YALMIP and MPT. YALMIP adds a layer above the algorithms in MPT, allowing you to, e.g., symbolically define and solve multi-parametric linear programs with binary variables, and easily construct dynamic programming based algorithms. Additionally, YALMIP adds support for working with piecewise affine functions in a symbolic fashion. Read more about this in the YALMIP manual (type open('yalmip.htm') in MATLAB.)

YALMIP can be found in the mpt/yalmip directory of your installation. You can learn more about YALMIP by looking on its demos; just run yalmipdemo and enjoy.

Optimal control of PWA systems with quadratic stage cost

MPT 2.5 introduces support for quadratic cost function in optimal control of PWA systems which means that the probStruct.subopt_lev=0, probStruct.norm=2 combination is now allowed. The computation is based on mpMIQPs and supports systems with boolean/integer inputs, multiple target sets, time varying penalties, etc. Example:
>> two_tanks     % 2D PWA system with one continuous and one boolean input
>> probStruct.N = 2;     % prediction horizon
>> probStruct.norm = 2;  % use quadratic performance index
>> ctrl = mpt_control(sysStruct, probStruct);
The optimal control problems are formulated using YALMIP and are then solved as multi-parametric mixed-integer quadratic programs. Currently it is not possible to export such controllers into C-code, but you can still use them in Simulink simulations.

mpMILP and mpMIQP solvers

Mixed-Integer LP/QP problems can now be solved in the multi-parametric fashion in MPT 2.5 by mpt_mpmilp and mpt_mpmiqp, respectively. The functions take the same Matrices arguments as mpt_mplp/mpt_mpqp do, with two additional fields: The solution of an mpMILP is a non-overlapping partition, whereas overlapping regions are returned for mpMIQPs.

Example:
>> Double_Integrator
>> probStruct.N = 2;
>> probStruct.norm = 2;   % leads to an mpMIQP
>> Matrices = mpt_constructMatrices(sysStruct, probStruct);

% 1st input can only take values -1, 0, or 1
>> Matrices.vartype(1) = 'A';
>> Matrices.alphabet{1} = [-1 0 1];

% 2nd input should be boolean (0/1)
>> Matrices.vartype(2) = 'B';

% solve the mpMIQP
>> solution = mpt_mpmiqp(Matrices);
>> plot(solution.Pn)
All praise for these two functions goes to Johan Löfberg and his YALMIP.

Evaluate controllers as functions

In order to obtain a control input for a given value of the state vector, it is now possible to evalute the controller object as a function, i.e.:
>> u = ctrl(x0)
will do the same thing as calling
>> u = mpt_getInput(ctrl, x0)
This approach works for explicit as well as for on-line MPC controllers. You can also pass additional options if you want to:
>> u = ctrl(x0, Options)

Improved simulation functions

MPT 2.5 introduces two new functions for simulation of explicit and on-line controllers. The first one is the sim() function which replaces mpt_computeTrajectory:
>> Double_Integrator
>> ctrl = mpt_control(sysStruct, probStruct);
>> x0 = [2; 0];                      % initial state
>> [X, U, Y] = sim(ctrl, x0);
>> X

X =

    2.0000         0
    1.0000   -0.5000
    0.4502   -0.5249
    0.1847   -0.3952
    0.0650   -0.2575
    0.0157   -0.1533
   -0.0016   -0.0854
   -0.0059   -0.0448
   -0.0055   -0.0222
   -0.0040   -0.0103
   -0.0025   -0.0044
   -0.0015   -0.0017
   -0.0008   -0.0005
To compute the evolution of a given dynamical system subject to a given control policy, sim(), by default, uses the system structure which is stored in the controller object (ctrl.sysStruct). It is, however, possible to specify a different dynamical system when simulating the closed-loop. In this example we use a different system structure when computing the evolution of the states in the closed-loop:
>> sysStruct.A = 0.9*sysStruct.A;   % modify the system dynamics
>> X = sim(ctrl, sysStruct, x0)
It is also possible to specify arbitrary dynamical systems in the sim function. To use this feature, first create your own function which takes x(k) and u(k) as inputs and generates x(k+1) and y(k) as outputs:
function [xnext, yk] = di_sim_fun(xk, uk)

A = [1 1; 0 1]; B = [1; 0.5]; C = [1 0];
xnext = A*xk + B*uk;
yk = C*xk;
Once such function exists, you can use it as a function handle when calling sim:
>> X = sim(ctrl, @di_sim_fun, x0)
The nice property of this feature is that you can easily simulate a given controller in connection with a non-linear plant which is specified in discrete-time domain. For more information, see help mptctrl/sim.
The simplot function replaces mpt_plotTrajectory and mpt_plotTimeTrajectory and can thus be used to visualize closed-loop trajectories. If the initial state x0 is not specified and the controller is in 2D, the function will allow you to specify the initial state by mouse, e.g.
>> Double_Integrator
>> ctrl = mpt_control(sysStruct, probStruct);
>> simplot(ctrl)
If x0 is specified, simplot will plot the evolution of states, inputs and outputs versus time, e.g.
>> Double_Integrator
>> ctrl = mpt_control(sysStruct, probStruct);
>> x0 = [2; 0];
>> simplot(ctrl, x0)
Again, it is possible to specify a different system dynamics by either providing your own sysStruct or giving a handle of a function which should be used to compute the state update:
>> Double_Integrator
>> ctrl = mpt_control(sysStruct, probStruct);
>> x0 = [2; 0];
>> simplot(ctrl, @di_sim_fun, x0)
For more information about this function, see help mptctrl/simplot.

Support for lower-dimensional noise polytopes

MPT now supports lower-dimensional noise polytopes! If you want to define noise only on a subset of system states, you can now do so by defining sysStruct.noise as a set of vertices representing the noise. Say you want to impose a +/- 0.1 noise on x1, but no noise should be used for x2. You can do that by:
>> sysStruct.noise = [-0.1 0.1; 0 0];
Just keep in mind that the noise polytope must have vertices stored column-wise.

MEX files for the GLNXA64 platform

Thanks to Marco Laumanns, MPT now includes all necessary MEX files compiled for the GLNXA64 (64-bit Linux for AMP processors) platform.

More detailed display of system structures

The command mpt_sysStructInfo is now extended to display detailed information about a given linear or hybrid systems. To use the new feature, call the function with no output arguments, e.g.
>> pwa_DI
>> mpt_sysStructInfo(sysStruct)
which will generate the following output:
  PWA system (4 dynamics), 2 states, 1 input, 2 outputs

  Guards of dynamics 1:
  x(1) >= 0
  x(2) >= 0

  Guards of dynamics 2:
  x(1) <= 0
  x(2) <= 0

  Guards of dynamics 3:
  x(1) <= 0
  x(2) >= 0

  Guards of dynamics 4:
  x(1) >= 0
  x(2) <= 0

Execute arbitrary functions on each element of a polytope array

PELEMFUN(@FHANDLE, Pn, [X1, ..., Xn]) evaluates a function defined by the function handle FHANDLE on all elements of the polytope array Pn. Additional input arguments X1,...,Xn can be specified as well. A couple of examples:

E = pelemfun(@extreme, Pn) returns the extreme points of all polytopes stored in the polytope array Pn as a cell array:
>> p = unitbox(2);
>> P = [p p+[1; 0] p+[-1; 0]];
>> E = pelemfun(@extreme, P)

E = 

    [4x2 double]    [4x2 double]    [4x2 double]
    
>> E{1}

ans =

     1    -1
     1     1
    -1     1
    -1    -1
[X, R] = pelemfun(@chebyball, Pn) returns centers and radii of the chebychev ball of each element of Pn:
>> [X, R] = pelemfun(@chebyball, P)

X = 

    [2x1 double]    [2x1 double]    [2x1 double]


R = 

    [1]    [1]    [1]
B = pelemfun(@bounding_box, Pn, struct('Voutput', 1)); V = [B{:}] returns bounding boxes of all elements of Pn converted to a matrix.

I = pelemfun(@le, Pn, Q) returns a cell array of logical statements with true value at position "i" if Pn(i) is a subset of Q:
>> I = pelemfun(@le, P, unitbox(2, 1.5)); 
>> [I{:}]

ans =

     1     0     0

Convert a linear norm into a PWA function

The new function mpt_norm2pwa transforms a linear norm ||P*x||_l into an equivalent PWA function, ||P*x||_l = pwafcn.Bi{i}*x + pwafcn.Ci{i} for x \in pwafcn.Pn(i). Example:
>> P = diag([0.5 1]);  % scaling matrix
>> N = 1;              % transform the 1-norm
>> Pn = unitbox(2);    % only look for a solution inside of this box
>> pwafcn = mpt_norm2pwa(P, N, struct('Pn', Pn));
>> mpt_plotPWA(pwafcn.Pn, pwafcn.Bi, pwafcn.Ci);

Allow to deal with holes in explicit solutions

If a hole is present in an explicit solution, you can now tell mpt_getInput to take the control law of the nearest neighboring region if a state lies in the hole. To use this feature, you must set Options.recover=1, i.e.
>> Double_Integrator
>> ctrl = mpt_control(sysStruct, probStruct);  % compute the explicit controller
>> Pfinal = ctrl.Pfinal;                       % record feasible set
>> ctrl = modify(ctrl, 'remove', 2);           % remove 2nd region
>> ctrl = set(ctrl, 'Pfinal', Pfinal);         % set back the feasible set
>> plot(ctrl)
Here we see that our explicit controller contains a hole, so there is no control law defined for the initial state x0 = [-5; 1]:
>> u = mpt_getInput(ctrl, [-5; 1])
MPT_GETINPUT: NO REGION FOUND FOR STATE x = [-5  1]

u =

     []

However, with the recovery mode turned on, we take the control law of the nearest neighbor:
>> Options.recover = 1;
>> u = mpt_getInput(ctrl, [-5; 1], Options)
MPT_GETINPUT: State x = [-5  1] lies in a hole, taking the nearest neighbor

u =

     1
     

New function to compute the list of adjacent polytopes

The new function mpt_buildAdjacency now allows to compute which polytopes of a given polytope array are adjacent, i.e. which of them share a common facet. See help mpt_buildAdjacency for more details. Small example:
>> p1 = unitbox(2); 
>> p2 = unitbox(2) + [2; 0]; 
>> p3 = polytope([0 1; 0 3; 1 1; 2 3]);
>> P = [p1 p2 p3];
>> plot(P); identifyRegion(P)
>> adj = mpt_buildAdjacency(P);
>> adj{1}
ans =

     2     0
     3  -Inf
  -Inf     0
  -Inf     0
this output means that polytope p1 and polytope p2 share a common facet, so do polytopes p1 and p3.
>> adj{3}
ans =

     1
  -Inf
  -Inf
  -Inf
and this shows that polytope p3 is only adjacent to polytope p1, but not to p2. Have a look at help mpt_buildAdjacency for more information.

Improved computation of maximum attractive sets

The function mpt_maxCtrlSet has undergone a major revision:
  1. Sets obtained at each iteration can now be returned
  2. Computation of maximal attractive sets can now be aborted prematurely if convergence is very slow (have a look at help mpt_maxCtrlSet and look at Options.Vconverge
  3. Custom problem structure can now be passed (Options.probStruct)

Allow to disable the construction of a simulator when importing HYSDEL models

mpt_sys now allows to disable the construction of a simulator when hybrid systems modeled by HYSDEL are imported. To use this feature, call mpt_sys with an additional 'nosimulator' input argument:
>> sysStruct = mpt_sys('hysdelfile', 'nosimulator')
This is especially handy when you want to use the generated model only for on-line MPC of systems which are not well defined.

Sort voronoi cells according to seed points

P=mpt_voronoi(S) now returns the regions sorted in a way such that region P(i) corresponds to seed point S(i, :). Example:
>> S = rand(5, 2);      % 5 random seed points in 2D
>> V = mpt_voronoi(S);  % compute the voronoi cells
>> [isin, inwhich] = isinside(V, S(1, :)'); inwhich

inwhich =

1

>> [isin, inwhich] = isinside(V, S(2, :)'); inwhich

inwhich =

2

Allow to specify a "bounding polytope" when computing Voronoi cells

P=mpt_voronoi(S) now allows you to specify a "bounding polytope", i.e. the polytope inside of which the Voronoi cells should be computed.
% generate 10 random seed points in 2D
>> S = rand(10, 2);  

% compute voronoi cells without specifying a bounding polytope
>> V = mpt_voronoi(S);
% look for solution inside of a box with sides of +/- 3
>> Options.pbound = unitbox(2, 3);

% compute the Voronoi cells
>> P = mpt_voronoi(S);

Allow to specify the type of Lyapunov function to compute for one-step controllers

When constructing a one-step solution for PWA systems (probStruct.subopt_lev=2), MPT now allows to specify which type of Lyapunov function should be used to testify stability of the closed-loop system. The Lyapunov function can now be specified in Options.lyapunov_type which can take the following strings:

Easy detection of overlaps

Assume you have a polytope array and want to find out which polytopes do intersect. Now you can do
>> p1 = unitbox(2);
>> p2 = unitbox(2)+[1; 0];
>> p3 = unitbox(2)+[-1; 0];
>> p = [p1 p2 p3];
>> [r, ia, ib, iab] = dointersect(P, P);
>> iab

iab =

     1     1
     1     2
     1     3
     2     1
     2     2
     3     1
     3     3
and this output tells you that p1 intersects with p2 and p3, but p2 does not intersect with p3.

Improved facetcircle function

polytope/facetcircle now allows to pass the whole range of facets to explore, e.g:
>> P = unitbox(3);
>> [x, r] = facetcircle(P, [1 3])

x =

     1     0
     0     0
     0     1


r =

     1     1
Notice that the centers of facets nos. 1 and 3 returned in x are stored column-wise.

Function to compute a voronoi diagram for facets of a polytope

Similar to the idea of Voronoi diagrams one can compute the partition of a polytope for which the set of points in a polytope is closer to one facet than to all the others:
>> P = unitbox(2);
>> V = facetvoronoi(P)
V=

Polytope array: 4 polytopes in 2D

>> plot(V)
Here V(i) is a polytope which contains all points which are closer to facet no. i of P than to any other facet. A subset of facets to investigate can also be provided:
>> P = unitbox(2);
>> V = facetvoronoi(P, [1 2 4])
V=

Polytope array: 3 polytopes in 2D

>> plot(V)

New function to remove redundant entries of a polytope array

If your polytope array contains duplicate elements, you can now use the overloaded function unique which will return only unique elements of the array:
>> p1 = unitbox(2);
>> p2 = unitbox(2, 5);
>> P = [p1 p2 p1 p1 p2]    % P contains redundant entries

P=

Polytope array: 5 polytopes in 2D

>> U = unique(P)

U=

Polytope array: 2 polytopes in 2D

>> U(1)==p1

ans =

     1
     
>> U(2)==p2
 
ans =

     1

Improved projection algorithms

A new projection method has been added - Options.projection=7. When this algorithm is selected, the projection is solved as a multi-parametric linear program (mpLP). This method is efficient especially when projecting to, say, less than 5 dimensions. We have also improved other algorithms, mainly increased numerical robustness of the ESP method (Options.projection=4) and changed heuristics which decides which projection method best suits a particular problem.

New options for plotting of polytopes

Gradient coloring can now be used when plotting 3D polytopes:
>> P = polytope(randn(10,3));
>> plot(P); % plot with gradient coloring disabled
>> plot(P, struct('gradcolor', 1)); % plot with gradient coloring enabled
Moreover, a colormap can now be specified when plotting polytope arrays:
>> plot(Pn, struct('colormap', 'summer'));

Improved plotting of piecewise affine and piecewise quadratic functions

Functions mpt_plotPWA and mpt_plotPWQ have been extended to allow the user to specify color of edges of patches (Options.edgecolor) and level of transparency (Options.shade). The width of edge lines can be specified by Options.edgewidth. Have a look at respective help descriptions for more details.
>> mpt_plotPWA(Pn, Li, Ci, struct('shade', 0.6));
>> mpt_plotPWQ(Pn, Li, Ci, struct('edgecolor', 'w', 'edgewidth', 3));

Notable changes and bug fixes in the polytope library

Other notable changes and bug fixes

  • mpt_computeTrajectory fixed computation of closed-loop cost for systems with deltaU constraints
  • mpt_exportc: allows to specify name of output file
  • mpt_getInput: don't check regions twice
  • mpt_infsetPWA: properly detect cases where invariant set is empty
  • mpt_invariantSet: speed improvements
  • mpt_invariantSet: allow to simplify intermediate steps using greedy merging
  • mpt_init: improve speed
  • mpt_mplp: fix problems with cycling
  • mpt_mplp: fix random perturbations for 1D systems
  • mpt_mplp: fix problems with "xBeyond violates more than one bounds"
  • mpt_mpqp: improved handling of degeneracies
  • mpt_optControlPWA: fixed handling of 1D systems
  • mpt_optControlPWA: always return Pfinal as a polytope array
  • mpt_plotPWA, mpt_plotPartition, mpt_plotU: respect user's choice of subplots
  • mpt_plotU: fixed handling of 1D systems with multiple inputs
  • mpt_solveQP: properly impose equality constraints for NAG QP solver
  • mpt_voronoi: make mpt_mplp() silent