Main Content

nlmpcmoveCodeGeneration

Compute nonlinear MPC control moves with code generation support

Since R2020a

Syntax

``````[mv,newOnlineData] = nlmpcmoveCodeGeneration(coreData,x,lastMV,onlineData)``````
``[___,info] = nlmpcmoveCodeGeneration(___)``

Description

example

``````[mv,newOnlineData] = nlmpcmoveCodeGeneration(coreData,x,lastMV,onlineData)``` 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 (`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.```
````[___,info] = nlmpcmoveCodeGeneration(___)` returns additional information about the optimization result, including the number of iterations and the objective function cost.```

Examples

collapse all

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

`nlobj = nlmpc(4,2,1);`
```Zero weights are applied 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:

1. Correct the previous prediction using the current measurement.

2. 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.

3. Predict the model states.

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

5. Generate sensor data with white noise.

6. 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™.

```cfg = coder.config('mex'); cfg.EnableDynamicMemoryAllocation = false; mexfun = buildMEX(nlobj, 'nlmpcmoveMEX', coreData, onlineData, cfg);```
```Generating MEX function "nlmpcmoveMEX" from nonlinear MPC to speed up simulation. Code generation successful. MEX function "nlmpcmoveMEX" successfully generated. ```

Input Arguments

collapse all

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

Note

When using `codegen` (MATLAB Coder), `coreData` must be defined as `coder.Constant` (MATLAB Coder).

Current prediction model states, specified as a vector of lengthNx, where Nx is the number of prediction model states. The prediction model state function is defined in `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.

Control signals used in plant at previous control interval, specified as a column vector of lengthNmv, where Nmv is the number of manipulated variables.

Note

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.

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.

Plant output reference values, specified as a row vector of length Ny or an array with Ny columns, where Ny is the number of output variables.

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.

Manipulated variable targets, specified as a row vector of length Nmv or an array with Nmv columns, where Nmv is the number of manipulated variables.

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.

Initial guesses for the optimal state solutions, specified as a row vector of length Nx or an array with Nx columns, where Nx is the number of states.

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.

Initial guesses for the optimal manipulated variable solutions, specified as a row vector of length Nmv or an array with Nmv columns, where Nmv is the number of manipulated variables.

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.

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.

Measured disturbance values, specified as a row vector of length Nmd or an array with Nmd columns, where Nmd is the number of measured disturbances. If your controller has measured disturbances, you must specify `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.

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.

Output variable tuning weights that replace the default tuning weights at run time, specified as a row vector of length Ny or an array with Ny columns, where Ny is the number of output variables. If you expect your output variable weights to vary at run time, you must add this field to the online data structure when you call `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.

Manipulated variable tuning weights that replace the default tuning weights at run time, specified as a row vector of length Nmv or an array with Nmv columns, where Nmv is the number of manipulated variables. If you expect your manipulated variable weights to vary at run time, you must add this field to the online data structure when you call `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.

Manipulated variable rate tuning weights that replace the default tuning weights at run time, specified as a row vector of length Nmv or an array with Nmv columns, where Nmv is the number of manipulated variables. If you expect your manipulated variable rate weights to vary at run time, you must add this field to the online data structure when you call `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.

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`.

Output variable lower bounds that replace the default lower bounds at run time, specified as a row vector of length Ny or an array with Ny columns, where Ny is the number of output variables. If you expect your output variable lower bounds to vary at run time, you must add this field to the online data structure when you call `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.

Output variable upper bounds that replace the default upper bounds at run time, specified as a row vector of length Ny or an array with Ny columns, where Ny is the number of output variables. If you expect your output variable upper bounds to vary at run time, you must add this field to the online data structure when you call `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.

State lower bounds that replace the default lower bounds at run time, specified as a row vector of length Nx or an array with Nx columns, where Nx is the number of states. If you expect your state lower bounds to vary at run time, you must add this field to the online data structure when you call `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.

State upper bounds that replace the default upper bounds at run time, specified as a row vector of length Nx or an array with Nx columns, where Nx is the number of states. If you expect your state upper bounds to vary at run time, you must add this field to the online data structure when you call `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.

Manipulated variable lower bounds that replace the default lower bounds at run time, specified as a row vector of length Nmv or an array with Nmv columns, where Nmv is the number of manipulated variables. If you expect your manipulated variable lower bounds to vary at run time, you must add this field to the online data structure when you call `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.

Manipulated variable upper bounds that replace the default upper bounds at run time, specified as a row vector of length Nmv or an array with Nmv columns, where Nmv is the number of manipulated variables. If you expect your manipulated variable upper bounds to vary at run time, you must add this field to the online data structure when you call `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.

Manipulated variable rate lower bounds that replace the default lower bounds at run time, specified as a row vector of length Nmv or an array with Nmv columns, where Nmv is the number of manipulated variables. If you expect your manipulated variable rate lower bounds to vary at run time, you must add this field to the online data structure when you call `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.

Manipulated variable rate upper bounds that replace the default upper bounds at run time, specified as a row vector of length Nmv or an array with Nmv columns, where Nmv is the number of manipulated variables. If you expect your manipulated variable rate upper bounds to vary at run time, you must add this field to the online data structure when you call `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.

Output Arguments

collapse all

Optimal manipulated variable control action, returned as a column vector of length Nmv, where Nmv is the number of manipulated variables.

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`.

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.

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

Optimal manipulated variable sequence, returned as a (p+1)-by-Nmv array, where p is the prediction horizon and Nmv is the number of manipulated variables.

`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,:)`.

Optimal prediction model state sequence, returned as a (p+1)-by-Nx array, where p is the prediction horizon and Nx is the number of states in the prediction model.

`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`.

Optimal output variable sequence, returned as a (p+1)-by-Ny array, where p is the prediction horizon and Ny is the number of outputs.

`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.

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 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).

Optimization exit code, returned as one of the following:

• Positive Integer — Optimal solution found

• `0` — Feasible suboptimal solution found after the maximum number of iterations

• Negative integer — No feasible solution found

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

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.

Version History

Introduced in R2020a