Skip to content

Commit 90d935b

Browse files
Merge pull request #334 from SciML/bgc/siso_defaults
Remove defaults from Blocks.SISO
2 parents cf25a05 + 13b9308 commit 90d935b

File tree

6 files changed

+84
-53
lines changed

6 files changed

+84
-53
lines changed

docs/src/connectors/connections.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ using ModelingToolkitStandardLibrary
136136
const TV = ModelingToolkitStandardLibrary.Mechanical.Translational
137137
138138
systems = @named begin
139-
damping = TV.Damper(d = 1, flange_a.v = 1)
140-
body = TV.Mass(m = 1, v = 1)
139+
damping = TV.Damper(d = 1)
140+
body = TV.Mass(m = 1)
141141
ground = TV.Fixed()
142142
end
143143
@@ -155,7 +155,8 @@ nothing # hide
155155
As expected, we have a similar solution…
156156

157157
```@example connections
158-
prob = ODEProblem(sys, [], (0, 10.0), [])
158+
prob = ODEProblem(
159+
sys, [], (0, 10.0), []; initialization_eqs = [sys.body.s ~ 0, sys.body.v ~ 1])
159160
sol_v = solve(prob)
160161
161162
p1 = plot(sol_v, idxs = [body.v])
@@ -228,7 +229,7 @@ In this problem, we have a mass, spring, and damper which are connected to a fix
228229
The damper will connect the flange/flange 1 (`flange_a`) to the mass, and flange/flange 2 (`flange_b`) to the fixed point. For both position- and velocity-based domains, we set the damping constant `d=1` and `va=1` and leave the default for `v_b_0` at 0. For the position domain, we also need to set the initial positions for `flange_a` and `flange_b`.
229230

230231
```@example connections
231-
@named dv = TV.Damper(d = 1, flange_a.v = 1)
232+
@named dv = TV.Damper(d = 1)
232233
@named dp = TP.Damper(d = 1, va = 1, vb = 0.0, flange_a__s = 3, flange_b__s = 1)
233234
nothing # hide
234235
```
@@ -238,7 +239,7 @@ nothing # hide
238239
The spring will connect the flange/flange 1 (`flange_a`) to the mass, and flange/flange 2 (`flange_b`) to the fixed point. For both position- and velocity-based domains, we set the spring constant `k=1`. The velocity domain then requires the initial velocity `va` and initial spring stretch `delta_s`. The position domain instead needs the initial positions for `flange_a` and `flange_b` and the natural spring length `l`.
239240

240241
```@example connections
241-
@named sv = TV.Spring(k = 1, flange_a__v = 1, delta_s = 1)
242+
@named sv = TV.Spring(k = 1)
242243
@named sp = TP.Spring(k = 1, flange_a__s = 3, flange_b__s = 1, l = 1)
243244
nothing # hide
244245
```
@@ -248,7 +249,7 @@ nothing # hide
248249
For both position- and velocity-based domains, we set the mass `m=1` and initial velocity `v=1`. Like the damper, the position domain requires the position initial conditions set as well.
249250

250251
```@example connections
251-
@named bv = TV.Mass(m = 1, v = 1)
252+
@named bv = TV.Mass(m = 1)
252253
@named bp = TP.Mass(m = 1, v = 1, s = 3)
253254
nothing # hide
254255
```
@@ -270,7 +271,7 @@ As can be seen, the position-based domain requires more initial condition inform
270271
Let's define a quick function to simplify and solve the 2 different systems. Note, we will solve with a fixed time step and a set tolerance to compare the numerical differences.
271272

272273
```@example connections
273-
function simplify_and_solve(damping, spring, body, ground)
274+
function simplify_and_solve(damping, spring, body, ground; initialization_eqs = Equation[])
274275
eqs = [connect(spring.flange_a, body.flange, damping.flange_a)
275276
connect(spring.flange_b, damping.flange_b, ground.flange)]
276277
@@ -280,8 +281,8 @@ function simplify_and_solve(damping, spring, body, ground)
280281
281282
println.(full_equations(sys))
282283
283-
prob = ODEProblem(sys, [], (0, 10.0), [])
284-
sol = solve(prob; dt = 0.1, adaptive = false, reltol = 1e-9, abstol = 1e-9)
284+
prob = ODEProblem(sys, [], (0, 10.0), []; initialization_eqs)
285+
sol = solve(prob; abstol = 1e-9, reltol = 1e-9)
285286
286287
return sol
287288
end
@@ -291,7 +292,10 @@ nothing # hide
291292
Now let's solve the velocity domain model
292293

293294
```@example connections
294-
solv = simplify_and_solve(dv, sv, bv, gv);
295+
initialization_eqs = [bv.s ~ 3
296+
bv.v ~ 1
297+
sv.delta_s ~ 1]
298+
solv = simplify_and_solve(dv, sv, bv, gv; initialization_eqs);
295299
nothing # hide
296300
```
297301

@@ -346,12 +350,11 @@ By definition, the spring stretch is
346350
\Delta s = s - s_{b_0} - l
347351
```
348352

349-
Which means both systems are actually solving the same exact system. We can plot the numerical difference between the 2 systems and see the result is negligible.
353+
Which means both systems are actually solving the same exact system. We can plot the numerical difference between the 2 systems and see the result is negligible (much less than the tolerance of 1e-9).
350354

351355
```@example connections
352356
plot(title = "numerical difference: vel. vs. pos. domain", xlabel = "time [s]",
353357
ylabel = "solv[bv.v] .- solp[bp.v]")
354358
time = 0:0.1:10
355359
plot!(time, (solv(time)[bv.v] .- solp(time)[bp.v]), label = "")
356-
Plots.ylims!(-1e-15, 1e-15)
357360
```

src/Blocks/nonlinear.jl

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -93,20 +93,30 @@ Initial value of state `Y` can be set with `int.y`
9393
- `input`
9494
- `output`
9595
"""
96-
@mtkmodel SlewRateLimiter begin
97-
@parameters begin
98-
rising = 1.0, [description = "Maximum rising slew rate of SlewRateLimiter"]
99-
falling = -rising, [description = "Derivative time constant of SlewRateLimiter"]
100-
Td = 0.001, [description = "Derivative time constant"]
101-
end
102-
begin
103-
getdefault(rising) getdefault(falling) ||
104-
throw(ArgumentError("`rising` must be smaller than `falling`"))
105-
getdefault(Td) > 0 ||
106-
throw(ArgumentError("Time constant `Td` must be strictly positive"))
96+
@component function SlewRateLimiter(;
97+
name, y_start = 0.0, rising = 1.0, falling = -rising, Td = 0.001)
98+
pars = @parameters begin
99+
rising = rising, [description = "Maximum rising slew rate of SlewRateLimiter"]
100+
falling = falling, [description = "Derivative time constant of SlewRateLimiter"]
101+
Td = Td, [description = "Derivative time constant"]
102+
y_start = y_start
107103
end
108-
@extend u, y = siso = SISO(; y_start)
109-
@equations begin
104+
105+
getdefault(rising) getdefault(falling) ||
106+
throw(ArgumentError("`rising` must be smaller than `falling`"))
107+
getdefault(Td) > 0 ||
108+
throw(ArgumentError("Time constant `Td` must be strictly positive"))
109+
110+
@named siso = SISO(; y_start)
111+
@unpack y, u = siso
112+
113+
eqs = [
110114
D(y) ~ max(min((u - y) / Td, rising), falling)
111-
end
115+
]
116+
117+
initialization_eqs = [
118+
y ~ y_start
119+
]
120+
121+
return extend(ODESystem(eqs, t, [], pars; name, initialization_eqs), siso)
112122
end

src/Blocks/utils.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ Single input single output (SISO) continuous system block.
130130
y_start = 0.0
131131
end
132132
@variables begin
133-
u(t) = u_start, [description = "Input of SISO system"]
134-
y(t) = y_start, [description = "Output of SISO system"]
133+
u(t), [guess = u_start, description = "Input of SISO system"]
134+
y(t), [guess = y_start, description = "Output of SISO system"]
135135
end
136136
@components begin
137137
input = RealInput(guess = u_start)

src/Mechanical/Translational/components.jl

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ Sliding mass with inertia
6565
@named flange = MechanicalPort()
6666

6767
vars = @variables begin
68-
s(t)
69-
v(t)
70-
f(t)
68+
s(t), [guess = 0]
69+
v(t), [guess = 0]
70+
f(t), [guess = 0]
7171
end
7272

7373
eqs = [flange.v ~ v
@@ -98,22 +98,21 @@ Linear 1D translational spring
9898
- `flange_a`: 1-dim. translational flange on one side of spring
9999
- `flange_b`: 1-dim. translational flange on opposite side of spring
100100
"""
101-
@component function Spring(; name, k, delta_s = 0.0, flange_a__v = 0.0, flange_b__v = 0.0)
102-
Spring(REL; name, k, delta_s, flange_a__v, flange_b__v)
101+
@component function Spring(; name, k)
102+
Spring(REL; name, k)
103103
end # default
104104

105-
@component function Spring(::Val{:relative}; name, k, delta_s = 0.0, flange_a__v = 0.0,
106-
flange_b__v = 0.0)
105+
@component function Spring(::Val{:relative}; name, k)
107106
pars = @parameters begin
108107
k = k
109108
end
110109
vars = @variables begin
111-
delta_s(t) = delta_s
112-
f(t)
110+
delta_s(t), [guess = 0]
111+
f(t), [guess = 0]
113112
end
114113

115-
@named flange_a = MechanicalPort(; v = flange_a__v)
116-
@named flange_b = MechanicalPort(; v = flange_b__v)
114+
@named flange_a = MechanicalPort()
115+
@named flange_b = MechanicalPort()
117116

118117
eqs = [D(delta_s) ~ flange_a.v - flange_b.v
119118
f ~ k * delta_s
@@ -125,20 +124,19 @@ end # default
125124
end
126125

127126
const ABS = Val(:absolute)
128-
@component function Spring(::Val{:absolute}; name, k, sa = 0, sb = 0, flange_a__v = 0.0,
129-
flange_b__v = 0.0, l = 0)
127+
@component function Spring(::Val{:absolute}; name, k, l = 0)
130128
pars = @parameters begin
131129
k = k
132130
l = l
133131
end
134132
vars = @variables begin
135-
sa(t) = sa
136-
sb(t) = sb
137-
f(t)
133+
sa(t), [guess = 0]
134+
sb(t), [guess = 0]
135+
f(t), [guess = 0]
138136
end
139137

140-
@named flange_a = MechanicalPort(; v = flange_a__v)
141-
@named flange_b = MechanicalPort(; v = flange_b__v)
138+
@named flange_a = MechanicalPort()
139+
@named flange_b = MechanicalPort()
142140

143141
eqs = [D(sa) ~ flange_a.v
144142
D(sb) ~ flange_b.v
@@ -169,8 +167,8 @@ Linear 1D translational damper
169167
d
170168
end
171169
@variables begin
172-
v(t)
173-
f(t)
170+
v(t), [guess = 0]
171+
f(t), [guess = 0]
174172
end
175173

176174
@components begin

test/Blocks/utils.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using ModelingToolkitStandardLibrary.Blocks
22
using ModelingToolkit
3+
using OrdinaryDiffEq
4+
using ModelingToolkit: t_nounits as t, D_nounits as D
35

46
@testset "Array Guesses" begin
57
for (block, guess) in [
@@ -23,6 +25,22 @@ end
2325
end
2426
end
2527

28+
@testset "SISO Check" begin
29+
k, w, d = 1.0, 1.0, 0.5
30+
@named c = Constant(; k = 1)
31+
@named so = SecondOrder(; k = k, w = w, d = d, xd = 1)
32+
@named iosys = ODESystem(connect(c.output, so.input), t, systems = [so, c])
33+
sys = structural_simplify(iosys)
34+
35+
initsys = ModelingToolkit.generate_initializesystem(sys)
36+
initsys = structural_simplify(initsys)
37+
initprob = NonlinearProblem(initsys, [t => 0])
38+
initsol = solve(initprob)
39+
40+
@test initsol[sys.so.xd] == 1.0
41+
@test initsol[sys.so.u] == 1.0
42+
end
43+
2644
@test_deprecated RealInput(; name = :a, u_start = 1.0)
2745
@test_deprecated RealInput(; name = :a, nin = 2, u_start = ones(2))
2846
@test_deprecated RealOutput(; name = :a, u_start = 1.0)

test/Mechanical/translational.jl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ end
3434
@named dv = TV.Damper(d = 1)
3535
@named dp = TP.Damper(d = 1, va = 1, vb = 0.0, flange_a.s = 3, flange_b.s = 1)
3636

37-
@named sv = TV.Spring(k = 1, flange_a__v = 1, delta_s = 1)
37+
@named sv = TV.Spring(k = 1)
3838
@named sp = TP.Spring(k = 1, flange_a__s = 3, flange_b__s = 1, l = 1)
3939

4040
@named bv = TV.Mass(m = 1)
@@ -43,21 +43,23 @@ end
4343
@named gv = TV.Fixed()
4444
@named gp = TP.Fixed(s_0 = 1)
4545

46-
function simplify_and_solve(damping, spring, body, ground)
46+
function simplify_and_solve(
47+
damping, spring, body, ground; initialization_eqs = Equation[])
4748
eqs = [connect(spring.flange_a, body.flange, damping.flange_a)
4849
connect(spring.flange_b, damping.flange_b, ground.flange)]
4950

5051
@named model = ODESystem(eqs, t; systems = [ground, body, spring, damping])
5152

5253
sys = structural_simplify(model)
5354

54-
prob = ODEProblem(sys, [body.s => 0], (0, 20.0), [])
55-
sol = solve(prob, ImplicitMidpoint(), dt = 0.01)
55+
prob = ODEProblem(sys, [], (0, 20.0), []; initialization_eqs)
56+
sol = solve(prob; abstol = 1e-9, reltol = 1e-9)
5657

5758
return sol
5859
end
5960

60-
solv = simplify_and_solve(dv, sv, bv, gv)
61+
solv = simplify_and_solve(
62+
dv, sv, bv, gv; initialization_eqs = [bv.s ~ 3, bv.v ~ 1, sv.delta_s ~ 1])
6163
solp = simplify_and_solve(dp, sp, bp, gp)
6264

6365
@test solv[bv.v][1] == 1.0

0 commit comments

Comments
 (0)