Skip to content

Commit c47f844

Browse files
committed
additional timing tests
1 parent 949269f commit c47f844

File tree

2 files changed

+108
-69
lines changed

2 files changed

+108
-69
lines changed

src/systems/clock_inference.jl

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,10 @@ function generate_discrete_affect(syss, inputs, continuous_id, id_to_clock;
211211
copyto!(d2c_view, d2c_obs(disc_state, p, t))
212212
end)
213213

214+
# @show disc_to_cont_idxs
215+
# @show cont_to_disc_idxs
216+
# @show disc_range
217+
214218
affect! = :(function (integrator, saved_values)
215219
@unpack u, p, t = integrator
216220
c2d_obs = $cont_to_disc_obs
@@ -221,14 +225,25 @@ function generate_discrete_affect(syss, inputs, continuous_id, id_to_clock;
221225
d2c_view = view(p, $disc_to_cont_idxs)
222226
disc_state = view(p, $disc_range)
223227
disc = $disc
224-
# Update discrete states
225-
$empty_disc || disc(disc_state, disc_state, p, t)
228+
229+
push!(saved_values.t, t)
230+
push!(saved_values.saveval, $save_vec)
231+
226232
# Write continuous into to discrete: handles `Sample`
227-
copyto!(c2d_view, c2d_obs(integrator.u, p, t))
228233
# Write discrete into to continuous
234+
# Update discrete states
235+
236+
# At a tick, c2d must come first
237+
# state update comes in the middle
238+
# d2c comes last
239+
# @show t
240+
# @show "incoming", p
241+
copyto!(c2d_view, c2d_obs(integrator.u, p, t))
242+
# @show "after c2d", p
243+
$empty_disc || disc(disc_state, disc_state, p, t)
244+
# @show "after state update", p
229245
copyto!(d2c_view, d2c_obs(disc_state, p, t))
230-
push!(saved_values.t, t)
231-
push!(saved_values.saveval, $save_vec)
246+
# @show "after d2c", p
232247
end)
233248
sv = SavedValues(Float64, Vector{Float64})
234249
push!(affect_funs, affect!)

test/clock.jl

Lines changed: 88 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -113,46 +113,50 @@ z(k + 1) ~ z′(k)
113113
]
114114
@named sys = ODESystem(eqs)
115115
ss = structural_simplify(sys);
116-
if VERSION >= v"1.7"
117-
prob = ODEProblem(ss, [x => 0.0, y => 0.0], (0.0, 1.0),
118-
[kp => 1.0; z => 3.0; z(k + 1) => 2.0])
119-
sol = solve(prob, Tsit5(), kwargshandle = KeywordArgSilent)
120-
# For all inputs in parameters, just initialize them to 0.0, and then set them
121-
# in the callback.
122-
123-
# kp is the only real parameter
124-
function foo!(du, u, p, t)
125-
x = u[1]
126-
ud = p[2]
127-
du[1] = -x + ud
128-
end
129-
function affect!(integrator, saved_values)
130-
z_t, z = integrator.p[3], integrator.p[4]
131-
yd = integrator.u[1]
132-
kp = integrator.p[1]
133-
r = 1.0
134-
ud = kp * (r - yd) + z
135-
integrator.p[2] = ud
136116

137-
push!(saved_values.t, integrator.t)
138-
push!(saved_values.saveval, [z_t, z])
117+
Tf = 1.0
118+
prob = ODEProblem(ss, [x => 0.0, y => 0.0], (0.0, Tf),
119+
[kp => 1.0; z => 3.0; z(k + 1) => 2.0])
120+
@test sort(prob.p) == [0, 1.0, 2.0, 3.0, 4.0] # yd, kp, z(k+1), z(k), ud
121+
sol = solve(prob, Tsit5(), kwargshandle = KeywordArgSilent)
122+
# For all inputs in parameters, just initialize them to 0.0, and then set them
123+
# in the callback.
124+
125+
# kp is the only real parameter
126+
function foo!(du, u, p, t)
127+
x = u[1]
128+
ud = p[2]
129+
du[1] = -x + ud
130+
end
131+
function affect!(integrator, saved_values)
132+
z_t, z = integrator.p[3], integrator.p[4]
133+
yd = integrator.u[1]
134+
kp = integrator.p[1]
135+
r = 1.0
136+
137+
push!(saved_values.t, integrator.t)
138+
push!(saved_values.saveval, [z_t, z])
139139

140-
# Update the discrete state
141-
z_t, z = z + yd, z_t
142-
integrator.p[3] = z_t
143-
integrator.p[4] = z
144-
nothing
145-
end
146-
saved_values = SavedValues(Float64, Vector{Float64})
147-
cb = PeriodicCallback(Base.Fix2(affect!, saved_values), 0.1)
148-
# kp ud z_t z
149-
prob = ODEProblem(foo!, [0.0], (0.0, 1.0), [1.0, 4.0, 3.0, 2.0], callback = cb)
150-
# ud initializes to kp * (r - yd) + z = 1 * (1 - 0) + 3 = 4
151-
sol2 = solve(prob, Tsit5())
152-
@test sol.u == sol2.u
153-
@test saved_values.t == sol.prob.kwargs[:disc_saved_values][1].t
154-
@test saved_values.saveval == sol.prob.kwargs[:disc_saved_values][1].saveval
140+
# Update the discrete state
141+
z_t, z = z + yd, z_t
142+
# @show z_t, z
143+
integrator.p[3] = z_t
144+
integrator.p[4] = z
145+
146+
ud = kp * (r - yd) + z
147+
integrator.p[2] = ud
148+
149+
nothing
155150
end
151+
saved_values = SavedValues(Float64, Vector{Float64})
152+
cb = PeriodicCallback(Base.Fix2(affect!, saved_values), 0.1)
153+
# kp ud z_t z
154+
prob = ODEProblem(foo!, [0.0], (0.0, Tf), [1.0, 4.0, 2.0, 3.0], callback = cb)
155+
# ud initializes to kp * (r - yd) + z = 1 * (1 - 0) + 3 = 4
156+
sol2 = solve(prob, Tsit5())
157+
@test sol.u == sol2.u
158+
@test saved_values.t == sol.prob.kwargs[:disc_saved_values][1].t
159+
@test saved_values.saveval == sol.prob.kwargs[:disc_saved_values][1].saveval
156160

157161
@info "Testing multi-rate hybrid system"
158162
dt = 0.1
@@ -314,7 +318,7 @@ if VERSION >= v"1.7"
314318
prob = ODEProblem(foo!, [0.0], (0.0, 1.0), [1.0, 1.0, 1.0], callback = cb)
315319
sol2 = solve(prob, Tsit5())
316320

317-
@test sol.u sol2.u atol = 1e-6
321+
@test sol.usol2.u atol=1e-6
318322
end
319323

320324
##
@@ -341,10 +345,10 @@ k = ShiftIndex(d)
341345
y(t)
342346
end
343347
@equations begin
344-
x(k + 1) ~ x(k) + ki * u
345-
output.u ~ y
346-
input.u ~ u
347-
y ~ x(k) + kp * u
348+
x(k) ~ x(k - 1) + ki * u(k)
349+
output.u(k) ~ y(k)
350+
input.u(k) ~ u(k)
351+
y(k) ~ x(k - 1) + kp * u(k)
348352
end
349353
end
350354

@@ -414,35 +418,55 @@ ci, varmap = infer_clocks(expand_connections(model))
414418

415419
ssys = structural_simplify(model)
416420

417-
timevec = 0:(d.dt):10
421+
Tf = 0.2
422+
timevec = 0:(d.dt):Tf
418423

419424
import ControlSystemsBase as CS
420425
import ControlSystemsBase: c2d, tf, feedback, lsim
421-
P = c2d(tf(0.3, [1, 1]), d.dt)
426+
# z = tf('z', d.dt)
427+
# P = c2d(tf(0.3, [1, 1]), d.dt)
428+
P = c2d(CS.ss([-1], [0.3], [1], 0), d.dt)
422429
C = CS.ss([1], [2], [1], [2], d.dt)
423430

424431
# Test the output of the continuous partition
425432
G = feedback(P * C)
426433
res = lsim(G, (x, t) -> [0.5], timevec)
427434
y = res.y[:]
428435

429-
prob = ODEProblem(ssys,
430-
[model.plant.x => 0.0],
431-
(0.0, 10.0),
432-
[model.controller.kp => 2.0; model.controller.ki => 2.0])
433-
434-
@test prob.p[9] == 1 # constant output * kp issue https://github.com/SciML/ModelingToolkit.jl/issues/2356
435-
sol = solve(prob, Tsit5(), kwargshandle = KeywordArgSilent)
436-
# plot([sol(timevec .+ 1e-12, idxs=model.plant.output.u) y])
437-
438-
##
439-
440-
@test sol(timevec, idxs = model.plant.output.u)y rtol=1e-8 # The output of the continuous partition is delayed exactly one sample
441-
442-
# Test the output of the discrete partition
443-
G = feedback(C, P)
444-
res = lsim(G, (x, t) -> [0.5], timevec)
445-
y = res.y[:]
446-
447-
@test_broken sol(timevec .+ 1e-10, idxs = model.controller.output.u)y rtol=1e-8 # Broken due to discrete observed
448-
# plot([sol(timevec .+ 1e-12, idxs=model.controller.output.u) y])
436+
# plant = FirstOrder(k = 0.3, T = 1)
437+
# controller = DiscretePI(kp = 2, ki = 2)
438+
# ref = Constant(k = 0.5)
439+
440+
# ; model.controller.x(k-1) => 0.0
441+
@test_skip begin
442+
prob = ODEProblem(ssys,
443+
[model.plant.x => 0.0; model.controller.kp => 2.0; model.controller.ki => 2.0],
444+
(0.0, Tf))
445+
446+
@test prob.p[9] == 1 # constant output * kp issue https://github.com/SciML/ModelingToolkit.jl/issues/2356
447+
@test prob.p[10] == 0 # c2d
448+
@test prob.p[11] == 0 # disc state
449+
sol = solve(prob,
450+
Tsit5(),
451+
kwargshandle = KeywordArgSilent,
452+
abstol = 1e-8,
453+
reltol = 1e-8)
454+
plot([y sol(timevec, idxs = model.plant.output.u)], m = :o, lab = ["CS" "MTK"])
455+
456+
##
457+
458+
@test sol(timevec, idxs = model.plant.output.u)y rtol=1e-8 # The output of the continuous partition is delayed exactly one sample
459+
460+
# Test the output of the discrete partition
461+
G = feedback(C, P)
462+
res = lsim(G, (x, t) -> [0.5], timevec)
463+
y = res.y[:]
464+
465+
@test_broken sol(timevec .+ 1e-10, idxs = model.controller.output.u)y rtol=1e-8 # Broken due to discrete observed
466+
# plot([y sol(timevec .+ 1e-12, idxs=model.controller.output.u)], lab=["CS" "MTK"])
467+
468+
# TODO: test the same system, but with the PI contorller implemented as
469+
# x(k) ~ x(k-1) + ki * u
470+
# y ~ x(k-1) + kp * u
471+
# Instead. This should be equivalent to the above, but gve me an error when I tried
472+
end

0 commit comments

Comments
 (0)