Skip to content

Commit 4cdc9d9

Browse files
author
Brad Carman
committed
PID block fix for symbolic parameters
1 parent 0fbd414 commit 4cdc9d9

File tree

4 files changed

+66
-35
lines changed

4 files changed

+66
-35
lines changed

src/Blocks/Blocks.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export Limiter, DeadZone, SlewRateLimiter
2626
include("nonlinear.jl")
2727

2828
export Integrator, Derivative, FirstOrder, SecondOrder, StateSpace
29-
export PI, LimPI, PID, LimPID
29+
export PI, LimPI, PID, PD, LimPID
3030
include("continuous.jl")
3131

3232
export AnalysisPoint, get_sensitivity, get_comp_sensitivity,

src/Blocks/continuous.jl

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -214,15 +214,15 @@ See also [`LimPI`](@ref)
214214
end
215215

216216
"""
217-
PID(;name, k=1, Ti=false, Td=false, Nd=10, int__x=0, der__x=0)
217+
PID(with_I = true, with_D = true; name, k=1, Ti=0.1, Td=0.1, Nd=10, int__x=0, der__x=0)
218218
219219
Text-book version of a PID-controller without actuator saturation and anti-windup measure.
220220
221221
# Parameters:
222222
223223
- `k`: Gain
224-
- `Ti`: [s] Integrator time constant (Ti>0 required). If set to false, no integral action is used.
225-
- `Td`: [s] Derivative time constant (Td>0 required). If set to false, no derivative action is used.
224+
- `Ti`: [s] Integrator time constant (Ti>0 required). If `with_I` set to false, no integral action is used.
225+
- `Td`: [s] Derivative time constant (Td>0 required). If `with_D` set to false, no derivative action is used.
226226
- `Nd`: [s] Time constant for the derivative approximation (Nd>0 required; Nd=0 is ideal derivative).
227227
- `int__x`: Initial value for the integrator.
228228
- `der__x`: Initial value for the derivative state.
@@ -234,29 +234,40 @@ Text-book version of a PID-controller without actuator saturation and anti-windu
234234
235235
See also [`LimPID`](@ref)
236236
"""
237-
@component function PID(; name, k = 1, Ti = false, Td = false, Nd = 10, int__x = 0,
237+
@component function PID(with_I = true, with_D = true; name, k = 1, Ti = 0.1, Td = 0.1, Nd = 10, int__x = 0,
238238
der__x = 0)
239-
with_I = !isequal(Ti, false)
240-
with_D = !isequal(Td, false)
239+
240+
pars = @parameters begin
241+
k = k
242+
Ti = Ti
243+
Td = Td
244+
Nd = Nd
245+
int__x = int__x
246+
der__x = der__x
247+
end
248+
241249
@named err_input = RealInput() # control error
242250
@named ctr_output = RealOutput() # control signal
243-
!isequal(Ti, false) &&
244-
(Ti 0 || throw(ArgumentError("Ti out of bounds, got $(Ti) but expected Ti ≥ 0")))
245-
!isequal(Td, false) &&
246-
(Td 0 || throw(ArgumentError("Td out of bounds, got $(Td) but expected Td ≥ 0")))
247-
Nd > 0 || throw(ArgumentError("Nd out of bounds, got $(Nd) but expected Nd > 0"))
248251

249-
@named gainPID = Gain(k)
252+
with_I &&
253+
(@symcheck Ti 0 || throw(ArgumentError("Ti out of bounds, got $(Ti) but expected Ti ≥ 0")))
254+
with_D &&
255+
(@symcheck Td 0 || throw(ArgumentError("Td out of bounds, got $(Td) but expected Td ≥ 0")))
256+
257+
@symcheck Nd > 0 ||
258+
throw(ArgumentError("Nd out of bounds, got $(Nd) but expected Nd ≥ 0"))
259+
260+
@named gainPID = Gain(; k)
250261
@named addPID = Add3()
251262
if with_I
252-
@named int = Integrator(k = 1 / Ti, x = int__x)
263+
@named int = Integrator(;k = 1 / Ti, x = int__x)
253264
else
254-
@named Izero = Constant(k = 0)
265+
@named Izero = Constant(;k = 0)
255266
end
256267
if with_D
257-
@named der = Derivative(k = Td, T = 1 / Nd, x = der__x)
268+
@named der = Derivative(;k = Td, T = 1 / Nd, x = der__x)
258269
else
259-
@named Dzero = Constant(k = 0)
270+
@named Dzero = Constant(;k = 0)
260271
end
261272
sys = [err_input, ctr_output, gainPID, addPID]
262273
if with_I
@@ -286,9 +297,16 @@ See also [`LimPID`](@ref)
286297
else
287298
push!(eqs, connect(Dzero.output, addPID.input3))
288299
end
289-
ODESystem(eqs, t, [], []; name = name, systems = sys)
300+
ODESystem(eqs, t, [], pars; name = name, systems = sys)
290301
end
291302

303+
with_I(type::Union{AbstractString, Symbol}) = contains(lowercase(string(type)), "i")
304+
with_D(type::Union{AbstractString, Symbol}) = contains(lowercase(string(type)), "d")
305+
306+
PID(type::Union{AbstractString, Symbol}; kwargs...) = PID(with_I(type), with_D(type); kwargs...)
307+
308+
309+
292310
"""
293311
LimPI(; name, k = 1.0, T, Ta, int__x = 0.0, u_max = 1.0, u_min = -u_max)
294312

test/Blocks/continuous.jl

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Test
12
using ModelingToolkit, ModelingToolkitStandardLibrary, OrdinaryDiffEq
23
using ModelingToolkitStandardLibrary.Blocks
34
using OrdinaryDiffEq: ReturnCode.Success
@@ -12,9 +13,13 @@ an integrator with a constant input is often used together with the system under
1213
=#
1314

1415
@testset "Constant" begin
15-
@named c = Constant(; k = 1)
16-
@named int = Integrator(x = 1)
17-
@named iosys = ODESystem(connect(c.output, int.input), t, systems = [int, c])
16+
pars = @parameters begin
17+
k = 1
18+
x = 1
19+
end
20+
@named c = Constant(; k)
21+
@named int = Integrator(; x)
22+
@named iosys = ODESystem(connect(c.output, int.input), t, [], pars; systems = [int, c])
1823
sys = structural_simplify(iosys)
1924
prob = ODEProblem(sys, Pair[], (0.0, 1.0))
2025
sol = solve(prob, Rodas4())
@@ -167,9 +172,12 @@ end
167172
end
168173

169174
@testset "PID" begin
175+
176+
@parameters Ti=0.5 Td=1/100
177+
@named pid_controller = PID(; k = 3, Ti, Td)
178+
170179
re_val = 2
171-
@named ref = Constant(; k = re_val)
172-
@named pid_controller = PID(k = 3, Ti = 0.5, Td = 1 / 100)
180+
@named ref = Constant(; k = re_val)
173181
@named plant = Plant()
174182
@named fb = Feedback()
175183
@named model = ODESystem([
@@ -178,8 +186,7 @@ end
178186
connect(fb.output, pid_controller.err_input),
179187
connect(pid_controller.ctr_output, plant.input),
180188
],
181-
t,
182-
systems = [pid_controller, plant, ref, fb])
189+
t, [], [Ti, Td]; systems = [pid_controller, plant, ref, fb])
183190
sys = structural_simplify(model)
184191
prob = ODEProblem(sys, Pair[], (0.0, 100.0))
185192
sol = solve(prob, Rodas4())
@@ -188,15 +195,14 @@ end
188195
@test sol[plant.output.u][end]re_val atol=1e-3 # zero control error after 100s
189196

190197
@testset "PI" begin
191-
@named pid_controller = PID(k = 3, Ti = 0.5, Td = false)
198+
@named pid_controller = PID("PI"; k = 3, Ti)
192199
@named model = ODESystem([
193200
connect(ref.output, fb.input1),
194201
connect(plant.output, fb.input2),
195202
connect(fb.output, pid_controller.err_input),
196203
connect(pid_controller.ctr_output, plant.input),
197204
],
198-
t,
199-
systems = [pid_controller, plant, ref, fb])
205+
t, [], [Ti]; systems = [pid_controller, plant, ref, fb])
200206
sys = structural_simplify(model)
201207
prob = ODEProblem(sys, Pair[], (0.0, 100.0))
202208
sol = solve(prob, Rodas4())
@@ -206,7 +212,7 @@ end
206212
end
207213

208214
@testset "PD" begin
209-
@named pid_controller = PID(k = 10, Ti = false, Td = 1)
215+
@named pid_controller = PID("PD"; k = 10, Td = 1)
210216
@named model = ODESystem([
211217
connect(ref.output, fb.input1),
212218
connect(plant.output, fb.input2),
@@ -284,7 +290,7 @@ end
284290
@testset "LimPID" begin
285291
re_val = 1
286292
@named ref = Constant(; k = re_val)
287-
@named pid_controller = LimPID(k = 3, Ti = 0.5, Td = 1 / 100, u_max = 1.5, u_min = -1.5,
293+
@named pid_controller = LimPID(; k = 3, Ti = 0.5, Td = 1 / 100, u_max = 1.5, u_min = -1.5,
288294
Ni = 0.1 / 0.5)
289295
@named plant = Plant()
290296
@named model = ODESystem([
@@ -305,7 +311,7 @@ end
305311
@test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit
306312

307313
@testset "PI" begin
308-
@named pid_controller = LimPID(k = 3, Ti = 0.5, Td = false, u_max = 1.5,
314+
@named pid_controller = LimPID(; k = 3, Ti = 0.5, Td = false, u_max = 1.5,
309315
u_min = -1.5, Ni = 0.1 / 0.5)
310316
@named model = ODESystem([
311317
connect(ref.output, pid_controller.reference),
@@ -325,7 +331,7 @@ end
325331
@test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit
326332
end
327333
@testset "PD" begin
328-
@named pid_controller = LimPID(k = 10, Ti = false, Td = 1, u_max = 1.5,
334+
@named pid_controller = LimPID(; k = 10, Ti = false, Td = 1, u_max = 1.5,
329335
u_min = -1.5)
330336
@named model = ODESystem([
331337
connect(ref.output, pid_controller.reference),
@@ -346,7 +352,7 @@ end
346352
end
347353
@testset "set-point weights" begin
348354
@testset "wp" begin
349-
@named pid_controller = LimPID(k = 3, Ti = 0.5, Td = 1 / 100, u_max = 1.5,
355+
@named pid_controller = LimPID(; k = 3, Ti = 0.5, Td = 1 / 100, u_max = 1.5,
350356
u_min = -1.5, Ni = 0.1 / 0.5, wp = 0, wd = 1)
351357
@named model = ODESystem([
352358
connect(ref.output, pid_controller.reference),
@@ -367,7 +373,7 @@ end
367373
@test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit
368374
end
369375
@testset "wd" begin
370-
@named pid_controller = LimPID(k = 3, Ti = 0.5, Td = 1 / 100, u_max = 1.5,
376+
@named pid_controller = LimPID(; k = 3, Ti = 0.5, Td = 1 / 100, u_max = 1.5,
371377
u_min = -1.5, Ni = 0.1 / 0.5, wp = 1, wd = 0)
372378
@named model = ODESystem([
373379
connect(ref.output, pid_controller.reference),
@@ -389,7 +395,7 @@ end
389395
end
390396
end
391397
@testset "PI without AWM" begin
392-
@named pid_controller = LimPID(k = 3, Ti = 0.5, Td = false, u_max = 1.5,
398+
@named pid_controller = LimPID(; k = 3, Ti = 0.5, Td = false, u_max = 1.5,
393399
u_min = -1.5, Ni = Inf)
394400
@named model = ODESystem([
395401
connect(ref.output, pid_controller.reference),

test/runtests.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
using SafeTestsets
2+
using ModelingToolkitStandardLibrary
3+
4+
# ModelingToolkitStandardLibrary
5+
# symcheck
6+
@parameters x = 1
7+
@symcheck x > 0
8+
29

310
# Blocks
411
@safetestset "Blocks: math" begin

0 commit comments

Comments
 (0)