Skip to content

Commit 58e355e

Browse files
authored
Merge pull request #52 from JuliaControl/adapt_linmpc
Added: adaptatation of `LinMPC` model through `setmodel!`
2 parents 3228f29 + 3353368 commit 58e355e

18 files changed

+178
-97
lines changed

docs/src/public/generic_func.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ initstate!
3737
setstate!
3838
```
3939

40+
## Set Plant Model
41+
42+
```@docs
43+
setmodel!
44+
```
45+
4046
## Quick Simulation
4147

4248
### Simulate

src/ModelPredictiveControl.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import OSQP, Ipopt
2323

2424
export SimModel, LinModel, NonLinModel
2525
export DiffSolver, RungeKutta
26-
export setop!, setstate!, updatestate!, evaloutput, linearize
26+
export setop!, setstate!, setmodel!, updatestate!, evaloutput, linearize
2727
export StateEstimator, InternalModel, Luenberger
2828
export SteadyKalmanFilter, KalmanFilter, UnscentedKalmanFilter, ExtendedKalmanFilter
2929
export MovingHorizonEstimator

src/controller/construct.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ function init_quadprog(::LinModel{NT}, Ẽ, S̃, M_Hp, Ñ_Hc, L_Hp) where {NT<:
548548
end
549549
"Return empty matrices if `model` is not a [`LinModel`](@ref)."
550550
function init_quadprog(::SimModel{NT}, Ẽ, S̃, M_Hp, Ñ_Hc, L_Hp) where {NT<:Real}
551-
= Hermitian(zeros(NT, 0, 0))
551+
= Hermitian(zeros(NT, 0, 0), :L)
552552
= zeros(NT, 0)
553553
p = zeros(NT, 1) # dummy value (updated just before optimization)
554554
return H̃, q̃, p
@@ -679,7 +679,7 @@ function relaxΔU(::SimModel{NT}, C, C_Δumin, C_Δumax, ΔUmin, ΔUmax, N_Hc) w
679679
ΔŨmin, ΔŨmax = [ΔUmin; NT[0.0]], [ΔUmax; NT[Inf]]
680680
A_ϵ = [zeros(NT, 1, length(ΔUmin)) NT[1.0]]
681681
A_ΔŨmin, A_ΔŨmax = -[I C_Δumin; A_ϵ], [I -C_Δumax; A_ϵ]
682-
Ñ_Hc = Hermitian([N_Hc zeros(NT, nΔU, 1);zeros(NT, 1, nΔU) C])
682+
Ñ_Hc = Hermitian([N_Hc zeros(NT, nΔU, 1);zeros(NT, 1, nΔU) C], :L)
683683
else # ΔŨ = ΔU (only hard constraints)
684684
ΔŨmin, ΔŨmax = ΔUmin, ΔUmax
685685
I_Hc = Matrix{NT}(I, nΔU, nΔU)

src/controller/execute.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,3 +474,10 @@ Call [`updatestate!`](@ref) on `mpc.estim` [`StateEstimator`](@ref).
474474
"""
475475
updatestate!(mpc::PredictiveController, u, ym, d=empty(mpc.estim.x̂)) = updatestate!(mpc.estim,u,ym,d)
476476
updatestate!(::PredictiveController, _ ) = throw(ArgumentError("missing measured outputs ym"))
477+
478+
"""
479+
setstate!(mpc::PredictiveController, x̂)
480+
481+
Set the estimate at `mpc.estim.x̂`.
482+
"""
483+
setstate!(mpc::PredictiveController, x̂) = (setstate!(mpc.estim, x̂); return mpc)

src/controller/explicitmpc.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ struct ExplicitMPC{NT<:Real, SE<:StateEstimator} <: PredictiveController{NT}
4242
Ewt = 0 # economic costs not supported for ExplicitMPC
4343
validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt)
4444
# Matrix() call is needed to convert `Diagonal` to normal `Matrix`
45-
M_Hp, N_Hc, L_Hp = Hermitian(Matrix(M_Hp)), Hermitian(Matrix(N_Hc)), Hermitian(Matrix(L_Hp))
45+
M_Hp = Hermitian(Matrix(M_Hp), :L)
46+
N_Hc = Hermitian(Matrix(N_Hc), :L)
47+
L_Hp = Hermitian(Matrix(L_Hp), :L)
4648
# dummy vals (updated just before optimization):
4749
R̂y, R̂u, T_lastu = zeros(NT, ny*Hp), zeros(NT, nu*Hp), zeros(NT, nu*Hp)
4850
noR̂u = iszero(L_Hp)

src/controller/linmpc.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ struct LinMPC{
5050
Ewt = 0 # economic costs not supported for LinMPC
5151
validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt)
5252
# Matrix() call is needed to convert `Diagonal` to normal `Matrix`
53-
M_Hp, N_Hc, L_Hp = Hermitian(Matrix(M_Hp)), Hermitian(Matrix(N_Hc)), Hermitian(Matrix(L_Hp))
53+
M_Hp = Hermitian(Matrix(M_Hp), :L)
54+
N_Hc = Hermitian(Matrix(N_Hc), :L)
55+
L_Hp = Hermitian(Matrix(L_Hp), :L)
5456
# dummy vals (updated just before optimization):
5557
R̂y, R̂u, T_lastu = zeros(NT, ny*Hp), zeros(NT, nu*Hp), zeros(NT, nu*Hp)
5658
noR̂u = iszero(L_Hp)

src/controller/nonlinmpc.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ struct NonLinMPC{
5151
= copy(model.yop) # dummy vals (updated just before optimization)
5252
validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt)
5353
# Matrix() call is needed to convert `Diagonal` to normal `Matrix`
54-
M_Hp, N_Hc, L_Hp = Hermitian(Matrix(M_Hp)), Hermitian(Matrix(N_Hc)), Hermitian(Matrix(L_Hp))
54+
M_Hp = Hermitian(Matrix(M_Hp), :L)
55+
N_Hc = Hermitian(Matrix(N_Hc), :L)
56+
L_Hp = Hermitian(Matrix(L_Hp), :L)
5557
# dummy vals (updated just before optimization):
5658
R̂y, R̂u, T_lastu = zeros(NT, ny*Hp), zeros(NT, nu*Hp), zeros(NT, nu*Hp)
5759
noR̂u = iszero(L_Hp)

src/estimator/execute.jl

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,60 @@ function validate_args(estim::StateEstimator, u, ym, d)
221221
nym = estim.nym
222222
size(ym) (nym,) && throw(DimensionMismatch("ym size $(size(ym)) ≠ meas. output size ($nym,)"))
223223
end
224+
225+
"""
226+
setstate!(estim::StateEstimator, x̂)
227+
228+
Set `estim.x̂` states to values specified by `x̂`.
229+
"""
230+
function setstate!(estim::StateEstimator, x̂)
231+
size(x̂) == (estim.nx̂,) || error("x̂ size must be $((estim.nx̂,))")
232+
estim.x̂[:] =
233+
return estim
234+
end
235+
236+
"""
237+
setmodel!(estim::StateEstimator, model::LinModel) -> estim
238+
239+
Set `estim.model` state-space matrices and operating points to `model` values.
240+
241+
Not supported by [`Luenberger`](@ref) and [`SteadyKalmanFilter`](@ref) estimators, use the
242+
time-varying [`KalmanFilter`](@ref) instead. The matrix dimensions and sample time must stay
243+
the same. The observability and controllability of the new augmented model is not verified.
244+
"""
245+
function setmodel!(estim::StateEstimator, model::LinModel)
246+
validate_model(estim, model)
247+
estim.model.A .= model.A
248+
estim.model.Bu .= model.Bu
249+
estim.model.C .= model.C
250+
estim.model.Bd .= model.Bd
251+
estim.model.Dd .= model.Dd
252+
estim.model.uop .= model.uop
253+
estim.model.yop .= model.yop
254+
estim.model.dop .= model.dop
255+
setmodel_estimator!(estim, model)
256+
return estim
257+
end
258+
259+
"Validate the dimensions and sample time of `model` against `estim.model`."
260+
function validate_model(estim::StateEstimator, model::LinModel)
261+
model.Ts == estim.model.Ts || throw(ArgumentError("model.Ts must be $(estim.model.Ts) s"))
262+
model.nu == estim.model.nu || throw(ArgumentError("model.nu must be $(estim.model.nu)"))
263+
model.nx == estim.model.nx || throw(ArgumentError("model.nx must be $(estim.model.nx)"))
264+
model.ny == estim.model.ny || throw(ArgumentError("model.ny must be $(estim.model.ny)"))
265+
model.nd == estim.model.nd || throw(ArgumentError("model.nd must be $(estim.model.nd)"))
266+
end
267+
268+
"Update the augmented model matrices of `estim` by default."
269+
function setmodel_estimator!(estim::StateEstimator, model::LinModel)
270+
As, Cs_u, Cs_y = estim.As, estim.Cs_u, estim.Cs_y
271+
Â, B̂u, Ĉ, B̂d, D̂d = augment_model(model, As, Cs_u, Cs_y, verify_obsv=false)
272+
estim. .=
273+
estim.B̂u .= B̂u
274+
estim.Ĉ .=
275+
estim.B̂d .= B̂d
276+
estim.D̂d .= D̂d
277+
estim.Ĉm .= @views Ĉ[estim.i_ym, :]
278+
estim.D̂dm .= @views D̂d[estim.i_ym, :]
279+
return nothing
280+
end

src/estimator/internal_model.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ function init_internalmodel(As, Bs, Cs, Ds)
197197
return Âs, B̂s
198198
end
199199

200+
"Do nothing else for `InternalModel` estimator."
201+
setmodel_estimator!(estim::InternalModel, ::LinModel) = nothing
202+
200203
@doc raw"""
201204
update_estimate!(estim::InternalModel, u, ym, d=empty(estim.x̂)) -> x̂d
202205

src/estimator/kalman.jl

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ function SteadyKalmanFilter(model::SM, i_ym, nint_u, nint_ym, Q̂, R̂) where {N
166166
return SteadyKalmanFilter{NT, SM}(model, i_ym, nint_u, nint_ym, Q̂, R̂)
167167
end
168168

169+
"Throw an error if `setmodel!` is called on a SteadyKalmanFilter"
170+
function setmodel_estimator!(estim::SteadyKalmanFilter, _ )
171+
error("SteadyKalmanFilter does not support setmodel! (use KalmanFilter instead)")
172+
end
169173

170174

171175
@doc raw"""
@@ -192,7 +196,7 @@ function update_estimate!(estim::SteadyKalmanFilter, u, ym, d=empty(estim.x̂))
192196
mul!(x̂next, B̂u, u, 1, 1)
193197
mul!(x̂next, B̂d, d, 1, 1)
194198
mul!(x̂next, K̂, v̂, 1, 1)
195-
x̂ .= x̂next
199+
estim.x̂ .= x̂next
196200
return nothing
197201
end
198202

@@ -347,6 +351,7 @@ function update_estimate!(estim::KalmanFilter, u, ym, d)
347351
return update_estimate_kf!(estim, u, ym, d, estim.Â, estim.Ĉm, estim.P̂, estim.x̂)
348352
end
349353

354+
350355
struct UnscentedKalmanFilter{NT<:Real, SM<:SimModel} <: StateEstimator{NT}
351356
model::SM
352357
lastu0::Vector{NT}
@@ -368,12 +373,13 @@ struct UnscentedKalmanFilter{NT<:Real, SM<:SimModel} <: StateEstimator{NT}
368373
B̂d::Matrix{NT}
369374
D̂d::Matrix{NT}
370375
P̂0::Hermitian{NT, Matrix{NT}}
371-
::Hermitian{NT, Matrix{NT}}
372-
::Hermitian{NT, Matrix{NT}}
376+
::Hermitian{NT, Matrix{NT}}
377+
::Hermitian{NT, Matrix{NT}}
373378
::Matrix{NT}
374379
::Hermitian{NT, Matrix{NT}}
375-
::Matrix{NT}
380+
::Matrix{NT}
376381
Ŷm::Matrix{NT}
382+
sqrtP̂::LowerTriangular{NT, Matrix{NT}}
377383
::Int
378384
γ::NT
379385
::Vector{NT}
@@ -396,14 +402,15 @@ struct UnscentedKalmanFilter{NT<:Real, SM<:SimModel} <: StateEstimator{NT}
396402
= zeros(NT, nx̂, nym)
397403
= Hermitian(zeros(NT, nym, nym), :L)
398404
X̂, Ŷm = zeros(NT, nx̂, nσ), zeros(NT, nym, nσ)
405+
sqrtP̂ = LowerTriangular(zeros(NT, nx̂, nx̂))
399406
return new{NT, SM}(
400407
model,
401408
lastu0, x̂, P̂,
402409
i_ym, nx̂, nym, nyu, nxs,
403410
As, Cs_u, Cs_y, nint_u, nint_ym,
404411
Â, B̂u, Ĉ, B̂d, D̂d,
405412
P̂0, Q̂, R̂,
406-
K̂, M̂, X̂, Ŷm,
413+
K̂, M̂, X̂, Ŷm, sqrtP̂,
407414
nσ, γ, m̂, Ŝ
408415
)
409416
end
@@ -571,21 +578,23 @@ noise, respectively.
571578
"""
572579
function update_estimate!(estim::UnscentedKalmanFilter{NT}, u, ym, d) where NT<:Real
573580
x̂, P̂, Q̂, R̂, K̂, M̂ = estim.x̂, estim.P̂, estim.Q̂, estim.R̂, estim.K̂, estim.
574-
X̂, Ŷm = estim.X̂, estim.Ŷm
575581
nym, nx̂, nσ = estim.nym, estim.nx̂, estim.
576582
γ, m̂, Ŝ = estim.γ, estim.m̂, estim.
583+
X̂, Ŷm = estim.X̂, estim.Ŷm
584+
sqrtP̂ = estim.sqrtP̂
577585
# --- initialize matrices ---
578-
X̂_next = Matrix{NT}(undef, nx̂, nσ)
586+
x̂next = Vector{NT}(undef, nx̂)
579587
= Vector{NT}(undef, estim.model.nu)
580588
ŷm = Vector{NT}(undef, nym)
581589
= Vector{NT}(undef, estim.model.ny)
582-
sqrt_P̂ = LowerTriangular{NT, Matrix{NT}}(Matrix{NT}(undef, nx̂, nx̂))
583590
# --- correction step ---
584-
sqrt_P̂ .= cholesky(P̂).L
585-
γ_sqrt_P̂ = lmul!(γ, sqrt_P̂)
591+
P̂_chol = sqrtP̂.data
592+
P̂_chol .=
593+
cholesky!(Hermitian(P̂_chol, :L)) # also modifies sqrtP̂
594+
γ_sqrtP̂ = lmul!(γ, sqrtP̂)
586595
X̂ .=
587-
X̂[:, 2:nx̂+1] .+= γ_sqrt_P̂
588-
X̂[:, nx̂+2:end] .-= γ_sqrt_P̂
596+
X̂[:, 2:nx̂+1] .+= γ_sqrtP̂
597+
X̂[:, nx̂+2:end] .-= γ_sqrtP̂
589598
for j in axes(Ŷm, 2)
590599
@views ĥ!(ŷ, estim, estim.model, X̂[:, j], d)
591600
@views Ŷm[:, j] .= ŷ[estim.i_ym]
@@ -594,27 +603,36 @@ function update_estimate!(estim::UnscentedKalmanFilter{NT}, u, ym, d) where NT<:
594603
X̄, Ȳm = X̂, Ŷm
595604
X̄ .=.-
596605
Ȳm .= Ŷm .- ŷm
597-
M̂ .= Hermitian(Ȳm ** Ȳm' .+)
606+
.data .= Ȳm ** Ȳm' .+
598607
mul!(K̂, X̄, lmul!(Ŝ, Ȳm'))
599608
rdiv!(K̂, cholesky(M̂))
600609
= ŷm
601610
v̂ .= ym .- ŷm
602-
x̂_cor =+*
603-
P̂_cor =- Hermitian(K̂ **', :L)
611+
x̂cor = x̂next
612+
x̂cor .=
613+
mul!(x̂cor, K̂, v̂, 1, 1)
614+
P̂cor = Hermitian(P̂ .-**', :L)
604615
# --- prediction step ---
605-
X̂_cor, sqrt_P̂_cor = X̂, sqrt_P̂
606-
sqrt_P̂_cor .= cholesky(P̂_cor).L
607-
γ_sqrt_P̂_cor = lmul!(γ, sqrt_P̂_cor)
608-
X̂_cor .= x̂_cor
609-
X̂_cor[:, 2:nx̂+1] .+= γ_sqrt_P̂_cor
610-
X̂_cor[:, nx̂+2:end] .-= γ_sqrt_P̂_cor
611-
for j in axes(X̂_next, 2)
612-
@views f̂!(X̂_next[:, j], û, estim, estim.model, X̂_cor[:, j], u, d)
616+
X̂cor, sqrtP̂cor = X̂, sqrtP̂
617+
P̂cor_chol = sqrtP̂cor.data
618+
P̂cor_chol .= P̂cor
619+
cholesky!(Hermitian(P̂cor_chol, :L)) # also modifies sqrtP̂cor
620+
γ_sqrtP̂cor = lmul!(γ, sqrtP̂cor)
621+
X̂cor .= x̂cor
622+
X̂cor[:, 2:nx̂+1] .+= γ_sqrtP̂cor
623+
X̂cor[:, nx̂+2:end] .-= γ_sqrtP̂cor
624+
X̂next = X̂cor
625+
for j in axes(X̂next, 2)
626+
@views x̂cor .= X̂cor[:, j]
627+
@views f̂!(X̂next[:, j], û, estim, estim.model, x̂cor, u, d)
613628
end
614-
x̂_next = mul!(x̂, X̂_next, m̂)
615-
X̄_next = X̂_next
616-
X̄_next .= X̂_next .- x̂_next
617-
P̂ .= Hermitian(X̄_next ** X̄_next' .+ Q̂)
629+
x̂next .= mul!(x̂, X̂next, m̂)
630+
X̄next = X̂next
631+
X̄next .= X̂next .- x̂next
632+
P̂next = P̂cor
633+
P̂next.data .= X̄next ** X̄next' .+
634+
estim.x̂ .= x̂next
635+
estim.P̂ .= P̂next
618636
return nothing
619637
end
620638

@@ -822,17 +840,17 @@ function update_estimate_kf!(estim::StateEstimator{NT}, u, ym, d, Â, Ĉm, P̂
822840
Q̂, R̂, M̂, K̂ = estim.Q̂, estim.R̂, estim.M̂, estim.
823841
nx̂, nu, ny = estim.nx̂, estim.model.nu, estim.model.ny
824842
x̂next, û, ŷ = Vector{NT}(undef, nx̂), Vector{NT}(undef, nu), Vector{NT}(undef, ny)
825-
P̂next = similar(P̂)
826843
mul!(M̂, P̂.data, Ĉm') # the ".data" weirdly removes a type instability in mul!
827-
rdiv!(M̂, cholesky!(Hermitian(Ĉm ** Ĉm' .+ R̂)))
844+
rdiv!(M̂, cholesky!(Hermitian(Ĉm ** Ĉm' .+, :L)))
828845
mul!(K̂, Â, M̂)
829846
ĥ!(ŷ, estim, estim.model, x̂, d)
830847
ŷm = @views ŷ[estim.i_ym]
831848
= ŷm
832849
v̂ .= ym .- ŷm
833850
f̂!(x̂next, û, estim, estim.model, x̂, u, d)
834851
mul!(x̂next, K̂, v̂, 1, 1)
852+
P̂next = Hermitian(Â * (P̂ .-* Ĉm * P̂) *' .+ Q̂, :L)
835853
estim.x̂ .= x̂next
836-
P̂ .= Hermitian(Â * (P̂ .-* Ĉm * P̂) *' .+ Q̂)
854+
estim.P̂ .= P̂next
837855
return nothing
838856
end

src/estimator/luenberger.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ function update_estimate!(estim::Luenberger, u, ym, d=empty(estim.x̂))
118118
mul!(x̂next, B̂u, u, 1, 1)
119119
mul!(x̂next, B̂d, d, 1, 1)
120120
mul!(x̂next, K̂, v̂, 1, 1)
121-
x̂ .= x̂next
121+
estim.x̂ .= x̂next
122122
return nothing
123-
end
123+
end
124+
125+
"Throw an error if `setmodel!` is called on `Luenberger` observer."
126+
setmodel_estimator!(estim::Luenberger, ::LinModel) = error("Luenberger does not support setmodel!")

src/estimator/mhe/execute.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ function update_estimate!(estim::MovingHorizonEstimator{NT}, u, ym, d) where NT<
8181
# --------- update estimate -----------------------
8282
estim.Ŵ[1:nŵ*Nk] .= @views estim.Z̃[nx̃+1:nx̃+nŵ*Nk] # update Ŵ with optimum for warm-start
8383
V̂, X̂ = predict!(V̂, X̂, û, ŷ, estim, model, estim.Z̃)
84-
x̂ .= X̂[end-nx̂+1:end]
84+
estim.x̂ .= @views X̂[end-nx̂+1:end]
8585
Nk == estim.He && update_cov!(estim::MovingHorizonEstimator)
8686
return nothing
8787
end

src/model/linmodel.jl

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,14 @@ struct LinModel{NT<:Real} <: SimModel{NT}
1414
yop::Vector{NT}
1515
dop::Vector{NT}
1616
function LinModel{NT}(A, Bu, C, Bd, Dd, Ts) where {NT<:Real}
17-
A, Bu, C, Bd, Dd = to_mat(A), to_mat(Bu), to_mat(C), to_mat(Bd), to_mat(Dd)
18-
nu, nx, ny, nd = size(Bu,2), size(A,2), size(C,1), size(Bd,2)
17+
A, Bu = to_mat(A, 1, 1), to_mat(Bu, 1, 1)
18+
nu, nx = size(Bu, 2), size(A, 2)
19+
(C == I) && (C = Matrix{NT}(I, nx, nx))
20+
C = to_mat(C, 1, 1)
21+
ny = size(C, 1)
22+
Bd = to_mat(Bd, nx, Bd 0)
23+
nd = size(Bd, 2)
24+
Dd = to_mat(Dd, ny, nd)
1925
size(A) == (nx,nx) || error("A size must be $((nx,nx))")
2026
size(Bu) == (nx,nu) || error("Bu size must be $((nx,nu))")
2127
size(C) == (ny,nx) || error("C size must be $((ny,nx))")
@@ -188,31 +194,14 @@ end
188194
189195
Construct the model from the discrete state-space matrices `A, Bu, C, Bd, Dd` directly.
190196
191-
See [`LinModel(::StateSpace)`](@ref) Extended Help for the meaning of the matrices. This
197+
See [`LinModel(::StateSpace)`](@ref) Extended Help for the meaning of the matrices. The
198+
arguments `Bd` and `Dd` can be the scalar `0` if there is no measured disturbance. This
192199
syntax do not modify the state-space representation provided in argument (`minreal` is not
193-
called). Care must be taken to ensure that the model is controllable and observable. The
194-
optional parameter `NT` explicitly specifies the number type of the matrices.
200+
called). Care must be taken to ensure that the model is controllable and observable. The
201+
optional parameter `NT` explicitly set the number type of vectors (default to `Float64`).
195202
"""
196203
LinModel{NT}(A, Bu, C, Bd, Dd, Ts) where NT<:Real
197-
198-
function LinModel(
199-
A::Array{NT}, Bu::Array{NT}, C::Array{NT}, Bd::Array{NT}, Dd::Array{NT}, Ts::Real
200-
) where {NT<:Real}
201-
return LinModel{NT}(A, Bu, C, Bd, Dd, Ts)
202-
end
203-
204-
function LinModel(
205-
A::Array{<:Real},
206-
Bu::Array{<:Real},
207-
C::Array{<:Real},
208-
Bd::Array{<:Real},
209-
Dd::Array{<:Real},
210-
Ts::Real
211-
)
212-
A, Bu, C, Bd, Dd = to_mat(A), to_mat(Bu), to_mat(C), to_mat(Bd), to_mat(Dd)
213-
A, Bu, C, Bd, Dd = promote(A, Bu, C, Bd, Dd)
214-
return LinModel(A, Bu, C, Bd, Dd, Ts)
215-
end
204+
LinModel(A, Bu, C, Bd, Dd, Ts) = LinModel{Float64}(A, Bu, C, Bd, Dd, Ts)
216205

217206
@doc raw"""
218207
steadystate!(model::LinModel, u, d)

0 commit comments

Comments
 (0)