Examples.LinearMPCScheduledExample ​
Level control of TankPlant by the three gain-scheduled controllers of MPCComponents.Experimental, on identical tanks and the same reference, so their trajectories and costs can be compared (benchmark_scheduled_controllers runs this model and reports the solve counts, solve times and closed-loop costs).
All three take the same bank of three controllers, built from the linearization of the tank at the levels 0.5, 1.5 and 3 (build_tank_mpc_bank), and are scheduled on the measured level, which is fed to each controller both as the measurement y and as the scheduling variable rho. The reference steps through the operating range, so the weights w move from one member to the next as the level rises and falls.
mpc(signalsy1,u1) isLinearMPCScheduledController: it solves the quadratic programs of the members enclosing the level and interpolates their controls and Kalman filters.mpc2(y2,u2) isACADOSScheduledControllerwith the weights as online parameters of the interpolated model, held over the horizon: the same information as the bank, in one solve.mpc3(y3,u3) isACADOSScheduledControllerwithpredict_scheduling, whose model follows the predicted level along the horizon (rho_C = [1], the level being the only state).
backend and acados_backend select the solver backends of the LinearMPC and acados controllers.
Usage ​
MPCComponents.Examples.LinearMPCScheduledExample()
Parameters: ​
| Name | Description | Units | Default value |
|---|---|---|---|
bank | Bank of controllers linearized at the levels of the grid, shared by the three controllers | – | build_tank_mpc_bank() |
backend | QP solver backend of the LinearMPC-based controller | – | MPCComponen...kend.Auto() |
acados_backend | Solver backend of the two acados-based controllers | – | MPCComponen...kend.Auto() |
Variables ​
| Name | Description | Units |
|---|---|---|
r1 | Level reference | – |
rs | Sampled level reference, the reference the controllers see (per tick) | – |
y1 | Level under the LinearMPC bank | – |
u1 | Inflow of the LinearMPC bank | – |
w1 | Weight of the first member (level 0.5) | – |
w2 | Weight of the second member (level 1.5) | – |
w3 | Weight of the third member (level 3) | – |
ys1 | Sampled level of the LinearMPC bank loop (per tick, what the cost is evaluated on) | – |
ys2 | Sampled level of the acados loop with the weights as parameters (per tick) | – |
ys3 | Sampled level of the acados loop predicting the scheduling variable (per tick) | – |
y2 | Level under the acados controller with the weights as parameters | – |
u2 | Inflow of the acados controller with the weights as parameters | – |
flag2 | acados status of that controller | – |
y3 | Level under the acados controller predicting the scheduling variable | – |
u3 | Inflow of the acados controller predicting the scheduling variable | – |
flag3 | acados status of that controller | – |
Behavior ​
Behavior of this component cannot be rendered because it includes path variables.
Source ​
"""
Level control of `TankPlant` by the three gain-scheduled controllers of `MPCComponents.Experimental`,
on identical tanks and the same reference, so their trajectories and costs can be compared
(`benchmark_scheduled_controllers` runs this model and reports the solve counts, solve times and
closed-loop costs).
All three take the same bank of three controllers, built from the linearization of the tank at the
levels 0.5, 1.5 and 3 (`build_tank_mpc_bank`), and are scheduled on the measured level, which is fed
to each controller both as the measurement `y` and as the scheduling variable `rho`. The reference
steps through the operating range, so the weights `w` move from one member to the next as the level
rises and falls.
- `mpc` (signals `y1`, `u1`) is `LinearMPCScheduledController`: it solves the quadratic programs of the
members enclosing the level and interpolates their controls and Kalman filters.
- `mpc2` (`y2`, `u2`) is `ACADOSScheduledController` with the weights as online parameters of the
interpolated model, held over the horizon: the same information as the bank, in one solve.
- `mpc3` (`y3`, `u3`) is `ACADOSScheduledController` with `predict_scheduling`, whose model follows the
predicted level along the horizon (`rho_C = [1]`, the level being the only state).
`backend` and `acados_backend` select the solver backends of the LinearMPC and acados controllers.
"""
example component LinearMPCScheduledExample
periodicclock = DiscreteComponents.PeriodicClock(dt = 0.5) {
"Dyad": {"placement": {"diagram": {"x1": 1050, "y1": 700, "x2": 1150, "y2": 800}}}
}
step1 = BlockComponents.Sources.Step(offset = 0.5, height = 1.0, start_time = 5.0) {
"Dyad": {"placement": {"diagram": {"x1": 30, "y1": 260, "x2": 140, "y2": 370}}}
}
step2 = BlockComponents.Sources.Step(height = 1.5, start_time = 25.0) {
"Dyad": {"placement": {"diagram": {"x1": 30, "y1": 390, "x2": 130, "y2": 490}}}
}
step3 = BlockComponents.Sources.Step(height = -2.5, start_time = 45.0) {
"Dyad": {"placement": {"diagram": {"x1": 30, "y1": 510, "x2": 130, "y2": 610}}}
}
ref = BlockComponents.Math.Add3() {
"Dyad": {"placement": {"diagram": {"x1": 350, "y1": 390, "x2": 460, "y2": 490}}}
}
sr = DiscreteComponents.Sampler() {
"Dyad": {"placement": {"diagram": {"x1": 500, "y1": 390, "x2": 600, "y2": 490}}}
}
tank = TankPlant(h0 = 0.5) {
"Dyad": {"placement": {"diagram": {"x1": 1290, "y1": 401.5, "x2": 1490, "y2": 601.5}}}
}
s1 = DiscreteComponents.Sampler() {
"Dyad": {"placement": {"diagram": {"x1": 1150, "y1": 830, "x2": 1050, "y2": 930}}}
}
zoh = DiscreteComponents.ZeroOrderHold() {
"Dyad": {"placement": {"diagram": {"x1": 1095, "y1": 451.5, "x2": 1195, "y2": 551.5}}}
}
mpc = MPCComponents.Experimental.LinearMPCScheduledController(mpc = bank, backend = backend) {
"Dyad": {"placement": {"diagram": {"x1": 690, "y1": 411.5, "x2": 990, "y2": 711.5}}}
}
tank2 = TankPlant(h0 = 0.5) {
"Dyad": {"placement": {"diagram": {"x1": 1290, "y1": 83.5, "x2": 1490, "y2": 283.5}}}
}
s2 = DiscreteComponents.Sampler() {
"Dyad": {"placement": {"diagram": {"x1": 1110, "y1": -60, "x2": 1010, "y2": 40}}}
}
zoh2 = DiscreteComponents.ZeroOrderHold() {
"Dyad": {"placement": {"diagram": {"x1": 1095, "y1": 133.5, "x2": 1195, "y2": 233.5}}}
}
mpc2 = MPCComponents.Experimental.ACADOSScheduledController(mpc = bank, backend = acados_backend) {
"Dyad": {"placement": {"diagram": {"x1": 690, "y1": 71, "x2": 990, "y2": 371}}}
}
tank3 = TankPlant(h0 = 0.5) {
"Dyad": {"placement": {"diagram": {"x1": 1290, "y1": 944, "x2": 1490, "y2": 1144}}}
}
s3 = DiscreteComponents.Sampler() {
"Dyad": {"placement": {"diagram": {"x1": 1100, "y1": 1230, "x2": 1000, "y2": 1330}}}
}
zoh3 = DiscreteComponents.ZeroOrderHold() {
"Dyad": {"placement": {"diagram": {"x1": 1095, "y1": 994, "x2": 1195, "y2": 1094}}}
}
mpc3 = MPCComponents.Experimental.ACADOSScheduledController(mpc = bank, backend = acados_backend, predict_scheduling = true, rho_C = [1.0]) {
"Dyad": {"placement": {"diagram": {"x1": 690, "y1": 931.5, "x2": 990, "y2": 1231.5}}}
}
"Bank of controllers linearized at the levels of the grid, shared by the three controllers"
structural parameter bank::MPCComponents.MPCRef = build_tank_mpc_bank()
"QP solver backend of the LinearMPC-based controller"
structural parameter backend::MPCComponents.Backend = MPCComponents.Backend.Auto()
"Solver backend of the two acados-based controllers"
structural parameter acados_backend::MPCComponents.Backend = MPCComponents.Backend.Auto()
"Level reference"
variable r1::Real
"Sampled level reference, the reference the controllers see (per tick)"
variable rs::Real
"Level under the LinearMPC bank"
variable y1::Real
"Inflow of the LinearMPC bank"
variable u1::Real
"Weight of the first member (level 0.5)"
variable w1::Real
"Weight of the second member (level 1.5)"
variable w2::Real
"Weight of the third member (level 3)"
variable w3::Real
"Sampled level of the LinearMPC bank loop (per tick, what the cost is evaluated on)"
variable ys1::Real
"Sampled level of the acados loop with the weights as parameters (per tick)"
variable ys2::Real
"Sampled level of the acados loop predicting the scheduling variable (per tick)"
variable ys3::Real
"Level under the acados controller with the weights as parameters"
variable y2::Real
"Inflow of the acados controller with the weights as parameters"
variable u2::Real
"acados status of that controller"
variable flag2::Real
"Level under the acados controller predicting the scheduling variable"
variable y3::Real
"Inflow of the acados controller predicting the scheduling variable"
variable u3::Real
"acados status of that controller"
variable flag3::Real
relations
r1 = ref.y
rs = sr.y
ys1 = s1.y
ys2 = s2.y
ys3 = s3.y
y1 = tank.y
u1 = mpc.u[1]
w1 = mpc.w[1]
w2 = mpc.w[2]
w3 = mpc.w[3]
y2 = tank2.y
u2 = mpc2.u[1]
flag2 = mpc2.exitflag
y3 = tank3.y
u3 = mpc3.u[1]
flag3 = mpc3.exitflag
connect(step1.y, ref.u1) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 250, "y": 315}, {"x": 250, "y": 410}], "E": 2}],
"path": {}
}
}
connect(step2.y, ref.u2) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(step3.y, ref.u3) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 250, "y": 560}, {"x": 250, "y": 470}], "E": 2}],
"path": {}
}
}
connect(ref.y, sr.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(zoh.y, tank.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(tank.y, s1.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 1566.5, "y": 501.5}, {"x": 1566.5, "y": 880}], "E": 2}],
"path": {}
}
}
connect(s1.y, mpc.y[1], mpc.rho, periodicclock.y) {
"Dyad": {
"edges": [
{"S": 1, "M": [{"x": 640, "y": 880}, {"x": 640, "y": 681.5}], "E": 2},
{"S": 2, "M": [{"x": 650, "y": 681.5}, {"x": 650, "y": 561.5}], "E": 3},
{"S": 3, "M": [{"x": 630, "y": 561.5}, {"x": 630, "y": 750}], "E": 4}
],
"path": {}
}
}
connect(sr.y, mpc.r[1]) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 640, "y": 440}, {"x": 640, "y": 441.5}], "E": 2}],
"path": {}
}
}
connect(mpc.u[1], zoh.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(zoh2.y, tank2.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(tank2.y, s2.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 1520, "y": 183.5}, {"x": 1520, "y": -10}], "E": 2}],
"path": {}
}
}
connect(s2.y, mpc2.y[1], mpc2.rho) {
"Dyad": {
"edges": [
{"S": 1, "M": [{"x": 640, "y": -10}, {"x": 640, "y": 321.5}], "E": 2},
{"S": 2, "M": [{"x": 650, "y": 321.5}, {"x": 650, "y": 221}], "E": 3}
],
"path": {}
}
}
connect(sr.y, mpc2.r[1]) {
"Dyad": {
"edges": [
{"S": 1, "M": [{"x": 612.5, "y": 440}, {"x": 612.5, "y": 441.5}], "E": -1},
{"S": -1, "M": [{"x": 620, "y": 120.5}], "E": 2}
],
"junctions": [{"x": 620, "y": 441.5}],
"path": {}
}
}
connect(mpc2.u[1], zoh2.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(zoh3.y, tank3.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(tank3.y, s3.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 1520, "y": 1044}, {"x": 1520, "y": 1280}], "E": 2}],
"path": {}
}
}
connect(s3.y, mpc3.y[1], mpc3.rho) {
"Dyad": {
"edges": [
{"S": 1, "M": [{"x": 640, "y": 1280}, {"x": 640, "y": 1182}], "E": 2},
{"S": 2, "M": [{"x": 650, "y": 1182}, {"x": 650, "y": 1081.5}], "E": 3}
],
"path": {}
}
}
connect(sr.y, mpc3.r[1]) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 620, "y": 440}, {"x": 620, "y": 981}], "E": 2}],
"path": {}
}
}
connect(mpc3.u[1], zoh3.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
metadata {"Dyad": {"tests": {"case1": {"stop": 60}}, "doc": {"behavior": false}}}
endFlattened Source
"""
Level control of `TankPlant` by the three gain-scheduled controllers of `MPCComponents.Experimental`,
on identical tanks and the same reference, so their trajectories and costs can be compared
(`benchmark_scheduled_controllers` runs this model and reports the solve counts, solve times and
closed-loop costs).
All three take the same bank of three controllers, built from the linearization of the tank at the
levels 0.5, 1.5 and 3 (`build_tank_mpc_bank`), and are scheduled on the measured level, which is fed
to each controller both as the measurement `y` and as the scheduling variable `rho`. The reference
steps through the operating range, so the weights `w` move from one member to the next as the level
rises and falls.
- `mpc` (signals `y1`, `u1`) is `LinearMPCScheduledController`: it solves the quadratic programs of the
members enclosing the level and interpolates their controls and Kalman filters.
- `mpc2` (`y2`, `u2`) is `ACADOSScheduledController` with the weights as online parameters of the
interpolated model, held over the horizon: the same information as the bank, in one solve.
- `mpc3` (`y3`, `u3`) is `ACADOSScheduledController` with `predict_scheduling`, whose model follows the
predicted level along the horizon (`rho_C = [1]`, the level being the only state).
`backend` and `acados_backend` select the solver backends of the LinearMPC and acados controllers.
"""
example component LinearMPCScheduledExample
periodicclock = DiscreteComponents.PeriodicClock(dt = 0.5) {
"Dyad": {"placement": {"diagram": {"x1": 1050, "y1": 700, "x2": 1150, "y2": 800}}}
}
step1 = BlockComponents.Sources.Step(offset = 0.5, height = 1.0, start_time = 5.0) {
"Dyad": {"placement": {"diagram": {"x1": 30, "y1": 260, "x2": 140, "y2": 370}}}
}
step2 = BlockComponents.Sources.Step(height = 1.5, start_time = 25.0) {
"Dyad": {"placement": {"diagram": {"x1": 30, "y1": 390, "x2": 130, "y2": 490}}}
}
step3 = BlockComponents.Sources.Step(height = -2.5, start_time = 45.0) {
"Dyad": {"placement": {"diagram": {"x1": 30, "y1": 510, "x2": 130, "y2": 610}}}
}
ref = BlockComponents.Math.Add3() {
"Dyad": {"placement": {"diagram": {"x1": 350, "y1": 390, "x2": 460, "y2": 490}}}
}
sr = DiscreteComponents.Sampler() {
"Dyad": {"placement": {"diagram": {"x1": 500, "y1": 390, "x2": 600, "y2": 490}}}
}
tank = TankPlant(h0 = 0.5) {
"Dyad": {"placement": {"diagram": {"x1": 1290, "y1": 401.5, "x2": 1490, "y2": 601.5}}}
}
s1 = DiscreteComponents.Sampler() {
"Dyad": {"placement": {"diagram": {"x1": 1150, "y1": 830, "x2": 1050, "y2": 930}}}
}
zoh = DiscreteComponents.ZeroOrderHold() {
"Dyad": {"placement": {"diagram": {"x1": 1095, "y1": 451.5, "x2": 1195, "y2": 551.5}}}
}
mpc = MPCComponents.Experimental.LinearMPCScheduledController(mpc = bank, backend = backend) {
"Dyad": {"placement": {"diagram": {"x1": 690, "y1": 411.5, "x2": 990, "y2": 711.5}}}
}
tank2 = TankPlant(h0 = 0.5) {
"Dyad": {"placement": {"diagram": {"x1": 1290, "y1": 83.5, "x2": 1490, "y2": 283.5}}}
}
s2 = DiscreteComponents.Sampler() {
"Dyad": {"placement": {"diagram": {"x1": 1110, "y1": -60, "x2": 1010, "y2": 40}}}
}
zoh2 = DiscreteComponents.ZeroOrderHold() {
"Dyad": {"placement": {"diagram": {"x1": 1095, "y1": 133.5, "x2": 1195, "y2": 233.5}}}
}
mpc2 = MPCComponents.Experimental.ACADOSScheduledController(mpc = bank, backend = acados_backend) {
"Dyad": {"placement": {"diagram": {"x1": 690, "y1": 71, "x2": 990, "y2": 371}}}
}
tank3 = TankPlant(h0 = 0.5) {
"Dyad": {"placement": {"diagram": {"x1": 1290, "y1": 944, "x2": 1490, "y2": 1144}}}
}
s3 = DiscreteComponents.Sampler() {
"Dyad": {"placement": {"diagram": {"x1": 1100, "y1": 1230, "x2": 1000, "y2": 1330}}}
}
zoh3 = DiscreteComponents.ZeroOrderHold() {
"Dyad": {"placement": {"diagram": {"x1": 1095, "y1": 994, "x2": 1195, "y2": 1094}}}
}
mpc3 = MPCComponents.Experimental.ACADOSScheduledController(mpc = bank, backend = acados_backend, predict_scheduling = true, rho_C = [1.0]) {
"Dyad": {"placement": {"diagram": {"x1": 690, "y1": 931.5, "x2": 990, "y2": 1231.5}}}
}
"Bank of controllers linearized at the levels of the grid, shared by the three controllers"
structural parameter bank::MPCComponents.MPCRef = build_tank_mpc_bank()
"QP solver backend of the LinearMPC-based controller"
structural parameter backend::MPCComponents.Backend = MPCComponents.Backend.Auto()
"Solver backend of the two acados-based controllers"
structural parameter acados_backend::MPCComponents.Backend = MPCComponents.Backend.Auto()
"Level reference"
variable r1::Real
"Sampled level reference, the reference the controllers see (per tick)"
variable rs::Real
"Level under the LinearMPC bank"
variable y1::Real
"Inflow of the LinearMPC bank"
variable u1::Real
"Weight of the first member (level 0.5)"
variable w1::Real
"Weight of the second member (level 1.5)"
variable w2::Real
"Weight of the third member (level 3)"
variable w3::Real
"Sampled level of the LinearMPC bank loop (per tick, what the cost is evaluated on)"
variable ys1::Real
"Sampled level of the acados loop with the weights as parameters (per tick)"
variable ys2::Real
"Sampled level of the acados loop predicting the scheduling variable (per tick)"
variable ys3::Real
"Level under the acados controller with the weights as parameters"
variable y2::Real
"Inflow of the acados controller with the weights as parameters"
variable u2::Real
"acados status of that controller"
variable flag2::Real
"Level under the acados controller predicting the scheduling variable"
variable y3::Real
"Inflow of the acados controller predicting the scheduling variable"
variable u3::Real
"acados status of that controller"
variable flag3::Real
relations
r1 = ref.y
rs = sr.y
ys1 = s1.y
ys2 = s2.y
ys3 = s3.y
y1 = tank.y
u1 = mpc.u[1]
w1 = mpc.w[1]
w2 = mpc.w[2]
w3 = mpc.w[3]
y2 = tank2.y
u2 = mpc2.u[1]
flag2 = mpc2.exitflag
y3 = tank3.y
u3 = mpc3.u[1]
flag3 = mpc3.exitflag
connect(step1.y, ref.u1) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 250, "y": 315}, {"x": 250, "y": 410}], "E": 2}],
"path": {}
}
}
connect(step2.y, ref.u2) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(step3.y, ref.u3) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 250, "y": 560}, {"x": 250, "y": 470}], "E": 2}],
"path": {}
}
}
connect(ref.y, sr.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(zoh.y, tank.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(tank.y, s1.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 1566.5, "y": 501.5}, {"x": 1566.5, "y": 880}], "E": 2}],
"path": {}
}
}
connect(s1.y, mpc.y[1], mpc.rho, periodicclock.y) {
"Dyad": {
"edges": [
{"S": 1, "M": [{"x": 640, "y": 880}, {"x": 640, "y": 681.5}], "E": 2},
{"S": 2, "M": [{"x": 650, "y": 681.5}, {"x": 650, "y": 561.5}], "E": 3},
{"S": 3, "M": [{"x": 630, "y": 561.5}, {"x": 630, "y": 750}], "E": 4}
],
"path": {}
}
}
connect(sr.y, mpc.r[1]) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 640, "y": 440}, {"x": 640, "y": 441.5}], "E": 2}],
"path": {}
}
}
connect(mpc.u[1], zoh.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(zoh2.y, tank2.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(tank2.y, s2.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 1520, "y": 183.5}, {"x": 1520, "y": -10}], "E": 2}],
"path": {}
}
}
connect(s2.y, mpc2.y[1], mpc2.rho) {
"Dyad": {
"edges": [
{"S": 1, "M": [{"x": 640, "y": -10}, {"x": 640, "y": 321.5}], "E": 2},
{"S": 2, "M": [{"x": 650, "y": 321.5}, {"x": 650, "y": 221}], "E": 3}
],
"path": {}
}
}
connect(sr.y, mpc2.r[1]) {
"Dyad": {
"edges": [
{"S": 1, "M": [{"x": 612.5, "y": 440}, {"x": 612.5, "y": 441.5}], "E": -1},
{"S": -1, "M": [{"x": 620, "y": 120.5}], "E": 2}
],
"junctions": [{"x": 620, "y": 441.5}],
"path": {}
}
}
connect(mpc2.u[1], zoh2.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(zoh3.y, tank3.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(tank3.y, s3.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 1520, "y": 1044}, {"x": 1520, "y": 1280}], "E": 2}],
"path": {}
}
}
connect(s3.y, mpc3.y[1], mpc3.rho) {
"Dyad": {
"edges": [
{"S": 1, "M": [{"x": 640, "y": 1280}, {"x": 640, "y": 1182}], "E": 2},
{"S": 2, "M": [{"x": 650, "y": 1182}, {"x": 650, "y": 1081.5}], "E": 3}
],
"path": {}
}
}
connect(sr.y, mpc3.r[1]) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 620, "y": 440}, {"x": 620, "y": 981}], "E": 2}],
"path": {}
}
}
connect(mpc3.u[1], zoh3.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
metadata {"Dyad": {"tests": {"case1": {"stop": 60}}, "doc": {"behavior": false}}}
endTest Cases ​
Test Case case1 ​
Related ​
Examples
Experiments
Analyses