Skip to content

Commit 0317dde

Browse files
committed
add convenience functions
1 parent d67b536 commit 0317dde

File tree

3 files changed

+77
-3
lines changed

3 files changed

+77
-3
lines changed

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ControlSystemsMTK"
22
uuid = "687d7614-c7e5-45fc-bfc3-9ee385575c88"
33
authors = ["Fredrik Bagge Carlson"]
4-
version = "0.1.0"
4+
version = "0.1.1"
55

66
[deps]
77
ControlSystemIdentification = "3abffc1c-5106-53b7-b354-a47bfc086282"
@@ -18,7 +18,7 @@ UnPack = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
1818
[compat]
1919
ControlSystemIdentification = "2.4.1"
2020
ControlSystemsBase = "1.0.1"
21-
ModelingToolkit = "8.18"
21+
ModelingToolkit = "8.26"
2222
ModelingToolkitStandardLibrary = "1.5"
2323
Optim = "1"
2424
OrdinaryDiffEq = "6"

src/ControlSystemsMTK.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ using Optim, Optim.LineSearches
3030
using SymbolicControlSystems
3131

3232
export sconnect, feedback, ODESystem, states, observed, named_ss
33-
33+
export build_quadratic_cost_matrix
3434

3535
include("ode_system.jl")
3636
include("symbolic_optimization.jl")

src/ode_system.jl

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,77 @@ function RobustAndOptimalControl.named_ss(
230230
y = symstr.(outputs),
231231
)
232232
end
233+
234+
function ModelingToolkit.get_disturbance_system(dist::ModelingToolkit.DisturbanceModel{<:LTISystem})
235+
ControlSystemsBase.issiso(dist.model) || error("Disturbance model must be SISO")
236+
Blocks.StateSpace(ssdata(ss(dist.model))..., name=dist.name)
237+
end
238+
239+
240+
"""
241+
build_quadratic_cost_matrix(matrices::NamedTuple, ssys::ODESystem, costs::Vector{Pair})
242+
243+
For a system that has been linearized, assemble a quadratic cost matrix (for LQR or Kalman filtering) that penalizes states or outputs of simplified system `ssys` accoring to the vector of pairs `costs`.
244+
245+
The motivation for this function is that ModelingToolkit does not guarantee
246+
- Which states are selected as states after simplification.
247+
- The order of the states.
248+
249+
The second problem above, the ordering of the states, can be worked around using `reorder_states`, but the first problem cannot be solved by trivial reordering. This function thus accepts an array of costs for a user-selected state realization, and assembles the correct cost matrix for the state realization selected by MTK. To do this, the funciton needs the linearization (`matrices`) as well as the simplified system, both of which are outputs of `linearize`.
250+
251+
# Arguments:
252+
- `matrices`: Output of `linearize`, an object containing a property called `C`.
253+
- `ssys`: Output of `linearize`.
254+
- `costs`: A vector of pairs
255+
"""
256+
function build_quadratic_cost_matrix(matrices::NamedTuple, ssys::ODESystem, costs::AbstractVector{<:Pair})
257+
x = ModelingToolkit.states(ssys)
258+
y = ModelingToolkit.outputs(ssys)
259+
nx = length(x)
260+
new_Cs = map(costs) do (xi, ci)
261+
i = findfirst(isequal(xi), x)
262+
if i !== nothing
263+
sqrt(ci) .* ((1:nx)' .== i)
264+
else # not a state, get output instead
265+
i = findfirst(isequal(xi), y)
266+
i === nothing && error("$xi is neither a state nor an output")
267+
sqrt(ci) .* matrices.C[i, :]
268+
end
269+
end
270+
C = reduce(vcat, new_Cs)
271+
C'C
272+
end
273+
274+
"""
275+
build_quadratic_cost_matrix(sys::ODESystem, inputs::Vector, costs::Vector{Pair}; kwargs...)
276+
277+
Assemble a quadratic cost matrix (for LQR or Kalman filtering) that penalizes states or outputs of system `sys` accoring to the vector of pairs `costs`.
278+
279+
The motivation for this function is that ModelingToolkit does not guarantee
280+
- Which states are selected as states after simplification.
281+
- The order of the states.
282+
283+
The second problem above, the ordering of the states, can be worked around using `reorder_states`, but the first problem cannot be solved by trivial reordering. This function thus accepts an array of costs for a user-selected state realization, and assembles the correct cost matrix for the state realization selected by MTK. To do this, the funciton needs the linearization (`matrices`) as well as the simplified system, both of which are outputs of `linearize`.
284+
285+
# Arguments:
286+
- `inputs`: A vector of variables that are to be considered controlled inputs for the LQR controller.
287+
- `costs`: A vector of pairs.
288+
"""
289+
function build_quadratic_cost_matrix(sys::ODESystem, inputs::AbstractVector, costs::AbstractVector{<:Pair}; kwargs...)
290+
matrices, ssys = ModelingToolkit.linearize(sys, inputs, first.(costs); kwargs...)
291+
x = ModelingToolkit.states(ssys)
292+
y = ModelingToolkit.outputs(ssys)
293+
nx = length(x)
294+
new_Cs = map(costs) do (xi, ci)
295+
i = findfirst(isequal(xi), x)
296+
if i !== nothing
297+
sqrt(ci) .* ((1:nx)' .== i)
298+
else # not a state, get output instead
299+
i = findfirst(isequal(xi), y)
300+
i === nothing && error("$xi is neither a state nor an output")
301+
sqrt(ci) .* matrices.C[i, :]
302+
end
303+
end
304+
C = reduce(vcat, new_Cs)
305+
C'C
306+
end

0 commit comments

Comments
 (0)