Skip to content

Commit 7f94ed7

Browse files
Merge pull request #43 from ValentinKaisermayer/vk-more-tests
adds more tests
2 parents e5e6ab7 + 5a5075f commit 7f94ed7

File tree

5 files changed

+275
-97
lines changed

5 files changed

+275
-97
lines changed

src/Blocks/Blocks.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ D = Differential(t)
1111
export RealInput, RealOutput, SISO
1212
include("utils.jl")
1313

14-
export Gain, Sum, MatrixGain, Feedback, Add, Product, Division
14+
export Gain, Sum, MatrixGain, Feedback, Add, Add3, Product, Division
1515
export Abs, Sign, Sqrt, Sin, Cos, Tan, Asin, Acos, Atan, Atan2, Sinh, Cosh, Tanh, Exp
1616
export Log, Log10
1717
include("math.jl")

src/Blocks/continuous.jl

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -192,14 +192,12 @@ function PID(;name, k=1, Ti=false, Td=false, Nd=10, xi_start=0, xd_start=0)
192192
push!(eqs, connect(err_input, int.input))
193193
push!(eqs, connect(int.output, addPID.input2))
194194
else
195-
push!(eqs, connect(err_input, Izero.input))
196195
push!(eqs, connect(Izero.output, addPID.input2))
197196
end
198197
if with_D
199198
push!(eqs, connect(err_input, der.input))
200199
push!(eqs, connect(der.output, addPID.input3))
201200
else
202-
push!(eqs, connect(err_input, Dzero.input))
203201
push!(eqs, connect(Dzero.output, addPID.input3))
204202
end
205203
ODESystem(eqs, t, [], []; name=name, systems=sys)
@@ -285,6 +283,7 @@ function LimPID(; name, k=1, Ti=false, Td=false, wp=1, wd=1,
285283
)
286284
with_I = !isequal(Ti, false)
287285
with_D = !isequal(Td, false)
286+
with_AWM = Ni != Inf
288287
if gains
289288
Ti = k / Ti
290289
Td = Td / k
@@ -302,12 +301,16 @@ function LimPID(; name, k=1, Ti=false, Td=false, wp=1, wd=1,
302301
@named addP = Add(k1=wp, k2=-1)
303302
@named gainPID = Gain(k)
304303
@named addPID = Add3()
304+
@named limiter = Limiter(y_max=u_max, y_min=u_min)
305305
if with_I
306-
@named addI = Add3(k1=1, k2=-1, k3=1)
306+
if with_AWM
307+
@named addI = Add3(k1=1, k2=-1, k3=1)
308+
@named addSat = Add(k1=1, k2=-1)
309+
@named gainTrack = Gain(1/(k * Ni))
310+
else
311+
@named addI = Add(k1=1, k2=-1)
312+
end
307313
@named int = Integrator(k=1/Ti, x_start=xi_start)
308-
@named limiter = Limiter(y_max=u_max, y_min=u_min)
309-
@named addSat = Add(k1=1, k2=-1)
310-
@named gainTrack = Gain(1/(k * Ni))
311314
else
312315
@named Izero = Constant(k=0)
313316
end
@@ -318,9 +321,12 @@ function LimPID(; name, k=1, Ti=false, Td=false, wp=1, wd=1,
318321
@named Dzero = Constant(k=0)
319322
end
320323

321-
sys = [reference, measurement, ctr_output, addP, gainPID, addPID]
324+
sys = [reference, measurement, ctr_output, addP, gainPID, addPID, limiter]
322325
if with_I
323-
push!(sys, [addI, int, limiter, addSat, gainTrack]...)
326+
if with_AWM
327+
push!(sys, [addSat, gainTrack]...)
328+
end
329+
push!(sys, [addI, int]...)
324330
else
325331
push!(sys, Izero)
326332
end
@@ -335,16 +341,18 @@ function LimPID(; name, k=1, Ti=false, Td=false, wp=1, wd=1,
335341
connect(measurement, addP.input2),
336342
connect(addP.output, addPID.input1),
337343
connect(addPID.output, gainPID.input),
344+
connect(gainPID.output, limiter.input),
345+
connect(limiter.output, ctr_output),
338346
]
339347
if with_I
340348
push!(eqs, connect(reference, addI.input1))
341349
push!(eqs, connect(measurement, addI.input2))
342-
push!(eqs, connect(gainPID.output, limiter.input))
343-
push!(eqs, connect(limiter.output, ctr_output))
344-
push!(eqs, connect(limiter.input, addSat.input2))
345-
push!(eqs, connect(limiter.output, addSat.input1))
346-
push!(eqs, connect(addSat.output, gainTrack.input))
347-
push!(eqs, connect(gainTrack.output, addI.input3))
350+
if with_AWM
351+
push!(eqs, connect(limiter.input, addSat.input2))
352+
push!(eqs, connect(limiter.output, addSat.input1))
353+
push!(eqs, connect(addSat.output, gainTrack.input))
354+
push!(eqs, connect(gainTrack.output, addI.input3))
355+
end
348356
push!(eqs, connect(addI.output, int.input))
349357
push!(eqs, connect(int.output, addPID.input3))
350358
else

test/Blocks/continuous.jl

Lines changed: 169 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ an integrator with a constant input is often used together with the system under
1717
sys = structural_simplify(iosys)
1818
prob = ODEProblem(sys, Pair[int.x=>1.0], (0.0, 1.0))
1919
sol = solve(prob, Rodas4())
20-
@test sol[int.output.u][end] 2
20+
@test all(sol[c.output.u] .≈ 1)
21+
@test sol[int.output.u][end] .≈ 2 # expected solution
2122
end
2223

2324
@testset "Derivative" begin
@@ -34,7 +35,7 @@ end
3435
sys = structural_simplify(iosys)
3536
prob = ODEProblem(sys, Pair[int.x=>0.0], (0.0, 10.0))
3637
sol = solve(prob, Rodas4())
37-
@test isapprox(sol[source.output.u], sol[int.output.u], atol=1e-1)
38+
@test all(isapprox.(sol[source.output.u], sol[int.output.u], atol=1e-1))
3839
end
3940

4041
@testset "PT1" begin
@@ -88,6 +89,9 @@ end
8889
sys = structural_simplify(model)
8990
prob = ODEProblem(sys, Pair[], (0.0, 100.0))
9091
sol = solve(prob, Rodas4())
92+
# initial condition
93+
@test sol[ss.x[1]][1] 0 atol=1e-3
94+
@test sol[ss.x[2]][1] 0 atol=1e-3
9195
# equilibrium point is at [1, 0]
9296
@test sol[ss.x[1]][end] 1 atol=1e-3
9397
@test sol[ss.x[2]][end] 0 atol=1e-3
@@ -108,7 +112,8 @@ function Plant(;name, x_start=zeros(2))
108112
end
109113

110114
@testset "PI" begin
111-
@named ref = Constant(; k=2)
115+
re_val = 2
116+
@named ref = Constant(; k=re_val)
112117
@named pi_controller = PI(k=1, T=1)
113118
@named plant = Plant()
114119
@named fb = Feedback()
@@ -125,11 +130,13 @@ end
125130
sys = structural_simplify(model)
126131
prob = ODEProblem(sys, Pair[], (0.0, 100.0))
127132
sol = solve(prob, Rodas4())
128-
@test sol[ref.output.u - plant.output.u][end] 0 atol=1e-3 # zero control error after 100s
133+
@test all(isapprox.(sol[ref.output.u], re_val, atol=1e-3)) # check reference
134+
@test sol[plant.output.u][end] re_val atol=1e-3 # zero control error after 100s
129135
end
130136

131137
@testset "PID" begin
132-
@named ref = Constant(; k=2)
138+
re_val = 2
139+
@named ref = Constant(; k=re_val)
133140
@named pid_controller = PID(k=3, Ti=0.5, Td=100)
134141
@named plant = Plant()
135142
@named fb = Feedback()
@@ -146,7 +153,46 @@ end
146153
sys = structural_simplify(model)
147154
prob = ODEProblem(sys, Pair[], (0.0, 100.0))
148155
sol = solve(prob, Rodas4())
149-
@test sol[ref.output.u - plant.output.u][end] 0 atol=1e-3 # zero control error after 100s
156+
@test all(isapprox.(sol[ref.output.u], re_val, atol=1e-3)) # check reference
157+
@test sol[plant.output.u][end] re_val atol=1e-3 # zero control error after 100s
158+
159+
@testset "PI" begin
160+
@named pid_controller = PID(k=3, Ti=0.5, Td=false)
161+
@named model = ODESystem(
162+
[
163+
connect(ref.output, fb.input1),
164+
connect(plant.output, fb.input2),
165+
connect(fb.output, pid_controller.err_input),
166+
connect(pid_controller.ctr_output, plant.input),
167+
],
168+
t,
169+
systems=[pid_controller, plant, ref, fb]
170+
)
171+
sys = structural_simplify(model)
172+
prob = ODEProblem(sys, Pair[], (0.0, 100.0))
173+
sol = solve(prob, Rodas4())
174+
@test all(isapprox.(sol[ref.output.u], re_val, atol=1e-3)) # check reference
175+
@test sol[plant.output.u][end] re_val atol=1e-3 # zero control error after 100s
176+
end
177+
178+
@testset "PD" begin
179+
@named pid_controller = PID(k=10, Ti=false, Td=1)
180+
@named model = ODESystem(
181+
[
182+
connect(ref.output, fb.input1),
183+
connect(plant.output, fb.input2),
184+
connect(fb.output, pid_controller.err_input),
185+
connect(pid_controller.ctr_output, plant.input),
186+
],
187+
t,
188+
systems=[pid_controller, plant, ref, fb]
189+
)
190+
sys = structural_simplify(model)
191+
prob = ODEProblem(sys, Pair[], (0.0, 100.0))
192+
sol = solve(prob, Rodas4())
193+
@test all(isapprox.(sol[ref.output.u], re_val, atol=1e-3)) # check reference
194+
@test sol[plant.output.u][end] > 1 # without I there will be a steady-state error
195+
end
150196
end
151197

152198
@test_skip begin
@@ -236,7 +282,8 @@ end
236282
end
237283

238284
@testset "LimPI" begin
239-
@named ref = Constant(; k=1)
285+
re_val = 1
286+
@named ref = Constant(; k=re_val)
240287
@named pi_controller_lim = LimPI(k=3, T=0.5, u_max=1.5, u_min=-1.5, Ta=0.1)
241288
@named pi_controller = PI(k=3, T=0.5)
242289
@named sat = Limiter(y_max=1.5, y_min=-1.5)
@@ -279,15 +326,19 @@ end
279326
sol = solve(prob, Rodas4())
280327
end
281328

282-
@test sol[ref.output.u - plant.output.u][end] 0 atol=1e-3 # zero control error after 100s
283-
@test sol_lim[ref.output.u - plant.output.u][end] 0 atol=1e-3 # zero control error after 100s
329+
@test all(isapprox.(sol[ref.output.u], re_val, atol=1e-3)) # check reference
330+
@test all(isapprox.(sol_lim[ref.output.u], re_val, atol=1e-3)) # check reference
331+
@test sol[plant.output.u][end] re_val atol=1e-3 # zero control error after 100s
332+
@test sol_lim[plant.output.u][end] re_val atol=1e-3 # zero control error after 100s
333+
@test all(-1.5 .<= sol_lim[pi_controller_lim.ctr_output.u] .<= 1.5) # test limit
284334

285335
# Plots.plot(sol; vars=[plant.output.u]) # without anti-windup measure
286336
# Plots.plot!(sol_lim; vars=[plant.output.u]) # with anti-windup measure
287337
end
288338

289339
@testset "LimPID" begin
290-
@named ref = Constant(; k=1)
340+
re_val = 1
341+
@named ref = Constant(; k=re_val)
291342
@named pid_controller = LimPID(k=3, Ti=0.5, Td=100, u_max=1.5, u_min=-1.5, Ni=0.1/0.5)
292343
@named plant = Plant()
293344
@named model = ODESystem(
@@ -304,5 +355,112 @@ end
304355
sol = solve(prob, Rodas4())
305356

306357
# Plots.plot(sol, vars=[plant.output.u, plant.input.u])
307-
@test sol[ref.output.u - plant.output.u][end] 0 atol=1e-3 # zero control error after 100s
358+
@test all(isapprox.(sol[ref.output.u], re_val, atol=1e-3)) # check reference
359+
@test sol[plant.output.u][end] re_val atol=1e-3 # zero control error after 100s
360+
@test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit
361+
362+
@testset "PI" begin
363+
@named pid_controller = LimPID(k=3, Ti=0.5, Td=false, u_max=1.5, u_min=-1.5, Ni=0.1/0.5)
364+
@named model = ODESystem(
365+
[
366+
connect(ref.output, pid_controller.reference),
367+
connect(plant.output, pid_controller.measurement),
368+
connect(pid_controller.ctr_output, plant.input),
369+
],
370+
t,
371+
systems=[pid_controller, plant, ref]
372+
)
373+
sys = structural_simplify(model)
374+
prob = ODEProblem(sys, Pair[], (0.0, 100.0))
375+
sol = solve(prob, Rodas4())
376+
377+
# Plots.plot(sol, vars=[plant.output.u, plant.input.u])
378+
@test all(isapprox.(sol[ref.output.u], re_val, atol=1e-3)) # check reference
379+
@test sol[plant.output.u][end] re_val atol=1e-3 # zero control error after 100s
380+
@test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit
381+
end
382+
@testset "PD" begin
383+
@named pid_controller = LimPID(k=10, Ti=false, Td=1, u_max=1.5, u_min=-1.5)
384+
@named model = ODESystem(
385+
[
386+
connect(ref.output, pid_controller.reference),
387+
connect(plant.output, pid_controller.measurement),
388+
connect(pid_controller.ctr_output, plant.input),
389+
],
390+
t,
391+
systems=[pid_controller, plant, ref]
392+
)
393+
sys = structural_simplify(model)
394+
prob = ODEProblem(sys, Pair[], (0.0, 100.0))
395+
sol = solve(prob, Rodas4())
396+
397+
# Plots.plot(sol, vars=[plant.output.u, plant.input.u])
398+
@test all(isapprox.(sol[ref.output.u], re_val, atol=1e-3)) # check reference
399+
@test sol[plant.output.u][end] > 0.5 # without I there will be a steady-state error
400+
@test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit
401+
end
402+
@testset "set-point weights" begin
403+
@testset "wp" begin
404+
@named pid_controller = LimPID(k=3, Ti=0.5, Td=100, u_max=1.5, u_min=-1.5, Ni=0.1/0.5, wp=0, wd=1)
405+
@named model = ODESystem(
406+
[
407+
connect(ref.output, pid_controller.reference),
408+
connect(plant.output, pid_controller.measurement),
409+
connect(pid_controller.ctr_output, plant.input),
410+
],
411+
t,
412+
systems=[pid_controller, plant, ref]
413+
)
414+
sys = structural_simplify(model)
415+
prob = ODEProblem(sys, Pair[], (0.0, 100.0))
416+
sol = solve(prob, Rodas4())
417+
418+
# Plots.plot(sol, vars=[plant.output.u, plant.input.u])
419+
@test all(isapprox.(sol[ref.output.u], re_val, atol=1e-3)) # check reference
420+
sol[pid_controller.addP.output.u] == -sol[pid_controller.measurement.u]
421+
@test sol[plant.output.u][end] re_val atol=1e-3 # zero control error after 100s
422+
@test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit
423+
end
424+
@testset "wd" begin
425+
@named pid_controller = LimPID(k=3, Ti=0.5, Td=100, u_max=1.5, u_min=-1.5, Ni=0.1/0.5, wp=1, wd=0)
426+
@named model = ODESystem(
427+
[
428+
connect(ref.output, pid_controller.reference),
429+
connect(plant.output, pid_controller.measurement),
430+
connect(pid_controller.ctr_output, plant.input),
431+
],
432+
t,
433+
systems=[pid_controller, plant, ref]
434+
)
435+
sys = structural_simplify(model)
436+
prob = ODEProblem(sys, Pair[], (0.0, 100.0))
437+
sol = solve(prob, Rodas4())
438+
439+
# Plots.plot(sol, vars=[plant.output.u, plant.input.u])
440+
@test all(isapprox.(sol[ref.output.u], re_val, atol=1e-3)) # check reference
441+
@test sol[plant.output.u][end] re_val atol=1e-3 # zero control error after 100s
442+
sol[pid_controller.addD.output.u] == -sol[pid_controller.measurement.u]
443+
@test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit
444+
end
445+
end
446+
@testset "PI without AWM" begin
447+
@named pid_controller = LimPID(k=3, Ti=0.5, Td=false, u_max=1.5, u_min=-1.5, Ni=Inf)
448+
@named model = ODESystem(
449+
[
450+
connect(ref.output, pid_controller.reference),
451+
connect(plant.output, pid_controller.measurement),
452+
connect(pid_controller.ctr_output, plant.input),
453+
],
454+
t,
455+
systems=[pid_controller, plant, ref]
456+
)
457+
sys = structural_simplify(model)
458+
prob = ODEProblem(sys, Pair[], (0.0, 100.0))
459+
sol = solve(prob, Rodas4())
460+
461+
# Plots.plot(sol, vars=[plant.output.u, plant.input.u])
462+
@test all(isapprox.(sol[ref.output.u], re_val, atol=1e-3)) # check reference
463+
@test sol[plant.output.u][end] re_val atol=1e-3 # zero control error after 100s
464+
@test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit
465+
end
308466
end

0 commit comments

Comments
 (0)