LIBRARY
Examples.PIDEquivalentMPCExample ​
The PID-equivalent MPC next to the PID it reproduces: two identical continuous double integrators, one closed with PIDEquivalentMPCController (given the exact plant model) and one with DiscreteComponents.DiscretePIDStandard using the same gains. With the wide output limits used here neither controller saturates, so y1 = y2 and u1 = u2 up to solver tolerance.
Usage ​
MPCComponents.Examples.PIDEquivalentMPCExample()
Parameters: ​
| Name | Description | Units | Default value |
|---|---|---|---|
output_trajectories | Record the predicted trajectories and the QP statistics of the controller(s), for mpc_gui | – | false |
Variables ​
| Name | Description | Units |
|---|---|---|
y1 | Position under the MPC form | – |
u1 | Control of the MPC form | – |
y2 | Position under the PID | – |
u2 | Control of the PID | – |
Behavior ​
Behavior of this component cannot be rendered because it includes path variables.
Source ​
dyad
"""
The PID-equivalent MPC next to the PID it reproduces: two identical continuous double integrators,
one closed with `PIDEquivalentMPCController` (given the exact plant model) and one with
`DiscreteComponents.DiscretePIDStandard` using the same gains. With the wide output limits used
here neither controller saturates, so `y1 = y2` and `u1 = u2` up to solver tolerance.
"""
example component PIDEquivalentMPCExample
periodicclock = DiscreteComponents.PeriodicClock(dt = 0.1) {
"Dyad": {"placement": {"diagram": {"x1": 810, "x2": 910, "y1": 730, "y2": 830}}}
}
periodicclock2 = DiscreteComponents.PeriodicClock(dt = 0.1) {
"Dyad": {"placement": {"diagram": {"x1": 780, "x2": 880, "y1": 310, "y2": 410}}}
}
ref = BlockComponents.Sources.Step(start_time = 1.0, height = 1.0) {
"Dyad": {"placement": {"diagram": {"x1": 240, "x2": 340, "y1": 260, "y2": 360}}}
}
"Plant driven by the MPC form"
vel1 = BlockComponents.Continuous.Integrator(x0 = 0.3) {
"Dyad": {"placement": {"diagram": {"x1": 860, "x2": 960, "y1": 460, "y2": 560}}}
}
pos1 = BlockComponents.Continuous.Integrator(x0 = 1.0) {
"Dyad": {"placement": {"diagram": {"x1": 1000, "x2": 1100, "y1": 460, "y2": 560}}}
}
s1 = DiscreteComponents.Sampler() {
"Dyad": {"placement": {"diagram": {"x1": 910, "x2": 810, "y1": 600, "y2": 700}}}
}
sr1 = DiscreteComponents.Sampler() {
"Dyad": {"placement": {"diagram": {"x1": 400, "x2": 500, "y1": 440, "y2": 540}}}
}
zoh1 = DiscreteComponents.ZeroOrderHold() {
"Dyad": {"placement": {"diagram": {"x1": 714, "x2": 814, "y1": 460, "y2": 560}}}
}
mpc = MPCComponents.PIDEquivalentMPCController(A = [[0.0, 1.0], [0.0, 0.0]], B = [[0.0], [1.0]], C = [[1.0, 0.0]], continuous = true, Ts = 0.1, Np = 10, K = 2.0, Ti = 1.5, Td = 0.3, Nd = 8.0, wp = 0.7, wd = 0.4, y_max = 100.0, x0 = [1.0, 0.3], output_trajectories = output_trajectories) {
"Dyad": {"placement": {"diagram": {"x1": 580, "x2": 680, "y1": 460, "y2": 560}}}
}
"Plant driven by the PID"
vel2 = BlockComponents.Continuous.Integrator(x0 = 0.3) {
"Dyad": {"placement": {"diagram": {"x1": 860, "x2": 960, "y1": 30, "y2": 130}}}
}
pos2 = BlockComponents.Continuous.Integrator(x0 = 1.0) {
"Dyad": {"placement": {"diagram": {"x1": 1000, "x2": 1100, "y1": 30, "y2": 130}}}
}
s2 = DiscreteComponents.Sampler() {
"Dyad": {"placement": {"diagram": {"x1": 880, "x2": 780, "y1": 190, "y2": 290}}}
}
sr2 = DiscreteComponents.Sampler() {"Dyad": {"placement": {"diagram": {"x1": 400, "x2": 500, "y1": 0, "y2": 100}}}}
zoh2 = DiscreteComponents.ZeroOrderHold() {
"Dyad": {"placement": {"diagram": {"x1": 720, "x2": 820, "y1": 30, "y2": 130}}}
}
pid = DiscreteComponents.DiscretePIDStandard(Ts = 0.1, K = 2.0, Ti = 1.5, Td = 0.3, Nd = 8.0, wp = 0.7, wd = 0.4, y_max = 100.0) {
"Dyad": {"placement": {"diagram": {"x1": 580, "x2": 680, "y1": 30, "y2": 130}}}
}
"Record the predicted trajectories and the QP statistics of the controller(s), for mpc_gui"
structural parameter output_trajectories::Boolean = false
"Position under the MPC form"
variable y1::Real
"Control of the MPC form"
variable u1::Real
"Position under the PID"
variable y2::Real
"Control of the PID"
variable u2::Real
relations
y1 = pos1.y
u1 = zoh1.y
y2 = pos2.y
u2 = zoh2.y
connect(zoh1.y, vel1.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(vel1.y, pos1.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(pos1.y, s1.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 1140, "y": 510}, {"x": 1140, "y": 650}], "E": 2}],
"path": {}
}
}
connect(s1.y, mpc.u_m, periodicclock.y) {
"Dyad": {
"edges": [
{"S": 1, "M": [], "E": -1},
{"S": -1, "M": [{"x": 550, "y": 650}, {"x": 550, "y": 535}], "E": 2},
{"S": -1, "M": [{"x": 670, "y": 780}], "E": 3}
],
"junctions": [{"x": 670, "y": 650}],
"path": {}
}
}
connect(ref.y, sr1.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 388, "y": 310}, {"x": 388, "y": 490}], "E": 2}],
"path": {}
}
}
connect(sr1.y, mpc.u_s) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 540, "y": 490}, {"x": 540, "y": 486}], "E": 2}],
"path": {}
}
}
connect(mpc.y, zoh1.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 700, "y": 535}, {"x": 700, "y": 510}], "E": 2}],
"path": {}
}
}
connect(zoh2.y, vel2.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(vel2.y, pos2.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(pos2.y, s2.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 1110, "y": 80}, {"x": 1110, "y": 240}], "E": 2}],
"path": {}
}
}
connect(s2.y, pid.u_m, periodicclock2.y) {
"Dyad": {
"edges": [
{"S": 1, "M": [], "E": -1},
{"S": -1, "M": [{"x": 560, "y": 240}, {"x": 560, "y": 104}], "E": 2},
{"S": 3, "M": [{"x": 670, "y": 360}], "E": -1}
],
"junctions": [{"x": 670, "y": 240}],
"path": {}
}
}
connect(ref.y, sr2.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 390, "y": 310}, {"x": 390, "y": 50}], "E": 2}],
"path": {}
}
}
connect(sr2.y, pid.u_s) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 543, "y": 50}, {"x": 543, "y": 52}], "E": 2}],
"path": {}
}
}
connect(pid.y, zoh2.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
metadata {"Dyad": {"tests": {"case1": {"stop": 5}}, "doc": {"behavior": false}}}
endFlattened Source
dyad
"""
The PID-equivalent MPC next to the PID it reproduces: two identical continuous double integrators,
one closed with `PIDEquivalentMPCController` (given the exact plant model) and one with
`DiscreteComponents.DiscretePIDStandard` using the same gains. With the wide output limits used
here neither controller saturates, so `y1 = y2` and `u1 = u2` up to solver tolerance.
"""
example component PIDEquivalentMPCExample
periodicclock = DiscreteComponents.PeriodicClock(dt = 0.1) {
"Dyad": {"placement": {"diagram": {"x1": 810, "x2": 910, "y1": 730, "y2": 830}}}
}
periodicclock2 = DiscreteComponents.PeriodicClock(dt = 0.1) {
"Dyad": {"placement": {"diagram": {"x1": 780, "x2": 880, "y1": 310, "y2": 410}}}
}
ref = BlockComponents.Sources.Step(start_time = 1.0, height = 1.0) {
"Dyad": {"placement": {"diagram": {"x1": 240, "x2": 340, "y1": 260, "y2": 360}}}
}
"Plant driven by the MPC form"
vel1 = BlockComponents.Continuous.Integrator(x0 = 0.3) {
"Dyad": {"placement": {"diagram": {"x1": 860, "x2": 960, "y1": 460, "y2": 560}}}
}
pos1 = BlockComponents.Continuous.Integrator(x0 = 1.0) {
"Dyad": {"placement": {"diagram": {"x1": 1000, "x2": 1100, "y1": 460, "y2": 560}}}
}
s1 = DiscreteComponents.Sampler() {
"Dyad": {"placement": {"diagram": {"x1": 910, "x2": 810, "y1": 600, "y2": 700}}}
}
sr1 = DiscreteComponents.Sampler() {
"Dyad": {"placement": {"diagram": {"x1": 400, "x2": 500, "y1": 440, "y2": 540}}}
}
zoh1 = DiscreteComponents.ZeroOrderHold() {
"Dyad": {"placement": {"diagram": {"x1": 714, "x2": 814, "y1": 460, "y2": 560}}}
}
mpc = MPCComponents.PIDEquivalentMPCController(A = [[0.0, 1.0], [0.0, 0.0]], B = [[0.0], [1.0]], C = [[1.0, 0.0]], continuous = true, Ts = 0.1, Np = 10, K = 2.0, Ti = 1.5, Td = 0.3, Nd = 8.0, wp = 0.7, wd = 0.4, y_max = 100.0, x0 = [1.0, 0.3], output_trajectories = output_trajectories) {
"Dyad": {"placement": {"diagram": {"x1": 580, "x2": 680, "y1": 460, "y2": 560}}}
}
"Plant driven by the PID"
vel2 = BlockComponents.Continuous.Integrator(x0 = 0.3) {
"Dyad": {"placement": {"diagram": {"x1": 860, "x2": 960, "y1": 30, "y2": 130}}}
}
pos2 = BlockComponents.Continuous.Integrator(x0 = 1.0) {
"Dyad": {"placement": {"diagram": {"x1": 1000, "x2": 1100, "y1": 30, "y2": 130}}}
}
s2 = DiscreteComponents.Sampler() {
"Dyad": {"placement": {"diagram": {"x1": 880, "x2": 780, "y1": 190, "y2": 290}}}
}
sr2 = DiscreteComponents.Sampler() {"Dyad": {"placement": {"diagram": {"x1": 400, "x2": 500, "y1": 0, "y2": 100}}}}
zoh2 = DiscreteComponents.ZeroOrderHold() {
"Dyad": {"placement": {"diagram": {"x1": 720, "x2": 820, "y1": 30, "y2": 130}}}
}
pid = DiscreteComponents.DiscretePIDStandard(Ts = 0.1, K = 2.0, Ti = 1.5, Td = 0.3, Nd = 8.0, wp = 0.7, wd = 0.4, y_max = 100.0) {
"Dyad": {"placement": {"diagram": {"x1": 580, "x2": 680, "y1": 30, "y2": 130}}}
}
"Record the predicted trajectories and the QP statistics of the controller(s), for mpc_gui"
structural parameter output_trajectories::Boolean = false
"Position under the MPC form"
variable y1::Real
"Control of the MPC form"
variable u1::Real
"Position under the PID"
variable y2::Real
"Control of the PID"
variable u2::Real
relations
y1 = pos1.y
u1 = zoh1.y
y2 = pos2.y
u2 = zoh2.y
connect(zoh1.y, vel1.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(vel1.y, pos1.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(pos1.y, s1.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 1140, "y": 510}, {"x": 1140, "y": 650}], "E": 2}],
"path": {}
}
}
connect(s1.y, mpc.u_m, periodicclock.y) {
"Dyad": {
"edges": [
{"S": 1, "M": [], "E": -1},
{"S": -1, "M": [{"x": 550, "y": 650}, {"x": 550, "y": 535}], "E": 2},
{"S": -1, "M": [{"x": 670, "y": 780}], "E": 3}
],
"junctions": [{"x": 670, "y": 650}],
"path": {}
}
}
connect(ref.y, sr1.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 388, "y": 310}, {"x": 388, "y": 490}], "E": 2}],
"path": {}
}
}
connect(sr1.y, mpc.u_s) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 540, "y": 490}, {"x": 540, "y": 486}], "E": 2}],
"path": {}
}
}
connect(mpc.y, zoh1.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 700, "y": 535}, {"x": 700, "y": 510}], "E": 2}],
"path": {}
}
}
connect(zoh2.y, vel2.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(vel2.y, pos2.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
connect(pos2.y, s2.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 1110, "y": 80}, {"x": 1110, "y": 240}], "E": 2}],
"path": {}
}
}
connect(s2.y, pid.u_m, periodicclock2.y) {
"Dyad": {
"edges": [
{"S": 1, "M": [], "E": -1},
{"S": -1, "M": [{"x": 560, "y": 240}, {"x": 560, "y": 104}], "E": 2},
{"S": 3, "M": [{"x": 670, "y": 360}], "E": -1}
],
"junctions": [{"x": 670, "y": 240}],
"path": {}
}
}
connect(ref.y, sr2.u) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 390, "y": 310}, {"x": 390, "y": 50}], "E": 2}],
"path": {}
}
}
connect(sr2.y, pid.u_s) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 543, "y": 50}, {"x": 543, "y": 52}], "E": 2}],
"path": {}
}
}
connect(pid.y, zoh2.u) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "path": {}}}
metadata {"Dyad": {"tests": {"case1": {"stop": 5}}, "doc": {"behavior": false}}}
endTest Cases ​
Test Case case1 ​
Related ​
Examples
Experiments
Analyses