Skip to content

Commit a6ac6c9

Browse files
authored
Merge branch 'SciML:main' into bgc/revolute
2 parents 4d56fe5 + 06fa9bd commit a6ac6c9

File tree

7 files changed

+99
-17
lines changed

7 files changed

+99
-17
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ModelingToolkitStandardLibrary"
22
uuid = "16a59e39-deab-5bd0-87e4-056b12336739"
33
authors = ["Chris Rackauckas and Julia Computing"]
4-
version = "1.6.0"
4+
version = "1.7.0"
55

66
[deps]
77
IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"

docs/make.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ using ModelingToolkitStandardLibrary.Magnetic.FluxTubes
77
using ModelingToolkitStandardLibrary.Electrical
88
using ModelingToolkitStandardLibrary.Thermal
99

10+
ENV["GKSwstype"] = "100"
11+
1012
include("pages.jl")
1113

1214
makedocs(sitename = "ModelingToolkitStandardLibrary.jl",

src/Blocks/continuous.jl

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -414,16 +414,29 @@ function LimPID(; name, k = 1, Ti = false, Td = false, wp = 1, wd = 1,
414414
end
415415

416416
"""
417-
StateSpace(A, B, C, D=0; x_start=zeros(size(A,1)), name)
417+
StateSpace(A, B, C, D=0; x_start=zeros(size(A,1)), u0=zeros(size(B,2)), y0=zeros(size(C,1)), name)
418418
419419
A linear, time-invariant state-space system on the form.
420-
```
420+
```math
421421
ẋ = Ax + Bu
422422
y = Cx + Du
423423
```
424424
Transfer functions can also be simulated by converting them to a StateSpace form.
425+
426+
`y0` and `u0` can be used to set an operating point, providing them changes the dynamics from an LTI system to the affine system
427+
```math
428+
ẋ = Ax + B(u - u0)
429+
y = Cx + D(u - u0) + y0
430+
```
431+
For a nonlinear system
432+
```math
433+
ẋ = f(x, u)
434+
y = h(x, u)
435+
```
436+
linearized around the operating point `x₀, u₀`, we have `y0, u0 = h(x₀, u₀), u₀`.
425437
"""
426-
function StateSpace(; A, B, C, D = nothing, x_start = zeros(size(A, 1)), name)
438+
function StateSpace(; A, B, C, D = nothing, x_start = zeros(size(A, 1)), name,
439+
u0 = zeros(size(B, 2)), y0 = zeros(size(C, 1)))
427440
nx, nu, ny = size(A, 1), size(B, 2), size(C, 1)
428441
size(A, 2) == nx || error("`A` has to be a square matrix.")
429442
size(B, 1) == nx || error("`B` has to be of dimension ($nx x $nu).")
@@ -442,9 +455,11 @@ function StateSpace(; A, B, C, D = nothing, x_start = zeros(size(A, 1)), name)
442455
# pars = @parameters A=A B=B C=C D=D # This is buggy
443456
eqs = [ # FIXME: if array equations work
444457
[Differential(t)(x[i]) ~ sum(A[i, k] * x[k] for k in 1:nx) +
445-
sum(B[i, j] * input.u[j] for j in 1:nu) for i in 1:nx]..., # cannot use D here
458+
sum(B[i, j] * (input.u[j] - u0[j]) for j in 1:nu)
459+
for i in 1:nx]..., # cannot use D here
446460
[output.u[j] ~ sum(C[j, i] * x[i] for i in 1:nx) +
447-
sum(D[j, k] * input.u[k] for k in 1:nu) for j in 1:ny]...,
461+
sum(D[j, k] * (input.u[k] - u0[k]) for k in 1:nu) + y0[j]
462+
for j in 1:ny]...,
448463
]
449464
compose(ODESystem(eqs, t, vcat(x...), [], name = name), [input, output])
450465
end

src/Mechanical/Translational/Translational.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ include("components.jl")
1717
export PositionSensor
1818
include("sensors.jl")
1919

20-
#export SineForce
20+
export Force
2121
include("sources.jl")
2222

2323
end
Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
#=
2-
function SineForce(; name, amp, freq)
1+
using ModelingToolkitStandardLibrary.Blocks
2+
3+
function Force(; name)
34
@named flange = MechanicalPort()
5+
@named f = RealInput()
46

5-
pars = @parameters begin
6-
amp = amp
7-
freq = freq
8-
end
9-
vars = []
7+
vars = pars = []
108
eqs = [
11-
flange.f ~ amp * sin(2 * π * t * freq),
9+
flange.f ~ -f.u,
1210
]
13-
compose(ODESystem(eqs, t, vars, pars; name = name, defaults = [flange.v => 0]), flange)
11+
compose(ODESystem(eqs, t, vars, pars; name = name, defaults = [flange.v => 0]),
12+
[flange, f])
1413
end
15-
=#

test/Blocks/continuous.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,25 @@ end
108108
# equilibrium point is at [1, 0]
109109
@test sol[ss.x[1]][end]1 atol=1e-3
110110
@test sol[ss.x[2]][end]0 atol=1e-3
111+
112+
# non-zero operating point
113+
u0 = [1] # This causes no effective input to the system since c.k = 1
114+
y0 = [2]
115+
@named ss = StateSpace(; A, B, C, D, x_start = zeros(2), u0, y0)
116+
@named model = ODESystem([
117+
connect(c.output, ss.input),
118+
],
119+
t,
120+
systems = [ss, c])
121+
sys = structural_simplify(model)
122+
prob = ODEProblem(sys, Pair[], (0.0, 100.0))
123+
sol = solve(prob, Rodas4())
124+
@test sol.retcode == :Success
125+
126+
@test sol[ss.x[1]][end ÷ 2]0 atol=1e-3 # Test that x did not move
127+
@test sol[ss.x[1]][end]0 atol=1e-3 # Test that x did not move
128+
@test sol[ss.x[2]][end]0 atol=1e-3
129+
@test sol[ss.output.u[1]][end]y0[] atol=1e-3 # Test that the output equals the operating point
111130
end
112131

113132
"""Second order demo plant"""

test/Mechanical/translational.jl

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using ModelingToolkit, OrdinaryDiffEq, Test
22

3+
using ModelingToolkitStandardLibrary.Blocks
34
import ModelingToolkitStandardLibrary.Mechanical.Translational as TV
45
import ModelingToolkitStandardLibrary.Mechanical.TranslationalPosition as TP
56

@@ -44,3 +45,50 @@ D = Differential(t)
4445
@test solp[bp.v][1] == 1.0
4546
@test solp[bp.v][end]0.0 atol=1e-4
4647
end
48+
49+
@testset "driven spring damper mass" begin
50+
@named dv = TV.Damper(d = 1, v_a_0 = 1)
51+
@named dp = TP.Damper(d = 1, v_a_0 = 1, s_a_0 = 3, s_b_0 = 1)
52+
53+
@named sv = TV.Spring(k = 1, v_a_0 = 1, delta_s_0 = 1)
54+
@named sp = TP.Spring(k = 1, s_a_0 = 3, s_b_0 = 1, l = 1)
55+
56+
@named bv = TV.Mass(m = 1, v_0 = 1)
57+
@named bp = TP.Mass(m = 1, v_0 = 1, s_0 = 3)
58+
59+
@named gv = TV.Fixed()
60+
@named gp = TP.Fixed(s_0 = 1)
61+
62+
@named fv = TV.Force()
63+
@named fp = TP.Force()
64+
65+
@named source = Sine(frequency = 3, amplitude = 2)
66+
67+
function simplify_and_solve(damping, spring, body, ground, f, source)
68+
eqs = [connect(f.f, source.output)
69+
connect(f.flange, body.flange)
70+
connect(spring.flange_a, body.flange, damping.flange_a)
71+
connect(spring.flange_b, damping.flange_b, ground.flange)]
72+
73+
@named model = ODESystem(eqs, t;
74+
systems = [ground, body, spring, damping, f, source])
75+
76+
sys = structural_simplify(model)
77+
78+
println.(full_equations(sys))
79+
80+
prob = ODEProblem(sys, [], (0, 20.0), [])
81+
sol = solve(prob, Rodas4())
82+
83+
return sol
84+
end
85+
86+
solv = simplify_and_solve(dv, sv, bv, gv, fv, source)
87+
solp = simplify_and_solve(dp, sp, bp, gp, fp, source)
88+
89+
for sol in (solv, solp)
90+
lb, ub = extrema(solv(15:0.05:20, idxs = bv.v).u)
91+
@test -lbub atol=1e-2
92+
@test -0.11 < lb < -0.1
93+
end
94+
end

0 commit comments

Comments
 (0)