Skip to content

Commit 6a082a1

Browse files
committed
add component-based hybrid system test
1 parent d3a0dc5 commit 6a082a1

File tree

1 file changed

+127
-2
lines changed

1 file changed

+127
-2
lines changed

test/clock.jl

Lines changed: 127 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ z(k + 1) ~ z′(k)
115115
ss = structural_simplify(sys);
116116
if VERSION >= v"1.7"
117117
prob = ODEProblem(ss, [x => 0.0, y => 0.0], (0.0, 1.0),
118-
[kp => 1.0; z => 0.0; z(k + 1) => 0.0])
118+
[kp => 1.0; z => 2.0; z(k + 1) => 3.0])
119119
sol = solve(prob, Tsit5(), kwargshandle = KeywordArgSilent)
120120
# For all inputs in parameters, just initialize them to 0.0, and then set them
121121
# in the callback.
@@ -142,7 +142,7 @@ if VERSION >= v"1.7"
142142
end
143143
saved_values = SavedValues(Float64, Vector{Float64})
144144
cb = PeriodicCallback(Base.Fix2(affect!, saved_values), 0.1)
145-
prob = ODEProblem(foo!, [0.0], (0.0, 1.0), [1.0, 0.0, 0.0, 0.0], callback = cb)
145+
prob = ODEProblem(foo!, [0.0], (0.0, 1.0), [1.0, 0.0, 3.0, 2.0], callback = cb)
146146
sol2 = solve(prob, Tsit5())
147147
@test sol.u == sol2.u
148148
@test saved_values.t == sol.prob.kwargs[:disc_saved_values][1].t
@@ -310,3 +310,128 @@ if VERSION >= v"1.7"
310310

311311
@test sol.u sol2.u
312312
end
313+
314+
##
315+
@info "Testing hybrid system with components"
316+
using ModelingToolkitStandardLibrary.Blocks
317+
318+
dt = 0.05
319+
@variables t
320+
d = Clock(t, dt)
321+
k = ShiftIndex(d)
322+
323+
@mtkmodel DiscretePI begin
324+
@components begin
325+
input = RealInput()
326+
output = RealOutput()
327+
end
328+
@parameters begin
329+
kp = 1, [description = "Proportional gain"]
330+
ki = 1, [description = "Integral gain"]
331+
end
332+
@variables begin
333+
x(t) = 0, [description = "Integral state"]
334+
u(t)
335+
y(t)
336+
end
337+
@equations begin
338+
x(k + 1) ~ x(k) + ki * u
339+
output.u ~ y
340+
input.u ~ u
341+
y ~ x(k) + kp * u
342+
end
343+
end
344+
345+
@mtkmodel Sampler begin
346+
@components begin
347+
input = RealInput()
348+
output = RealOutput()
349+
end
350+
@equations begin
351+
output.u ~ Sample(t, dt)(input.u)
352+
end
353+
end
354+
355+
@mtkmodel Holder begin
356+
@components begin
357+
input = RealInput()
358+
output = RealOutput()
359+
end
360+
@equations begin
361+
output.u ~ Hold(input.u)
362+
end
363+
end
364+
365+
@mtkmodel ClosedLoop begin
366+
@components begin
367+
plant = FirstOrder(k = 0.3, T = 1)
368+
sampler = Sampler()
369+
holder = Holder()
370+
controller = DiscretePI(kp = 2, ki = 2)
371+
feedback = Feedback()
372+
ref = Constant(k = 0.5)
373+
end
374+
@equations begin
375+
connect(ref.output, feedback.input1)
376+
connect(feedback.output, controller.input)
377+
connect(controller.output, holder.input)
378+
connect(holder.output, plant.input)
379+
connect(plant.output, sampler.input)
380+
connect(sampler.output, feedback.input2)
381+
end
382+
end
383+
384+
@named model = ClosedLoop()
385+
model = complete(model)
386+
387+
ci, varmap = infer_clocks(expand_connections(model))
388+
389+
@test varmap[model.plant.input.u] == Continuous()
390+
@test varmap[model.plant.u] == Continuous()
391+
@test varmap[model.plant.x] == Continuous()
392+
@test varmap[model.plant.y] == Continuous()
393+
@test varmap[model.plant.output.u] == Continuous()
394+
@test varmap[model.holder.output.u] == Continuous()
395+
@test varmap[model.sampler.input.u] == Continuous()
396+
@test varmap[model.controller.u] == d
397+
@test varmap[model.holder.input.u] == d
398+
@test varmap[model.controller.output.u] == d
399+
@test varmap[model.controller.y] == d
400+
@test varmap[model.feedback.input1.u] == d
401+
@test varmap[model.ref.output.u] == d
402+
@test varmap[model.controller.input.u] == d
403+
@test varmap[model.controller.x] == d
404+
@test varmap[model.sampler.output.u] == d
405+
@test varmap[model.feedback.output.u] == d
406+
@test varmap[model.feedback.input2.u] == d
407+
408+
ssys = structural_simplify(model)
409+
410+
timevec = 0:(d.dt):20
411+
412+
if VERSION >= v"1.7"
413+
using ControlSystems
414+
P = c2d(tf(0.3, [1, 1]), d.dt)
415+
C = ControlSystems.ss([1], [2], [1], [2], d.dt)
416+
417+
# Test the output of the continuous partition
418+
G = feedback(P * C)
419+
res = lsim(G, (x, t) -> [0.5], timevec)
420+
y = res.y[:]
421+
422+
prob = ODEProblem(ssys,
423+
[model.plant.x => 0.0],
424+
(0.0, 20.0),
425+
[model.controller.kp => 2.0; model.controller.ki => 2.0])
426+
sol = solve(prob, Tsit5(), kwargshandle = KeywordArgSilent)
427+
@test sol(timevec, idxs = model.plant.output.u)y rtol=1e-10 # The output of the continuous partition is delayed exactly one sample
428+
# plot([sol(timevec .+ 1e-12, idxs=model.plant.output.u) y])
429+
430+
# Test the output of the discrete partition
431+
G = feedback(C, P)
432+
res = lsim(G, (x, t) -> [0.5], timevec)
433+
y = res.y[:]
434+
435+
@test sol(timevec .+ 1e-10, idxs = model.controller.output.u)y rtol=1e-10
436+
# plot([sol(timevec .+ 1e-12, idxs=model.controller.output.u) y])
437+
end

0 commit comments

Comments
 (0)