@@ -115,7 +115,7 @@ z(k + 1) ~ z′(k)
115
115
ss = structural_simplify (sys);
116
116
if VERSION >= v " 1.7"
117
117
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 ])
119
119
sol = solve (prob, Tsit5 (), kwargshandle = KeywordArgSilent)
120
120
# For all inputs in parameters, just initialize them to 0.0, and then set them
121
121
# in the callback.
@@ -142,7 +142,7 @@ if VERSION >= v"1.7"
142
142
end
143
143
saved_values = SavedValues (Float64, Vector{Float64})
144
144
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)
146
146
sol2 = solve (prob, Tsit5 ())
147
147
@test sol. u == sol2. u
148
148
@test saved_values. t == sol. prob. kwargs[:disc_saved_values ][1 ]. t
@@ -310,3 +310,128 @@ if VERSION >= v"1.7"
310
310
311
311
@test sol. u ≈ sol2. u
312
312
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