Skip to content
LIBRARY
LinearMPCOptimizer.md

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: ​

NameDescriptionUnitsDefault value
mpcSet-up LinearMPC.jl MPC object wrapped in an MPCRef (see build_linear_mpc)–
nxState dimension of the model (derived from mpc)–_lmpc_nx(mpc)
nuNumber of controls (derived from mpc)–_lmpc_nu(mpc)
ny_measNumber of measured outputs, the rows of the observer's measurement matrix; 0 without an observer (derived from mpc)–_lmpc_ny_meas(mpc)
ndoNumber of estimated offset-free disturbances, 0 for a plain Kalman filter (derived from mpc)–_lmpc_ndo(mpc)
nxaLength of the augmented observer state, nx + ndo (derived)–nx + ndo
nr_inWidth of the reference input: 0, ny or ny*Np (derived from mpc)–_lmpc_nr_in(mpc)
nd_inWidth of the measured-disturbance input: 0, nd_meas or nd_meas*Np (derived from mpc)–_lmpc_nd_in(mpc)
np_inWidth of the generalized-parameter input: 0, np or np*Np (derived from mpc)–_lmpc_np_in(mpc)
has_rWhether the r connector exists (derived)–nr_in > 0
has_dWhether the d connector exists (derived)–nd_in > 0
has_dhatWhether the dhat connector exists (derived)–ndo > 0
has_pWhether the p connector exists (derived)–np_in > 0
backendQP solver backend; Auto uses the compiled C code when a C compiler is available–Backend.Auto()
precisionFloat type of the generated QP code (C backend only)–MPCPrecision.Double()
output_trajectoriesAlso 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_statisticsRecord the QP statistics of every tick (variable stats) without the predicted trajectories; Julia backend only. One equation. Implied by output_trajectories–false
use_cWhether the compiled C code solves the QP (resolved from backend; building the library on first use)–_lmpc_use_c...statistics)
record_statsWhether the step records the QP statistics, from either flag (derived)–_lmpc_recor...statistics)
nr_effWidth of the internal reference vector, max(nr_in, 1) (derived)–max(nr_in, 1)
nd_effWidth of the internal disturbance vector, max(nd_in, 1) (derived)–max(nd_in, 1)
ndo_effWidth of the internal estimated-disturbance vector, max(ndo, 1) (derived)–max(ndo, 1)
np_effWidth of the internal generalized-parameter vector, max(np_in, 1) (derived)–max(np_in, 1)
nxpLength of the predicted state trajectory, (Np + 1) nx (derived from mpc)–_lmpc_nxp(mpc)
nupLength of the predicted control trajectory, Np nu (derived from mpc)–_lmpc_nup(mpc)
nypLength of the predicted output trajectory, (Np + 1) ny (derived from mpc)–_lmpc_nyp(mpc)
u0Control 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 ​

NameDescriptionUnits
r_intReference vector handed to the step function–
d_intDisturbance vector handed to the step function–
dhat_intEstimated-disturbance vector handed to the step function–
p_intGeneralized-parameter vector handed to the step function–
x_predPredicted states at stages 0..Np, column-major nx × (Np+1) (only with output_trajectories)–
u_predPredicted controls at stages 0..Np-1, column-major nu × Np (only with output_trajectories)–
y_predPredicted outputs C x + Dd d + h_offset of the prediction model at stages 0..Np, column-major ny × (Np+1) (only with output_trajectories)–
statsStatistics 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 ​

dyad
"""
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}
  }
}
end
Flattened Source
dyad
"""
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}
  }
}
end


Test Cases ​

No test cases defined.

  • Examples

  • Experiments

  • Analyses