Experimental.LinearMPCScheduledOptimizer ​
Gain-scheduled constrained optimizer of a bank of LinearMPC.jl controllers: at every tick the members whose weight w[j] (from LinearMPCScheduler) is positive solve their QP for the same state estimate, references, disturbances, generalized parameters and the same applied previous control, and the control output is the blend Σ_j w_j u_j of their first moves. With Nearest scheduling one member solves per tick, with Linear two (one exactly at a knot). Inputs and their widths follow the members' shared settings as for LinearMPCOptimizer.
Each member is solved by its own generated C code (or by LinearMPC.jl's Julia solver, see backend); the selection of the active members and the blending are Julia code that the synchronous code generator cross-compiles, so a model containing this component is exported to standalone C by CCodeExport with one library per member. exitflag is the composite DAQP exit flag of the active members: the first negative one when a member failed, else 2 when one reported active soft constraints, else 1, on either backend.
Blending the controls of neighbouring members is exact at the knots and first-order accurate between them; the input bounds hold for the blend (a convex combination), output and general constraints only approximately. See LinearMPCScheduledController.
This component extends from LinearMPCBankPart
Usage ​
MPCComponents.Experimental.LinearMPCScheduledOptimizer(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) | – | MPCComponen...mpc_nx(mpc) |
nu | Number of controls (derived from mpc) | – | MPCComponen...mpc_nu(mpc) |
ny_meas | Number of measured outputs, the rows of the observer's measurement matrix; 0 without an observer (derived from mpc) | – | MPCComponen...y_meas(mpc) |
ndo | Number of estimated offset-free disturbances, 0 for a plain Kalman filter (derived from mpc) | – | MPCComponen...pc_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) | – | MPCComponen..._nr_in(mpc) |
nd_in | Width of the measured-disturbance input: 0, nd_meas or nd_meas*Np (derived from mpc) | – | MPCComponen..._nd_in(mpc) |
np_in | Width of the generalized-parameter input: 0, np or np*Np (derived from mpc) | – | MPCComponen..._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 |
N | Number of controllers in the bank (derived from mpc) | – | _lmpc_bank_N(mpc) |
backend | QP solver backend; Auto uses the compiled C code when a C compiler is available | – | MPCComponen...kend.Auto() |
precision | Float type of the generated QP code (C backend only) | – | MPCComponen...on.Double() |
use_c | Whether the compiled C code solves the QPs (resolved from backend; building the members' libraries on first use) | – | lmpc_bank... precision) |
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) |
u0 | Control assumed applied before the first tick, by default the operating-point control of the members | – | _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)w- 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 | – |
Behavior ​
Behavior of this component cannot be rendered because it includes path variables.
Source ​
"""
Gain-scheduled constrained optimizer of a bank of LinearMPC.jl controllers: at every tick the
members whose weight `w[j]` (from `LinearMPCScheduler`) is positive solve their QP for the same
state estimate, references, disturbances, generalized parameters and the same applied previous
control, and the control output is the blend `Σ_j w_j u_j` of their first moves. With `Nearest`
scheduling one member solves per tick, with `Linear` two (one exactly at a knot). Inputs and their
widths follow the members' shared settings as for `LinearMPCOptimizer`.
Each member is solved by its own generated C code (or by LinearMPC.jl's Julia solver, see
`backend`); the selection of the active members and the blending are Julia code that the
synchronous code generator cross-compiles, so a model containing this component is exported to
standalone C by `CCodeExport` with one library per member. `exitflag` is the composite DAQP exit
flag of the active members: the first negative one when a member failed, else 2 when one reported
active soft constraints, else 1, on either backend.
Blending the controls of neighbouring members is exact at the knots and first-order accurate
between them; the input bounds hold for the blend (a convex combination), output and general
constraints only approximately. See `LinearMPCScheduledController`.
"""
component LinearMPCScheduledOptimizer
extends LinearMPCBankPart()
"State estimate at the current tick"
xhat = [RealInput@[clk]() for i in 1:nx] {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 535, "x2": 0, "y2": 635}}}
}
"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": 35, "x2": 0, "y2": 135}}}}
"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": 700, "x2": 0, "y2": 800}}}
}
"Estimated offset-free disturbances from LinearMPCScheduledObserver (only for offset-free observers)"
dhat = [RealInput@[clk]() for i in 1:ndo] if has_dhat {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 865, "x2": 0, "y2": 965}}}
}
"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": 200, "x2": 0, "y2": 300}}}
}
"Member weights from LinearMPCScheduler"
w = [RealInput@[clk]() for j in 1:N] {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 365, "x2": 0, "y2": 465}}}
}
"Control signal (blend of the active members' first moves)"
u = [RealOutput@[clk]() for i in 1:nu] {
"Dyad": {"placement": {"diagram": {"x1": 1000, "y1": 700, "x2": 1100, "y2": 800}}}
}
"Composite solver status of the last step (first negative member flag, else 2 with active soft constraints, else 1), on either backend"
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::MPCComponents.Backend = MPCComponents.Backend.Auto()
"Float type of the generated QP code (C backend only)"
structural parameter precision::MPCComponents.MPCPrecision = MPCComponents.MPCPrecision.Double()
"Whether the compiled C code solves the QPs (resolved from backend; building the members' libraries on first use)"
final structural parameter use_c::Boolean = _lmpc_bank_use_c(mpc, backend, precision)
"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)
"Control assumed applied before the first tick, by default the operating-point control of the members"
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]
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 scalar solve per tick (the composite flag), the blended control read back through an
# accessor that depends on it; see LinearMPCOptimizer. The blended control of the previous tick
# is the previous control every member sees.
if use_c
exitflag@clk = lmpc_bank_solve_c(w@clk, 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_bank_u_c(exitflag, w, i, mpc)
end
else
exitflag@clk = lmpc_bank_solve(w@clk, 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_bank_u(exitflag, w, i, mpc)
end
end
metadata {
"Dyad": {
"icons": {"default": "dyad://MPCComponents/LinearMPCScheduledOptimizer.svg"},
"doc": {"behavior": false}
}
}
endFlattened Source
"""
Gain-scheduled constrained optimizer of a bank of LinearMPC.jl controllers: at every tick the
members whose weight `w[j]` (from `LinearMPCScheduler`) is positive solve their QP for the same
state estimate, references, disturbances, generalized parameters and the same applied previous
control, and the control output is the blend `Σ_j w_j u_j` of their first moves. With `Nearest`
scheduling one member solves per tick, with `Linear` two (one exactly at a knot). Inputs and their
widths follow the members' shared settings as for `LinearMPCOptimizer`.
Each member is solved by its own generated C code (or by LinearMPC.jl's Julia solver, see
`backend`); the selection of the active members and the blending are Julia code that the
synchronous code generator cross-compiles, so a model containing this component is exported to
standalone C by `CCodeExport` with one library per member. `exitflag` is the composite DAQP exit
flag of the active members: the first negative one when a member failed, else 2 when one reported
active soft constraints, else 1, on either backend.
Blending the controls of neighbouring members is exact at the knots and first-order accurate
between them; the input bounds hold for the blend (a convex combination), output and general
constraints only approximately. See `LinearMPCScheduledController`.
"""
component LinearMPCScheduledOptimizer
"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
"Number of controllers in the bank (derived from mpc)"
final structural parameter N::Integer = _lmpc_bank_N(mpc)
"State estimate at the current tick"
xhat = [RealInput@[clk]() for i in 1:nx] {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 535, "x2": 0, "y2": 635}}}
}
"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": 35, "x2": 0, "y2": 135}}}}
"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": 700, "x2": 0, "y2": 800}}}
}
"Estimated offset-free disturbances from LinearMPCScheduledObserver (only for offset-free observers)"
dhat = [RealInput@[clk]() for i in 1:ndo] if has_dhat {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 865, "x2": 0, "y2": 965}}}
}
"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": 200, "x2": 0, "y2": 300}}}
}
"Member weights from LinearMPCScheduler"
w = [RealInput@[clk]() for j in 1:N] {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 365, "x2": 0, "y2": 465}}}
}
"Control signal (blend of the active members' first moves)"
u = [RealOutput@[clk]() for i in 1:nu] {
"Dyad": {"placement": {"diagram": {"x1": 1000, "y1": 700, "x2": 1100, "y2": 800}}}
}
"Composite solver status of the last step (first negative member flag, else 2 with active soft constraints, else 1), on either backend"
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::MPCComponents.Backend = MPCComponents.Backend.Auto()
"Float type of the generated QP code (C backend only)"
structural parameter precision::MPCComponents.MPCPrecision = MPCComponents.MPCPrecision.Double()
"Whether the compiled C code solves the QPs (resolved from backend; building the members' libraries on first use)"
final structural parameter use_c::Boolean = _lmpc_bank_use_c(mpc, backend, precision)
"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)
"Control assumed applied before the first tick, by default the operating-point control of the members"
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]
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 scalar solve per tick (the composite flag), the blended control read back through an
# accessor that depends on it; see LinearMPCOptimizer. The blended control of the previous tick
# is the previous control every member sees.
if use_c
exitflag@clk = lmpc_bank_solve_c(w@clk, 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_bank_u_c(exitflag, w, i, mpc)
end
else
exitflag@clk = lmpc_bank_solve(w@clk, 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_bank_u(exitflag, w, i, mpc)
end
end
metadata {
"Dyad": {
"icons": {"default": "dyad://MPCComponents/LinearMPCScheduledOptimizer.svg"},
"doc": {"behavior": false}
}
}
endTest Cases ​
No test cases defined.
Related ​
Examples
Experiments
Analyses