UI /

# Code generation

MPT3 allows to export parametric solutions in two ways:

## Export to pure Matlab code

Arbitrary parametric solutions can be exported to a standalone m-file by the PolyUnion/toMatlab method (see help PolyUnion/toMatlab for more information). The exported code is completely MPT-independent and, more importantly, much faster to execute compared to built-in MPT function-evaluation code (which needs to perform lots of sanity checks which slow down the evaluation process).

The general syntax is as follows:

solution.toMatlab('name_of_file.m', 'function_to_export', 'tiebreak_function')

The method takes any PolyUnion object (or an array thereof) and exports the function function_to_export to file name_of_file, resolving tiebreak (when a particular point is contained in multiple regions) using the function tiebreak_function. If you have a single optimizer that is continuous, you can use set tiebreak_function='first-region'. Here, the search for a region that contains a particular point is finished upon hitting the first such region.

The exported parametric solution can then be evaluated by

[z, region] = name_of_file(x)

where x is the vector of parameters at which to evaluate, z is the value of the optimizer at x, and region is the index of the region that constains x. If there is no region containing x, then z=NaN and region=0.

To export explicit MPC feedbacks, use the following syntax:

controller.optimizer.toMatlab('name_of_file.m', 'primal', 'obj')

This tells MPT to export the primal optimizer (stored as the primal function of the optimizer field of the controller), resolving tiebreaks using the cost function of the controller (stored as the obj function of controller.optimizer).

Note that, by default, the toMatlab method exports the full open-loop optimizer. In the case of explicit MPC this implies that the output of z=name_of_file(x) will be an {$N n_u \times 1$} vector, where {$N$} is the prediction horizon and {$n_u$} is the number of control inputs. Then the closed-loop control action is given by u = z(1:nu). Alternatively, you can ask toMatlab() to only export the closed-loop optimizer. This can be achieved by:

solution.trimFunction('primal', nu);
solution.toMatlab('name_of_file.m', 'primal', 'obj')

Here, trimFunction('primal', nu) will change the primal function such that it only returns the closed-loop optimizer (i.e., the first nu components of the open-loop optimizer). The added benefit is in decreased memory consumption.

Full example:

% prediction model
model = LTISystem('A', [1 1; 0 1], 'B', [1; 0.5]);
model.x.min = [-5; -5];
model.x.max = [5; 5];
model.u.min = -1;
model.u.max = 1;
% prediction horizon
N = 5;
% construct the explicit MPC controller
ctrl = MPCController(model, N).toExplicit();

% export the explicit solution to a standalone m-file
ctrl.optimizer.toMatlab('mycontroller.m', 'primal', 'obj');

% evaluate the exported solution for a particular state
x0 = [2; 1];
[U, region] = mycontroller(x0)
if region==0
error('No region for state %s.', mat2str(x0));
end

% note that U contains the open-loop optimizer. to get the closed-loop control action, use
nu = 1; % number of control inputs
uopt = U(1:nu)

## Export of binary trees to pure Matlab code

The BinTreePolyUnion/toMatlab method exports a given binary tree to a pure Matlab code, similarly to the procedure above. Note that the method has following limitations:

• supports only a single BinTreePolyUnion object
• no tiebreaking

Example:

% construct the binary tree
tree = BinTreePolyUnion(ctrl.optimizer);

% export the tree solution to a standalone m-file
tree.toMatlab('mycontroller.m', 'primal');

% evaluate the exported solution for a particular state
x0 = [2; 1];
[U, region] = mycontroller(x0)

## Export to C code

### Export of PWA control law stored in EMPCController object

The EMPCController object contains a method exportToC that exports PWA control law stored in the optimizer property to C language. The syntax of exportToC method is given as

ctrl.exportToC('output','directory')

where output is the base name for the C-files to be generated in directory. In the new directory there will be three files located:

• output.c - pure C-code with PWA control law
• output_mex.c - mex interface for fast evaluation in Matlab
• output_sfunc.c - Simulink interface for fast evaluation in Simulink

The output.c contains the pure C-code that can be ported to target application. For fast evaluation in Matlab (Simulink), one may be interested to compile the mex (Simulink) interfaces by issuing the command

mex output_mex.c
mex output_sfunc.c

The compiled files can be called from Matlab (Simulink) as any other function. For the above example, the compiled function output_mex evaluates to the same output as the generated Matlab files

% output from the compiled C-mex function
output_mex(x0)

ans =

-1
-1
-0.76229508196722
-0.0737704918032785
1.32093882317646e-15

% output from the generated matlab file
mycontroller(x0)

ans =

-1
-1
-0.76229508196722
-0.0737704918032785
1.32093882317646e-15

### Export of general PWA/PWQ functions

From version 3.0.14 we have introduced toC() methods that export general PWA/PWQ functions to C language. The basic sequential search (including tie-breaking) is exported using the toC() method operating over PolyUnion object. The binary search trees are exported in BinTreePolyUnion/toC() method. The syntax for code generation applied for the example above is given as

ctrl.optimizer.toC('primal','file','obj')
Output written to "file.c".
C-mex function written to "file_mex.c".

The first argument represents the PWA/PWQ function to export, the second argument is the base name for the files to be generated and the third argument is the tie-breaking function to deal with multiple valued cases. The generated mex-file can be compiled:

mex file_mex.c

and evaluated inside Matlab

file_mex(x0)

ans =

-1
-1
-0.76229508196722
-0.0737704918032785
1.32093882317646e-15

The result gives the same output as evaluating the Matlab file mycontroller in the above example.

### Export using Matlab Coder toolbox

One straightforward way to obtain a C-code representation of parametric solutions is to use the Matlab Coder toolbox:

controller.optimizer.toMatlab('mycontroller.m', 'primal', 'obj');
coder mycontroller -args {zeros(nx, 1)}

where nx is the number of parameters. The coder function will generate the mex-function controller_mex() which is much faster to execute compared to executing controller.m.

For explicit MPC controllers you can obtain nx by nx=controller.xinitFormat.n_xinit (this number already includes any additional parameters introduced by free reference tracking and/or by the {$\Delta u$} formulation).