Compute nonlinear MPC control moves with code generation support

`[`

computes optimal nonlinear MPC control moves and supports code generation for deployment to
real-time targets. Control moves are calculated using the current prediction model states
(`mv`

,`newOnlineData`

]
= nlmpcmoveCodeGeneration(`coreData`

,`x`

,`lastMV`

,`onlineData`

)`x`

), the control moves from the previous control interval
(`lastMV`

), and input data structures (`coreData`

and `nlOnlineData`

) generated using `getCodeGenerationData`

.

`nlmpcmoveCodeGeneration`

does not check input arguments for correct
dimensions and data types.

`[___,`

returns additional information about the optimization result, including the number of
iterations and the objective function cost.`info`

] = nlmpcmoveCodeGeneration(___)

Create a nonlinear MPC controller with four states, two outputs, and one input.

nlobj = nlmpc(4,2,1);

In standard cost function, zero weights are applied by default to one or more OVs because there are fewer MVs than OVs.

Specify the sample time and horizons of the controller.

Ts = 0.1; nlobj.Ts = Ts; nlobj.PredictionHorizon = 10; nlobj.ControlHorizon = 5;

Specify the state function for the controller, which is in the file `pendulumDT0.m`

. This discrete-time model integrates the continuous time model defined in `pendulumCT0.m`

using a multistep forward Euler method.

```
nlobj.Model.StateFcn = "pendulumDT0";
nlobj.Model.IsContinuousTime = false;
```

The prediction model uses an optional parameter, `Ts`

, to represent the sample time. Specify the number of parameters and create a parameter vector.

nlobj.Model.NumberOfParameters = 1; params = {Ts};

Specify the output function of the model, passing the sample time parameter as an input argument.

`nlobj.Model.OutputFcn = "pendulumOutputFcn";`

Define standard constraints for the controller.

nlobj.Weights.OutputVariables = [3 3]; nlobj.Weights.ManipulatedVariablesRate = 0.1; nlobj.OV(1).Min = -10; nlobj.OV(1).Max = 10; nlobj.MV.Min = -100; nlobj.MV.Max = 100;

Validate the prediction model functions.

x0 = [0.1;0.2;-pi/2;0.3]; u0 = 0.4; validateFcns(nlobj,x0,u0,[],params);

Model.StateFcn is OK. Model.OutputFcn is OK. Analysis of user-provided model, cost, and constraint functions complete.

Only two of the plant states are measurable. Therefore, create an extended Kalman filter for estimating the four plant states. Its state transition function is defined in `pendulumStateFcn.m`

and its measurement function is defined in `pendulumMeasurementFcn.m`

.

EKF = extendedKalmanFilter(@pendulumStateFcn,@pendulumMeasurementFcn);

Define initial conditions for the simulation, initialize the extended Kalman filter state, and specify a zero initial manipulated variable value.

x0 = [0;0;-pi;0]; y0 = [x0(1);x0(3)]; EKF.State = x0; mv0 = 0;

Create code generation data structures for the controller, specifying the initial conditions and parameters.

[coreData,onlineData] = getCodeGenerationData(nlobj,x0,mv0,params);

Specify the output reference value in the online data structure.

onlineData.ref = [0 0];

To verify the controller operation, run a simulation for `10`

seconds. During each control interval:

Correct the previous prediction using the current measurement.

Compute optimal control moves using

`nlmpcmoveCodeGeneration`

. This function returns the computed optimal sequences in`onlineData`

. Passing the updated data structure to`nlmpcmoveCodeGeneration`

in the next control interval provides initial guesses for the optimal sequences.Predict the model states.

Apply the first computed optimal control move to the plant, updating the plant states.

Generate sensor data with white noise.

Save the plant states.

mv = mv0; y = y0; x = x0; Duration = 10; xHistory = x0; for ct = 1:(Duration/Ts) % Correct previous prediction xk = correct(EKF,y); % Compute optimal control move [mv,onlineData] = nlmpcmoveCodeGeneration(coreData,xk,mv,onlineData); % Predict prediction model states for the next iteration predict(EKF,[mv; Ts]); % Implement first optimal control move x = pendulumDT0(x,mv,Ts); % Generate sensor data y = x([1 3]) + randn(2,1)*0.01; % Save plant states xHistory = [xHistory x]; end

Generate a MEX function with MATLAB® Coder™, specifying `coreData`

as a constant.

func = 'nlmpcmoveCodeGeneration'; funcOutput = 'nlmpcmoveMEX'; Cfg = coder.config('mex'); Cfg.DynamicMemoryAllocation = 'off'; codegen('-config',Cfg,func,'-o',funcOutput,'-args',... {coder.Constant(coreData),xk,mv,onlineData});

`coreData`

— Nonlinear MPC configuration parametersstructure

Nonlinear MPC configuration parameters that are constant at run time, specified as a
structure generated using `getCodeGenerationData`

.

When using `codegen`

, `coreData`

must be defined as `coder.Constant`

.

`x`

— Current prediction model statescolumn vector

Current prediction model states, specified as a vector of
length*N _{x}*, where

`nlobj.Model.StateFcn`

.Since the nonlinear MPC controller does not perform state estimation, you must either measure or estimate the current prediction model states at each control interval. For more information on nonlinear MPC prediction models, see Specify Prediction Model for Nonlinear MPC.

`lastMV`

— Control signals used in plant at previous control intervalcolumn vector

Control signals used in plant at previous control interval, specified as a column
vector of length*N _{mv}*, where

Specify `lastMV`

as the manipulated variable signals applied to
the plant in the previous control interval. Typically, these signals are the values
generated by the controller (`mv`

). However, this is not always the
case. For example, if your controller is offline and running in tracking mode; that
is, the controller output is not driving the plant, then feeding the actual control
signal to `last_mv`

can help achieve bumpless transfer when the
controller is switched back online.

`onlineData`

— Online controller datastructure

Online controller data that you must update at run time, specified as a structure
with the following fields. Generate the initial structure using `getCodeGenerationData`

. Some structure fields are not required, depending
on the configuration of the controller and what weights or constraints vary at run
time.

`ref`

— Output reference valuesrow vector | array

Plant output reference values, specified as a row vector of length
*N _{y}* or an array with

To use the same reference values across the prediction horizon, specify a row vector.

To vary the reference values over the prediction horizon from time
*k*+1 to time *k*+*p*,
specify an array with up to *p* rows. Here, *k*
is the current time and *p* is the prediction horizon. Each row
contains the reference values for one prediction horizon step. If you specify
fewer than *p* rows, the values in the final row are used for the
remaining steps of the prediction horizon.

If your controller cost function does not use `ref`

, leave
`ref`

at its default value.

`mvTarget`

— Manipulated variable targetsrow vector | array

Manipulated variable targets, specified as a row vector of length
*N _{mv}* or an array with

To use the same manipulated variable targets across the prediction horizon, specify a row vector.

To vary the targets over the prediction horizon (previewing) from time
*k* to time *k*+*p*-1,
specify an array with up to *p* rows. Here, *k*
is the current time and *p* is the prediction horizon. Each row
contains the targets for one prediction horizon step. If you specify fewer than
*p* rows, the final targets are used for the remaining steps of
the prediction horizon.

If your controller cost function does not use `mvTarget`

,
leave `mvTarget`

at its default value.

`X0`

— Initial guesses for the optimal state solutionsvector | array

Initial guesses for the optimal state solutions, specified as a row vector of
length *N _{x}* or an array with

To use the same initial guesses across the prediction horizon, specify a row vector.

To vary the initial guesses over the prediction horizon from time
*k*+1 to time *k*+*p*,
specify an array with up to *p* rows. Here, *k*
is the current time and *p* is the prediction horizon. Each row
contains the initial guesses for one prediction horizon step. If you specify fewer
than *p* rows, the final guesses are used for the remaining steps
of the prediction horizon.

In general, during closed-loop simulation, you do not specify
`X0`

yourself. Instead, when calling `nlmpcmoveCodeGeneration`

, return the
`newOnlineData`

output argument, which contains updated
`X0`

estimates. You can then pass
`newOnlineData`

in as the `onlineData`

input argument to `nlmpcmoveCodeGeneration`

for the next
control interval.

`MV0`

— Initial guesses for the optimal manipulated variable solutionsvector | array

Initial guesses for the optimal manipulated variable solutions, specified as a
row vector of length *N _{mv}* or an array
with

To use the same initial guesses across the prediction horizon, specify a row vector.

To vary the initial guesses over the prediction horizon from time
*k* to time *k*+*p*-1,
specify an array with up to *p* rows. Here, *k*
is the current time and *p* is the prediction horizon. Each row
contains the initial guesses for one prediction horizon step. If you specify fewer
than *p* rows, the final guesses are used for the remaining steps
of the prediction horizon.

In general, during closed-loop simulation, you do not specify
`MV0`

yourself. Instead, when calling `nlmpcmoveCodeGeneration`

, return the
`newOnlineData`

output argument, which contains updated
`MV0`

estimates. You can then pass
`newOnlineData`

in as the `onlineData`

input argument to `nlmpcmoveCodeGeneration`

for the next
control interval.

`Slack0`

— Initial guess for the slack variable at the solutionnonnegative scalar

Initial guess for the slack variable at the solution, specified as a nonnegative scalar.

In general, during closed-loop simulation, you do not specify
`Slack0`

yourself. Instead, when calling `nlmpcmoveCodeGeneration`

, return the
`newOnlineData`

output argument, which contains updated
`Slack0`

estimates. You can then pass
`newOnlineData`

in as the `onlineData`

input argument to `nlmpcmoveCodeGeneration`

for the next
control interval.

`md`

— Measured disturbance valuesrow vector | array

Measured disturbance values, specified as a row vector of length
*N _{md}* or an array with

`md`

. If your controller has no measured disturbances, then
`getCodeGenerationData`

omits this field.To use the same disturbance values across the prediction horizon, specify a row vector.

To vary the disturbance values over the prediction horizon from time
*k* to time *k*+*p*, specify
an array with up to *p*+1 rows. Here, *k* is the
current time and *p* is the prediction horizon. Each row contains
the disturbance values for one prediction horizon step. If you specify fewer than
*p* rows, the values in the final row are used for the
remaining steps of the prediction horizon.

`Parameters`

— Parameter valuescell vector

Parameter values used by the prediction model, custom cost function, and
custom constraints, specified as a cell vector with length equal to the
`Model.NumberOfParameters`

property of the controller. If the
controller has no parameters, then `getCodeGenerationData`

omits this field.

The order of the parameters must match the order defined for the prediction model, custom cost function, and custom constraints.

`OutputWeights`

— Output variable tuning weightsrow vector | array

Output variable tuning weights that replace the default tuning weights at run
time, specified as a row vector of length
*N _{y}* or an array with

`getCodeGenerationData`

.To use the same weights across the prediction horizon, specify a row vector.

To vary the weights over the prediction horizon from time
*k*+1 to time *k*+*p*, specify
an array with up to *p* rows. Here, *k* is the
current time and *p* is the prediction horizon. Each row contains
the weights for one prediction horizon step. If you specify fewer than
*p* rows, the final weights are used for the remaining steps of
the prediction horizon.

`MVWeights`

— Manipulated variable tuning weightsrow vector | array

Manipulated variable tuning weights that replace the default tuning weights at
run time, specified as a row vector of length
*N _{mv}* or an array with

`getCodeGenerationData`

.To use the same weights across the prediction horizon, specify a row vector.

To vary the weights over the prediction horizon from time
*k*+1 to time *k*+*p*, specify
an array with up to *p* rows. Here, *k* is the
current time and *p* is the prediction horizon. Each row contains
the weights for one prediction horizon step. If you specify fewer than
*p* rows, the final weights are used for the remaining steps of
the prediction horizon.

`MVRateWeights`

— Manipulated variable rate tuning weightsrow vector | array

Manipulated variable rate tuning weights that replace the default tuning
weights at run time, specified as a row vector of length
*N _{mv}* or an array with

`getCodeGenerationData`

.To use the same weights across the prediction horizon, specify a row vector.

To vary the weights over the prediction horizon from time
*k*+1 to time *k*+*p*, specify
an array with up to *p* rows. Here, *k* is the
current time and *p* is the prediction horizon. Each row contains
the weights for one prediction horizon step. If you specify fewer than
*p* rows, the final weights are used for the remaining steps of
the prediction horizon.

`ECRWeight`

— Slack variable tuning weightpositive scalar

Slack variable rate tuning weight that replaces the default tuning weight at
run time, specified as a positive scalar. If you expect your slack variable weight
to vary at run time, you must add this field to the online data structure when you
call `getCodeGenerationData`

.

`OutputMin`

— Output variable lower boundsrow vector | array

Output variable lower bounds that replace the default lower bounds at run
time, specified as a row vector of length
*N _{y}* or an array with

`getCodeGenerationData`

.To use the same bounds across the prediction horizon, specify a row vector.

To vary the bounds over the prediction horizon from time
*k*+1 to time *k*+*p*, specify
an array with up to *p* rows. Here, *k* is the
current time and *p* is the prediction horizon. Each row contains
the bounds for one prediction horizon step. If you specify fewer than
*p* rows, the final bounds are used for the remaining steps of
the prediction horizon.

`OutputMax`

— Output variable upper boundsrow vector | array

Output variable upper bounds that replace the default upper bounds at run
time, specified as a row vector of length
*N _{y}* or an array with

`getCodeGenerationData`

.To use the same bounds across the prediction horizon, specify a row vector.

To vary the bounds over the prediction horizon from time
*k*+1 to time *k*+*p*, specify
an array with up to *p* rows. Here, *k* is the
current time and *p* is the prediction horizon. Each row contains
the bounds for one prediction horizon step. If you specify fewer than
*p* rows, the final bounds are used for the remaining steps of
the prediction horizon.

`StateMin`

— State lower boundsrow vector | array

State lower bounds that replace the default lower bounds at run time,
specified as a row vector of length *N _{x}*
or an array with

`getCodeGenerationData`

.To use the same bounds across the prediction horizon, specify a row vector.

To vary the bounds over the prediction horizon from time
*k*+1 to time *k*+*p*, specify
an array with up to *p* rows. Here, *k* is the
current time and *p* is the prediction horizon. Each row contains
the bounds for one prediction horizon step. If you specify fewer than
*p* rows, the final bounds are used for the remaining steps of
the prediction horizon.

`StateMax`

— State upper boundsrow vector | array

State upper bounds that replace the default upper bounds at run time,
specified as a row vector of length *N _{x}*
or an array with

`getCodeGenerationData`

.To use the same bounds across the prediction horizon, specify a row vector.

*k*+1 to time *k*+*p*, specify
an array with up to *p* rows. Here, *k* is the
current time and *p* is the prediction horizon. Each row contains
the bounds for one prediction horizon step. If you specify fewer than
*p* rows, the final bounds are used for the remaining steps of
the prediction horizon.

`MVMin`

— Manipulated variable lower boundsrow vector | array

Manipulated variable lower bounds that replace the default lower bounds at run
time, specified as a row vector of length
*N _{mv}* or an array with

`getCodeGenerationData`

.To use the same bounds across the prediction horizon, specify a row vector.

*k*+1 to time *k*+*p*, specify
an array with up to *p* rows. Here, *k* is the
current time and *p* is the prediction horizon. Each row contains
the bounds for one prediction horizon step. If you specify fewer than
*p* rows, the final bounds are used for the remaining steps of
the prediction horizon.

`MVMax`

— Manipulated variable upper boundsrow vector | array

Manipulated variable upper bounds that replace the default upper bounds at run
time, specified as a row vector of length
*N _{mv}* or an array with

`getCodeGenerationData`

.To use the same bounds across the prediction horizon, specify a row vector.

*k*+1 to time *k*+*p*, specify
an array with up to *p* rows. Here, *k* is the
current time and *p* is the prediction horizon. Each row contains
the bounds for one prediction horizon step. If you specify fewer than
*p* rows, the final bounds are used for the remaining steps of
the prediction horizon.

`MVRateMin`

— Manipulated variable rate lower boundsrow vector | array

Manipulated variable rate lower bounds that replace the default lower bounds
at run time, specified as a row vector of length
*N _{mv}* or an array with

`getCodeGenerationData`

.To use the same bounds across the prediction horizon, specify a row vector.

*k*+1 to time *k*+*p*, specify
an array with up to *p* rows. Here, *k* is the
current time and *p* is the prediction horizon. Each row contains
the bounds for one prediction horizon step. If you specify fewer than
*p* rows, the final bounds are used for the remaining steps of
the prediction horizon.

`MVRateMax`

— Manipulated variable rate upper boundsrow vector | array

Manipulated variable rate upper bounds that replace the default upper bounds
at run time, specified as a row vector of length
*N _{mv}* or an array with

`getCodeGenerationData`

.To use the same bounds across the prediction horizon, specify a row vector.

*k*+1 to time *k*+*p*, specify
an array with up to *p* rows. Here, *k* is the
current time and *p* is the prediction horizon. Each row contains
the bounds for one prediction horizon step. If you specify fewer than
*p* rows, the final bounds are used for the remaining steps of
the prediction horizon.

`mv`

— Optimal manipulated variable control actioncolumn vector

Optimal manipulated variable control action, returned as a column vector of length
*N _{mv}*, where

If the solver converges to a local optimum solution
(`info.ExitFlag`

is positive), then `mv`

contains
the optimal solution.

If the solver reaches the maximum number of iterations, finds a feasible suboptimal
solution (`info.ExitFlag = 0`

) and:

`coredata.usesuboptimalsolution`

is`true`

, then`mv`

contains the suboptimal solution`coredata.usesuboptimalsolution`

is`false`

, then`mv`

contains`lastMV`

If the solver fails to find a feasible solution (`info.ExitFlag`

is
negative), then `mv`

contains `lastMV`

.

`newOnlineData`

— Updated online controller datastructure

Updated online controller data, returned as a structure. This structure is the same
as `onlineData`

, except that the decision variable initial guesses
(`X0`

, `MV0`

, and `Slack0`

) are
updated.

For subsequent control intervals, *warm start* the solver by
modifying the online data in `newOnlineData`

and passing the updated
structure to `nlmpcmoveCodeGeneration`

as
`onlineData`

. Doing so allows the solver to use the decision
variable initial guesses as a starting point for its solution.

`info`

— Solution detailsstructure

Solution details, returned as a structure with the following fields.

`MVopt`

— Optimal manipulated variable sequencearray

Optimal manipulated variable sequence, returned as a
(*p*+1)-by-*N _{mv}*
array, where

`MVopt(i,:)`

contains the calculated optimal manipulated
variable values at time `k+i-1`

, for ```
i =
1,...,p
```

, where `k`

is the current time.
`MVopt(1,:)`

contains the same manipulated variable values as
output argument `mv`

. Since the controller does not calculate
optimal control moves at time `k+p`

,
`MVopt(p+1,:)`

is equal to
`MVopt(p,:)`

.

`Xopt`

— Optimal prediction model state sequencearray

Optimal prediction model state sequence, returned as a
(*p*+1)-by-*N _{x}*
array, where

`Xopt(i,:)`

contains the calculated state values at time
`k+i-1`

, for `i = 2,...,p+1`

, where
`k`

is the current time. `Xopt(1,:)`

is the
same as the current states in `x`

.

`Yopt`

— Optimal output variable sequencearray

Optimal output variable sequence, returned as a
(*p*+1)-by-*N _{y}*
array, where

`Yopt(i,:)`

contains the calculated output values at time
`k+i-1`

, for `i = 2,...,p+1`

, where
`k`

is the current time. `Yopt(1,:)`

is
computed based on the current states in `x`

and the current
measured disturbances in `md`

, if any.

`Topt`

— Prediction horizon time sequencecolumn vector

Prediction horizon time sequence, returned as a column vector of length
*p*+1, where *p* is the prediction horizon.
`Topt`

contains the time sequence from time
*k* to time *k*+*p*, where
*k* is the current time.

`Topt(1)`

= 0 represents the current time. Subsequent time
steps `Topt(i)`

are `Ts*(i-1)`

, where
`Ts`

is the controller sample time.

Use `Topt`

when plotting the `MVopt`

,
`Xopt`

, or `Yopt`

sequences.

`Slack`

— Slack variable at optimumnonnegative scalar

Slack variable at optimum, ε, used in constraint softening, returned as a nonnegative scalar value.

ε = 0 — All soft constraints are satisfied over the entire prediction horizon.

ε > 0 — At least one soft constraint is violated. When more than one constraint is violated, ε represents the worst-case soft constraint violation (scaled by your ECR values for each constraint).

`ExitFlag`

— Optimization exit codeinteger

Optimization exit code, returned as one of the following:

Positive Integer — Optimal solution found

`0`

— Feasible suboptimal solution found after the maximum number of iterationsNegative integer — No feasible solution found

`Iterations`

— Number of iterationspositive integer

Number of iterations used by the solver, returned as a positive integer.

`Cost`

— Objective function costnonnegative scalar

Objective function cost, returned as a nonnegative scalar value. The cost quantifies the degree to which the controller has achieved its objectives.

The cost value is only meaningful when `ExitFlag`

is
nonnegative.

Generate C and C++ code using MATLAB® Coder™.

Usage notes and limitations:

`nlmpcmoveCodeGeneration`

supports generating code only for nonlinear MPC controllers that use the default`fmincon`

solver with the SQP algorithm. However, you can simulate controllers using other`fmincon`

algorithms.When used for code generation, nonlinear MPC controllers do not support anonymous functions for the prediction model, custom cost function, or custom constraint functions. However,

`nlmpcmoveCodeGeneration`

can still simulate controllers that use anonymous functions.Your custom functions must be on the MATLAB

^{®}path and compatible with MATLAB Coder™. For more information on checking compatibility, see Check Code by Using the Code Generation Readiness Tool (MATLAB Coder).Code generation for nonlinear MPC controllers supports only double-precision data.

To generate code for computing optimal control moves for a nonlinear MPC controller:

Generate data structures from a nonlinear MPC controller using

`getCodeGenerationData`

.To verify that your controller produces the expected closed-loop results, simulate it using

`nlmpcmoveCodeGeneration`

in place of`nlmpcmove`

.Generate code for

`nlmpcmoveCodeGeneration`

using`codegen`

. This step requires MATLAB Coder software.

A modified version of this example exists on your system. Do you want to open this version instead?

You clicked a link that corresponds to this MATLAB command:

Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.

Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .

Select web siteYou can also select a web site from the following list:

Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.

- América Latina (Español)
- Canada (English)
- United States (English)

- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)

- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)