Experimental.LinearMPCScheduledObserver ​
Gain-scheduled state observer of a bank of LinearMPC.jl controllers: the steady-state Kalman filters (or offset-free observers) of the members, blended with the member weights w of LinearMPCScheduler. With F_j, G_j, ... the estimator matrices of member j, the recursion of LinearMPCObserver is run with the blended matrices Σ_j w_j F_j etc.:
The members' matrices are stacked side by side into final parameters at model-build time and multiplied with the Kronecker product of the weights and the vectors, so the component remains plain matrix arithmetic and is exported to C like LinearMPCObserver. The blended Kalman gain is the usual gain-scheduled observer, exact at the knots. See LinearMPCScheduledController.
This component extends from LinearMPCBankPart
Usage ​
MPCComponents.Experimental.LinearMPCScheduledObserver(xaug0=_lmpc_xaug0(mpc), d_dummy=fill(0.0, nd_eff), Fs=_lmpc_bank_obs_F(mpc), Gs=_lmpc_bank_obs_G(mpc), Gds=_lmpc_bank_obs_Gd(mpc, nd_eff), fs=_lmpc_bank_obs_f(mpc), Cs=_lmpc_bank_obs_C(mpc), Dds=_lmpc_bank_obs_Dd(mpc, nd_eff), hs=_lmpc_bank_obs_h(mpc), Ks=_lmpc_bank_obs_K(mpc))
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) |
nd_eff | Width of the internal disturbance vector, max(nd_in, 1) (derived) | – | max(nd_in, 1) |
nwx | Width of the stacked state matrices and of the weight-state Kronecker products, N*nxa (derived) | – | N * nxa |
nwu | Width of the stacked input matrices, N*nu (derived) | – | N * nu |
nwd | Width of the stacked disturbance matrices, N*nd_eff (derived) | – | N * nd_eff |
nwi | Width of the stacked Kalman gains, N*ny_meas (derived) | – | N * ny_meas |
xaug0 | Initial augmented state estimate [x0; d0], by default the one stored in the members | – | _lmpc_xaug0(mpc) |
Connectors ​
y- This connector represents a real signal as an input to a component (RealInput)u- 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)w- This connector represents a real signal as an input to a component (RealInput)xhat- This connector represents a real signal as an output from a component (RealOutput)dhat- This connector represents a real signal as an output from a component (RealOutput)
Variables ​
| Name | Description | Units |
|---|---|---|
xpred | Augmented state predicted for the current tick, before correction | – |
xprev | The prediction made at the previous tick, i.e. xpred delayed by one tick | – |
xcorr | Augmented state after correction with the current measurement | – |
innov | Innovation, the measurement minus its blended prediction | – |
d_int | Disturbance vector used by the observer equations | – |
wxp | Kronecker product of the weights and xprev | – |
wx | Kronecker product of the weights and xcorr | – |
wu | Kronecker product of the weights and u | – |
wd | Kronecker product of the weights and d_int | – |
wi | Kronecker product of the weights and innov | – |
Behavior ​
Behavior of this component cannot be rendered because it includes path variables.
Source ​
"""
Gain-scheduled state observer of a bank of LinearMPC.jl controllers: the steady-state Kalman
filters (or offset-free observers) of the members, blended with the member weights `w` of
`LinearMPCScheduler`. With `F_j, G_j, ...` the estimator matrices of member `j`, the recursion of
`LinearMPCObserver` is run with the blended matrices `Σ_j w_j F_j` etc.:
```math
\\begin{aligned}
\\hat x_{k|k} &= \\hat x_{k|k-1} + \\textstyle\\sum_j w_j K_j\\,(y_k - \\sum_j w_j (C_j\\hat x_{k|k-1} + D_{d,j} d_k + h_j)) \\\\
\\hat x_{k+1|k} &= \\textstyle\\sum_j w_j (F_j\\hat x_{k|k} + G_j u_k + G_{d,j} d_k + f_j)
\\end{aligned}
```
The members' matrices are stacked side by side into `final` parameters at model-build time and
multiplied with the Kronecker product of the weights and the vectors, so the component remains
plain matrix arithmetic and is exported to C like `LinearMPCObserver`. The blended Kalman gain is
the usual gain-scheduled observer, exact at the knots. See `LinearMPCScheduledController`.
"""
component LinearMPCScheduledObserver
extends LinearMPCBankPart()
"Sampled measurements (the rows of the observers' measurement matrix)"
y = [RealInput@[clk]() for i in 1:ny_meas] {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 825, "x2": 0, "y2": 925}}}
}
"Control applied at the current tick, used to predict the estimate for the next tick"
u = [RealInput@[clk]() for i in 1:nu] {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 325, "x2": 0, "y2": 425}}}
}
"Measured disturbances; nd_meas entries, or nd_meas*Np column-major entries with disturbance preview (only the first nd_meas are used here)"
d = [RealInput@[clk]() for i in 1:nd_in] if has_d {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 575, "x2": 0, "y2": 675}}}
}
"Member weights from LinearMPCScheduler"
w = [RealInput@[clk]() for j in 1:N] {"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 75, "x2": 0, "y2": 175}}}}
"State estimate corrected with the current measurement"
xhat = [RealOutput@[clk]() for i in 1:nx] {
"Dyad": {"placement": {"diagram": {"x1": 1000, "y1": 200, "x2": 1100, "y2": 300}}}
}
"Estimated offset-free disturbance (only for offset-free observers)"
dhat = [RealOutput@[clk]() for i in 1:ndo] if has_dhat {
"Dyad": {"placement": {"diagram": {"x1": 1000, "y1": 700, "x2": 1100, "y2": 800}}}
}
"Width of the internal disturbance vector, max(nd_in, 1) (derived)"
final structural parameter nd_eff::Integer = max(nd_in, 1)
"Width of the stacked state matrices and of the weight-state Kronecker products, N*nxa (derived)"
final structural parameter nwx::Integer = N * nxa
"Width of the stacked input matrices, N*nu (derived)"
final structural parameter nwu::Integer = N * nu
"Width of the stacked disturbance matrices, N*nd_eff (derived)"
final structural parameter nwd::Integer = N * nd_eff
"Width of the stacked Kalman gains, N*ny_meas (derived)"
final structural parameter nwi::Integer = N * ny_meas
"Initial augmented state estimate [x0; d0], by default the one stored in the members"
parameter xaug0::Real[nxa] = _lmpc_xaug0(mpc)
"Zero placeholder used as the disturbance vector when d is absent"
final parameter d_dummy::Real[nd_eff] = fill(0.0, nd_eff)
"State matrices of the estimators, stacked side by side [F_1 ... F_N]"
final parameter Fs::Real[nxa, nwx] = _lmpc_bank_obs_F(mpc)
"Input matrices of the estimators, stacked"
final parameter Gs::Real[nxa, nwu] = _lmpc_bank_obs_G(mpc)
"Measured-disturbance input matrices of the estimators, each padded to the internal disturbance width, stacked"
final parameter Gds::Real[nxa, nwd] = _lmpc_bank_obs_Gd(mpc, nd_eff)
"Affine offsets of the estimator state updates, one column per member"
final parameter fs::Real[nxa, N] = _lmpc_bank_obs_f(mpc)
"Measurement matrices of the estimators, stacked"
final parameter Cs::Real[ny_meas, nwx] = _lmpc_bank_obs_C(mpc)
"Measured-disturbance feedthroughs of the estimators, each padded to the internal disturbance width, stacked"
final parameter Dds::Real[ny_meas, nwd] = _lmpc_bank_obs_Dd(mpc, nd_eff)
"Affine offsets of the measurement equations, one column per member"
final parameter hs::Real[ny_meas, N] = _lmpc_bank_obs_h(mpc)
"Steady-state Kalman gains, stacked"
final parameter Ks::Real[nxa, nwi] = _lmpc_bank_obs_K(mpc)
"Augmented state predicted for the current tick, before correction"
variable xpred::Real[nxa]
"The prediction made at the previous tick, i.e. xpred delayed by one tick"
variable xprev::Real[nxa]
"Augmented state after correction with the current measurement"
variable xcorr::Real[nxa]
"Innovation, the measurement minus its blended prediction"
variable innov::Real[ny_meas]
"Disturbance vector used by the observer equations"
variable d_int::Real[nd_eff]
"Kronecker product of the weights and xprev"
variable wxp::Real[nwx]
"Kronecker product of the weights and xcorr"
variable wx::Real[nwx]
"Kronecker product of the weights and u"
variable wu::Real[nwu]
"Kronecker product of the weights and d_int"
variable wd::Real[nwd]
"Kronecker product of the weights and innov"
variable wi::Real[nwi]
relations
if has_d
d_int = d
else
d_int = d_dummy
end
initial xpred@(clk-1) = xaug0
xprev@clk = xpred@(clk-1)
for j in 1:N
for i in 1:nxa
wxp[(j - 1) * nxa + i] = w[j] * xprev[i]
wx[(j - 1) * nxa + i] = w[j] * xcorr[i]
end
for i in 1:nu
wu[(j - 1) * nu + i] = w[j] * u[i]
end
for i in 1:nd_eff
wd[(j - 1) * nd_eff + i] = w[j] * d_int[i]
end
for i in 1:ny_meas
wi[(j - 1) * ny_meas + i] = w[j] * innov[i]
end
end
innov = y - Cs * wxp - Dds * wd - hs * w
xcorr = xprev + Ks * wi
xpred = Fs * wx + Gs * wu + Gds * wd + fs * w
# The augmented state is [x; d_offset]
for i in 1:nx
xhat[i] = xcorr[i]
end
if has_dhat
for i in 1:ndo
dhat[i] = xcorr[nx + i]
end
end
metadata {
"Dyad": {
"icons": {"default": "dyad://MPCComponents/LinearMPCScheduledObserver.svg"},
"doc": {"behavior": false}
}
}
endFlattened Source
"""
Gain-scheduled state observer of a bank of LinearMPC.jl controllers: the steady-state Kalman
filters (or offset-free observers) of the members, blended with the member weights `w` of
`LinearMPCScheduler`. With `F_j, G_j, ...` the estimator matrices of member `j`, the recursion of
`LinearMPCObserver` is run with the blended matrices `Σ_j w_j F_j` etc.:
```math
\\begin{aligned}
\\hat x_{k|k} &= \\hat x_{k|k-1} + \\textstyle\\sum_j w_j K_j\\,(y_k - \\sum_j w_j (C_j\\hat x_{k|k-1} + D_{d,j} d_k + h_j)) \\\\
\\hat x_{k+1|k} &= \\textstyle\\sum_j w_j (F_j\\hat x_{k|k} + G_j u_k + G_{d,j} d_k + f_j)
\\end{aligned}
```
The members' matrices are stacked side by side into `final` parameters at model-build time and
multiplied with the Kronecker product of the weights and the vectors, so the component remains
plain matrix arithmetic and is exported to C like `LinearMPCObserver`. The blended Kalman gain is
the usual gain-scheduled observer, exact at the knots. See `LinearMPCScheduledController`.
"""
component LinearMPCScheduledObserver
"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)
"Sampled measurements (the rows of the observers' measurement matrix)"
y = [RealInput@[clk]() for i in 1:ny_meas] {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 825, "x2": 0, "y2": 925}}}
}
"Control applied at the current tick, used to predict the estimate for the next tick"
u = [RealInput@[clk]() for i in 1:nu] {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 325, "x2": 0, "y2": 425}}}
}
"Measured disturbances; nd_meas entries, or nd_meas*Np column-major entries with disturbance preview (only the first nd_meas are used here)"
d = [RealInput@[clk]() for i in 1:nd_in] if has_d {
"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 575, "x2": 0, "y2": 675}}}
}
"Member weights from LinearMPCScheduler"
w = [RealInput@[clk]() for j in 1:N] {"Dyad": {"placement": {"diagram": {"x1": -100, "y1": 75, "x2": 0, "y2": 175}}}}
"State estimate corrected with the current measurement"
xhat = [RealOutput@[clk]() for i in 1:nx] {
"Dyad": {"placement": {"diagram": {"x1": 1000, "y1": 200, "x2": 1100, "y2": 300}}}
}
"Estimated offset-free disturbance (only for offset-free observers)"
dhat = [RealOutput@[clk]() for i in 1:ndo] if has_dhat {
"Dyad": {"placement": {"diagram": {"x1": 1000, "y1": 700, "x2": 1100, "y2": 800}}}
}
"Width of the internal disturbance vector, max(nd_in, 1) (derived)"
final structural parameter nd_eff::Integer = max(nd_in, 1)
"Width of the stacked state matrices and of the weight-state Kronecker products, N*nxa (derived)"
final structural parameter nwx::Integer = N * nxa
"Width of the stacked input matrices, N*nu (derived)"
final structural parameter nwu::Integer = N * nu
"Width of the stacked disturbance matrices, N*nd_eff (derived)"
final structural parameter nwd::Integer = N * nd_eff
"Width of the stacked Kalman gains, N*ny_meas (derived)"
final structural parameter nwi::Integer = N * ny_meas
"Initial augmented state estimate [x0; d0], by default the one stored in the members"
parameter xaug0::Real[nxa] = _lmpc_xaug0(mpc)
"Zero placeholder used as the disturbance vector when d is absent"
final parameter d_dummy::Real[nd_eff] = fill(0.0, nd_eff)
"State matrices of the estimators, stacked side by side [F_1 ... F_N]"
final parameter Fs::Real[nxa, nwx] = _lmpc_bank_obs_F(mpc)
"Input matrices of the estimators, stacked"
final parameter Gs::Real[nxa, nwu] = _lmpc_bank_obs_G(mpc)
"Measured-disturbance input matrices of the estimators, each padded to the internal disturbance width, stacked"
final parameter Gds::Real[nxa, nwd] = _lmpc_bank_obs_Gd(mpc, nd_eff)
"Affine offsets of the estimator state updates, one column per member"
final parameter fs::Real[nxa, N] = _lmpc_bank_obs_f(mpc)
"Measurement matrices of the estimators, stacked"
final parameter Cs::Real[ny_meas, nwx] = _lmpc_bank_obs_C(mpc)
"Measured-disturbance feedthroughs of the estimators, each padded to the internal disturbance width, stacked"
final parameter Dds::Real[ny_meas, nwd] = _lmpc_bank_obs_Dd(mpc, nd_eff)
"Affine offsets of the measurement equations, one column per member"
final parameter hs::Real[ny_meas, N] = _lmpc_bank_obs_h(mpc)
"Steady-state Kalman gains, stacked"
final parameter Ks::Real[nxa, nwi] = _lmpc_bank_obs_K(mpc)
"Augmented state predicted for the current tick, before correction"
variable xpred::Real[nxa]
"The prediction made at the previous tick, i.e. xpred delayed by one tick"
variable xprev::Real[nxa]
"Augmented state after correction with the current measurement"
variable xcorr::Real[nxa]
"Innovation, the measurement minus its blended prediction"
variable innov::Real[ny_meas]
"Disturbance vector used by the observer equations"
variable d_int::Real[nd_eff]
"Kronecker product of the weights and xprev"
variable wxp::Real[nwx]
"Kronecker product of the weights and xcorr"
variable wx::Real[nwx]
"Kronecker product of the weights and u"
variable wu::Real[nwu]
"Kronecker product of the weights and d_int"
variable wd::Real[nwd]
"Kronecker product of the weights and innov"
variable wi::Real[nwi]
relations
if has_d
d_int = d
else
d_int = d_dummy
end
initial xpred@(clk-1) = xaug0
xprev@clk = xpred@(clk-1)
for j in 1:N
for i in 1:nxa
wxp[(j - 1) * nxa + i] = w[j] * xprev[i]
wx[(j - 1) * nxa + i] = w[j] * xcorr[i]
end
for i in 1:nu
wu[(j - 1) * nu + i] = w[j] * u[i]
end
for i in 1:nd_eff
wd[(j - 1) * nd_eff + i] = w[j] * d_int[i]
end
for i in 1:ny_meas
wi[(j - 1) * ny_meas + i] = w[j] * innov[i]
end
end
innov = y - Cs * wxp - Dds * wd - hs * w
xcorr = xprev + Ks * wi
xpred = Fs * wx + Gs * wu + Gds * wd + fs * w
# The augmented state is [x; d_offset]
for i in 1:nx
xhat[i] = xcorr[i]
end
if has_dhat
for i in 1:ndo
dhat[i] = xcorr[nx + i]
end
end
metadata {
"Dyad": {
"icons": {"default": "dyad://MPCComponents/LinearMPCScheduledObserver.svg"},
"doc": {"behavior": false}
}
}
endTest Cases ​
No test cases defined.
Related ​
Examples
Experiments
Analyses