Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add translational library #85

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
17 changes: 17 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add .vscode and .DS_Store in global git ignore setting. Check out https://sebastiandedeyne.com/setting-up-a-global-gitignore-file/

// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "julia",
"request": "launch",
"name": "Run active Julia file",
"program": "${file}",
"stopOnEntry": false,
"cwd": "${workspaceFolder}",
"juliaEnv": "${command:activeJuliaEnvironment}"
}
]
}
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
125 changes: 125 additions & 0 deletions docs/src/tutorials/mass_spring_damper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Translational Mass Spring Damper System

This tutorial demonstrates the response of a mass-spring-damper system. Rather than applying an external force, the mass is initialized with some positional offset from equilibrium and some non-zero velocity (system responses under such conditions are commonly referred to as "unforced" responses). Assuming a lossless system, a mass-spring system in the absence of a damper will continually oscillate at some natural frequency. The addition of a damper will result in (1) underdamped, (2) overdamped, or (3) critically damped motion, depending on the relative values of our mass (`m`), spring constant (`c`), and damping constant (`d`). In this first example, we will demonstrate an underdamped system. Values for `m`, `c`, and `d` were chosen such that the roots of the polynomial `s^2 + d/m * s + c/m` are complex conjugates (the equivalent condition for underdamped motion is `d < sqrt(4 * m * c)`). In the case of underdamped systems, our mass will undergo damped oscillations. This damping corresponds to system energy loss, and the amplitudes of said oscillations will decrease towards zero as time approaches infinity.

Let's start by importing what we need.

```@example
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```@example
```@example translational

using ModelingToolkitStandardLibrary.Mechanical.Translational, ModelingToolkit, OrdinaryDiffEq, ControlSystems, Plots
import ModelingToolkitStandardLibrary.Blocks
```

Now let's initialize our system state and define our components and connections. Here, `s0` is the fixed offset position of our flange housing, `s_rel0` is our unstretched spring length, and `s_start` and `v_start` are the initial values of the absolute position and linear velocity of our sliding mass, respectively. Finally, `m`, `c`, and `d` are our mass, spring, and damping constants, respectively. All units are in SI units.

```@parameters t
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```@parameters t
```@example translational
@parameters t

D = Differential(t)

s0 = 4.5
s_rel0 = 1
s_start = 3
v_start = 10
m = 1
c = 10
d = 1

@named fixed = Fixed(s0=s0)
@named mass = Mass(m=m, s_start=s_start, v_start=v_start)
@named damper = Damper(d=d)
@named spring = Spring(c=c, s_rel0=s_rel0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@named fixed = Fixed(s0=s0)
@named mass = Mass(m=m, s_start=s_start, v_start=v_start)
@named damper = Damper(d=d)
@named spring = Spring(c=c, s_rel0=s_rel0)
@named fixed = Fixed(; s0)
@named mass = Mass(; m, s_start, v_start)
@named damper = Damper(; d)
@named spring = Spring(; c, s_rel0)

In case you didn't know, if your variable shares the same name as a keyword argument (a common case), you do not need to repeat the name. You do need to have the semi-colon first though to indicate that keyword arguments are coming.


connections = [
connect(mass.flange_b, damper.flange_a, spring.flange_a)
connect(damper.flange_b, spring.flange_b, fixed.flange)
]
```

Before solving our ODE system, let us ensure that the condition for underdamped motion is met.

```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```
```@example translational

@assert(d < sqrt(4 * m * c))
```

Now let's solve our ODE system and plot our results (note that we are plotting the position of our mass as a function of time).

```@named model = ODESystem(connections, t, systems=[fixed, mass, damper, spring])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```@named model = ODESystem(connections, t, systems=[fixed, mass, damper, spring])
```@example translational
@named model = ODESystem(connections, t, systems=[fixed, mass, damper, spring])

sys = structural_simplify(model)
prob = DAEProblem(sys, D.(states(sys)) .=> 0.0, [D(D(mass.s)) => 1.0], (0, 10.0), saveat=0.002)
sol = solve(prob, DFBDF(), abstol=1e-12, reltol=1e-12)

plot(sol, vars = [mass.s],
title = "Mass Spring Damper - Underdamped Motion",
xlabel = "Time (s)",
ylabel = "Position (m)")

savefig("mass_spring_damper_underdamped.png"); nothing # hide
```

!["Position vs. Time Plot of a Mass in an Underdamped Mass-Spring-Damper System](mass_spring_damper_underdamped.png)

We'll now demonstrate a mass-spring-damper system that is overdamped. For such systems, `d > sqrt(4 * m * c)`, and the zeros of our characteristic polynomial are real. Let us re-initialize our `m`, `c`, and `d` constants accordingly, and re-define our components and connections.

```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```
```@example translational

m, c, d = 1, 1, 10

@named mass = Mass(m=m, s_start=s_start, v_start=v_start)
@named damper = Damper(d=d)
@named spring = Spring(c=c, s_rel0=s_rel0)

connections = [
connect(mass.flange_b, damper.flange_a, spring.flange_a)
connect(damper.flange_b, spring.flange_b, fixed.flange)
]
```

Let us ensure that the condition for overdamped motion is met.

```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```
```@example translational

@assert(d > sqrt(4 * m * c))
```

Let's solve our ODE system and plot our results. Observe that for overdamped systems, motion is non-oscillatory.

```@named model = ODESystem(connections, t, systems=[fixed, mass, damper, spring])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```@named model = ODESystem(connections, t, systems=[fixed, mass, damper, spring])
```@example translational
@named model = ODESystem(connections, t, systems=[fixed, mass, damper, spring])

sys = structural_simplify(model)
prob = DAEProblem(sys, D.(states(sys)) .=> 0.0, [D(D(mass.s)) => 1.0], (0, 10.0), saveat=0.002)
sol = solve(prob, DFBDF(), abstol=1e-12, reltol=1e-12)

plot(sol, vars = [mass.s],
title = "Mass Spring Damper - Overdamped Motion",
xlabel = "Time (s)",
ylabel = "Position (m)")

savefig("mass_spring_damper_overdamped.png"); nothing # hide
```

!["Position vs. Time Plot of a Mass in an Overdamped Mass-Spring-Damper System](mass_spring_damper_overdamped.png)

Our last demonstration will be of a mass-spring-damper system that is critically damped. The condition for critically damped motion is `d = sqrt(4 * m * c)`, where the roots of our characteristic polynomial are both equal to `d/2m`. Again, let us re-initialize and re-define our system state, components, and connections, solve our ODE system, and plot our results. Observe that for critically damped systems, motion is non-oscillatory.

```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```
```@example translational

m, c = 1, 1
d = sqrt(4 * m * c)

@named mass = Mass(m=m, s_start=s_start, v_start=v_start)
@named damper = Damper(d=d)
@named spring = Spring(c=c, s_rel0=s_rel0)

connections = [
connect(mass.flange_b, damper.flange_a, spring.flange_a)
connect(damper.flange_b, spring.flange_b, fixed.flange)
]

@named model = ODESystem(connections, t, systems=[fixed, mass, damper, spring])
sys = structural_simplify(model)
prob = DAEProblem(sys, D.(states(sys)) .=> 0.0, [D(D(mass.s)) => 1.0], (0, 10.0), saveat=0.002)
sol = solve(prob, DFBDF(), abstol=1e-12, reltol=1e-12)

plot(sol, vars = [mass.s],
title = "Mass Spring Damper - Critically Damped Motion",
xlabel = "Time (s)",
ylabel = "Position (m)")

savefig("mass_spring_damper_critically_damped.png"); nothing # hide
```

!["Position vs. Time Plot of a Mass in a Critically Damped Mass-Spring-Damper System](mass_spring_damper_critically_damped.png)
Binary file added src/.DS_Store
Binary file not shown.
Binary file added src/Mechanical/.DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions src/Mechanical/Mechanical.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module Mechanical
using ModelingToolkit

include("Rotational/Rotational.jl")
include("Translational/Translational.jl")

end

21 changes: 21 additions & 0 deletions src/Mechanical/Translational/Translational.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""
Library to model 1-dimensional, translational mechanical components.
"""
module Translational

using ModelingToolkit, Symbolics, IfElse, OrdinaryDiffEq
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
100 changes: 100 additions & 0 deletions src/Mechanical/Translational/components.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"""
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
12 changes: 12 additions & 0 deletions src/Mechanical/Translational/sources.jl
Original file line number Diff line number Diff line change
@@ -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
Loading