Skip to content

Commit bbb131b

Browse files
authored
Merge pull request #128 from JuliaControl/custom_constraints
Custom constraints : add tests
2 parents c36fc27 + 2240065 commit bbb131b

File tree

11 files changed

+287
-153
lines changed

11 files changed

+287
-153
lines changed

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ModelPredictiveControl"
22
uuid = "61f9bdb8-6ae4-484a-811f-bbf86720c31c"
33
authors = ["Francis Gagnon"]
4-
version = "1.0.2"
4+
version = "1.1.0"
55

66
[deps]
77
ControlSystemsBase = "aaaaaaaa-a6ca-5380-bf3e-84a91bcd477e"

README.md

+58-63
Original file line numberDiff line numberDiff line change
@@ -70,71 +70,66 @@ for more detailed examples.
7070

7171
## Features
7272

73-
### Legend
74-
75-
- [x] implemented feature
76-
- [ ] planned feature
77-
7873
### Model Predictive Control Features
7974

80-
- [x] linear and nonlinear plant models exploiting multiple dispatch
81-
- [x] model linearization based on automatic differentiation (exact Jacobians)
82-
- [x] supported objective function terms:
83-
- [x] output setpoint tracking
84-
- [x] move suppression
85-
- [x] input setpoint tracking
86-
- [x] terminal costs
87-
- [x] custom economic costs (economic model predictive control)
88-
- [x] adaptive linear model predictive controller
89-
- [x] manual model modification
90-
- [x] automatic successive linearization of a nonlinear model
91-
- [x] objective function weights and covariance matrices modification
92-
- [x] explicit predictive controller for problems without constraint
93-
- [x] online-tunable soft and hard constraints on:
94-
- [x] output predictions
95-
- [x] manipulated inputs
96-
- [x] manipulated inputs increments
97-
- [x] terminal states to ensure nominal stability
98-
- [x] custom economic inequality constraints (soft or hard)
99-
- [x] supported feedback strategy:
100-
- [x] state estimator (see State Estimation features)
101-
- [x] internal model structure with a custom stochastic model
102-
- [x] automatic model augmentation with integrating states for offset-free tracking
103-
- [x] support for unmeasured model outputs
104-
- [x] feedforward action with measured disturbances that supports direct transmission
105-
- [x] custom predictions for:
106-
- [x] output setpoints
107-
- [x] measured disturbances
108-
- [x] easy integration with `Plots.jl`
109-
- [x] optimization based on `JuMP.jl`:
110-
- [x] quickly compare multiple optimizers
111-
- [x] nonlinear solvers relying on automatic differentiation (exact derivative)
112-
- [x] additional information about the optimum to ease troubleshooting
113-
- [x] real-time control loop features:
114-
- [x] implementations that carefully limits the allocations
115-
- [x] simple soft real-time utilities
75+
- linear and nonlinear plant models exploiting multiple dispatch
76+
- model linearization based on automatic differentiation (exact Jacobians)
77+
- supported objective function terms:
78+
- output setpoint tracking
79+
- move suppression
80+
- input setpoint tracking
81+
- terminal costs
82+
- custom economic costs (economic model predictive control)
83+
- adaptive linear model predictive controller
84+
- manual model modification
85+
- automatic successive linearization of a nonlinear model
86+
- objective function weights and covariance matrices modification
87+
- explicit predictive controller for problems without constraint
88+
- online-tunable soft and hard constraints on:
89+
- output predictions
90+
- manipulated inputs
91+
- manipulated inputs increments
92+
- terminal states to ensure nominal stability
93+
- custom nonlinear inequality constraints (soft or hard)
94+
- supported feedback strategy:
95+
- state estimator (see State Estimation features)
96+
- internal model structure with a custom stochastic model
97+
- automatic model augmentation with integrating states for offset-free tracking
98+
- support for unmeasured model outputs
99+
- feedforward action with measured disturbances that supports direct transmission
100+
- custom predictions for:
101+
- output setpoints
102+
- measured disturbances
103+
- easy integration with `Plots.jl`
104+
- optimization based on `JuMP.jl`:
105+
- quickly compare multiple optimizers
106+
- nonlinear solvers relying on automatic differentiation (exact derivative)
107+
- additional information about the optimum to ease troubleshooting
108+
- real-time control loop features:
109+
- implementations that carefully limits the allocations
110+
- simple soft real-time utilities
116111

117112
### State Estimation Features
118113

119-
- [x] supported state estimators/observers:
120-
- [x] steady-state Kalman filter
121-
- [x] Kalman filter
122-
- [x] Luenberger observer
123-
- [x] internal model structure
124-
- [x] extended Kalman filter
125-
- [x] unscented Kalman filter
126-
- [x] moving horizon estimator
127-
- [x] easily estimate unmeasured disturbances by adding one or more integrators at the:
128-
- [x] manipulated inputs
129-
- [x] measured outputs
130-
- [x] bumpless manual to automatic transfer for control with a proper initial estimate
131-
- [x] estimators in two possible forms:
132-
- [x] filter (or current) form to improve accuracy and robustness
133-
- [x] predictor (or delayed) form to reduce computational load
134-
- [x] moving horizon estimator in two formulations:
135-
- [x] linear plant models (quadratic optimization)
136-
- [x] nonlinear plant models (nonlinear optimization)
137-
- [x] moving horizon estimator online-tunable soft and hard constraints on:
138-
- [x] state estimates
139-
- [x] process noise estimates
140-
- [x] sensor noise estimates
114+
- supported state estimators/observers:
115+
- steady-state Kalman filter
116+
- Kalman filter
117+
- Luenberger observer
118+
- internal model structure
119+
- extended Kalman filter
120+
- unscented Kalman filter
121+
- moving horizon estimator
122+
- easily estimate unmeasured disturbances by adding one or more integrators at the:
123+
- manipulated inputs
124+
- measured outputs
125+
- bumpless manual to automatic transfer for control with a proper initial estimate
126+
- estimators in two possible forms:
127+
- filter (or current) form to improve accuracy and robustness
128+
- predictor (or delayed) form to reduce computational load
129+
- moving horizon estimator in two formulations:
130+
- linear plant models (quadratic optimization)
131+
- nonlinear plant models (nonlinear optimization)
132+
- moving horizon estimator online-tunable soft and hard constraints on:
133+
- state estimates
134+
- process noise estimates
135+
- sensor noise estimates

docs/src/public/predictive_control.md

+12-7
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ assumes by default that the current model mismatch estimation is constant in the
1212
(same approach as dynamic matrix control, DMC).
1313

1414
!!! info
15-
The nomenclature uses capital letters for time series (and matrices) and hats for the
16-
predictions (and estimations, for state estimators).
15+
The nomenclature uses boldfaces for vectors or matrices, capital boldface letters for
16+
vectors representing time series (and also for matrices), and hats for the predictions
17+
(and also for the observer estimations).
1718

1819
To be precise, at the ``k``th control period, the vectors that encompass the future measured
1920
disturbances ``\mathbf{d̂}``, model outputs ``\mathbf{ŷ}`` and setpoints ``\mathbf{r̂_y}``
@@ -31,7 +32,9 @@ over the prediction horizon ``H_p`` are defined as:
3132
\end{bmatrix}
3233
```
3334

34-
The vectors for the manipulated input ``\mathbf{u}`` are shifted by one time step:
35+
in which ``\mathbf{D̂}``, ``\mathbf{Ŷ}`` and ``\mathbf{R̂_y}`` are vectors of `nd*Hp`, `ny*Hp`
36+
and `ny*Hp` elements, respectively. The vectors for the manipulated input ``\mathbf{u}``
37+
are shifted by one time step:
3538

3639
```math
3740
\mathbf{U} = \begin{bmatrix}
@@ -42,10 +45,10 @@ The vectors for the manipulated input ``\mathbf{u}`` are shifted by one time ste
4245
\end{bmatrix}
4346
```
4447

45-
Defining the manipulated input increment as ``\mathbf{Δu}(k+j) =
46-
\mathbf{u}(k+j) - \mathbf{u}(k+j-1)``, the control horizon ``H_c`` enforces that
47-
``\mathbf{Δu}(k+j) = \mathbf{0}`` for ``j ≥ H_c``. For this reason, the vector that collects
48-
them is truncated up to ``k+H_c-1``:
48+
in which ``\mathbf{U}`` and ``\mathbf{R̂_u}`` are both vectors of `nu*Hp` elements. Defining
49+
the manipulated input increment as ``\mathbf{Δu}(k+j) = \mathbf{u}(k+j) - \mathbf{u}(k+j-1)``,
50+
the control horizon ``H_c`` enforces that ``\mathbf{Δu}(k+j) = \mathbf{0}`` for ``j ≥ H_c``.
51+
For this reason, the vector that collects them is truncated up to ``k+H_c-1``:
4952

5053
```math
5154
\mathbf{ΔU} =
@@ -54,6 +57,8 @@ them is truncated up to ``k+H_c-1``:
5457
\end{bmatrix}
5558
```
5659

60+
in which ``\mathbf{ΔU}`` is a vector of `nu*Hc` elements.
61+
5762
## PredictiveController
5863

5964
```@docs

docs/src/public/sim_model.md

+6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ simulators by calling [`evaloutput`](@ref) and [`updatestate!`](@ref) methods on
1111
the states ``\mathbf{x}`` are stored inside [`SimModel`](@ref) instances. Use [`setstate!`](@ref)
1212
method to manually modify them.
1313

14+
!!! info
15+
The nomenclature in this page introduces the model manipulated input ``\mathbf{u}``,
16+
measured disturbances ``\mathbf{d}``, state ``\mathbf{x}`` and output ``\mathbf{y}``,
17+
four vectors of `nu`, `nd`, `nx` and `ny` elements, respectively. The ``\mathbf{z}``
18+
vector combines the elements of ``\mathbf{u}`` and ``\mathbf{d}``.
19+
1420
## SimModel
1521

1622
```@docs

docs/src/public/state_estim.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ solving the MPC problem with [`moveinput!`](@ref), for when the estimations are
2828
[^1]: also denoted ``\mathbf{x̂}_{k|k}`` [elsewhere](https://en.wikipedia.org/wiki/Kalman_filter).
2929

3030
!!! info
31-
All the estimators support measured ``\mathbf{y^m}`` and unmeasured ``\mathbf{y^u}``
32-
model outputs, where ``\mathbf{y}`` refers to all of them.
31+
The nomenclature in this page introduces the estimated state ``\mathbf{x̂}`` and output
32+
``\mathbf{ŷ}`` vectors of respectively `nx̂` and `ny` elements. Also, all the estimators
33+
support measured ``\mathbf{y^m}`` (`nym` elements) and unmeasured ``\mathbf{y^u}``
34+
(`nyu` elements) model output, where ``\mathbf{y}`` refers to all of them.
3335

3436
## StateEstimator
3537

src/controller/execute.jl

+17-17
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ function getinfo(mpc::PredictiveController{NT}) where NT<:Real
120120
Ȳ, Ū = similar(mpc.Yop), similar(mpc.Uop)
121121
Ŷe, Ue = Vector{NT}(undef, nŶe), Vector{NT}(undef, nUe)
122122
Ŷ0, x̂0end = predict!(Ŷ0, x̂0, x̂0next, u0, û0, mpc, model, mpc.ΔŨ)
123-
Ŷe, Ue = extended_predictions!(Ŷe, Ue, Ū, mpc, model, Ŷ0, mpc.ΔŨ)
124-
J = obj_nonlinprog!(Ȳ, Ū, mpc, model, Ŷe, Ue, mpc.ΔŨ)
123+
Ue, Ŷe = extended_predictions!(Ue, Ŷe, Ū, mpc, model, Ŷ0, mpc.ΔŨ)
124+
J = obj_nonlinprog!(Ȳ, Ū, mpc, model, Ue, Ŷe, mpc.ΔŨ)
125125
U =
126126
U .= @views Ue[1:end-model.nu]
127127
=
@@ -362,28 +362,28 @@ function predict!(Ŷ0, x̂0, x̂0next, u0, û0, mpc::PredictiveController, mod
362362
end
363363

364364
"""
365-
extended_predictions!(Ŷe, Ue, Ū, mpc, model, Ŷ0, ΔŨ) -> Ŷe, Ue
365+
extended_predictions!(Ue, Ŷe, Ū, mpc, model, Ŷ0, ΔŨ) -> Ŷe, Ue
366366
367-
Compute the extended predictions `Ŷe` and `Ue` for the nonlinear optimization.
367+
Compute the extended vectors `Ue` and `Ŷe` and for the nonlinear optimization.
368368
369-
The function mutates `Ŷe`, `Ue` and `Ū` in arguments, without assuming any initial values.
369+
The function mutates `Ue`, `Ŷe` and `Ū` in arguments, without assuming any initial values.
370370
"""
371-
function extended_predictions!(Ŷe, Ue, Ū, mpc, model, Ŷ0, ΔŨ)
371+
function extended_predictions!(Ue, Ŷe, Ū, mpc, model, Ŷ0, ΔŨ)
372372
ny, nu = model.ny, model.nu
373-
# --- extended output predictions Ŷe = [ŷ(k); Ŷ] ---
374-
Ŷe[1:ny] .= mpc.
375-
Ŷe[ny+1:end] .= Ŷ0 .+ mpc.Yop
376373
# --- extended manipulated inputs Ue = [U; u(k+Hp-1)] ---
377374
U0 =
378375
U0 .= mul!(U0, mpc.S̃, ΔŨ) .+ mpc.T_lastu0
379376
Ue[1:end-nu] .= U0 .+ mpc.Uop
380377
# u(k + Hp) = u(k + Hp - 1) since Δu(k+Hp) = 0 (because Hc ≤ Hp):
381378
Ue[end-nu+1:end] .= @views Ue[end-2nu+1:end-nu]
382-
return Ŷe, Ue
379+
# --- extended output predictions Ŷe = [ŷ(k); Ŷ] ---
380+
Ŷe[1:ny] .= mpc.
381+
Ŷe[ny+1:end] .= Ŷ0 .+ mpc.Yop
382+
return Ue, Ŷe
383383
end
384384

385385
"""
386-
obj_nonlinprog!( _ , _ , mpc::PredictiveController, model::LinModel, Ŷe, Ue, ΔŨ)
386+
obj_nonlinprog!( _ , _ , mpc::PredictiveController, model::LinModel, Ue, Ŷe, ΔŨ)
387387
388388
Nonlinear programming objective function when `model` is a [`LinModel`](@ref).
389389
@@ -392,23 +392,23 @@ also be called on any [`PredictiveController`](@ref)s to evaluate the objective
392392
at specific `Ue`, `Ŷe` and `ΔŨ`, values. It does not mutate any argument.
393393
"""
394394
function obj_nonlinprog!(
395-
_, _, mpc::PredictiveController, model::LinModel, Ŷe, Ue, ΔŨ::AbstractVector{NT}
395+
_, _, mpc::PredictiveController, model::LinModel, Ue, Ŷe, ΔŨ::AbstractVector{NT}
396396
) where NT <: Real
397397
JQP = obj_quadprog(ΔŨ, mpc.H̃, mpc.q̃) + mpc.r[]
398-
E_JE = obj_econ!(Ue, Ŷe, mpc, model)
398+
E_JE = obj_econ(mpc, model, Ue, Ŷe)
399399
return JQP + E_JE
400400
end
401401

402402
"""
403-
obj_nonlinprog!(Ȳ, Ū, mpc::PredictiveController, model::SimModel, Ŷe, Ue, ΔŨ)
403+
obj_nonlinprog!(Ȳ, Ū, mpc::PredictiveController, model::SimModel, Ue, Ŷe, ΔŨ)
404404
405405
Nonlinear programming objective method when `model` is not a [`LinModel`](@ref). The
406406
function `dot(x, A, x)` is a performant way of calculating `x'*A*x`. This method mutates
407407
`Ȳ` and `Ū` arguments, without assuming any initial values (it recuperates the values in
408408
`Ŷe` and `Ue` arguments).
409409
"""
410410
function obj_nonlinprog!(
411-
Ȳ, Ū, mpc::PredictiveController, model::SimModel, Ŷe, Ue, ΔŨ::AbstractVector{NT}
411+
Ȳ, Ū, mpc::PredictiveController, model::SimModel, Ue, Ŷe, ΔŨ::AbstractVector{NT}
412412
) where NT<:Real
413413
nu, ny = model.nu, model.ny
414414
# --- output setpoint tracking term ---
@@ -426,12 +426,12 @@ function obj_nonlinprog!(
426426
JR̂u = 0.0
427427
end
428428
# --- economic term ---
429-
E_JE = obj_econ!(Ue, Ŷe, mpc, model)
429+
E_JE = obj_econ(mpc, model, Ue, Ŷe)
430430
return JR̂y + JΔŨ + JR̂u + E_JE
431431
end
432432

433433
"By default, the economic term is zero."
434-
obj_econ!( _ , _ , ::PredictiveController, ::SimModel) = 0.0
434+
obj_econ(::PredictiveController, ::SimModel, _ , _ ) = 0.0
435435

436436
@doc raw"""
437437
optim_objective!(mpc::PredictiveController) -> ΔŨ

src/controller/linmpc.jl

+1
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ LinMPC controller with a sample time Ts = 4.0 s, OSQP optimizer, SteadyKalmanFil
175175
| ``H_p`` | prediction horizon (integer) | `()` |
176176
| ``H_c`` | control horizon (integer) | `()` |
177177
| ``\mathbf{ΔU}`` | manipulated input increments over ``H_c`` | `(nu*Hc,)` |
178+
| ``\mathbf{D̂}`` | predicted measured disturbances over ``H_p`` | `(nd*Hp,)` |
178179
| ``\mathbf{Ŷ}`` | predicted outputs over ``H_p`` | `(ny*Hp,)` |
179180
| ``\mathbf{U}`` | manipulated inputs over ``H_p`` | `(nu*Hp,)` |
180181
| ``\mathbf{R̂_y}`` | predicted output setpoints over ``H_p`` | `(ny*Hp,)` |

0 commit comments

Comments
 (0)