Skip to content

Commit 76ea724

Browse files
committed
Infer state-space f and h function types to eleminate the remaining abstract fields in SimModel object.
1 parent 67a509f commit 76ea724

File tree

7 files changed

+58
-46
lines changed

7 files changed

+58
-46
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
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 = "0.3.2"
4+
version = "0.3.3"
55

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

example/juMPC.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ function test_mpc(model, mpc)
130130
end
131131

132132
@time u_data, y_data, r_data, d_data = test_mpc(linModel4, mpc)
133-
@profview u_data, y_data, r_data, d_data = test_mpc(linModel4, mpc)
133+
#@profview u_data, y_data, r_data, d_data = test_mpc(linModel4, mpc)
134134
#=
135135
using PlotThemes, Plots
136136
#theme(:default)

src/estimator/internal_model.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ sum both values : ``\mathbf{ŷ = ŷ_d + ŷ_s}``.
6363
# Examples
6464
```jldoctest
6565
julia> estim = InternalModel(LinModel([tf(3, [30, 1]); tf(-2, [5, 1])], 0.5), i_ym=[2])
66-
InternalModel{LinModel} estimator with a sample time Ts = 0.5 s and:
66+
InternalModel estimator with a sample time Ts = 0.5 s, LinModel and:
6767
1 manipulated inputs u
6868
2 states x̂
6969
1 measured outputs ym

src/estimator/kalman.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ ones, for ``\mathbf{Ĉ^u, D̂_d^u}``).
9999
julia> model = LinModel([tf(3, [30, 1]); tf(-2, [5, 1])], 0.5);
100100
101101
julia> estim = SteadyKalmanFilter(model, i_ym=[2], σR=[1], σQ_int=[0.01])
102-
SteadyKalmanFilter estimator with a sample time Ts = 0.5 s and:
102+
SteadyKalmanFilter estimator with a sample time Ts = 0.5 s, LinModel and:
103103
1 manipulated inputs u
104104
3 states x̂
105105
1 measured outputs ym
@@ -244,7 +244,7 @@ with ``\mathbf{P̂}_{-1}(0) = \mathrm{diag}\{ \mathbf{P}(0), \mathbf{P_{int}}(0)
244244
julia> model = LinModel([tf(3, [30, 1]); tf(-2, [5, 1])], 0.5);
245245
246246
julia> estim = KalmanFilter(model, i_ym=[2], σR=[1], σP0=[100, 100], σQ_int=[0.01])
247-
KalmanFilter estimator with a sample time Ts = 0.5 s and:
247+
KalmanFilter estimator with a sample time Ts = 0.5 s, LinModel and:
248248
1 manipulated inputs u
249249
3 states x̂
250250
1 measured outputs ym
@@ -407,7 +407,7 @@ unmeasured ones, for ``\mathbf{ĥ^u}``).
407407
julia> model = NonLinModel((x,u,_)->0.1x+u, (x,_)->2x, 10, 1, 1, 1);
408408
409409
julia> estim = UnscentedKalmanFilter(model, σR=[1], nint_ym=[2], σP0_int=[1, 1])
410-
UnscentedKalmanFilter{NonLinModel} estimator with a sample time Ts = 10.0 s and:
410+
UnscentedKalmanFilter estimator with a sample time Ts = 10.0 s, NonLinModel and:
411411
1 manipulated inputs u
412412
3 states x̂
413413
1 measured outputs ym

src/predictive_control.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ default arguments.
416416
julia> model = NonLinModel((x,u,_)->0.5x+u, (x,_)->2x, 10, 1, 1, 1);
417417
418418
julia> mpc = NonLinMPC(model, Hp=20, Hc=1, Cwt=1e6)
419-
NonLinMPC controller with a sample time Ts = 10.0 s, UnscentedKalmanFilter{NonLinModel} estimator and:
419+
NonLinMPC controller with a sample time Ts = 10.0 s, UnscentedKalmanFilter estimator and:
420420
1 manipulated inputs u
421421
2 states x̂
422422
1 measured outputs ym
@@ -444,7 +444,7 @@ julia> model = NonLinModel((x,u,_)->0.5x+u, (x,_)->2x, 10, 1, 1, 1);
444444
julia> estim = UnscentedKalmanFilter(model, σQ_int=[0.05]);
445445
446446
julia> mpc = NonLinMPC(estim, Hp=20, Hc=1, Cwt=1e6)
447-
NonLinMPC controller with a sample time Ts = 10.0 s, UnscentedKalmanFilter{NonLinModel} estimator and:
447+
NonLinMPC controller with a sample time Ts = 10.0 s, UnscentedKalmanFilter estimator and:
448448
1 manipulated inputs u
449449
2 states x̂
450450
1 measured outputs ym
@@ -1232,8 +1232,8 @@ repeatdiag(A, n::Int) = kron(I(n), A)
12321232

12331233

12341234
function Base.show(io::IO, mpc::PredictiveController)
1235-
println(io, "$(typeof(mpc).name.name) controller with a sample time "*
1236-
"Ts = $(mpc.estim.model.Ts) s, $(typeof(mpc).parameters[1]) estimator and:")
1235+
println(io, "$(typeof(mpc).name.name) controller with a sample time Ts = "*
1236+
"$(mpc.estim.model.Ts) s, $(typeof(mpc.estim).name.name) estimator and:")
12371237
println(io, " $(mpc.estim.model.nu) manipulated inputs u")
12381238
println(io, " $(mpc.estim.nx̂) states x̂")
12391239
println(io, " $(mpc.estim.nym) measured outputs ym")

src/sim_model.jl

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const IntRangeOrVector = Union{UnitRange{Int}, Vector{Int}}
2+
13
@doc raw"""
24
Abstract supertype of [`LinModel`](@ref) and [`NonLinModel`](@ref) types.
35
@@ -18,7 +20,7 @@ julia> y = model()
1820
"""
1921
abstract type SimModel end
2022

21-
struct LinModel <: SimModel
23+
struct LinModel{F<:Function, H<:Function} <: SimModel
2224
A ::Matrix{Float64}
2325
Bu ::Matrix{Float64}
2426
C ::Matrix{Float64}
@@ -35,20 +37,15 @@ struct LinModel <: SimModel
3537
uop::Vector{Float64}
3638
yop::Vector{Float64}
3739
dop::Vector{Float64}
38-
function LinModel(A, Bu, C, Bd, Dd, Ts, nu, nx, ny, nd)
40+
function LinModel{F, H}(
41+
A, Bu, C, Bd, Dd, f::F, h::H, Ts, nu, nx, ny, nd
42+
) where{F<:Function, H<:Function}
3943
size(A) == (nx,nx) || error("A size must be $((nx,nx))")
4044
size(Bu) == (nx,nu) || error("Bu size must be $((nx,nu))")
4145
size(C) == (ny,nx) || error("C size must be $((ny,nx))")
4246
size(Bd) == (nx,nd) || error("Bd size must be $((nx,nd))")
4347
size(Dd) == (ny,nd) || error("Dd size must be $((ny,nd))")
4448
Ts > 0 || error("Sampling time Ts must be positive")
45-
# the `let` block captures and fixes A, Bu, Bd, C, Dd values (faster computations):
46-
f = let A=A, Bu=Bu, Bd=Bd
47-
(x,u,d) -> A*x + Bu*u + Bd*d
48-
end
49-
h = let C=C, Dd=Dd
50-
(x,d) -> C*x + Dd*d
51-
end
5249
uop = zeros(nu)
5350
yop = zeros(ny)
5451
dop = zeros(nd)
@@ -57,8 +54,12 @@ struct LinModel <: SimModel
5754
end
5855
end
5956

60-
61-
const IntRangeOrVector = Union{UnitRange{Int}, Vector{Int}}
57+
"Infer the type of state-space `f` and `h` functions and construct the linear model."
58+
function LinModel_ssfunc(
59+
A, Bu, C, Bd, Dd, f::F, h::H, Ts, nu, nx, ny, nd
60+
) where {F<:Function, H<:Function}
61+
return LinModel{F, H}(A, Bu, C, Bd, Dd, f, h, Ts, nu, nx, ny, nd)
62+
end
6263

6364
@doc raw"""
6465
LinModel(sys::StateSpace[, Ts]; i_u=1:size(sys,2), i_d=Int[])
@@ -159,7 +160,14 @@ function LinModel(
159160
Bd = sys_dis.B[:,nu+1:end]
160161
C = sys_dis.C;
161162
Dd = sys_dis.D[:,nu+1:end]
162-
return LinModel(A, Bu, C, Bd, Dd, Ts, nu, nx, ny, nd)
163+
# the `let` block captures and fixes A, Bu, Bd, C, Dd values (faster computations):
164+
f = let A=A, Bu=Bu, Bd=Bd
165+
(x,u,d) -> A*x + Bu*u + Bd*d
166+
end
167+
h = let C=C, Dd=Dd
168+
(x,d) -> C*x + Dd*d
169+
end
170+
return LinModel_ssfunc(A, Bu, C, Bd, Dd, f, h, Ts, nu, nx, ny, nd)
163171
end
164172

165173
@doc raw"""
@@ -208,7 +216,6 @@ function LinModel(sys::DelayLtiSystem, Ts::Real; kwargs...)
208216
return LinModel(sys_dis, Ts; kwargs...)
209217
end
210218

211-
212219
@doc raw"""
213220
steadystate(model::LinModel, u, d=Float64[])
214221
@@ -226,6 +233,28 @@ function steadystate(model::LinModel, u, d=Float64[])
226233
return pinv(I - model.A)*(model.Bu*(u - model.uop) + model.Bd*(d - model.dop))
227234
end
228235

236+
struct NonLinModel{F<:Function, H<:Function} <: SimModel
237+
x::Vector{Float64}
238+
f::F
239+
h::H
240+
Ts::Float64
241+
nu::Int
242+
nx::Int
243+
ny::Int
244+
nd::Int
245+
uop::Vector{Float64}
246+
yop::Vector{Float64}
247+
dop::Vector{Float64}
248+
function NonLinModel{F,H}(f::F, h::H, Ts, nu, nx, ny, nd) where {F<:Function,H<:Function}
249+
Ts > 0 || error("Sampling time Ts must be positive")
250+
validate_fcts(f, h)
251+
uop = zeros(nu)
252+
yop = zeros(ny)
253+
dop = zeros(nd)
254+
x = zeros(nx)
255+
return new(x, f, h, Ts, nu, nx, ny, nd, uop, yop, dop)
256+
end
257+
end
229258

230259
@doc raw"""
231260
NonLinModel(f::Function, h::Function, Ts, nu, nx, ny, nd=0)
@@ -260,27 +289,10 @@ Discrete-time nonlinear model with a sample time Ts = 10.0 s and:
260289
0 measured disturbances d
261290
```
262291
"""
263-
struct NonLinModel <: SimModel
264-
x::Vector{Float64}
265-
f::Function
266-
h::Function
267-
Ts::Float64
268-
nu::Int
269-
nx::Int
270-
ny::Int
271-
nd::Int
272-
uop::Vector{Float64}
273-
yop::Vector{Float64}
274-
dop::Vector{Float64}
275-
function NonLinModel(f, h, Ts::Real, nu::Int, nx::Int, ny::Int, nd::Int = 0)
276-
Ts > 0 || error("Sampling time Ts must be positive")
277-
validate_fcts(f, h)
278-
uop = zeros(nu)
279-
yop = zeros(ny)
280-
dop = zeros(nd)
281-
x = zeros(nx)
282-
return new(x, f, h, Ts, nu, nx, ny, nd, uop, yop, dop)
283-
end
292+
function NonLinModel(
293+
f::F, h::H, Ts::Real, nu::Int, nx::Int, ny::Int, nd::Int=0
294+
) where {F<:Function, H<:Function}
295+
return NonLinModel{F, H}(f, h, Ts, nu, nx, ny, nd)
284296
end
285297

286298
function validate_fcts(f, h)

src/state_estim.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ end
3434

3535

3636
function Base.show(io::IO, estim::StateEstimator)
37-
println(io, "$(typeof(estim)) estimator with "*
38-
"a sample time Ts = $(estim.model.Ts) s and:")
37+
println(io, "$(typeof(estim).name.name) estimator with a sample time "*
38+
"Ts = $(estim.model.Ts) s, $(typeof(estim.model).name.name) and:")
3939
println(io, " $(estim.model.nu) manipulated inputs u")
4040
println(io, " $(estim.nx̂) states x̂")
4141
println(io, " $(estim.nym) measured outputs ym")

0 commit comments

Comments
 (0)