Skip to content
LIBRARY
Examples.SaturatedLQRvsMPCExample.md

Examples.SaturatedLQRvsMPCExample ​

Comparison of a saturated LQR controller with an MPC controller on the double integrator DoubleIntegratorPlant, both regulating the position from -2 to the origin with the full state measured. The force is limited to    umax.

The first loop uses an unconstrained LinearMPCController with the LQR cost-to-go as terminal cost, which coincides with the LQR controller, followed by a Limiter at the plant input. The controller is unaware of the saturation. The second loop uses the same weights, with the force bound and the velocity bound    vmax given to the controller as constraints.

Verified in test/test_mpc.jl.

Usage ​

MPCComponents.Examples.SaturatedLQRvsMPCExample()

Parameters: ​

NameDescriptionUnitsDefault value
umaxForce bound–1.0
vmaxVelocity bound of the MPC controller–0.8

Variables ​

NameDescriptionUnits
x_lqrPosition with the saturated LQR controller–
v_lqrVelocity with the saturated LQR controller–
u_lqrForce with the saturated LQR controller (after the limiter)–
x_mpcPosition with the MPC controller–
v_mpcVelocity with the MPC controller–
u_mpcForce with the MPC controller–

Behavior ​

Behavior of this component cannot be rendered because it includes path variables.

Source ​

dyad
"""
Comparison of a saturated LQR controller with an MPC controller on the double integrator
`DoubleIntegratorPlant`, both regulating the position from -2 to the origin with the full state
measured. The force is limited to ``|u| \\le`` `umax`.

The first loop uses an unconstrained `LinearMPCController` with the LQR cost-to-go as terminal cost,
which coincides with the LQR controller, followed by a `Limiter` at the plant input. The controller is
unaware of the saturation. The second loop uses the same weights, with the force bound and the velocity
bound ``|v| \\le`` `vmax` given to the controller as constraints.

Verified in `test/test_mpc.jl`.
"""
example component SaturatedLQRvsMPCExample
  "Force bound"
  structural parameter umax::Real = 1.0
  "Velocity bound of the MPC controller"
  structural parameter vmax::Real = 0.8
  clock_lqr = DiscreteComponents.PeriodicClock(dt = 0.1) {}
  clock_mpc = DiscreteComponents.PeriodicClock(dt = 0.1) {}
  plant_lqr = MPCComponents.Examples.DoubleIntegratorPlant(x0 = -2.0) {}
  plant_mpc = MPCComponents.Examples.DoubleIntegratorPlant(x0 = -2.0) {}
  sx_lqr = DiscreteComponents.Sampler() {}
  sv_lqr = DiscreteComponents.Sampler() {}
  sx_mpc = DiscreteComponents.Sampler() {}
  sv_mpc = DiscreteComponents.Sampler() {}
  zoh_lqr = DiscreteComponents.ZeroOrderHold() {}
  zoh_mpc = DiscreteComponents.ZeroOrderHold() {}
  saturation = BlockComponents.Nonlinear.Limiter(final y_max = umax) {}
  lqr = MPCComponents.LinearMPCController(dynamics = plant_lqr, inputs = ["u"], outputs = ["position", "velocity"], state_variables = ["x", "v"], Ts = 0.1, Np = 50, Q1 = [1.0, 0.0], Q2 = [0.01], reference_tracking = false, terminal_lqr_cost = true, R1 = [1.0, 1.0], R2 = [1e-6, 1e-6]) {}
  mpc = MPCComponents.LinearMPCController(dynamics = plant_mpc, inputs = ["u"], outputs = ["position", "velocity"], state_variables = ["x", "v"], Ts = 0.1, Np = 50, Q1 = [1.0, 0.0], Q2 = [0.01], reference_tracking = false, terminal_lqr_cost = true, umin = [-umax], umax = [umax], ymin = [-1e3, -vmax], ymax = [1e3, vmax], R1 = [1.0, 1.0], R2 = [1e-6, 1e-6]) {}
  "Position with the saturated LQR controller"
  variable x_lqr::Real
  "Velocity with the saturated LQR controller"
  variable v_lqr::Real
  "Force with the saturated LQR controller (after the limiter)"
  variable u_lqr::Real
  "Position with the MPC controller"
  variable x_mpc::Real
  "Velocity with the MPC controller"
  variable v_mpc::Real
  "Force with the MPC controller"
  variable u_mpc::Real
relations
  x_lqr = plant_lqr.position
  v_lqr = plant_lqr.velocity
  u_lqr = saturation.y
  x_mpc = plant_mpc.position
  v_mpc = plant_mpc.velocity
  u_mpc = zoh_mpc.y
  connect(plant_lqr.position, sx_lqr.u)
  connect(plant_lqr.velocity, sv_lqr.u)
  connect(sx_lqr.y, lqr.y[1], clock_lqr.y)
  connect(sv_lqr.y, lqr.y[2])
  connect(lqr.u[1], zoh_lqr.u)
  connect(zoh_lqr.y, saturation.u)
  connect(saturation.y, plant_lqr.u)
  connect(plant_mpc.position, sx_mpc.u)
  connect(plant_mpc.velocity, sv_mpc.u)
  connect(sx_mpc.y, mpc.y[1], clock_mpc.y)
  connect(sv_mpc.y, mpc.y[2])
  connect(mpc.u[1], zoh_mpc.u)
  connect(zoh_mpc.y, plant_mpc.u)
metadata {"Dyad": {"tests": {"case1": {"stop": 10}}, "doc": {"behavior": false}}}
end
Flattened Source
dyad
"""
Comparison of a saturated LQR controller with an MPC controller on the double integrator
`DoubleIntegratorPlant`, both regulating the position from -2 to the origin with the full state
measured. The force is limited to ``|u| \\le`` `umax`.

The first loop uses an unconstrained `LinearMPCController` with the LQR cost-to-go as terminal cost,
which coincides with the LQR controller, followed by a `Limiter` at the plant input. The controller is
unaware of the saturation. The second loop uses the same weights, with the force bound and the velocity
bound ``|v| \\le`` `vmax` given to the controller as constraints.

Verified in `test/test_mpc.jl`.
"""
example component SaturatedLQRvsMPCExample
  "Force bound"
  structural parameter umax::Real = 1.0
  "Velocity bound of the MPC controller"
  structural parameter vmax::Real = 0.8
  clock_lqr = DiscreteComponents.PeriodicClock(dt = 0.1) {}
  clock_mpc = DiscreteComponents.PeriodicClock(dt = 0.1) {}
  plant_lqr = MPCComponents.Examples.DoubleIntegratorPlant(x0 = -2.0) {}
  plant_mpc = MPCComponents.Examples.DoubleIntegratorPlant(x0 = -2.0) {}
  sx_lqr = DiscreteComponents.Sampler() {}
  sv_lqr = DiscreteComponents.Sampler() {}
  sx_mpc = DiscreteComponents.Sampler() {}
  sv_mpc = DiscreteComponents.Sampler() {}
  zoh_lqr = DiscreteComponents.ZeroOrderHold() {}
  zoh_mpc = DiscreteComponents.ZeroOrderHold() {}
  saturation = BlockComponents.Nonlinear.Limiter(final y_max = umax) {}
  lqr = MPCComponents.LinearMPCController(dynamics = plant_lqr, inputs = ["u"], outputs = ["position", "velocity"], state_variables = ["x", "v"], Ts = 0.1, Np = 50, Q1 = [1.0, 0.0], Q2 = [0.01], reference_tracking = false, terminal_lqr_cost = true, R1 = [1.0, 1.0], R2 = [1e-6, 1e-6]) {}
  mpc = MPCComponents.LinearMPCController(dynamics = plant_mpc, inputs = ["u"], outputs = ["position", "velocity"], state_variables = ["x", "v"], Ts = 0.1, Np = 50, Q1 = [1.0, 0.0], Q2 = [0.01], reference_tracking = false, terminal_lqr_cost = true, umin = [-umax], umax = [umax], ymin = [-1e3, -vmax], ymax = [1e3, vmax], R1 = [1.0, 1.0], R2 = [1e-6, 1e-6]) {}
  "Position with the saturated LQR controller"
  variable x_lqr::Real
  "Velocity with the saturated LQR controller"
  variable v_lqr::Real
  "Force with the saturated LQR controller (after the limiter)"
  variable u_lqr::Real
  "Position with the MPC controller"
  variable x_mpc::Real
  "Velocity with the MPC controller"
  variable v_mpc::Real
  "Force with the MPC controller"
  variable u_mpc::Real
relations
  x_lqr = plant_lqr.position
  v_lqr = plant_lqr.velocity
  u_lqr = saturation.y
  x_mpc = plant_mpc.position
  v_mpc = plant_mpc.velocity
  u_mpc = zoh_mpc.y
  connect(plant_lqr.position, sx_lqr.u)
  connect(plant_lqr.velocity, sv_lqr.u)
  connect(sx_lqr.y, lqr.y[1], clock_lqr.y)
  connect(sv_lqr.y, lqr.y[2])
  connect(lqr.u[1], zoh_lqr.u)
  connect(zoh_lqr.y, saturation.u)
  connect(saturation.y, plant_lqr.u)
  connect(plant_mpc.position, sx_mpc.u)
  connect(plant_mpc.velocity, sv_mpc.u)
  connect(sx_mpc.y, mpc.y[1], clock_mpc.y)
  connect(sv_mpc.y, mpc.y[2])
  connect(mpc.u[1], zoh_mpc.u)
  connect(zoh_mpc.y, plant_mpc.u)
metadata {"Dyad": {"tests": {"case1": {"stop": 10}}, "doc": {"behavior": false}}}
end


Test Cases ​

Test Case case1 ​

  • Examples

  • Experiments

  • Analyses