From d5d81670a99c17f8567e446b901978ee74cdf9e0 Mon Sep 17 00:00:00 2001 From: Brad Carman Date: Sun, 11 Sep 2022 18:55:44 -0400 Subject: [PATCH 1/7] Start of Translational --- src/Mechanical/Mechanical.jl | 1 + src/Mechanical/Translational/Translational.jl | 22 +++ src/Mechanical/Translational/components.jl | 112 ++++++++++++++++ src/Mechanical/Translational/utils.jl | 16 +++ test/Mechanical/translational.jl | 126 ++++++++++++++++++ 5 files changed, 277 insertions(+) create mode 100644 src/Mechanical/Translational/Translational.jl create mode 100644 src/Mechanical/Translational/components.jl create mode 100644 src/Mechanical/Translational/utils.jl create mode 100644 test/Mechanical/translational.jl diff --git a/src/Mechanical/Mechanical.jl b/src/Mechanical/Mechanical.jl index f58b6e667..2e87392b9 100644 --- a/src/Mechanical/Mechanical.jl +++ b/src/Mechanical/Mechanical.jl @@ -6,5 +6,6 @@ module Mechanical using ModelingToolkit include("Rotational/Rotational.jl") +include("Translational/Translational.jl") end diff --git a/src/Mechanical/Translational/Translational.jl b/src/Mechanical/Translational/Translational.jl new file mode 100644 index 000000000..38323d904 --- /dev/null +++ b/src/Mechanical/Translational/Translational.jl @@ -0,0 +1,22 @@ +""" +Library to model 1-dimensional, translational mechanical systems +""" +module Translational + +using ModelingToolkit, Symbolics, IfElse +using ...Blocks: RealInput, RealOutput + +@parameters t +D = Differential(t) + +export Port +include("utils.jl") + +export Body, Spring +export SpringDamperBoundary, ForcedBoundary +include("components.jl") + +#export Torque +#include("sources.jl") + +end diff --git a/src/Mechanical/Translational/components.jl b/src/Mechanical/Translational/components.jl new file mode 100644 index 000000000..f43347984 --- /dev/null +++ b/src/Mechanical/Translational/components.jl @@ -0,0 +1,112 @@ + +@enum BoundaryType NoBoundary SpringDamperBoundary ForcedBoundary + +#Note: boundary is an argument because this is a compile time constant +function Body(boundary = NoBoundary; name, x0 = 0.0, v0 = 0.0, mass = 1.0, g=0.0, upper_limit = +Inf, lower_limit = -Inf, k=1e9, d=1e6) + @named T = Port(v0 = v0, f0 = mass*g) + @parameters mass=mass g=g + @variables begin + x(t) = x0 + dx(t) = v0 + ddx(t) = 0.0 + end + + if boundary != NoBoundary + @variables begin + f_floor(t) = 0.0 + f_ceil(t) = 0.0 + end + @parameters begin + ubnd = upper_limit + lbnd = lower_limit + k=k + d=d + end + end + + eqs = [ + T.v ~ dx + + D(x) ~ dx + D(dx) ~ ddx + ] + + if boundary == NoBoundary + feqs = [ + ddx * mass ~ mass*g + T.f + ] + return compose(ODESystem([eqs; feqs], t, [x, dx, ddx], [mass, g]; name = name), T) + elseif boundary == SpringDamperBoundary + + # let + Δceil = x - ubnd + Δfloor = lbnd - x + + feqs = [ + ddx * mass ~ mass*g + T.f - f_floor - f_ceil + f_ceil ~ ifelse(x < ubnd, 0.0, Δceil*k + dx*d) + f_floor ~ ifelse(x > lbnd, 0.0, Δfloor*k + dx*d) + ] + return compose(ODESystem([eqs; feqs], t, [x, dx, ddx, f_ceil, f_floor], [mass, g, ubnd, lbnd, k, d]; name = name), T) + elseif boundary == ForcedBoundary + + # let + f = mass*g + T.f # external forces + + feqs = [ + ddx * mass ~ f - f_floor - f_ceil + 0 ~ ifelse((x >= ubnd), + ( x ) - ( ubnd ), # make x=>ubnd, solve for f_ceil to make this true + ( f_ceil ) - ( 0 ) + ) + 0 ~ ifelse((x <= lbnd) , + ( x ) - ( lbnd ), # make x=>lbnd, solve for f_floor to make this true + ( f_floor ) - ( 0 ) + ) + ] + return compose(ODESystem([eqs; feqs], t, [x, dx, ddx, f_ceil, f_floor], [mass, g, ubnd, lbnd]; name = name), T) + end + + + +end + + +function Spring(;name, k = 1e3, delta0 = 0.0) + @parameters k=k + @variables begin + x(t) = delta0 + dx(t) = 0.0 + f(t) + end + + @named T1 = Port() + @named T2 = Port() + + eqs = [ + D(x) ~ dx + dx ~ T1.v - T2.v + f ~ k*x + T1.f ~ +f + T2.f ~ -f + ] + return compose(ODESystem(eqs, t, [x, dx, f], [k]; name = name), T1, T2) +end + +function Damper(; name, c=1e2) + @parameters c=c + @variables dx=0.0 + + @named T1 = Port() + @named T2 = Port() + + eqs = [ + T1.v - T2.v ~ dx + T1.f + T2.f ~ dx*c + ] + return compose(ODESystem(eqs, t, [x, dx, f], [k]; name = name), T1, T2) +end + + + + diff --git a/src/Mechanical/Translational/utils.jl b/src/Mechanical/Translational/utils.jl new file mode 100644 index 000000000..8865b41c6 --- /dev/null +++ b/src/Mechanical/Translational/utils.jl @@ -0,0 +1,16 @@ +@connector function Port(; name, v0=0.0, f0=0.0) + sts = @variables begin + v(t) + f(t), [connect = Flow] + end + ODESystem(Equation[], t, sts, [], name = name, defaults = Dict(v => v0, f => f0)) +end +Base.@doc """ + Port(;name, v_int=0.0, f_int=0.0) + +1-dim. rotational flange of a shaft. + +# States: +- `v`: [m/s] velocity of the node +- `f`: [N] force entering the node +""" Port diff --git a/test/Mechanical/translational.jl b/test/Mechanical/translational.jl new file mode 100644 index 000000000..a890988e8 --- /dev/null +++ b/test/Mechanical/translational.jl @@ -0,0 +1,126 @@ +using ModelingToolkitStandardLibrary.Mechanical.Translational, ModelingToolkit, OrdinaryDiffEq, + Test +import ModelingToolkitStandardLibrary.Blocks + + +@parameters t +D = Differential(t) + +@testset "one falling body" begin + #body starts at 1m, moving up at 2m/s in gravity of 10 + @named body = Body(x0 = 1.0, v0 = 2.0, g=-10.0) + + @named model = ODESystem(body.T.f ~ 0, t, [], []; systems=[body]) + + sys = structural_simplify(model) + prob = ODEProblem(sys, [], (0, 1.0)) + sol = solve(prob, ImplicitMidpoint(), dt=0.1) + + #x = g*t^2/2 + v_int*t + x_int + #dx = g*t + v_int + + @test sol.retcode == :Success + @test sol[body.x, 1] == 1.0 + @test sol[body.dx, 1] == 2.0 + @test sol[body.x, end] ≈ -10/2 + 2.0 + 1.0 + +#= + using CairoMakie + lines(sol.t, sol[body.x]) +=# + +end + + +@testset "two bodies ForcedBoundary" begin + @named body1 = Body(ForcedBoundary; mass=100.0, x0 = 10.0, g=-10.0, lower_limit = 0.0) + @named body2 = Body(mass = 1000.0, g = -10.0) + @named spring = Spring(k=1000.0) + + eqs = [ + connect(body1.T, spring.T1) + connect(body2.T, spring.T2) + ] + + @named model = ODESystem(eqs, t, [], []; systems=[body1, body2, spring]) + + sys = structural_simplify(model) + prob = ODEProblem(sys, [], (0, 20.0)) + + # + + sol = solve(prob, ImplicitEuler(nlsolve = NLNewton(check_div = false, always_new = true, max_iter=100, relax=0.0)), + dt = 4e-4, + adaptive=false) + + @test sol(5.0; idxs=body1.x) ≈ 0.0 atol=1e-7 +end + +#= + using CairoMakie + begin + f = Figure() + a = Axis(f[1,1]) + lines!(a, sol.t, sol[body1.x]) + lines!(a, sol.t, sol[body2.x]) + # ylims!(a, -0.0001, 0.0001) + + + a = Axis(f[2,1]) + lines!(a, sol.t, sol[body1.f_ceil]) + lines!(a, sol.t, sol[body1.f_floor]) + lines!(a, sol.t, sol[spring.f]) + # ylims!(a, -100000, 0) + + a = Axis(f[3,1]) + lines!(a, sol.t, sol[body1.x] .== 0) + + f + end + + using Makie + tm = Observable(0.0) + begin + f = Figure() + a = Axis(f[1,2], aspect=DataAspect(), ) + hidedecorations!(a) + s = @lift(sol($tm)) + + m1x = @lift($s[2]) + m2x = @lift($s[4]) + + sz1 = 0.5 + lines!(a, [-sz1, sz1, sz1, -sz1, -sz1], @lift([$m1x, $m1x, $m1x+sz1*2, $m1x+sz1*2, $m1x])) + + sz = 1.0 + lines!(a, [-sz, sz, sz, -sz, -sz], @lift([$m2x, $m2x, $m2x+sz*2, $m2x+sz*2, $m2x])) + + lines!(a, [0.0, 0.0], @lift([$m1x+0.5, $m2x+1.0]), color=:red, width=2, linestyle=:dot) + + hlines!(a, 0.0, color=:gray) + hlines!(a, -10.0, color=:gray, linestyle=:dash) + + ylims!(a, -40, 15) + + a = Axis(f[1, 1], xlabel="time [s]", ylabel="position [m]") + lines!(a, sol.t, sol[body1.x]) + lines!(a, sol.t, sol[body2.x]) + + scatter!(a, tm, m1x) + scatter!(a, tm, m2x) + ylims!(a, -40, 15) + + f + end + + framerate = 30 + timestamps = range(0, 20, step=1/framerate) + + record(f, "time_animation.mp4", timestamps; + framerate = framerate) do t + tm[] = t + end +=# + + + From fe7d103d3cba0750b932ae0d770388ec90339c8c Mon Sep 17 00:00:00 2001 From: Brad Carman Date: Tue, 13 Sep 2022 20:52:28 -0400 Subject: [PATCH 2/7] initial Body, Spring, Damper --- src/Mechanical/Translational/Translational.jl | 4 +- src/Mechanical/Translational/components.jl | 97 +++++-------------- test/Mechanical/translational.jl | 97 +------------------ 3 files changed, 29 insertions(+), 169 deletions(-) diff --git a/src/Mechanical/Translational/Translational.jl b/src/Mechanical/Translational/Translational.jl index 38323d904..c1786a7b8 100644 --- a/src/Mechanical/Translational/Translational.jl +++ b/src/Mechanical/Translational/Translational.jl @@ -4,7 +4,6 @@ Library to model 1-dimensional, translational mechanical systems module Translational using ModelingToolkit, Symbolics, IfElse -using ...Blocks: RealInput, RealOutput @parameters t D = Differential(t) @@ -12,8 +11,7 @@ D = Differential(t) export Port include("utils.jl") -export Body, Spring -export SpringDamperBoundary, ForcedBoundary +export Body, Spring, Damper include("components.jl") #export Torque diff --git a/src/Mechanical/Translational/components.jl b/src/Mechanical/Translational/components.jl index f43347984..4760c9b2e 100644 --- a/src/Mechanical/Translational/components.jl +++ b/src/Mechanical/Translational/components.jl @@ -1,74 +1,23 @@ - -@enum BoundaryType NoBoundary SpringDamperBoundary ForcedBoundary - -#Note: boundary is an argument because this is a compile time constant -function Body(boundary = NoBoundary; name, x0 = 0.0, v0 = 0.0, mass = 1.0, g=0.0, upper_limit = +Inf, lower_limit = -Inf, k=1e9, d=1e6) - @named T = Port(v0 = v0, f0 = mass*g) - @parameters mass=mass g=g +function Body(; name, x0 = 0.0, v0 = 0.0, m = 1.0, g=0.0) + @named port = Port(v0 = v0, f0 = m*g) + @parameters m=m g=g @variables begin x(t) = x0 dx(t) = v0 ddx(t) = 0.0 end - if boundary != NoBoundary - @variables begin - f_floor(t) = 0.0 - f_ceil(t) = 0.0 - end - @parameters begin - ubnd = upper_limit - lbnd = lower_limit - k=k - d=d - end - end - eqs = [ - T.v ~ dx + port.v ~ dx D(x) ~ dx D(dx) ~ ddx - ] - - if boundary == NoBoundary - feqs = [ - ddx * mass ~ mass*g + T.f - ] - return compose(ODESystem([eqs; feqs], t, [x, dx, ddx], [mass, g]; name = name), T) - elseif boundary == SpringDamperBoundary - - # let - Δceil = x - ubnd - Δfloor = lbnd - x - feqs = [ - ddx * mass ~ mass*g + T.f - f_floor - f_ceil - f_ceil ~ ifelse(x < ubnd, 0.0, Δceil*k + dx*d) - f_floor ~ ifelse(x > lbnd, 0.0, Δfloor*k + dx*d) - ] - return compose(ODESystem([eqs; feqs], t, [x, dx, ddx, f_ceil, f_floor], [mass, g, ubnd, lbnd, k, d]; name = name), T) - elseif boundary == ForcedBoundary - - # let - f = mass*g + T.f # external forces + ddx * m ~ m*g + port.f + ] - feqs = [ - ddx * mass ~ f - f_floor - f_ceil - 0 ~ ifelse((x >= ubnd), - ( x ) - ( ubnd ), # make x=>ubnd, solve for f_ceil to make this true - ( f_ceil ) - ( 0 ) - ) - 0 ~ ifelse((x <= lbnd) , - ( x ) - ( lbnd ), # make x=>lbnd, solve for f_floor to make this true - ( f_floor ) - ( 0 ) - ) - ] - return compose(ODESystem([eqs; feqs], t, [x, dx, ddx, f_ceil, f_floor], [mass, g, ubnd, lbnd]; name = name), T) - end - - + return compose(ODESystem(eqs, t, [x, dx, ddx], [m, g]; name = name), port) end @@ -80,33 +29,33 @@ function Spring(;name, k = 1e3, delta0 = 0.0) f(t) end - @named T1 = Port() - @named T2 = Port() + @named port_a = Port() + @named port_b = Port() eqs = [ D(x) ~ dx - dx ~ T1.v - T2.v + dx ~ port_a.v - port_b.v f ~ k*x - T1.f ~ +f - T2.f ~ -f + port_a.f ~ +f + port_b.f ~ -f ] - return compose(ODESystem(eqs, t, [x, dx, f], [k]; name = name), T1, T2) + return compose(ODESystem(eqs, t, [x, dx, f], [k]; name = name), port_a, port_b) end -function Damper(; name, c=1e2) - @parameters c=c - @variables dx=0.0 +function Damper(; name, d=1e2) + @parameters d=d + @variables dx(t)=0.0 f(t)=0.0 - @named T1 = Port() - @named T2 = Port() + @named port_a = Port() + @named port_b = Port() eqs = [ - T1.v - T2.v ~ dx - T1.f + T2.f ~ dx*c + port_a.v - port_b.v ~ dx + f ~ dx*d + port_a.f ~ +f + port_b.f ~ -f ] - return compose(ODESystem(eqs, t, [x, dx, f], [k]; name = name), T1, T2) + return compose(ODESystem(eqs, t, [dx, f], [d]; name = name), port_a, port_b) end - - diff --git a/test/Mechanical/translational.jl b/test/Mechanical/translational.jl index a890988e8..b488c6983 100644 --- a/test/Mechanical/translational.jl +++ b/test/Mechanical/translational.jl @@ -1,16 +1,17 @@ using ModelingToolkitStandardLibrary.Mechanical.Translational, ModelingToolkit, OrdinaryDiffEq, Test -import ModelingToolkitStandardLibrary.Blocks + @parameters t D = Differential(t) + @testset "one falling body" begin #body starts at 1m, moving up at 2m/s in gravity of 10 @named body = Body(x0 = 1.0, v0 = 2.0, g=-10.0) - @named model = ODESystem(body.T.f ~ 0, t, [], []; systems=[body]) + @named model = ODESystem(body.port.f ~ 0, t, [], []; systems=[body]) sys = structural_simplify(model) prob = ODEProblem(sys, [], (0, 1.0)) @@ -23,104 +24,16 @@ D = Differential(t) @test sol[body.x, 1] == 1.0 @test sol[body.dx, 1] == 2.0 @test sol[body.x, end] ≈ -10/2 + 2.0 + 1.0 +end + -#= - using CairoMakie - lines(sol.t, sol[body.x]) -=# -end -@testset "two bodies ForcedBoundary" begin - @named body1 = Body(ForcedBoundary; mass=100.0, x0 = 10.0, g=-10.0, lower_limit = 0.0) - @named body2 = Body(mass = 1000.0, g = -10.0) - @named spring = Spring(k=1000.0) - eqs = [ - connect(body1.T, spring.T1) - connect(body2.T, spring.T2) - ] - @named model = ODESystem(eqs, t, [], []; systems=[body1, body2, spring]) - sys = structural_simplify(model) - prob = ODEProblem(sys, [], (0, 20.0)) - - # - - sol = solve(prob, ImplicitEuler(nlsolve = NLNewton(check_div = false, always_new = true, max_iter=100, relax=0.0)), - dt = 4e-4, - adaptive=false) - - @test sol(5.0; idxs=body1.x) ≈ 0.0 atol=1e-7 -end -#= - using CairoMakie - begin - f = Figure() - a = Axis(f[1,1]) - lines!(a, sol.t, sol[body1.x]) - lines!(a, sol.t, sol[body2.x]) - # ylims!(a, -0.0001, 0.0001) - - - a = Axis(f[2,1]) - lines!(a, sol.t, sol[body1.f_ceil]) - lines!(a, sol.t, sol[body1.f_floor]) - lines!(a, sol.t, sol[spring.f]) - # ylims!(a, -100000, 0) - - a = Axis(f[3,1]) - lines!(a, sol.t, sol[body1.x] .== 0) - - f - end - - using Makie - tm = Observable(0.0) - begin - f = Figure() - a = Axis(f[1,2], aspect=DataAspect(), ) - hidedecorations!(a) - s = @lift(sol($tm)) - - m1x = @lift($s[2]) - m2x = @lift($s[4]) - - sz1 = 0.5 - lines!(a, [-sz1, sz1, sz1, -sz1, -sz1], @lift([$m1x, $m1x, $m1x+sz1*2, $m1x+sz1*2, $m1x])) - - sz = 1.0 - lines!(a, [-sz, sz, sz, -sz, -sz], @lift([$m2x, $m2x, $m2x+sz*2, $m2x+sz*2, $m2x])) - - lines!(a, [0.0, 0.0], @lift([$m1x+0.5, $m2x+1.0]), color=:red, width=2, linestyle=:dot) - - hlines!(a, 0.0, color=:gray) - hlines!(a, -10.0, color=:gray, linestyle=:dash) - - ylims!(a, -40, 15) - - a = Axis(f[1, 1], xlabel="time [s]", ylabel="position [m]") - lines!(a, sol.t, sol[body1.x]) - lines!(a, sol.t, sol[body2.x]) - - scatter!(a, tm, m1x) - scatter!(a, tm, m2x) - ylims!(a, -40, 15) - - f - end - - framerate = 30 - timestamps = range(0, 20, step=1/framerate) - - record(f, "time_animation.mp4", timestamps; - framerate = framerate) do t - tm[] = t - end -=# From ac567e68869d6db14c4b22efd02cd1dc3ce18d42 Mon Sep 17 00:00:00 2001 From: Brad Carman Date: Wed, 14 Sep 2022 13:02:34 -0400 Subject: [PATCH 3/7] implemented runtests --- test/runtests.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 7ecd62366..7587a1744 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -20,4 +20,6 @@ using SafeTestsets @safetestset "Magnetic" begin include("Magnetic/magnetic.jl") end # Mechanical -@safetestset "Mechanical" begin include("Mechanical/rotational.jl") end +@safetestset "Mechanical Rotation" begin include("Mechanical/rotational.jl") end +@safetestset "Mechanical Translation" begin include("Mechanical/translational.jl") end + From e40ba3a6c3a9357d73f36e687d363419ad4eeff5 Mon Sep 17 00:00:00 2001 From: Brad Carman Date: Thu, 15 Sep 2022 09:37:46 -0400 Subject: [PATCH 4/7] added Fixed and updated Spring --- src/Mechanical/Translational/components.jl | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Mechanical/Translational/components.jl b/src/Mechanical/Translational/components.jl index 4760c9b2e..ff20f652c 100644 --- a/src/Mechanical/Translational/components.jl +++ b/src/Mechanical/Translational/components.jl @@ -1,3 +1,9 @@ +function Fixed(; name) + @named port = Port() + eqs = [port.v ~ 0] + return compose(ODESystem(eqs, t, [], []; name = name), port) +end + function Body(; name, x0 = 0.0, v0 = 0.0, m = 1.0, g=0.0) @named port = Port(v0 = v0, f0 = m*g) @parameters m=m g=g @@ -15,7 +21,6 @@ function Body(; name, x0 = 0.0, v0 = 0.0, m = 1.0, g=0.0) ddx * m ~ m*g + port.f ] - return compose(ODESystem(eqs, t, [x, dx, ddx], [m, g]; name = name), port) end @@ -26,7 +31,7 @@ function Spring(;name, k = 1e3, delta0 = 0.0) @variables begin x(t) = delta0 dx(t) = 0.0 - f(t) + f(t) = k*x end @named port_a = Port() From 3318ffd1418358096bfde9b0275d1eda4dce42ca Mon Sep 17 00:00:00 2001 From: Brad Carman Date: Fri, 16 Sep 2022 23:23:09 -0400 Subject: [PATCH 5/7] Draft report comparing Position and Velocity --- docs/connections.html | 921 ++++++++++++++++++ docs/connections.jmd | 197 ++++ docs/through_across.png | Bin 0 -> 30457 bytes docs/through_across.svg | 317 ++++++ src/Mechanical/Mechanical.jl | 1 + src/Mechanical/Translational/Translational.jl | 2 +- src/Mechanical/Translational/components.jl | 51 +- .../TranslationalPosition.jl | 21 + .../TranslationalPosition/components.jl | 98 ++ .../TranslationalPosition/sources.jl | 12 + src/Mechanical/TranslationalPosition/utils.jl | 147 +++ 11 files changed, 1738 insertions(+), 29 deletions(-) create mode 100644 docs/connections.html create mode 100644 docs/connections.jmd create mode 100644 docs/through_across.png create mode 100644 docs/through_across.svg create mode 100644 src/Mechanical/TranslationalPosition/TranslationalPosition.jl create mode 100644 src/Mechanical/TranslationalPosition/components.jl create mode 100644 src/Mechanical/TranslationalPosition/sources.jl create mode 100644 src/Mechanical/TranslationalPosition/utils.jl diff --git a/docs/connections.html b/docs/connections.html new file mode 100644 index 000000000..0ee254502 --- /dev/null +++ b/docs/connections.html @@ -0,0 +1,921 @@ + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + +
+ +

Introduction

+

In Physical Network Acausal modeling each physical domain must define a connector to combine model components. This is somewhat analogus to real life connections that are seen in electronics (i.e. battery connected to a wire) or fluid dynamics (i.e. pump connected to a pipe), to name a couple examples. Each physical domain connector defines a minimum of 2 variables, one which is called a Through variable, and one which is called an Across variable. Both Modelica and SimScape define these variables in the same way:

+ +

However, the standard libraries differ on the selection of the Across variable for the Mechanical Translation and Rotation libraries, Modelica choosing position and angle and SimScape choosing velocity and angular velocity, respectively for Translation and Rotation. Modelica describes their decision here. In summary they would like to provide less integration in the model to avoid lossy numerical behavior, but this decision assumes the lowest order derivative is needed by the model. Numerically it is possible to define the connector either way, but there are some consequences to this decision, and therefore we will study them in detail here as they relate to ModelingToolkit.

+

Through and Across Variable Theory

+

General

+

The idea behind the selection of the through variable is that it should be a time derivative of some conserved quantity. The conserved quantity should be expressed by the across variable. In general terms the physical system is given by

+
    +
  • Energy Dissipation: $ \partial \color{blue}{across} / \partial t \cdot c_1 = \color{green}{through} $

    +
  • +
  • Flow: $ \color{green}{through} \cdot c_2 = \color{blue}{across} $

    +
  • +
+

Electrical

+

So for the Electrical domain the across variable is voltage and the through variable current. Therefore

+
    +
  • Energy Dissipation: $ \partial \color{blue}{voltage} / \partial t \cdot capacitance = \color{green}{current} $

    +
  • +
  • Flow: $ \color{green}{current} \cdot resistance = \color{blue}{voltage} $

    +
  • +
+

Translational

+

And for the translation domain, choosing velocity for the across variable and force for the through gives

+
    +
  • Energy Dissipation: $ \partial \color{blue}{velocity} / \partial t \cdot mass = \color{green}{force} $

    +
  • +
  • Flow: $ \color{green}{force} \cdot (1/damping) = \color{blue}{velocity} $

    +
  • +
+

The diagram here shows the similarity of problems in different physical domains.

+

Through and Across Variables

+

Electrical Domain Example

+

We can generate the above relationship with ModelingToolkit and the ModelingToolkitStandardLibrary using 3 blocks:

+
    +
  • Capacitor: for energy storage with initial voltage = 1V

    +
  • +
  • Resistor: for energy flow

    +
  • +
  • Ground: for energy sink

    +
  • +
+

As can be seen, this will give a 1 equation model matching our energy dissipation relationship

+ + +
+using ModelingToolkitStandardLibrary
+using ModelingToolkitStandardLibrary.Electrical, ModelingToolkit, OrdinaryDiffEq
+using CairoMakie
+
+@parameters t
+
+@named resistor = Resistor(R = 1)
+@named capacitor = Capacitor(C = 1)
+@named ground = Ground()
+
+eqs = [
+    connect(capacitor.n, resistor.p)
+    connect(resistor.n, ground.g, capacitor.p)
+    ]
+
+@named model = ODESystem(eqs, t; systems=[resistor, capacitor, ground])
+
+sys = structural_simplify(model)
+
+equations(sys)
+
+ + +
+1-element Vector{Equation}:
+ Differential(t)(capacitor₊v(t)) ~ capacitor₊i(t) / capacitor₊C
+
+ + +

The solution shows what we would expect, a non-linear disipation of voltage and releated decrease in current flow...

+ + +
+prob = ODEProblem(sys, [1.0], (0, 10.0), [])
+sol = solve(prob, ImplicitMidpoint(); dt=0.01)
+
+fig = Figure()
+ax = Axis(fig[1,1], ylabel="voltage [V]")
+lines!(ax, sol.t, sol[capacitor.v], label="sol[capacitor.v]")
+axislegend(ax)
+
+ax = Axis(fig[2,1], xlabel="time [s]", ylabel="current [A]")
+lines!(ax, sol.t, -sol[resistor.i], label="sol[resistor.i]")
+axislegend(ax)
+
+fig
+
+ + + + +

Translational Domain Example (Across Variable = velocity)

+

Now using the Translational library based on velocity, we can see the same relationship with a system reduced to a single equation, using the components:

+
    +
  • Body (i.e. moving mass): for kinetic energy storage with an initial velocity = 1m/s

    +
  • +
  • Damper: for energy flow

    +
  • +
  • Fixed: for energy sink

    +
  • +
+ + +
+module TranslationalVelocity
+    using ModelingToolkit
+    using ModelingToolkitStandardLibrary.Mechanical.Translational
+
+    @parameters t
+
+    @named damping = Damper(d = 1)
+    @named body = Body(m = 1, v0=1)
+    @named ground = Fixed()
+
+    eqs = [
+        connect(damping.port_a, body.port)
+        connect(ground.port, damping.port_b)
+        ]
+
+    @named model = ODESystem(eqs, t; systems=[damping, body, ground])
+
+    sys = structural_simplify(model)
+end
+
+sys = TranslationalVelocity.sys
+equations(sys)
+
+ + +
+1-element Vector{Equation}:
+ Differential(t)(body₊v(t)) ~ body₊f(t) / body₊m
+
+ + +

As expected we have a similar solution...

+ + +
+prob = ODEProblem(sys, [1.0], (0, 10.0), [])
+sol_v = solve(prob, ImplicitMidpoint(); dt=0.01)
+
+fig = Figure()
+ax = Axis(fig[1,1], ylabel="velocity [m/s]")
+lines!(ax, sol_v.t, sol_v[TranslationalVelocity.body.v], label="sol[body.v]")
+axislegend(ax)
+
+ax = Axis(fig[2,1], xlabel="time [s]", ylabel="force [N]")
+lines!(ax, sol_v.t, -sol_v[TranslationalVelocity.body.f], label="sol[body.f]")
+axislegend(ax)
+
+fig
+
+ + + + +

Translational Domain Example (Across Variable = position)

+

Now, let's consider the position based approach. We can build the same model with the same components. As can be seen, we now end of up with 2 equations, because we need to relate the lower derivative (position) to force (with acceleration).

+ + +
+module TranslationalPosition
+    using ModelingToolkit
+    using ModelingToolkitStandardLibrary.Mechanical.TranslationalPosition
+
+    @parameters t
+    D = Differential(t)
+
+    # Let's define a simple body that only tracks the across and through variables...
+    function Body(; name, m, v0 = 0.0)
+        @named flange = Flange()
+        pars = @parameters m=m v0=v0
+        vars = @variables begin
+            v(t) = v0
+            f(t) = m*v0
+        end
+        eqs = [
+            D(flange.s) ~ v
+            flange.f ~ f
+
+            D(v) ~ m/f
+            ]
+        return compose(ODESystem(eqs, t, vars, pars; name = name), flange)
+    end
+
+    @named damping = Damper(d = 1)
+    @named body = Body(m = 1, v0=1)
+    @named ground = Fixed()
+
+    eqs = [
+        connect(damping.flange_a, body.flange)
+        connect(ground.flange, damping.flange_b)
+        ]
+
+    @named model = ODESystem(eqs, t; systems=[damping, body, ground])
+
+    sys = structural_simplify(model)
+end
+
+sys = TranslationalPosition.sys
+
+full_equations(sys)
+
+ + +
+2-element Vector{Equation}:
+ Differential(t)(body₊flange₊s(t)) ~ body₊v(t)
+ Differential(t)(body₊v(t)) ~ -(body₊m / (damping₊d*body₊v(t)))
+
+ + +

Suprisingly this problem fails to converge! As can be seen something is not working when compared to the position based result.

+ + +
+prob = ODEProblem(sys, [0.0, 1.0], (0, 10.0), [])
+sol_p = solve(prob, ImplicitMidpoint(); dt=0.01)
+
+fig = Figure()
+ax = Axis(fig[1,1], ylabel="velocity [m/s]")
+lines!(ax, sol_p.t, sol_p[TranslationalPosition.body.v], label="sol[body.v] (position based)")
+lines!(ax, sol_v.t, sol_v[TranslationalVelocity.body.v], label="sol[body.v] (velocity based)")
+axislegend(ax)
+
+ax = Axis(fig[2,1], xlabel="time [s]", ylabel="force [N]")
+lines!(ax, sol_p.t, -sol_p[TranslationalVelocity.body.f], label="sol[body.f] (position based)")
+lines!(ax, sol_v.t, -sol_v[TranslationalVelocity.body.f], label="sol[body.f] (velocity based)")
+axislegend(ax)
+
+fig
+
+ + + + + +
+ +
+
+
+ + + diff --git a/docs/connections.jmd b/docs/connections.jmd new file mode 100644 index 000000000..52d327ce3 --- /dev/null +++ b/docs/connections.jmd @@ -0,0 +1,197 @@ +# Introduction +In Physical Network Acausal modeling each physical domain must define a **connector** to combine model components. This is somewhat analogus to real life connections that are seen in electronics (i.e. battery connected to a wire) or fluid dynamics (i.e. pump connected to a pipe), to name a couple examples. Each physical domain **connector** defines a minimum of 2 variables, one which is called a *Through* variable, and one which is called an *Across* variable. Both Modelica and SimScape define these variables in the same way: + +- [Modelica Connectors](https://mbe.modelica.university/components/connectors/#acausal-connection) +- [SimScape Connectors](https://www.mathworks.com/help/simscape/ug/basic-principles-of-modeling-physical-networks.html#bq89sba-6) + +However, the standard libraries differ on the selection of the Across variable for the Mechanical Translation and Rotation libraries, Modelica choosing position and angle and SimScape choosing velocity and angular velocity, respectively for Translation and Rotation. Modelica describes their decision [here](https://mbe.modelica.university/components/connectors/simple_domains/). In summary they would like to provide less integration in the model to avoid lossy numerical behavior, but this decision assumes the lowest order derivative is needed by the model. Numerically it is possible to define the connector either way, but there are some consequences to this decision, and therefore we will study them in detail here as they relate to ModelingToolkit. + +# Through and Across Variable Theory +### General +The idea behind the selection of the **through** variable is that it should be a time derivative of some conserved quantity. The conserved quantity should be expressed by the **across** variable. In general terms the physical system is given by + +- Energy Dissipation: $ \partial \color{blue}{across} / \partial t \cdot c_1 = \color{green}{through} $ +- Flow: $ \color{green}{through} \cdot c_2 = \color{blue}{across} $ + +### Electrical +So for the Electrical domain the across variable is *voltage* and the through variable *current*. Therefore + +- Energy Dissipation: $ \partial \color{blue}{voltage} / \partial t \cdot capacitance = \color{green}{current} $ +- Flow: $ \color{green}{current} \cdot resistance = \color{blue}{voltage} $ + +### Translational +And for the translation domain, choosing *velocity* for the across variable and *force* for the through gives + +- Energy Dissipation: $ \partial \color{blue}{velocity} / \partial t \cdot mass = \color{green}{force} $ +- Flow: $ \color{green}{force} \cdot (1/damping) = \color{blue}{velocity} $ + +The diagram here shows the similarity of problems in different physical domains. + +![Through and Across Variables](through_across.png) + + +# Electrical Domain Example +We can generate the above relationship with ModelingToolkit and the ModelingToolkitStandardLibrary using 3 blocks: + +- Capacitor: for energy storage with initial voltage = 1V +- Resistor: for energy flow +- Ground: for energy sink + +As can be seen, this will give a 1 equation model matching our energy dissipation relationship + +```julia +using ModelingToolkitStandardLibrary +using ModelingToolkitStandardLibrary.Electrical, ModelingToolkit, OrdinaryDiffEq +using CairoMakie + +@parameters t + +@named resistor = Resistor(R = 1) +@named capacitor = Capacitor(C = 1) +@named ground = Ground() + +eqs = [ + connect(capacitor.n, resistor.p) + connect(resistor.n, ground.g, capacitor.p) + ] + +@named model = ODESystem(eqs, t; systems=[resistor, capacitor, ground]) + +sys = structural_simplify(model) + +equations(sys) +``` + +The solution shows what we would expect, a non-linear disipation of voltage and releated decrease in current flow... + +```julia +prob = ODEProblem(sys, [1.0], (0, 10.0), []) +sol = solve(prob, ImplicitMidpoint(); dt=0.01) + +fig = Figure() +ax = Axis(fig[1,1], ylabel="voltage [V]") +lines!(ax, sol.t, sol[capacitor.v], label="sol[capacitor.v]") +axislegend(ax) + +ax = Axis(fig[2,1], xlabel="time [s]", ylabel="current [A]") +lines!(ax, sol.t, -sol[resistor.i], label="sol[resistor.i]") +axislegend(ax) + +fig +``` +# Translational Domain Example (Across Variable = velocity) +Now using the Translational library based on velocity, we can see the same relationship with a system reduced to a single equation, using the components: + +- Body (i.e. moving mass): for kinetic energy storage with an initial velocity = 1m/s +- Damper: for energy flow +- Fixed: for energy sink + +```julia +module TranslationalVelocity + using ModelingToolkit + using ModelingToolkitStandardLibrary.Mechanical.Translational + + @parameters t + + @named damping = Damper(d = 1) + @named body = Body(m = 1, v0=1) + @named ground = Fixed() + + eqs = [ + connect(damping.port_a, body.port) + connect(ground.port, damping.port_b) + ] + + @named model = ODESystem(eqs, t; systems=[damping, body, ground]) + + sys = structural_simplify(model) +end + +sys = TranslationalVelocity.sys +equations(sys) +``` + +As expected we have a similar solution... +```julia +prob = ODEProblem(sys, [1.0], (0, 10.0), []) +sol_v = solve(prob, ImplicitMidpoint(); dt=0.01) + +fig = Figure() +ax = Axis(fig[1,1], ylabel="velocity [m/s]") +lines!(ax, sol_v.t, sol_v[TranslationalVelocity.body.v], label="sol[body.v]") +axislegend(ax) + +ax = Axis(fig[2,1], xlabel="time [s]", ylabel="force [N]") +lines!(ax, sol_v.t, -sol_v[TranslationalVelocity.body.f], label="sol[body.f]") +axislegend(ax) + +fig +``` + +# Translational Domain Example (Across Variable = position) + +Now, let's consider the position based approach. We can build the same model with the same components. As can be seen, we now end of up with 2 equations, because we need to relate the lower derivative (position) to force (with acceleration). + +```julia +module TranslationalPosition + using ModelingToolkit + using ModelingToolkitStandardLibrary.Mechanical.TranslationalPosition + + @parameters t + D = Differential(t) + + # Let's define a simple body that only tracks the across and through variables... + function Body(; name, m, v0 = 0.0) + @named flange = Flange() + pars = @parameters m=m v0=v0 + vars = @variables begin + v(t) = v0 + f(t) = m*v0 + end + eqs = [ + D(flange.s) ~ v + flange.f ~ f + + D(v) ~ m/f + ] + return compose(ODESystem(eqs, t, vars, pars; name = name), flange) + end + + @named damping = Damper(d = 1) + @named body = Body(m = 1, v0=1) + @named ground = Fixed() + + eqs = [ + connect(damping.flange_a, body.flange) + connect(ground.flange, damping.flange_b) + ] + + @named model = ODESystem(eqs, t; systems=[damping, body, ground]) + + sys = structural_simplify(model) +end + +sys = TranslationalPosition.sys + +full_equations(sys) +``` + +Suprisingly this problem fails to converge! As can be seen something is not working when compared to the position based result. + +```julia +prob = ODEProblem(sys, [0.0, 1.0], (0, 10.0), []) +sol_p = solve(prob, ImplicitMidpoint(); dt=0.01) + +fig = Figure() +ax = Axis(fig[1,1], ylabel="velocity [m/s]") +lines!(ax, sol_p.t, sol_p[TranslationalPosition.body.v], label="sol[body.v] (position based)") +lines!(ax, sol_v.t, sol_v[TranslationalVelocity.body.v], label="sol[body.v] (velocity based)") +axislegend(ax) + +ax = Axis(fig[2,1], xlabel="time [s]", ylabel="force [N]") +lines!(ax, sol_p.t, -sol_p[TranslationalVelocity.body.f], label="sol[body.f] (position based)") +lines!(ax, sol_v.t, -sol_v[TranslationalVelocity.body.f], label="sol[body.f] (velocity based)") +axislegend(ax) + +fig +``` \ No newline at end of file diff --git a/docs/through_across.png b/docs/through_across.png new file mode 100644 index 0000000000000000000000000000000000000000..758704af8137c536caf0aef2816fb351c54143a4 GIT binary patch literal 30457 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 literal 0 HcmV?d00001 diff --git a/docs/through_across.svg b/docs/through_across.svg new file mode 100644 index 000000000..82edb6497 --- /dev/null +++ b/docs/through_across.svg @@ -0,0 +1,317 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + current + force + stored energy =capacitance x voltage + stored energy = mass x velocity + (f) + (i) + (v) + (v) + + + Through Variable + Across Variable + + diff --git a/src/Mechanical/Mechanical.jl b/src/Mechanical/Mechanical.jl index 2e87392b9..aa2f8dc7f 100644 --- a/src/Mechanical/Mechanical.jl +++ b/src/Mechanical/Mechanical.jl @@ -7,5 +7,6 @@ using ModelingToolkit include("Rotational/Rotational.jl") include("Translational/Translational.jl") +include("TranslationalPosition/TranslationalPosition.jl") end diff --git a/src/Mechanical/Translational/Translational.jl b/src/Mechanical/Translational/Translational.jl index c1786a7b8..c9f52b004 100644 --- a/src/Mechanical/Translational/Translational.jl +++ b/src/Mechanical/Translational/Translational.jl @@ -11,7 +11,7 @@ D = Differential(t) export Port include("utils.jl") -export Body, Spring, Damper +export Body, Spring, Damper, Fixed include("components.jl") #export Torque diff --git a/src/Mechanical/Translational/components.jl b/src/Mechanical/Translational/components.jl index ff20f652c..db0825bc0 100644 --- a/src/Mechanical/Translational/components.jl +++ b/src/Mechanical/Translational/components.jl @@ -4,63 +4,58 @@ function Fixed(; name) return compose(ODESystem(eqs, t, [], []; name = name), port) end -function Body(; name, x0 = 0.0, v0 = 0.0, m = 1.0, g=0.0) - @named port = Port(v0 = v0, f0 = m*g) - @parameters m=m g=g - @variables begin - x(t) = x0 - dx(t) = v0 - ddx(t) = 0.0 +function Body(; name, v0 = 0.0, m = 1.0) + @named port = Port(v0 = v0) + pars = @parameters m=m + vars = @variables begin + v(t) = v0 + f(t) = m*v0 end eqs = [ - port.v ~ dx - - D(x) ~ dx - D(dx) ~ ddx - - ddx * m ~ m*g + port.f + port.v ~ v + port.f ~ f + D(v) ~ f/m ] - return compose(ODESystem(eqs, t, [x, dx, ddx], [m, g]; name = name), port) + return compose(ODESystem(eqs, t, vars, pars; name = name), port) end function Spring(;name, k = 1e3, delta0 = 0.0) - @parameters k=k - @variables begin - x(t) = delta0 - dx(t) = 0.0 - f(t) = k*x + pars = @parameters k=k + vars = @variables begin + Δx(t) = delta0 + f(t) = k*delta0 end @named port_a = Port() @named port_b = Port() eqs = [ - D(x) ~ dx - dx ~ port_a.v - port_b.v - f ~ k*x + D(Δx) ~ port_a.v - port_b.v + f ~ k*Δx port_a.f ~ +f port_b.f ~ -f ] - return compose(ODESystem(eqs, t, [x, dx, f], [k]; name = name), port_a, port_b) + return compose(ODESystem(eqs, t, vars, pars; name = name), port_a, port_b) end function Damper(; name, d=1e2) - @parameters d=d - @variables dx(t)=0.0 f(t)=0.0 + pars = @parameters d=d + vars = @variables v(t)=0.0 f(t)=0.0 @named port_a = Port() @named port_b = Port() eqs = [ - port_a.v - port_b.v ~ dx - f ~ dx*d + v ~ port_a.v - port_b.v + f ~ v*d + port_a.f ~ +f port_b.f ~ -f ] - return compose(ODESystem(eqs, t, [dx, f], [d]; name = name), port_a, port_b) + return compose(ODESystem(eqs, t, vars, pars; name = name), port_a, port_b) end diff --git a/src/Mechanical/TranslationalPosition/TranslationalPosition.jl b/src/Mechanical/TranslationalPosition/TranslationalPosition.jl new file mode 100644 index 000000000..9891ddbcc --- /dev/null +++ b/src/Mechanical/TranslationalPosition/TranslationalPosition.jl @@ -0,0 +1,21 @@ +""" +Library to model 1-dimensional, translational mechanical components. +""" +module TranslationalPosition + +using ModelingToolkit, Symbolics, IfElse +using ...Blocks: RealInput, RealOutput + +@parameters t +D = Differential(t) + +export Flange +include("utils.jl") + +export Fixed, Mass, Spring, Damper, IdealGear +include("components.jl") + +export Force +include("sources.jl") + +end diff --git a/src/Mechanical/TranslationalPosition/components.jl b/src/Mechanical/TranslationalPosition/components.jl new file mode 100644 index 000000000..6e9ef0550 --- /dev/null +++ b/src/Mechanical/TranslationalPosition/components.jl @@ -0,0 +1,98 @@ +""" + Fixed(;name, s0=0.0) + +Flange fixed in housing at a given position. + +# Parameters: +- `s0`: [m] Fixed offset position of housing + +# Connectors: +- `flange: 1-dim. translational flange` +""" +function Fixed(; name, s0 = 0.0) + @named flange = Flange() + @parameters s0 = s0 + eqs = [flange.s ~ s0] + return compose(ODESystem(eqs, t, [], [s0]; name = name), flange) +end + +""" + Mass(;name, m, s_start=0.0, v_start=0.0, a_start=0.0) + +Sliding mass with inertia + +# Parameters: +- `m`: [kg] Mass of sliding mass +- `s_start`: [m] Initial value of absolute position of sliding mass +- `v_start`: [m/s] Initial value of absolute linear velocity of sliding mass +- `a_start`: [m/s²] Initial value of absolute linear acceleration of sliding mass + +# States: +- `s`: [m] Absolute position of sliding mass +- `v`: [m/s] Absolute linear velocity of sliding mass (= der(s)) +- `a`: [m/s²] Absolute linear acceleration of sliding mass (= der(v)) + +# Connectors: +- `flange_a: 1-dim. translational flange on one side of mass` +- `flange_b: 1-dim. translational flange on opposite side of mass` +""" +function Mass(; name, m, s_start = 0.0, v_start = 0.0, a_start = 0.0) + @named flange_a = Flange() + @named flange_b = Flange() + @parameters m = m + sts = @variables begin + s(t) = s_start + v(t) = v_start + a(t) = a_start + end + eqs = [s ~ flange_a.s + s ~ flange_b.s + D(s) ~ v + D(v) ~ a + m * a ~ flange_a.f + flange_b.f] + return compose(ODESystem(eqs, t, sts, [m]; name = name), flange_a, flange_b) +end + +""" + Spring(;name, c, s_rel0=0.0) + +Linear 1D translational spring + +# Parameters: +- `c`: [N/m] Spring constant +- `s_rel0`: Unstretched spring length + +# Connectors: +- `flange_a: 1-dim. translational flange on one side of spring` +- `flange_b: 1-dim. translational flange on opposite side of spring` +""" +function Spring(; name, c, s_rel0 = 0.0) + @named partial_comp = PartialCompliant() + @unpack s_rel, f = partial_comp + pars = @parameters begin + c = c + s_rel0 = s_rel0 + end + eqs = [f ~ c * (s_rel - s_rel0)] + extend(ODESystem(eqs, t, [], pars; name = name), partial_comp) +end + +""" + Damper(;name, d) + +Linear 1D translational damper + +# Parameters: +- `d`: [N.s/m] Damping constant + +# Connectors: +- `flange_a: 1-dim. translational flange on one side of damper` +- `flange_b: 1-dim. translational flange on opposite side of damper` +""" +function Damper(; name, d) + @named partial_comp = PartialCompliantWithRelativeStates() + @unpack v_rel, f = partial_comp + pars = @parameters d = d + eqs = [f ~ d * v_rel] + extend(ODESystem(eqs, t, [], pars; name = name), partial_comp) +end diff --git a/src/Mechanical/TranslationalPosition/sources.jl b/src/Mechanical/TranslationalPosition/sources.jl new file mode 100644 index 000000000..3854cb82b --- /dev/null +++ b/src/Mechanical/TranslationalPosition/sources.jl @@ -0,0 +1,12 @@ +""" + Force(;name) + +Input signal acting as external force on a flange +""" +function Force(; name, use_support = false) + @named partial_element = PartialElementaryOneFlangeAndSupport2(use_support = use_support) + @unpack flange = partial_element + @named f = RealInput() # Accelerating force acting at flange (= -flange.tau) + eqs = [flange.f ~ -f.u] + return extend(ODESystem(eqs, t, [], []; name = name, systems = [f]), partial_element) +end diff --git a/src/Mechanical/TranslationalPosition/utils.jl b/src/Mechanical/TranslationalPosition/utils.jl new file mode 100644 index 000000000..e419fbfc0 --- /dev/null +++ b/src/Mechanical/TranslationalPosition/utils.jl @@ -0,0 +1,147 @@ +@connector function Flange(; name) + sts = @variables begin + s(t) + f(t), [connect = Flow] + end + ODESystem(Equation[], t, sts, [], name = name, defaults = Dict(s => 0.0, f => 0.0)) +end +Base.@doc """ + Flange(;name) + +1-dim. translational flange. + +# States: +- `s`: [m] Absolute position of flange +- `f`: [N] Cut force into the flange +""" Flange + +@connector function Support(; name) + sts = @variables begin + s(t) + f(t), [connect = Flow] + end + ODESystem(Equation[], t, sts, [], name = name, defaults = Dict(s => 0.0, f => 0.0)) +end +Base.@doc """ + Support(;name) + +Support/housing 1-dim. translational flange. + +# States: +- `s`: [m] Absolute position of the support/housing +- `f`: [N] Cut force into the flange +""" Support + +""" + PartialCompliant(;name, s_rel_start=0.0, f_start=0.0) + +Partial model for the compliant connection of two translational 1-dim. flanges. + +# Parameters: +- `s_rel_start`: [m] Initial relative distance between the flanges +- `f_start`: [N] Initial force between flanges + +# States: +- `s_rel`: [m] Relative distance (= flange_b.s - flange_a.s) +- `f`: [N] Force between flanges (= flange_b.f) +""" +function PartialCompliant(; name, s_rel_start = 0.0, f_start = 0.0) + @named flange_a = Flange() + @named flange_b = Flange() + sts = @variables begin + s_rel(t) = s_rel_start + f(t) = f_start + end + eqs = [s_rel ~ flange_b.s - flange_a.s + flange_b.f ~ f + flange_a.f ~ -f] + return compose(ODESystem(eqs, t, sts, []; name = name), flange_a, flange_b) +end + +""" + PartialCompliantWithRelativeStates(;name, s_rel_start=0.0, v_rel_start=0.0, a_rel_start=0.0, f_start=0.0) + +Partial model for the compliant connection of two translational 1-dim. flanges. + +# Parameters: +- `s_rel_start`: [m] Initial relative distance +- `v_rel_start`: [m/s] Initial relative linear velocity (= der(s_rel)) +- `a_rel_start`: [m/s²] Initial relative linear acceleration (= der(v_rel)) +- `f_start`: [N] Initial force between flanges + +# States: +- `s_rel`: [m] Relative distance (= flange_b.phi - flange_a.phi) +- `v_rel`: [m/s] Relative linear velocity (= der(s_rel)) +- `a_rel`: [m/s²] Relative linear acceleration (= der(v_rel)) +- `f`: [N] Force between flanges (= flange_b.f) +""" +function PartialCompliantWithRelativeStates(; name, s_rel_start = 0.0, v_rel_start = 0.0, + a_rel_start = 0.0, f_start = 0.0) + @named flange_a = Flange() + @named flange_b = Flange() + sts = @variables begin + s_rel(t) = s_rel_start + v_rel(t) = v_rel_start + a_rel(t) = a_rel_start + f(t) = f_start + end + eqs = [s_rel ~ flange_b.s - flange_a.s + D(s_rel) ~ v_rel + D(v_rel) ~ a_rel + flange_b.f ~ f + flange_a.f ~ -f] + return compose(ODESystem(eqs, t, sts, []; name = name), flange_a, flange_b) +end + +""" + PartialElementaryOneFlangeAndSupport2(;name, use_support=false) + +Partial model for a component with one translational 1-dim. shaft flange and a support used for textual modeling, i.e., for elementary models + +# Parameters: +- `use_support`: If support flange enabled, otherwise implicitly grounded + +# States: +- `s_support`: [m] Absolute position of support flange" +""" +function PartialElementaryOneFlangeAndSupport2(; name, use_support = false) + @named flange = Flange() + sys = [flange] + @variables s_support(t) + if use_support + @named support = Support() + eqs = [support.s ~ s_support + support.f ~ -flange.f] + push!(sys, support) + else + eqs = [s_support ~ 0] + end + return compose(ODESystem(eqs, t, [s_support], []; name = name), sys) +end + +""" + PartialElementaryTwoFlangesAndSupport2(;name, use_support=false) + +Partial model for a component with two translational 1-dim. flanges and a support used for textual modeling, i.e., for elementary models + +# Parameters: +- `use_support`: If support flange enabled, otherwise implicitly grounded + +# States: +- `s_support`: [m] Absolute position of support flange" +""" +function PartialElementaryTwoFlangesAndSupport2(; name, use_support = false) + @named flange_a = Flange() + @named flange_b = Flange() + sys = [flange_a, flange_b] + @variables s_support(t) = 0.0 + if use_support + @named support = Support() + eqs = [support.s ~ s_support + support.f ~ -flange_a.f - flange_b.f] + push!(sys, support) + else + eqs = [s_support ~ 0] + end + return compose(ODESystem(eqs, t, [s_support], []; name = name), sys) +end From 04028605bde6b2a2ecf3a8cd374d498558a9e940 Mon Sep 17 00:00:00 2001 From: Brad Carman Date: Sat, 17 Sep 2022 06:14:00 -0400 Subject: [PATCH 6/7] fixed position bug --- docs/connections.html | 24 ++-- docs/connections.jmd | 20 ++- docs/connections.md | 239 +++++++++++++++++++++++++++++++ docs/figures/connections_2_1.png | Bin 0 -> 28110 bytes docs/figures/connections_4_1.png | Bin 0 -> 28184 bytes docs/figures/connections_6_1.png | Bin 0 -> 46573 bytes 6 files changed, 266 insertions(+), 17 deletions(-) create mode 100644 docs/connections.md create mode 100644 docs/figures/connections_2_1.png create mode 100644 docs/figures/connections_4_1.png create mode 100644 docs/figures/connections_6_1.png diff --git a/docs/connections.html b/docs/connections.html index 0ee254502..d640930bc 100644 --- a/docs/connections.html +++ b/docs/connections.html @@ -793,13 +793,13 @@

Translational Domain Example (Across Variable = velocity)

end sys = TranslationalVelocity.sys -equations(sys) +full_equations(sys)
 1-element Vector{Equation}:
- Differential(t)(body₊v(t)) ~ body₊f(t) / body₊m
+ Differential(t)(body₊v(t)) ~ (-damping₊d*body₊v(t)) / body₊m
 
@@ -849,7 +849,7 @@

Translational Domain Example (Across Variable = position)

D(flange.s) ~ v flange.f ~ f - D(v) ~ m/f + D(v) ~ f/m ] return compose(ODESystem(eqs, t, vars, pars; name = name), flange) end @@ -877,11 +877,11 @@

Translational Domain Example (Across Variable = position)

 2-element Vector{Equation}:
  Differential(t)(body₊flange₊s(t)) ~ body₊v(t)
- Differential(t)(body₊v(t)) ~ -(body₊m / (damping₊d*body₊v(t)))
+ Differential(t)(body₊v(t)) ~ -((damping₊d*body₊v(t)) / body₊m)
 
-

Suprisingly this problem fails to converge! As can be seen something is not working when compared to the position based result.

+

As can be seen, we get exactly the same result. The only difference here is that we are solving an extra equation, which allows us to plot the body position as well.

@@ -891,26 +891,30 @@ 

Translational Domain Example (Across Variable = position)

fig = Figure() ax = Axis(fig[1,1], ylabel="velocity [m/s]") lines!(ax, sol_p.t, sol_p[TranslationalPosition.body.v], label="sol[body.v] (position based)") -lines!(ax, sol_v.t, sol_v[TranslationalVelocity.body.v], label="sol[body.v] (velocity based)") +lines!(ax, sol_v.t, sol_v[TranslationalVelocity.body.v], label="sol[body.v] (velocity based)", linestyle=:dash) axislegend(ax) -ax = Axis(fig[2,1], xlabel="time [s]", ylabel="force [N]") +ax = Axis(fig[2,1], ylabel="force [N]") lines!(ax, sol_p.t, -sol_p[TranslationalVelocity.body.f], label="sol[body.f] (position based)") -lines!(ax, sol_v.t, -sol_v[TranslationalVelocity.body.f], label="sol[body.f] (velocity based)") +lines!(ax, sol_v.t, -sol_v[TranslationalVelocity.body.f], label="sol[body.f] (velocity based)", linestyle=:dash) +axislegend(ax) + +ax = Axis(fig[3,1], xlabel="time [s]", ylabel="position [m]") +lines!(ax, sol_p.t, sol_p[TranslationalPosition.body.flange.s], label="sol[body.flange.s]") axislegend(ax) fig
- +
diff --git a/docs/connections.jmd b/docs/connections.jmd index 52d327ce3..ef36bc53d 100644 --- a/docs/connections.jmd +++ b/docs/connections.jmd @@ -108,7 +108,7 @@ module TranslationalVelocity end sys = TranslationalVelocity.sys -equations(sys) +full_equations(sys) ``` As expected we have a similar solution... @@ -152,7 +152,7 @@ module TranslationalPosition D(flange.s) ~ v flange.f ~ f - D(v) ~ m/f + D(v) ~ f/m ] return compose(ODESystem(eqs, t, vars, pars; name = name), flange) end @@ -176,7 +176,7 @@ sys = TranslationalPosition.sys full_equations(sys) ``` -Suprisingly this problem fails to converge! As can be seen something is not working when compared to the position based result. +As can be seen, we get exactly the same result. The only difference here is that we are solving an extra equation, which allows us to plot the body position as well. ```julia prob = ODEProblem(sys, [0.0, 1.0], (0, 10.0), []) @@ -185,13 +185,19 @@ sol_p = solve(prob, ImplicitMidpoint(); dt=0.01) fig = Figure() ax = Axis(fig[1,1], ylabel="velocity [m/s]") lines!(ax, sol_p.t, sol_p[TranslationalPosition.body.v], label="sol[body.v] (position based)") -lines!(ax, sol_v.t, sol_v[TranslationalVelocity.body.v], label="sol[body.v] (velocity based)") +lines!(ax, sol_v.t, sol_v[TranslationalVelocity.body.v], label="sol[body.v] (velocity based)", linestyle=:dash) axislegend(ax) -ax = Axis(fig[2,1], xlabel="time [s]", ylabel="force [N]") +ax = Axis(fig[2,1], ylabel="force [N]") lines!(ax, sol_p.t, -sol_p[TranslationalVelocity.body.f], label="sol[body.f] (position based)") -lines!(ax, sol_v.t, -sol_v[TranslationalVelocity.body.f], label="sol[body.f] (velocity based)") +lines!(ax, sol_v.t, -sol_v[TranslationalVelocity.body.f], label="sol[body.f] (velocity based)", linestyle=:dash) +axislegend(ax) + +ax = Axis(fig[3,1], xlabel="time [s]", ylabel="position [m]") +lines!(ax, sol_p.t, sol_p[TranslationalPosition.body.flange.s], label="sol[body.flange.s]") axislegend(ax) fig -``` \ No newline at end of file +``` + + diff --git a/docs/connections.md b/docs/connections.md new file mode 100644 index 000000000..0f80bf2cc --- /dev/null +++ b/docs/connections.md @@ -0,0 +1,239 @@ +# Introduction +In Physical Network Acausal modeling each physical domain must define a **connector** to combine model components. This is somewhat analogus to real life connections that are seen in electronics (i.e. battery connected to a wire) or fluid dynamics (i.e. pump connected to a pipe), to name a couple examples. Each physical domain **connector** defines a minimum of 2 variables, one which is called a *Through* variable, and one which is called an *Across* variable. Both Modelica and SimScape define these variables in the same way: + +- [Modelica Connectors](https://mbe.modelica.university/components/connectors/#acausal-connection) +- [SimScape Connectors](https://www.mathworks.com/help/simscape/ug/basic-principles-of-modeling-physical-networks.html#bq89sba-6) + +However, the standard libraries differ on the selection of the Across variable for the Mechanical Translation and Rotation libraries, Modelica choosing position and angle and SimScape choosing velocity and angular velocity, respectively for Translation and Rotation. Modelica describes their decision [here](https://mbe.modelica.university/components/connectors/simple_domains/). In summary they would like to provide less integration in the model to avoid lossy numerical behavior, but this decision assumes the lowest order derivative is needed by the model. Numerically it is possible to define the connector either way, but there are some consequences to this decision, and therefore we will study them in detail here as they relate to ModelingToolkit. + +# Through and Across Variable Theory +### General +The idea behind the selection of the **through** variable is that it should be a time derivative of some conserved quantity. The conserved quantity should be expressed by the **across** variable. In general terms the physical system is given by + +- Energy Dissipation: $ \partial \color{blue}{across} / \partial t \cdot c_1 = \color{green}{through} $ +- Flow: $ \color{green}{through} \cdot c_2 = \color{blue}{across} $ + +### Electrical +So for the Electrical domain the across variable is *voltage* and the through variable *current*. Therefore + +- Energy Dissipation: $ \partial \color{blue}{voltage} / \partial t \cdot capacitance = \color{green}{current} $ +- Flow: $ \color{green}{current} \cdot resistance = \color{blue}{voltage} $ + +### Translational +And for the translation domain, choosing *velocity* for the across variable and *force* for the through gives + +- Energy Dissipation: $ \partial \color{blue}{velocity} / \partial t \cdot mass = \color{green}{force} $ +- Flow: $ \color{green}{force} \cdot (1/damping) = \color{blue}{velocity} $ + +The diagram here shows the similarity of problems in different physical domains. + +![Through and Across Variables](through_across.png) + + +# Electrical Domain Example +We can generate the above relationship with ModelingToolkit and the ModelingToolkitStandardLibrary using 3 blocks: + +- Capacitor: for energy storage with initial voltage = 1V +- Resistor: for energy flow +- Ground: for energy sink + +As can be seen, this will give a 1 equation model matching our energy dissipation relationship + +```julia +using ModelingToolkitStandardLibrary +using ModelingToolkitStandardLibrary.Electrical, ModelingToolkit, OrdinaryDiffEq +using CairoMakie + +@parameters t + +@named resistor = Resistor(R = 1) +@named capacitor = Capacitor(C = 1) +@named ground = Ground() + +eqs = [ + connect(capacitor.n, resistor.p) + connect(resistor.n, ground.g, capacitor.p) + ] + +@named model = ODESystem(eqs, t; systems=[resistor, capacitor, ground]) + +sys = structural_simplify(model) + +equations(sys) +``` + +``` +1-element Vector{Equation}: + Differential(t)(capacitor₊v(t)) ~ capacitor₊i(t) / capacitor₊C +``` + + + + + +The solution shows what we would expect, a non-linear disipation of voltage and releated decrease in current flow... + +```julia +prob = ODEProblem(sys, [1.0], (0, 10.0), []) +sol = solve(prob, ImplicitMidpoint(); dt=0.01) + +fig = Figure() +ax = Axis(fig[1,1], ylabel="voltage [V]") +lines!(ax, sol.t, sol[capacitor.v], label="sol[capacitor.v]") +axislegend(ax) + +ax = Axis(fig[2,1], xlabel="time [s]", ylabel="current [A]") +lines!(ax, sol.t, -sol[resistor.i], label="sol[resistor.i]") +axislegend(ax) + +fig +``` + +![](figures/connections_2_1.png) + + +# Translational Domain Example (Across Variable = velocity) +Now using the Translational library based on velocity, we can see the same relationship with a system reduced to a single equation, using the components: + +- Body (i.e. moving mass): for kinetic energy storage with an initial velocity = 1m/s +- Damper: for energy flow +- Fixed: for energy sink + +```julia +module TranslationalVelocity + using ModelingToolkit + using ModelingToolkitStandardLibrary.Mechanical.Translational + + @parameters t + + @named damping = Damper(d = 1) + @named body = Body(m = 1, v0=1) + @named ground = Fixed() + + eqs = [ + connect(damping.port_a, body.port) + connect(ground.port, damping.port_b) + ] + + @named model = ODESystem(eqs, t; systems=[damping, body, ground]) + + sys = structural_simplify(model) +end + +sys = TranslationalVelocity.sys +full_equations(sys) +``` + +``` +1-element Vector{Equation}: + Differential(t)(body₊v(t)) ~ (-damping₊d*body₊v(t)) / body₊m +``` + + + + + +As expected we have a similar solution... +```julia +prob = ODEProblem(sys, [1.0], (0, 10.0), []) +sol_v = solve(prob, ImplicitMidpoint(); dt=0.01) + +fig = Figure() +ax = Axis(fig[1,1], ylabel="velocity [m/s]") +lines!(ax, sol_v.t, sol_v[TranslationalVelocity.body.v], label="sol[body.v]") +axislegend(ax) + +ax = Axis(fig[2,1], xlabel="time [s]", ylabel="force [N]") +lines!(ax, sol_v.t, -sol_v[TranslationalVelocity.body.f], label="sol[body.f]") +axislegend(ax) + +fig +``` + +![](figures/connections_4_1.png) + + + +# Translational Domain Example (Across Variable = position) + +Now, let's consider the position based approach. We can build the same model with the same components. As can be seen, we now end of up with 2 equations, because we need to relate the lower derivative (position) to force (with acceleration). + +```julia +module TranslationalPosition + using ModelingToolkit + using ModelingToolkitStandardLibrary.Mechanical.TranslationalPosition + + @parameters t + D = Differential(t) + + # Let's define a simple body that only tracks the across and through variables... + function Body(; name, m, v0 = 0.0) + @named flange = Flange() + pars = @parameters m=m v0=v0 + vars = @variables begin + v(t) = v0 + f(t) = m*v0 + end + eqs = [ + D(flange.s) ~ v + flange.f ~ f + + D(v) ~ f/m + ] + return compose(ODESystem(eqs, t, vars, pars; name = name), flange) + end + + @named damping = Damper(d = 1) + @named body = Body(m = 1, v0=1) + @named ground = Fixed() + + eqs = [ + connect(damping.flange_a, body.flange) + connect(ground.flange, damping.flange_b) + ] + + @named model = ODESystem(eqs, t; systems=[damping, body, ground]) + + sys = structural_simplify(model) +end + +sys = TranslationalPosition.sys + +full_equations(sys) +``` + +``` +2-element Vector{Equation}: + Differential(t)(body₊flange₊s(t)) ~ body₊v(t) + Differential(t)(body₊v(t)) ~ -((damping₊d*body₊v(t)) / body₊m) +``` + + + + + +As can be seen, we get exactly the same result. The only difference here is that we are solving an extra equation, which allows us to plot the body position as well. + +```julia +prob = ODEProblem(sys, [0.0, 1.0], (0, 10.0), []) +sol_p = solve(prob, ImplicitMidpoint(); dt=0.01) + +fig = Figure() +ax = Axis(fig[1,1], ylabel="velocity [m/s]") +lines!(ax, sol_p.t, sol_p[TranslationalPosition.body.v], label="sol[body.v] (position based)") +lines!(ax, sol_v.t, sol_v[TranslationalVelocity.body.v], label="sol[body.v] (velocity based)", linestyle=:dash) +axislegend(ax) + +ax = Axis(fig[2,1], ylabel="force [N]") +lines!(ax, sol_p.t, -sol_p[TranslationalVelocity.body.f], label="sol[body.f] (position based)") +lines!(ax, sol_v.t, -sol_v[TranslationalVelocity.body.f], label="sol[body.f] (velocity based)", linestyle=:dash) +axislegend(ax) + +ax = Axis(fig[3,1], xlabel="time [s]", ylabel="position [m]") +lines!(ax, sol_p.t, sol_p[TranslationalPosition.body.flange.s], label="sol[body.flange.s]") +axislegend(ax) + +fig +``` + +![](figures/connections_6_1.png) diff --git a/docs/figures/connections_2_1.png b/docs/figures/connections_2_1.png new file mode 100644 index 0000000000000000000000000000000000000000..55cbd92417bf95ffff97a76d5f8943d77bce3958 GIT binary patch literal 28110 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

rY;m!!%lGQINZf9N#bbZYtnXZ`|hxIj0tSR6|zD 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 literal 0 HcmV?d00001 diff --git a/docs/figures/connections_6_1.png b/docs/figures/connections_6_1.png new file mode 100644 index 0000000000000000000000000000000000000000..3fde409d33fb9749065c539526c9ca5423a30275 GIT binary patch literal 46573 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 L8Xd{fcD(*CVo>UA literal 0 HcmV?d00001 From dc12bde5b098acdcb479218512fc62c1aab7a6c4 Mon Sep 17 00:00:00 2001 From: Brad Carman Date: Sun, 18 Sep 2022 17:46:07 -0400 Subject: [PATCH 7/7] latest Translational changes --- src/Mechanical/Translational/Translational.jl | 4 ++-- src/Mechanical/Translational/components.jl | 23 +++++++++++++++++-- src/Mechanical/Translational/sensors.jl | 11 +++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 src/Mechanical/Translational/sensors.jl diff --git a/src/Mechanical/Translational/Translational.jl b/src/Mechanical/Translational/Translational.jl index c9f52b004..e16cbb88d 100644 --- a/src/Mechanical/Translational/Translational.jl +++ b/src/Mechanical/Translational/Translational.jl @@ -14,7 +14,7 @@ include("utils.jl") export Body, Spring, Damper, Fixed include("components.jl") -#export Torque -#include("sources.jl") +export PositionSensor +include("sensors.jl") end diff --git a/src/Mechanical/Translational/components.jl b/src/Mechanical/Translational/components.jl index db0825bc0..21aca06cf 100644 --- a/src/Mechanical/Translational/components.jl +++ b/src/Mechanical/Translational/components.jl @@ -4,7 +4,7 @@ function Fixed(; name) return compose(ODESystem(eqs, t, [], []; name = name), port) end -function Body(; name, v0 = 0.0, m = 1.0) +function Body(; name, v0 = 0.0, m = 1.0, s0=nothing, g=nothing) @named port = Port(v0 = v0) pars = @parameters m=m vars = @variables begin @@ -15,8 +15,27 @@ function Body(; name, v0 = 0.0, m = 1.0) eqs = [ port.v ~ v port.f ~ f - D(v) ~ f/m ] + + # gravity option + if !isnothing(g) + @parameters g=g + push!(pars, g) + push!(eqs, D(v) ~ f/m+g) + else + push!(eqs, D(v) ~ f/m) + end + + # position option + if !isnothing(s0) + @parameters s0=s0 + push!(pars, s0) + + @variables s(t)=s0 + push!(vars, s) + + push!(eqs, D(s) ~ v) + end return compose(ODESystem(eqs, t, vars, pars; name = name), port) end diff --git a/src/Mechanical/Translational/sensors.jl b/src/Mechanical/Translational/sensors.jl new file mode 100644 index 000000000..ddcfe9106 --- /dev/null +++ b/src/Mechanical/Translational/sensors.jl @@ -0,0 +1,11 @@ +function PositionSensor(; name, s0=0.0) + @named port = Port() + + pars=@parameters s0=s0 + vars=@variables s(t)=s0 + eqs = [ + D(s) ~ port.v + 0 ~ p.f + ] + compose(ODESystem(eqs, t, vars, pars; name=name), port) +end \ No newline at end of file