Skip to content

Commit d45c0b4

Browse files
committed
handle operating points
1 parent a7fd9f3 commit d45c0b4

File tree

3 files changed

+29
-13
lines changed

3 files changed

+29
-13
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ UnPack = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
1717
[compat]
1818
ControlSystemsBase = "1.0.1"
1919
DataInterpolations = "3, 4, 5, 6, 7"
20-
ModelingToolkit = "10.0"
20+
ModelingToolkit = "10.3"
2121
ModelingToolkitStandardLibrary = "2"
2222
MonteCarloMeasurements = "1.1"
2323
RobustAndOptimalControl = "0.4.14"

src/ode_system.jl

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ function RobustAndOptimalControl.named_ss(
104104
out
105105
end
106106
end
107-
matrices, ssys = ModelingToolkit.linearize(sys, inputs, outputs; kwargs...)
107+
matrices, ssys, xpt = ModelingToolkit.linearize(sys, inputs, outputs; kwargs...)
108108
symstr(x) = Symbol(x isa AnalysisPoint ? x.name : string(x))
109109
unames = symstr.(inputs)
110110
if nu > 0 && size(matrices.B, 2) == 2nu
@@ -115,12 +115,19 @@ function RobustAndOptimalControl.named_ss(
115115
else
116116
lsys = ss(matrices...)
117117
end
118+
pind = [ModelingToolkit.parameter_index(ssys, i) for i in ModelingToolkit.inputs(ssys)]
119+
x0 = xpt.x
120+
u0 = [xpt.p[pi] for pi in pind]
121+
xu = (; x = x0, u = u0)
122+
extra = Dict(:operating_point => xu)
123+
118124
named_ss(
119125
lsys;
120126
x = symstr.(unknowns(ssys)),
121127
u = unames,
122128
y = symstr.(outputs),
123129
name = string(Base.nameof(sys)),
130+
extra,
124131
)
125132
end
126133

@@ -300,7 +307,7 @@ The second problem above, the ordering of the states, can be worked around using
300307
- `costs`: A vector of pairs.
301308
"""
302309
function build_quadratic_cost_matrix(sys::System, inputs::AbstractVector, costs::AbstractVector{<:Pair}; kwargs...)
303-
matrices, ssys = ModelingToolkit.linearize(sys, inputs, first.(costs); kwargs...)
310+
matrices, ssys, extras = ModelingToolkit.linearize(sys, inputs, first.(costs); kwargs...)
304311
x = ModelingToolkit.unknowns(ssys)
305312
y = ModelingToolkit.outputs(ssys)
306313
nx = length(x)
@@ -323,10 +330,12 @@ function batch_linearize(sys, inputs, outputs, ops::AbstractVector{<:AbstractDic
323330
allow_input_derivatives = false,
324331
kwargs...)
325332
lin_fun, ssys = linearization_function(sys, inputs, outputs; op=ops[1], kwargs...)
326-
lins = map(ops) do op
333+
lins_ops = map(ops) do op
327334
linearize(ssys, lin_fun; op, t, allow_input_derivatives)
328335
end
329-
lins, ssys
336+
lins = first.(lins_ops)
337+
resolved_ops = last.(lins_ops)
338+
lins, ssys, resolved_ops
330339
end
331340

332341
"""
@@ -404,8 +413,8 @@ nyquistcircles!(w, centers, radii, ylims = (-4, 1), xlims = (-3, 4))
404413
See also [`trajectory_ss`](@ref) and [`fuzz`](@ref).
405414
"""
406415
function batch_ss(args...; kwargs...)
407-
lins, ssys = batch_linearize(args...; kwargs...)
408-
[ss(l...) for l in lins], ssys
416+
lins, ssys, resolved_ops = batch_linearize(args...; kwargs...)
417+
[ss(l...) for l in lins], ssys, resolved_ops
409418
end
410419

411420
"""
@@ -422,18 +431,22 @@ Linearize `sys` around the trajectory `sol` at times `t`. Returns a vector of `S
422431
- `verbose`: If `true`, print warnings for variables that are not found in `sol`.
423432
- `kwargs`: Are sent to the linearization functions.
424433
"""
425-
function trajectory_ss(sys, inputs, outputs, sol; t = _max_100(sol.t), allow_input_derivatives = false, fuzzer = nothing, verbose = true, kwargs...)
434+
function trajectory_ss(sys, inputs, outputs, sol; t = _max_100(sol.t), allow_input_derivatives = false, fuzzer = nothing, verbose = true,kwargs...)
426435
maximum(t) > maximum(sol.t) && @warn("The maximum time in `t`: $(maximum(t)), is larger than the maximum time in `sol.t`: $(maximum(sol.t)).")
427436
minimum(t) < minimum(sol.t) && @warn("The minimum time in `t`: $(minimum(t)), is smaller than the minimum time in `sol.t`: $(minimum(sol.t)).")
428437
# NOTE: we call linearization_funciton twice :( The first call is to get x=unknowns(ssys), the second call provides the operating points.
429438
# lin_fun, ssys = linearization_function(sys, inputs, outputs; warn_initialize_determined = false, kwargs...)
430439
lin_fun, ssys = linearization_function(sys, inputs, outputs; warn_empty_op = false, warn_initialize_determined = false, kwargs...)
431-
432440
x = unknowns(ssys)
441+
442+
# TODO: The value of the output (or input) of the input analysis points should be mapped to the perturbation vars
443+
@show perturbation_vars = ModelingToolkit.inputs(ssys)
444+
# original_inputs = [ap.input.u for ap in vcat(inputs)] # assuming all inputs are analysis points for now
433445
op_nothing = Dict(unknowns(sys) .=> nothing) # Remove all defaults present in the original system
434446
defs = ModelingToolkit.defaults(sys)
435447
ops = map(t) do ti
436448
opsol = Dict(x => robust_sol_getindex(sol, ti, x, defs; verbose) for x in x)
449+
# opsolu = Dict(new_u => robust_sol_getindex(sol, ti, u, defs; verbose) for (new_u, u) in zip(perturbation_vars, original_inputs))
437450
merge(op_nothing, opsol)
438451
end
439452
# @show ops[1]
@@ -445,11 +458,13 @@ function trajectory_ss(sys, inputs, outputs, sol; t = _max_100(sol.t), allow_inp
445458
t = repeat(t, inner = length(ops) ÷ length(t))
446459
end
447460
lin_fun, ssys = linearization_function(sys, inputs, outputs; op=ops[1], kwargs...) # initializealg=ModelingToolkit.SciMLBase.NoInit()
448-
lins = map(zip(ops, t)) do (op, t)
461+
lins_ops = map(zip(ops, t)) do (op, t)
449462
linearize(ssys, lin_fun; op, t, allow_input_derivatives)
450463
# linearize(sys, inputs, outputs; op, t, allow_input_derivatives, initialize=false)[1]
451464
end
452-
(; linsystems = [ss(l...) for l in lins], ssys, ops)
465+
lins = first.(lins_ops)
466+
resolved_ops = last.(lins_ops)
467+
(; linsystems = [ss(l...) for l in lins], ssys, ops, resolved_ops)
453468
end
454469

455470
"_max_100(t) = length(t) > 100 ? range(extrema(t)..., 100) : t"

test/test_ODESystem.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ guesses = [link1.fy1 => 0.1, cart.f => 0.1]
303303
G = named_ss(model, lin_inputs, lin_outputs; allow_symbolic = true, op,
304304
allow_input_derivatives = true, zero_dummy_der = true, guesses)
305305
G = sminreal(G)
306+
@test 10 RobustAndOptimalControl.operating_point(G).x
306307
@info "minreal"
307308
G = minreal(G)
308309
@info "poles"
@@ -311,8 +312,8 @@ ps = poles(G)
311312
@test minimum(abs, ps) < 1e-6
312313
@test minimum(abs, complex(0, 1.3777260367206716) .- ps) < 1e-10
313314

314-
lsys, syss = linearize(model, lin_inputs, lin_outputs, op = op,
315-
allow_input_derivatives = true)
315+
lsys, syss = linearize(model, lin_inputs, lin_outputs; op = op,
316+
allow_input_derivatives = true, guesses)
316317
lsyss, sysss = ModelingToolkit.linearize_symbolic(model, lin_inputs, lin_outputs;
317318
allow_input_derivatives = true)
318319

0 commit comments

Comments
 (0)