Skip to content

Commit 2505ad3

Browse files
committed
refactor: Blocks/continuous.jl
1 parent 3985596 commit 2505ad3

File tree

2 files changed

+113
-84
lines changed

2 files changed

+113
-84
lines changed

src/Blocks/continuous.jl

Lines changed: 104 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
"""
2-
Integrator(;name, k=1, x_start=0.0)
2+
Integrator(;name, k = 1, x = 0.0)
33
44
Outputs `y = ∫k*u dt`, corresponding to the transfer function `1/s`.
5+
Initial value of integrator state `x` can be set with `x`
56
67
# Connectors:
78
@@ -11,22 +12,25 @@ Outputs `y = ∫k*u dt`, corresponding to the transfer function `1/s`.
1112
# Parameters:
1213
1314
- `k`: Gain of integrator
14-
- `x_start`: Initial value of integrator
1515
"""
16-
@component function Integrator(; name, k = 1, x_start = 0.0)
17-
@named siso = SISO()
18-
@unpack u, y = siso
19-
sts = @variables x(t)=x_start [description = "State of Integrator $name"]
20-
pars = @parameters k=k [description = "Gain of Integrator $name"]
21-
eqs = [D(x) ~ k * u
22-
y ~ x]
23-
extend(ODESystem(eqs, t, sts, pars; name = name), siso)
16+
@mtkmodel Integrator begin
17+
@extend u, y = siso = SISO()
18+
@variables begin
19+
x(t) = 0.0, [description = "State of Integrator"]
20+
end
21+
@parameters begin
22+
k = 1, [description = "Gain of Integrator"]
23+
end
24+
@equations begin
25+
D(x) ~ k * u
26+
y ~ x
27+
end
2428
end
25-
2629
"""
27-
Derivative(; name, k=1, T, x_start=0.0)
30+
Derivative(; name, k = 1, T, x = 0.0)
2831
2932
Outputs an approximate derivative of the input. The transfer function of this block is
33+
Initial value of the state `x` can be set with `x`
3034
3135
```
3236
k k
@@ -44,31 +48,37 @@ A smaller `T` leads to a more ideal approximation of the derivative.
4448
4549
- `k`: Gain
4650
- `T`: [s] Time constants (T>0 required; T=0 is ideal derivative block)
47-
- `x_start`: Initial value of state
4851
4952
# Connectors:
5053
5154
- `input`
5255
- `output`
5356
"""
54-
@component function Derivative(; name, k = 1, T, x_start = 0.0)
55-
@symcheck T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
56-
@named siso = SISO()
57-
@unpack u, y = siso
58-
sts = @variables x(t)=x_start [description = "State of Derivative $name"]
59-
pars = @parameters T=T [description = "Time constant of Derivative $name"] k=k [
60-
description = "Gain of Derivative $name",
61-
]
62-
eqs = [D(x) ~ (u - x) / T
63-
y ~ (k / T) * (u - x)]
64-
extend(ODESystem(eqs, t, sts, pars; name = name), siso)
57+
@mtkmodel Derivative begin
58+
@extend u, y = siso = SISO()
59+
@variables begin
60+
x(t) = 0.0, [description = "State of Derivative"]
61+
end
62+
@parameters begin
63+
T = T, [description = "Time constant of Derivative"]
64+
k = 1, [description = "Gain of Derivative"]
65+
end
66+
begin
67+
@symcheck T > 0 ||
68+
throw(ArgumentError("Time constant `T` has to be strictly positive"))
69+
end
70+
@equations begin
71+
D(x) ~ (u - x) / T
72+
y ~ (k / T) * (u - x)
73+
end
6574
end
6675

6776
"""
68-
FirstOrder(; name, k=1, T, x_start=0.0, lowpass=true)
77+
FirstOrder(; name, k = 1.0, T, x = 0.0, lowpass = true)
6978
7079
A first-order filter with a single real pole in `s = -T` and gain `k`. If `lowpass=true` (default), the transfer function
7180
is given by `Y(s)/U(s) = `
81+
Initial value of the state `x` can be set with `x`
7282
7383
```
7484
k
@@ -88,7 +98,6 @@ sT + 1 - k
8898
8999
- `k`: Gain
90100
- `T`: [s] Time constants (T>0 required)
91-
- `x_start`: Initial value of state
92101
93102
# Connectors:
94103
@@ -97,21 +106,28 @@ sT + 1 - k
97106
98107
See also [`SecondOrder`](@ref)
99108
"""
100-
@component function FirstOrder(; name, k = 1, T, x_start = 0.0, lowpass = true)
101-
@symcheck T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
102-
@named siso = SISO()
103-
@unpack u, y = siso
104-
sts = @variables x(t)=x_start [description = "State of FirstOrder filter $name"]
105-
pars = @parameters T=T [description = "Time constant of FirstOrder filter $name"] k=k [
106-
description = "Gain of FirstOrder $name",
107-
]
108-
eqs = [D(x) ~ (k * u - x) / T
109-
lowpass ? y ~ x : y ~ k * u - x]
110-
extend(ODESystem(eqs, t, sts, pars; name = name), siso)
109+
@mtkmodel FirstOrder begin
110+
@extend u, y = siso = SISO()
111+
@variables begin
112+
x(t) = 0.0, [description = "State of FirstOrder filter"]
113+
end
114+
@parameters begin
115+
lowpass = true
116+
T = T, [description = "Time constant of FirstOrder filter"]
117+
k = 1.0, [description = "Gain of FirstOrder"]
118+
end
119+
begin
120+
@symcheck T > 0 ||
121+
throw(ArgumentError("Time constant `T` has to be strictly positive"))
122+
end
123+
@equations begin
124+
D(x) ~ (k * u - x) / T
125+
getdefault(lowpass) ? y ~ x : y ~ k * u - x
126+
end
111127
end
112128

113129
"""
114-
SecondOrder(; name, k=1, w, d, x_start=0.0, xd_start=0.0)
130+
SecondOrder(; name, k = 1.0, w, d, x = 0.0, xd = 0.0)
115131
116132
A second-order filter with gain `k`, a bandwidth of `w` rad/s and relative damping `d`. The transfer function
117133
is given by `Y(s)/U(s) = `
@@ -124,44 +140,47 @@ s² + 2d*w*s + w^2
124140
125141
Critical damping corresponds to `d=1`, which yields the fastest step response without overshoot, `d < 1` results in an underdamped filter while `d > 1` results in an overdamped filter.
126142
`d = 1/√2` corresponds to a Butterworth filter of order 2 (maximally flat frequency response).
143+
Initial value of the state `x` can be set with `x`, and of derivative state `xd` with `xd`.
127144
128145
# Parameters:
129146
130147
- `k`: Gain
131148
- `w`: [`rad/s`] Angular frequency
132149
- `d`: Damping
133-
- `x_start`: Initial value of state (output)
134-
- `xd_start`: Initial value of derivative of state (output)
135150
136151
# Connectors:
137152
138153
- `input`
139154
- `output`
140155
"""
141-
@component function SecondOrder(; name, k = 1, w, d, x_start = 0.0, xd_start = 0.0)
142-
@named siso = SISO()
143-
@unpack u, y = siso
144-
@variables x(t)=x_start [description = "State of SecondOrder filter $name"]
145-
@variables xd(t)=xd_start [description = "Derivative state of SecondOrder filter $name"]
146-
@parameters k=k [description = "Gain of SecondOrder $name"]
147-
@parameters w=w [description = "Bandwidth of SecondOrder $name"]
148-
@parameters d=d [description = "Relative damping of SecondOrder $name"]
149-
eqs = [D(x) ~ xd
156+
@mtkmodel SecondOrder begin
157+
@extend u, y = siso = SISO()
158+
@variables begin
159+
x(t) = 0.0, [description = "State of SecondOrder filter"]
160+
xd(t) = 0.0, [description = "Derivative state of SecondOrder filter"]
161+
end
162+
@parameters begin
163+
k = 1.0, [description = "Gain of SecondOrder"]
164+
w, [description = "Bandwidth of SecondOrder"]
165+
d, [description = "Relative damping of SecondOrder"]
166+
end
167+
@equations begin
168+
D(x) ~ xd
150169
D(xd) ~ w * (w * (k * u - x) - 2 * d * xd)
151-
y ~ x]
152-
extend(ODESystem(eqs, t; name = name), siso)
170+
y ~ x
171+
end
153172
end
154173

155174
"""
156-
PI(;name, k=1, T, x_start=0.0)
175+
PI(;name, gainPI.k = 1.0, T, int.x = 0.0)
157176
158177
Textbook version of a PI-controller without actuator saturation and anti-windup measure.
178+
Initial value of integrator state `x` can be set with `int.x`
179+
Initial value of gain can be set with `gainPI.k`
159180
160181
# Parameters:
161182
162-
- `k`: Gain
163183
- `T`: [s] Integrator time constant (T>0 required)
164-
- `x_start`: Initial value for the integrator
165184
166185
# Connectors:
167186
@@ -170,22 +189,28 @@ Textbook version of a PI-controller without actuator saturation and anti-windup
170189
171190
See also [`LimPI`](@ref)
172191
"""
173-
@component function PI(; name, k = 1, T, x_start = 0.0)
174-
@symcheck T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive"))
175-
@named err_input = RealInput() # control error
176-
@named ctr_output = RealOutput() # control signal
177-
@named gainPI = Gain(k)
178-
@named addPI = Add()
179-
@named int = Integrator(k = 1 / T, x_start = x_start)
180-
sys = [err_input, ctr_output, gainPI, addPI, int]
181-
eqs = [
182-
connect(err_input, addPI.input1),
183-
connect(addPI.output, gainPI.input),
184-
connect(gainPI.output, ctr_output),
185-
connect(err_input, int.input),
186-
connect(int.output, addPI.input2),
187-
]
188-
ODESystem(eqs, t, [], []; name = name, systems = sys)
192+
@mtkmodel PI begin
193+
@parameters begin
194+
T, [description = "Integrator time constant"]
195+
end
196+
begin
197+
@symcheck T > 0 ||
198+
throw(ArgumentError("Time constant `T` has to be strictly positive"))
199+
end
200+
@components begin
201+
err_input = RealInput() # control error
202+
ctr_output = RealOutput() # control signal
203+
gainPI = Gain(; k = 1.0)
204+
addPI = Add()
205+
int = Integrator(k = 1 / T, x = 0.0)
206+
end
207+
@equations begin
208+
connect(err_input, addPI.input1)
209+
connect(addPI.output, gainPI.input)
210+
connect(gainPI.output, ctr_output)
211+
connect(err_input, int.input)
212+
connect(int.output, addPI.input2)
213+
end
189214
end
190215

191216
"""
@@ -224,12 +249,12 @@ See also [`LimPID`](@ref)
224249
@named gainPID = Gain(k)
225250
@named addPID = Add3()
226251
if with_I
227-
@named int = Integrator(k = 1 / Ti, x_start = xi_start)
252+
@named int = Integrator(k = 1 / Ti, x = xi_start)
228253
else
229254
@named Izero = Constant(k = 0)
230255
end
231256
if with_D
232-
@named der = Derivative(k = Td, T = 1 / Nd, x_start = xd_start)
257+
@named der = Derivative(k = Td, T = 1 / Nd, x = xd_start)
233258
else
234259
@named Dzero = Constant(k = 0)
235260
end
@@ -265,16 +290,16 @@ See also [`LimPID`](@ref)
265290
end
266291

267292
"""
268-
LimPI(;name, k=1, T, u_max=1, u_min=-u_max, Ta)
293+
LimPI(; name, T, Ta, k = 1.0, x_start = 0.0, u_max = 1.0, u_min = -u_max)
269294
270295
Text-book version of a PI-controller with actuator saturation and anti-windup measure.
296+
Initial value of gain can be set with `gainPI.k`
297+
Initial value of integrator state `x` can be set with `int.x`
271298
272299
# Parameters:
273300
274-
- `k`: Gain
275301
- `T`: [s] Integrator time constant (T>0 required)
276302
- `Ta`: [s] Tracking time constant (Ta>0 required)
277-
- `x_start`: Initial value for the integrator
278303
279304
# Connectors:
280305
@@ -291,7 +316,7 @@ Text-book version of a PI-controller with actuator saturation and anti-windup me
291316
@named gainPI = Gain(k)
292317
@named addPI = Add()
293318
@named addTrack = Add()
294-
@named int = Integrator(k = 1 / T, x_start = x_start)
319+
@named int = Integrator(k = 1 / T, x = x_start)
295320
@named limiter = Limiter(y_max = u_max, y_min = u_min)
296321
@named addSat = Add(k1 = 1, k2 = -1)
297322
@named gainTrack = Gain(1 / Ta)
@@ -376,7 +401,7 @@ where the transfer function for the derivative includes additional filtering, se
376401
@named measurement = RealInput()
377402
@named ctr_output = RealOutput() # control signal
378403
@named addP = Add(k1 = wp, k2 = -1)
379-
@named gainPID = Gain(k)
404+
@named gainPID = Gain(; k)
380405
@named addPID = Add3()
381406
@named limiter = Limiter(y_max = u_max, y_min = u_min)
382407
if with_I
@@ -387,12 +412,12 @@ where the transfer function for the derivative includes additional filtering, se
387412
else
388413
@named addI = Add(k1 = 1, k2 = -1)
389414
end
390-
@named int = Integrator(k = 1 / Ti, x_start = xi_start)
415+
@named int = Integrator(k = 1 / Ti, x = xi_start)
391416
else
392417
@named Izero = Constant(k = 0)
393418
end
394419
if with_D
395-
@named der = Derivative(k = Td, T = 1 / Nd, x_start = xd_start)
420+
@named der = Derivative(k = Td, T = 1 / Nd, x = xd_start)
396421
@named addD = Add(k1 = wd, k2 = -1)
397422
else
398423
@named Dzero = Constant(k = 0)

test/Blocks/continuous.jl

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ an integrator with a constant input is often used together with the system under
1313

1414
@testset "Constant" begin
1515
@named c = Constant(; k = 1)
16-
@named int = Integrator()
16+
@named int = Integrator(x = 1)
1717
@named iosys = ODESystem(connect(c.output, int.input), t, systems = [int, c])
1818
sys = structural_simplify(iosys)
19-
prob = ODEProblem(sys, Pair[int.x => 1.0], (0.0, 1.0))
19+
prob = ODEProblem(sys, Pair[], (0.0, 1.0))
2020
sol = solve(prob, Rodas4())
2121
@test sol.retcode == Success
2222
@test all(sol[c.output.u] .≈ 1)
@@ -147,7 +147,7 @@ end
147147
@testset "PI" begin
148148
re_val = 2
149149
@named ref = Constant(; k = re_val)
150-
@named pi_controller = PI(k = 1, T = 1)
150+
@named pi_controller = PI(int.k = 1, T = 1)
151151
@named plant = Plant()
152152
@named fb = Feedback()
153153
@named model = ODESystem([
@@ -227,8 +227,12 @@ end
227227
@testset "LimPI" begin
228228
re_val = 1
229229
@named ref = Constant(; k = re_val)
230-
@named pi_controller_lim = LimPI(k = 3, T = 0.5, u_max = 1.5, u_min = -1.5, Ta = 0.1)
231-
@named pi_controller = PI(k = 3, T = 0.5)
230+
@named pi_controller_lim = LimPI(k = 3,
231+
T = 0.5,
232+
u_max = 1.5,
233+
u_min = -1.5,
234+
Ta = 0.1)
235+
@named pi_controller = PI(gainPI.k = 3, T = 0.5)
232236
@named sat = Limiter(y_max = 1.5, y_min = -1.5)
233237
@named plant = Plant()
234238
@named fb = Feedback()

0 commit comments

Comments
 (0)