LinearMPCOptimizer ​
Constrained finite-horizon optimizer of a LinearMPC.jl controller, run as a clocked component.
At every tick the parameter vector [x; r; d; u_prev; p] is formed from the state estimate xhat, the references r, the measured disturbances d (stacked on the estimated disturbances dhat of an offset-free observer), the generalized parameters p and the control applied at the previous tick, the QP (or MIQP, for binary control inputs) is solved with DAQP, and the first move of the optimal control sequence is output as u. Which inputs exist and how wide they are follows from the settings of the MPC object (reference_tracking, reference_preview, disturbance_preview, parameter_preview). Preview trajectories are flat column-major vectors: r[(j-1)*ny + i] is reference i at prediction step j, and likewise for d and p.
The QP is solved either by the C code LinearMPC.jl generates for the controller, compiled into a library and called through a ccall (which is also what makes a model containing this component exportable to standalone C), or by LinearMPC.jl's Julia solver (DyadLinearMPC.solve, the QP behind compute_control); see backend (Backend) and precision (MPCPrecision, the float type of the generated C). Both use DAQP and agree to solver tolerance, and both report the DAQP exit flag of the last solve on the exitflag output (1 optimal, 2 optimal with active soft constraints, negative when the QP is infeasible or the solver failed, in which case the control is the solver's last iterate).
All weights and constraints are fixed at model-build time and are not tunable parameters. The control must be held (ZeroOrderHold) outside this component. Used on its own with the plant state connected to xhat, this is a state-feedback MPC; see LinearMPCController for the combination with LinearMPCObserver and for the list of options.
This component extends from LinearMPCPart
Usage ​
MPCComponents.LinearMPCOptimizer(u0=_lmpc_u0(mpc), r_dummy=fill(0.0, nr_eff), d_dummy=fill(0.0, nd_eff), dhat_dummy=fill(0.0, ndo_eff), p_dummy=fill(0.0, np_eff))
Parameters: ​
| Name | Description | Units | Default value |
|---|---|---|---|
mpc | Set-up LinearMPC.jl MPC object wrapped in an MPCRef (see build_linear_mpc) | – | |
nx | State dimension of the model (derived from mpc) | – | _lmpc_nx(mpc) |
nu | Number of controls (derived from mpc) | – | _lmpc_nu(mpc) |
ny_meas | Number of measured outputs, the rows of the observer's measurement matrix; 0 without an observer (derived from mpc) | – | _lmpc_ny_meas(mpc) |
ndo | Number of estimated offset-free disturbances, 0 for a plain Kalman filter (derived from mpc) | – | _lmpc_ndo(mpc) |
nxa | Length of the augmented observer state, nx + ndo (derived) | – | nx + ndo |
nr_in | Width of the reference input: 0, ny or ny*Np (derived from mpc) | – | _lmpc_nr_in(mpc) |
nd_in | Width of the measured-disturbance input: 0, nd_meas or nd_meas*Np (derived from mpc) | – | _lmpc_nd_in(mpc) |
np_in | Width of the generalized-parameter input: 0, np or np*Np (derived from mpc) | – | _lmpc_np_in(mpc) |
has_r | Whether the r connector exists (derived) | – | nr_in > 0 |
has_d | Whether the d connector exists (derived) | – | nd_in > 0 |
has_dhat | Whether the dhat connector exists (derived) | – | ndo > 0 |
has_p | Whether the p connector exists (derived) | – | np_in > 0 |
backend | QP solver backend; Auto uses the compiled C code when a C compiler is available | – | Backend.Auto() |
precision | Float type of the generated QP code (C backend only) | – | MPCPrecision.Double() |
output_trajectories | Also record the predicted state, control and output trajectories and the QP statistics of every tick (variables x_pred, u_pred, y_pred, stats), for debugging and mpc_gui; Julia backend only. The readbacks are four equations whose number does not grow with the prediction horizon, though the trajectories themselves are stored in the solution; output_statistics records the statistics alone | – | false |
output_statistics | Record the QP statistics of every tick (variable stats) without the predicted trajectories; Julia backend only. One equation. Implied by output_trajectories | – | false |
use_c | Whether the compiled C code solves the QP (resolved from backend; building the library on first use) | – | _lmpc_use_c...statistics) |
record_stats | Whether the step records the QP statistics, from either flag (derived) | – | _lmpc_recor...statistics) |
nr_eff | Width of the internal reference vector, max(nr_in, 1) (derived) | – | max(nr_in, 1) |
nd_eff | Width of the internal disturbance vector, max(nd_in, 1) (derived) | – | max(nd_in, 1) |
ndo_eff | Width of the internal estimated-disturbance vector, max(ndo, 1) (derived) | – | max(ndo, 1) |
np_eff | Width of the internal generalized-parameter vector, max(np_in, 1) (derived) | – | max(np_in, 1) |
nxp | Length of the predicted state trajectory, (Np + 1) nx (derived from mpc) | – | _lmpc_nxp(mpc) |
nup | Length of the predicted control trajectory, Np nu (derived from mpc) | – | _lmpc_nup(mpc) |
nyp | Length of the predicted output trajectory, (Np + 1) ny (derived from mpc) | – | _lmpc_nyp(mpc) |
u0 | Control assumed applied before the first tick, by default the operating-point control of the MPC object | – | _lmpc_u0(mpc) |
Connectors ​
xhat- This connector represents a real signal as an input to a component (RealInput)r- This connector represents a real signal as an input to a component (RealInput)d- This connector represents a real signal as an input to a component (RealInput)dhat- This connector represents a real signal as an input to a component (RealInput)p- This connector represents a real signal as an input to a component (RealInput)u- This connector represents a real signal as an output from a component (RealOutput)exitflag- This connector represents a real signal as an output from a component (RealOutput)
Variables ​
| Name | Description | Units |
|---|---|---|
r_int | Reference vector handed to the step function | – |
d_int | Disturbance vector handed to the step function | – |
dhat_int | Estimated-disturbance vector handed to the step function | – |
p_int | Generalized-parameter vector handed to the step function | – |
x_pred | Predicted states at stages 0..Np, column-major nx × (Np+1) (only with output_trajectories) | – |
u_pred | Predicted controls at stages 0..Np-1, column-major nu × Np (only with output_trajectories) | – |
y_pred | Predicted outputs C x + Dd d + h_offset of the prediction model at stages 0..Np, column-major ny × (Np+1) (only with output_trajectories) | – |
stats | Statistics of the QP: objective value, solve time in seconds, active-set iterations, branch-and-bound nodes (with output_statistics or output_trajectories) | – |
Behavior ​
Behavior of this component cannot be rendered because it includes path variables.
Source ​
"""
Constrained finite-horizon optimizer of a LinearMPC.jl controller, run as a clocked component.
At every tick the parameter vector `[x; r; d; u_prev; p]` is formed from the state estimate
`xhat`, the references `r`, the measured disturbances `d` (stacked on the estimated
disturbances `dhat` of an offset-free observer), the generalized parameters `p` and the control
applied at the previous tick, the QP (or MIQP, for binary control inputs) is solved with DAQP, and the
first move of the optimal control sequence is output as `u`. Which inputs exist and how wide
they are follows from the settings of the MPC object (`reference_tracking`, `reference_preview`,
`disturbance_preview`, `parameter_preview`). Preview trajectories are flat column-major vectors:
`r[(j-1)*ny + i]` is reference `i` at prediction step `j`, and likewise for `d` and `p`.
The QP is solved either by the C code LinearMPC.jl generates for the controller, compiled into a
library and called through a `ccall` (which is also what makes a model containing this component
exportable to standalone C), or by LinearMPC.jl's Julia solver (`DyadLinearMPC.solve`, the QP behind `compute_control`); see `backend`
(`Backend`) and `precision` (`MPCPrecision`, the float type of the generated C). Both use DAQP
and agree to solver tolerance, and both report the DAQP exit flag of the last solve on the
`exitflag` output (1 optimal, 2 optimal with active soft constraints, negative when the QP is
infeasible or the solver failed, in which case the control is the solver's last iterate).
All weights and constraints are fixed at model-build time and are not tunable parameters. The
control must be held (`ZeroOrderHold`) outside this component. Used on its own with the plant
state connected to `xhat`, this is a state-feedback MPC; see `LinearMPCController` for the
combination with `LinearMPCObserver` and for the list of options.
"""
component LinearMPCOptimizer
extends LinearMPCPart()
"State estimate at the current tick"
xhat = [RealInput@[clk]() for i in 1:nx] {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 450, "x2": 0, "y2": 550}}}
}
"References; ny entries, or ny*Np column-major entries with reference preview (only with reference_tracking)"
r = [RealInput@[clk]() for i in 1:nr_in] if has_r {"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 50, "x2": 0, "y2": 150}}}}
"Measured disturbances; nd_meas entries, or nd_meas*Np column-major entries with disturbance preview"
d = [RealInput@[clk]() for i in 1:nd_in] if has_d {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 650, "x2": 0, "y2": 750}}}
}
"Estimated offset-free disturbances from LinearMPCObserver (only for an offset-free observer)"
dhat = [RealInput@[clk]() for i in 1:ndo] if has_dhat {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 850, "x2": 0, "y2": 950}}}
}
"Generalized parameters; np entries, or np*Np column-major entries with parameter preview"
p = [RealInput@[clk]() for i in 1:np_in] if has_p {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 250, "x2": 0, "y2": 350}}}
}
"Control signal (first move of the optimal sequence)"
u = [RealOutput@[clk]() for i in 1:nu] {
"Dyad": {"placement": {"diagram": {"x1": 1000, "y1": 700, "x2": 1100, "y2": 800}}}
}
"Solver status of the last step: the DAQP exit flag (1 optimal, 2 with active soft constraints, negative on failure), from the generated C code or from the Julia solve; lmpc_status_name names it"
exitflag = RealOutput@[clk]() {
"Dyad": {"placement": {"diagram": {"x1": 1000, "y1": 200, "x2": 1100, "y2": 300}}}
}
"QP solver backend; Auto uses the compiled C code when a C compiler is available"
structural parameter backend::Backend = Backend.Auto()
"Float type of the generated QP code (C backend only)"
structural parameter precision::MPCPrecision = MPCPrecision.Double()
"Also record the predicted state, control and output trajectories and the QP statistics of every tick (variables x_pred, u_pred, y_pred, stats), for debugging and mpc_gui; Julia backend only. The readbacks are four equations whose number does not grow with the prediction horizon, though the trajectories themselves are stored in the solution; output_statistics records the statistics alone"
structural parameter output_trajectories::Boolean = false
"Record the QP statistics of every tick (variable stats) without the predicted trajectories; Julia backend only. One equation. Implied by output_trajectories"
structural parameter output_statistics::Boolean = false
"Whether the compiled C code solves the QP (resolved from backend; building the library on first use)"
final structural parameter use_c::Boolean = _lmpc_use_c(mpc, backend, precision, output_trajectories, output_statistics)
"Whether the step records the QP statistics, from either flag (derived)"
final structural parameter record_stats::Boolean = _lmpc_record_stats(output_trajectories, output_statistics)
"Width of the internal reference vector, max(nr_in, 1) (derived)"
final structural parameter nr_eff::Integer = max(nr_in, 1)
"Width of the internal disturbance vector, max(nd_in, 1) (derived)"
final structural parameter nd_eff::Integer = max(nd_in, 1)
"Width of the internal estimated-disturbance vector, max(ndo, 1) (derived)"
final structural parameter ndo_eff::Integer = max(ndo, 1)
"Width of the internal generalized-parameter vector, max(np_in, 1) (derived)"
final structural parameter np_eff::Integer = max(np_in, 1)
"Length of the predicted state trajectory, (Np + 1) nx (derived from mpc)"
final structural parameter nxp::Integer = _lmpc_nxp(mpc)
"Length of the predicted control trajectory, Np nu (derived from mpc)"
final structural parameter nup::Integer = _lmpc_nup(mpc)
"Length of the predicted output trajectory, (Np + 1) ny (derived from mpc)"
final structural parameter nyp::Integer = _lmpc_nyp(mpc)
"Control assumed applied before the first tick, by default the operating-point control of the MPC object"
parameter u0::Real[nu] = _lmpc_u0(mpc)
"Zero placeholder passed as the reference argument when r is absent"
final parameter r_dummy::Real[nr_eff] = fill(0.0, nr_eff)
"Zero placeholder passed as the disturbance argument when d is absent"
final parameter d_dummy::Real[nd_eff] = fill(0.0, nd_eff)
"Zero placeholder passed as the estimated-disturbance argument when dhat is absent"
final parameter dhat_dummy::Real[ndo_eff] = fill(0.0, ndo_eff)
"Zero placeholder passed as the generalized-parameter argument when p is absent"
final parameter p_dummy::Real[np_eff] = fill(0.0, np_eff)
"Reference vector handed to the step function"
variable r_int::Real[nr_eff]
"Disturbance vector handed to the step function"
variable d_int::Real[nd_eff]
"Estimated-disturbance vector handed to the step function"
variable dhat_int::Real[ndo_eff]
"Generalized-parameter vector handed to the step function"
variable p_int::Real[np_eff]
"Predicted states at stages 0..Np, column-major nx × (Np+1) (only with output_trajectories)"
variable x_pred::Real[nxp] if output_trajectories
"Predicted controls at stages 0..Np-1, column-major nu × Np (only with output_trajectories)"
variable u_pred::Real[nup] if output_trajectories
"Predicted outputs C x + Dd d + h_offset of the prediction model at stages 0..Np, column-major ny × (Np+1) (only with output_trajectories)"
variable y_pred::Real[nyp] if output_trajectories
"Statistics of the QP: objective value, solve time in seconds, active-set iterations, branch-and-bound nodes (with output_statistics or output_trajectories)"
variable stats::Real[4] if record_stats
relations
if has_r
r_int = r
else
r_int = r_dummy
end
if has_d
d_int = d
else
d_int = d_dummy
end
if has_dhat
dhat_int = dhat
else
dhat_int = dhat_dummy
end
if has_p
p_int = p
else
p_int = p_dummy
end
initial u@(clk-1) = u0
# One QP solve per tick: the scalar exit flag is the only result of the call, and the control is
# read back through an accessor that depends on it, so that no consumer can duplicate the solve.
# The recorded trajectories and statistics are pure reads of what that solve left behind, and are
# taken a whole buffer at a time: the clocked compiler keeps an array-valued equation intact and
# emits a single call for it, so their cost does not grow with the prediction horizon.
if use_c
exitflag@clk = lmpc_solve_c(xhat@clk, r_int@clk, d_int@clk, dhat_int@clk, p_int@clk, u@(clk-1), mpc)
for i in 1:nu
u[i] = lmpc_u_c(exitflag, i, mpc)
end
elseif output_trajectories
exitflag@clk = lmpc_solve_full(xhat@clk, r_int@clk, d_int@clk, dhat_int@clk, p_int@clk, u@(clk-1), mpc)
for i in 1:nu
u[i] = lmpc_u(exitflag, i, mpc)
end
x_pred = lmpc_x_pred_vec(exitflag, mpc)
u_pred = lmpc_u_pred_vec(exitflag, mpc)
y_pred = lmpc_y_pred_vec(exitflag, mpc)
stats = lmpc_stats_vec(exitflag, mpc)
elseif output_statistics
# The same recording step, read back only through the four statistics. The trajectories are
# still computed into the bundle, but they cost no equations and no storage in the model.
exitflag@clk = lmpc_solve_full(xhat@clk, r_int@clk, d_int@clk, dhat_int@clk, p_int@clk, u@(clk-1), mpc)
for i in 1:nu
u[i] = lmpc_u(exitflag, i, mpc)
end
stats = lmpc_stats_vec(exitflag, mpc)
else
exitflag@clk = lmpc_solve(xhat@clk, r_int@clk, d_int@clk, dhat_int@clk, p_int@clk, u@(clk-1), mpc)
for i in 1:nu
u[i] = lmpc_u(exitflag, i, mpc)
end
end
metadata {
"Dyad": {
"icons": {"default": "dyad://MPCComponents/LinearMPCOptimizer.svg"},
"doc": {"behavior": false}
}
}
endFlattened Source
"""
Constrained finite-horizon optimizer of a LinearMPC.jl controller, run as a clocked component.
At every tick the parameter vector `[x; r; d; u_prev; p]` is formed from the state estimate
`xhat`, the references `r`, the measured disturbances `d` (stacked on the estimated
disturbances `dhat` of an offset-free observer), the generalized parameters `p` and the control
applied at the previous tick, the QP (or MIQP, for binary control inputs) is solved with DAQP, and the
first move of the optimal control sequence is output as `u`. Which inputs exist and how wide
they are follows from the settings of the MPC object (`reference_tracking`, `reference_preview`,
`disturbance_preview`, `parameter_preview`). Preview trajectories are flat column-major vectors:
`r[(j-1)*ny + i]` is reference `i` at prediction step `j`, and likewise for `d` and `p`.
The QP is solved either by the C code LinearMPC.jl generates for the controller, compiled into a
library and called through a `ccall` (which is also what makes a model containing this component
exportable to standalone C), or by LinearMPC.jl's Julia solver (`DyadLinearMPC.solve`, the QP behind `compute_control`); see `backend`
(`Backend`) and `precision` (`MPCPrecision`, the float type of the generated C). Both use DAQP
and agree to solver tolerance, and both report the DAQP exit flag of the last solve on the
`exitflag` output (1 optimal, 2 optimal with active soft constraints, negative when the QP is
infeasible or the solver failed, in which case the control is the solver's last iterate).
All weights and constraints are fixed at model-build time and are not tunable parameters. The
control must be held (`ZeroOrderHold`) outside this component. Used on its own with the plant
state connected to `xhat`, this is a state-feedback MPC; see `LinearMPCController` for the
combination with `LinearMPCObserver` and for the list of options.
"""
component LinearMPCOptimizer
"Set-up LinearMPC.jl MPC object wrapped in an MPCRef (see build_linear_mpc)"
structural parameter mpc::MPCRef
"State dimension of the model (derived from mpc)"
final structural parameter nx::Integer = _lmpc_nx(mpc)
"Number of controls (derived from mpc)"
final structural parameter nu::Integer = _lmpc_nu(mpc)
"Number of measured outputs, the rows of the observer's measurement matrix; 0 without an observer (derived from mpc)"
final structural parameter ny_meas::Integer = _lmpc_ny_meas(mpc)
"Number of estimated offset-free disturbances, 0 for a plain Kalman filter (derived from mpc)"
final structural parameter ndo::Integer = _lmpc_ndo(mpc)
"Length of the augmented observer state, nx + ndo (derived)"
final structural parameter nxa::Integer = nx + ndo
"Width of the reference input: 0, ny or ny*Np (derived from mpc)"
final structural parameter nr_in::Integer = _lmpc_nr_in(mpc)
"Width of the measured-disturbance input: 0, nd_meas or nd_meas*Np (derived from mpc)"
final structural parameter nd_in::Integer = _lmpc_nd_in(mpc)
"Width of the generalized-parameter input: 0, np or np*Np (derived from mpc)"
final structural parameter np_in::Integer = _lmpc_np_in(mpc)
"Whether the r connector exists (derived)"
final structural parameter has_r::Boolean = nr_in > 0
"Whether the d connector exists (derived)"
final structural parameter has_d::Boolean = nd_in > 0
"Whether the dhat connector exists (derived)"
final structural parameter has_dhat::Boolean = ndo > 0
"Whether the p connector exists (derived)"
final structural parameter has_p::Boolean = np_in > 0
"State estimate at the current tick"
xhat = [RealInput@[clk]() for i in 1:nx] {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 450, "x2": 0, "y2": 550}}}
}
"References; ny entries, or ny*Np column-major entries with reference preview (only with reference_tracking)"
r = [RealInput@[clk]() for i in 1:nr_in] if has_r {"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 50, "x2": 0, "y2": 150}}}}
"Measured disturbances; nd_meas entries, or nd_meas*Np column-major entries with disturbance preview"
d = [RealInput@[clk]() for i in 1:nd_in] if has_d {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 650, "x2": 0, "y2": 750}}}
}
"Estimated offset-free disturbances from LinearMPCObserver (only for an offset-free observer)"
dhat = [RealInput@[clk]() for i in 1:ndo] if has_dhat {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 850, "x2": 0, "y2": 950}}}
}
"Generalized parameters; np entries, or np*Np column-major entries with parameter preview"
p = [RealInput@[clk]() for i in 1:np_in] if has_p {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 250, "x2": 0, "y2": 350}}}
}
"Control signal (first move of the optimal sequence)"
u = [RealOutput@[clk]() for i in 1:nu] {
"Dyad": {"placement": {"diagram": {"x1": 1000, "y1": 700, "x2": 1100, "y2": 800}}}
}
"Solver status of the last step: the DAQP exit flag (1 optimal, 2 with active soft constraints, negative on failure), from the generated C code or from the Julia solve; lmpc_status_name names it"
exitflag = RealOutput@[clk]() {
"Dyad": {"placement": {"diagram": {"x1": 1000, "y1": 200, "x2": 1100, "y2": 300}}}
}
"QP solver backend; Auto uses the compiled C code when a C compiler is available"
structural parameter backend::Backend = Backend.Auto()
"Float type of the generated QP code (C backend only)"
structural parameter precision::MPCPrecision = MPCPrecision.Double()
"Also record the predicted state, control and output trajectories and the QP statistics of every tick (variables x_pred, u_pred, y_pred, stats), for debugging and mpc_gui; Julia backend only. The readbacks are four equations whose number does not grow with the prediction horizon, though the trajectories themselves are stored in the solution; output_statistics records the statistics alone"
structural parameter output_trajectories::Boolean = false
"Record the QP statistics of every tick (variable stats) without the predicted trajectories; Julia backend only. One equation. Implied by output_trajectories"
structural parameter output_statistics::Boolean = false
"Whether the compiled C code solves the QP (resolved from backend; building the library on first use)"
final structural parameter use_c::Boolean = _lmpc_use_c(mpc, backend, precision, output_trajectories, output_statistics)
"Whether the step records the QP statistics, from either flag (derived)"
final structural parameter record_stats::Boolean = _lmpc_record_stats(output_trajectories, output_statistics)
"Width of the internal reference vector, max(nr_in, 1) (derived)"
final structural parameter nr_eff::Integer = max(nr_in, 1)
"Width of the internal disturbance vector, max(nd_in, 1) (derived)"
final structural parameter nd_eff::Integer = max(nd_in, 1)
"Width of the internal estimated-disturbance vector, max(ndo, 1) (derived)"
final structural parameter ndo_eff::Integer = max(ndo, 1)
"Width of the internal generalized-parameter vector, max(np_in, 1) (derived)"
final structural parameter np_eff::Integer = max(np_in, 1)
"Length of the predicted state trajectory, (Np + 1) nx (derived from mpc)"
final structural parameter nxp::Integer = _lmpc_nxp(mpc)
"Length of the predicted control trajectory, Np nu (derived from mpc)"
final structural parameter nup::Integer = _lmpc_nup(mpc)
"Length of the predicted output trajectory, (Np + 1) ny (derived from mpc)"
final structural parameter nyp::Integer = _lmpc_nyp(mpc)
"Control assumed applied before the first tick, by default the operating-point control of the MPC object"
parameter u0::Real[nu] = _lmpc_u0(mpc)
"Zero placeholder passed as the reference argument when r is absent"
final parameter r_dummy::Real[nr_eff] = fill(0.0, nr_eff)
"Zero placeholder passed as the disturbance argument when d is absent"
final parameter d_dummy::Real[nd_eff] = fill(0.0, nd_eff)
"Zero placeholder passed as the estimated-disturbance argument when dhat is absent"
final parameter dhat_dummy::Real[ndo_eff] = fill(0.0, ndo_eff)
"Zero placeholder passed as the generalized-parameter argument when p is absent"
final parameter p_dummy::Real[np_eff] = fill(0.0, np_eff)
"Reference vector handed to the step function"
variable r_int::Real[nr_eff]
"Disturbance vector handed to the step function"
variable d_int::Real[nd_eff]
"Estimated-disturbance vector handed to the step function"
variable dhat_int::Real[ndo_eff]
"Generalized-parameter vector handed to the step function"
variable p_int::Real[np_eff]
"Predicted states at stages 0..Np, column-major nx × (Np+1) (only with output_trajectories)"
variable x_pred::Real[nxp] if output_trajectories
"Predicted controls at stages 0..Np-1, column-major nu × Np (only with output_trajectories)"
variable u_pred::Real[nup] if output_trajectories
"Predicted outputs C x + Dd d + h_offset of the prediction model at stages 0..Np, column-major ny × (Np+1) (only with output_trajectories)"
variable y_pred::Real[nyp] if output_trajectories
"Statistics of the QP: objective value, solve time in seconds, active-set iterations, branch-and-bound nodes (with output_statistics or output_trajectories)"
variable stats::Real[4] if record_stats
relations
if has_r
r_int = r
else
r_int = r_dummy
end
if has_d
d_int = d
else
d_int = d_dummy
end
if has_dhat
dhat_int = dhat
else
dhat_int = dhat_dummy
end
if has_p
p_int = p
else
p_int = p_dummy
end
initial u@(clk-1) = u0
# One QP solve per tick: the scalar exit flag is the only result of the call, and the control is
# read back through an accessor that depends on it, so that no consumer can duplicate the solve.
# The recorded trajectories and statistics are pure reads of what that solve left behind, and are
# taken a whole buffer at a time: the clocked compiler keeps an array-valued equation intact and
# emits a single call for it, so their cost does not grow with the prediction horizon.
if use_c
exitflag@clk = lmpc_solve_c(xhat@clk, r_int@clk, d_int@clk, dhat_int@clk, p_int@clk, u@(clk-1), mpc)
for i in 1:nu
u[i] = lmpc_u_c(exitflag, i, mpc)
end
elseif output_trajectories
exitflag@clk = lmpc_solve_full(xhat@clk, r_int@clk, d_int@clk, dhat_int@clk, p_int@clk, u@(clk-1), mpc)
for i in 1:nu
u[i] = lmpc_u(exitflag, i, mpc)
end
x_pred = lmpc_x_pred_vec(exitflag, mpc)
u_pred = lmpc_u_pred_vec(exitflag, mpc)
y_pred = lmpc_y_pred_vec(exitflag, mpc)
stats = lmpc_stats_vec(exitflag, mpc)
elseif output_statistics
# The same recording step, read back only through the four statistics. The trajectories are
# still computed into the bundle, but they cost no equations and no storage in the model.
exitflag@clk = lmpc_solve_full(xhat@clk, r_int@clk, d_int@clk, dhat_int@clk, p_int@clk, u@(clk-1), mpc)
for i in 1:nu
u[i] = lmpc_u(exitflag, i, mpc)
end
stats = lmpc_stats_vec(exitflag, mpc)
else
exitflag@clk = lmpc_solve(xhat@clk, r_int@clk, d_int@clk, dhat_int@clk, p_int@clk, u@(clk-1), mpc)
for i in 1:nu
u[i] = lmpc_u(exitflag, i, mpc)
end
end
metadata {
"Dyad": {
"icons": {"default": "dyad://MPCComponents/LinearMPCOptimizer.svg"},
"doc": {"behavior": false}
}
}
endTest Cases ​
No test cases defined.
Related ​
Examples
Experiments
Analyses