Examples.Oscillator
Oscillator demonstrates the use of initial conditions.
Replicates the structure of Modelica.Mechanics.Translational.Examples.Oscillator.
A spring–mass system is a mechanical oscillator. The resonant frequency is ω_res = sqrt(c / m). For c=10000 N/m and m=1 kg, f_res = ω_res/(2π) ≈ 15.9155 Hz.
System 1 (top, undamped): A sinusoidal force at the resonant frequency drives mass1 through a spring to a wall. Without damping, the amplitude grows without bound (resonance).
System 2 (bottom, damped): Same as system 1 but with a damper in parallel with the spring. Damping bounds the amplitude.
Note: MSL uses a one-flange Force source. Here we use the two-flange Force with flange_b connected to a Fixed ground, which is equivalent to a grounded one-flange Force.
Usage
TranslationalComponents.Examples.Oscillator()
Behavior
using TranslationalComponents #hide
using ModelingToolkit #hide
@named sys = TranslationalComponents.Examples.Oscillator() #hide
full_equations(sys) #hide<< @example-block not executed in draft mode >>Source
"""
Oscillator demonstrates the use of initial conditions.
Replicates the structure of Modelica.Mechanics.Translational.Examples.Oscillator.
A spring–mass system is a mechanical oscillator. The resonant frequency is
ω_res = sqrt(c / m). For c=10000 N/m and m=1 kg, f_res = ω_res/(2π) ≈ 15.9155 Hz.
**System 1 (top, undamped):** A sinusoidal force at the resonant frequency
drives mass1 through a spring to a wall. Without damping, the amplitude grows
without bound (resonance).
**System 2 (bottom, damped):** Same as system 1 but with a damper in parallel
with the spring. Damping bounds the amplitude.
Note: MSL uses a one-flange Force source. Here we use the two-flange Force
with flange_b connected to a Fixed ground, which is equivalent to a grounded
one-flange Force.
"""
example component Oscillator
"Sinusoidal force signal at resonance frequency"
sine1 = BlockComponents.Sources.Sine(amplitude = 1, frequency = 15.9155) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 80, "y1": 30, "x2": 180, "y2": 130, "rot": 0}
},
"tags": []
}
}
"Force source for system 1"
force1 = TranslationalComponents.Sources.Force() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 210, "y1": 210, "x2": 310, "y2": 310, "rot": 0}
},
"tags": []
}
}
"Ground for force source 1"
force1_ground = TranslationalComponents.Components.Fixed() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 90, "y1": 440, "x2": 190, "y2": 340, "rot": 180}
},
"tags": []
}
}
"Mass for system 1 (undamped)"
mass1 = TranslationalComponents.Components.Mass(L = 1, m = 1, s = initial -0.5, v = initial 0) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 400, "y1": 210, "x2": 500, "y2": 310, "rot": 0}
},
"tags": []
}
}
"Spring for system 1"
spring1 = TranslationalComponents.Components.Spring(s_rel0 = 1, c = 10000) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 640, "y1": 210, "x2": 740, "y2": 310, "rot": 0}
},
"tags": []
}
}
"Wall for system 1"
fixed1 = TranslationalComponents.Components.Fixed(s0 = 1) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 830, "y1": 340, "x2": 930, "y2": 440, "rot": 0}
},
"tags": []
}
}
"Sinusoidal force signal at resonance frequency"
sine2 = BlockComponents.Sources.Sine(amplitude = 1, frequency = 15.9155) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 80, "y1": 500, "x2": 180, "y2": 600, "rot": 0}
},
"tags": []
}
}
"Force source for system 2"
force2 = TranslationalComponents.Sources.Force() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 220, "y1": 620, "x2": 320, "y2": 720, "rot": 0}
},
"tags": []
}
}
"Ground for force source 2"
force2_ground = TranslationalComponents.Components.Fixed() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 70, "y1": 770, "x2": 170, "y2": 870, "rot": 0}
},
"tags": []
}
}
"Mass for system 2 (damped)"
mass2 = TranslationalComponents.Components.Mass(L = 1, m = 1, s = initial -0.5, v = initial 0) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 400, "y1": 620, "x2": 500, "y2": 720, "rot": 0}
},
"tags": []
}
}
"Spring for system 2"
spring2 = TranslationalComponents.Components.Spring(s_rel0 = 1, c = 10000) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 620, "y1": 770, "x2": 720, "y2": 870, "rot": 0}
},
"tags": []
}
}
"Damper for system 2"
damper1 = TranslationalComponents.Components.Damper(d = 10) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 610, "y1": 620, "x2": 710, "y2": 720, "rot": 0}
},
"tags": []
}
}
"Wall for system 2"
fixed2 = TranslationalComponents.Components.Fixed(s0 = 1) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 830, "y1": 770, "x2": 930, "y2": 870, "rot": 0}
},
"tags": []
}
}
relations
# System 1: force → mass → spring → fixed
connect(sine1.y, force1.f) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 260, "y": 80}], "E": 2}],
"renderStyle": "standard"
}
}
connect(force1.flange_b, mass1.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(force1.flange_a, force1_ground.flange) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 122.5, "y": 260}, {"x": 122.5, "y": 340}], "E": 2}],
"renderStyle": "standard"
}
}
connect(mass1.flange_b, spring1.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(spring1.flange_b, fixed1.flange) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 880, "y": 260}], "E": 2}],
"renderStyle": "standard"
}
}
# System 2: force → mass → [spring ‖ damper] → fixed
connect(sine2.y, force2.f) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 270, "y": 550}], "E": 2}],
"renderStyle": "standard"
}
}
connect(force2.flange_b, mass2.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(force2.flange_a, force2_ground.flange) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 120, "y": 670}], "E": 2}],
"renderStyle": "standard"
}
}
connect(mass2.flange_b, spring2.flange_a) {
"Dyad": {
"edges": [
{"S": 1, "M": [], "E": -1},
{"S": -1, "M": [{"x": 560, "y": 670}, {"x": 560, "y": 820}], "E": 2}
],
"junctions": [{"x": 610, "y": 670}],
"renderStyle": "standard"
}
}
connect(spring2.flange_b, fixed2.flange) {
"Dyad": {
"edges": [
{"S": 1, "M": [{"x": 750, "y": 820}], "E": -1},
{"S": -1, "M": [{"x": 880, "y": 670}], "E": 2}
],
"junctions": [{"x": 750, "y": 670}],
"renderStyle": "standard"
}
}
connect(mass2.flange_b, damper1.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(damper1.flange_b, fixed2.flange) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 880, "y": 670}], "E": 2}],
"renderStyle": "standard"
}
}
metadata {
"Dyad": {
"icons": {"default": "dyad://TranslationalComponents/Example.svg"},
"tests": {
"case1": {
"stop": 1,
"atol": {
"damper1.s_rel": 0.001,
"damper1.v_rel": 0.001,
"mass1.s": 0.001,
"mass1.v": 0.01
},
"expect": {
"final": {
"damper1.s_rel": 1.00086,
"damper1.v_rel": 0.0502,
"mass1.s": -0.50433,
"mass1.v": -0.25276
},
"signals": ["damper1.s_rel", "damper1.v_rel", "mass1.s", "mass1.v"]
}
}
}
}
}
endFlattened Source
"""
Oscillator demonstrates the use of initial conditions.
Replicates the structure of Modelica.Mechanics.Translational.Examples.Oscillator.
A spring–mass system is a mechanical oscillator. The resonant frequency is
ω_res = sqrt(c / m). For c=10000 N/m and m=1 kg, f_res = ω_res/(2π) ≈ 15.9155 Hz.
**System 1 (top, undamped):** A sinusoidal force at the resonant frequency
drives mass1 through a spring to a wall. Without damping, the amplitude grows
without bound (resonance).
**System 2 (bottom, damped):** Same as system 1 but with a damper in parallel
with the spring. Damping bounds the amplitude.
Note: MSL uses a one-flange Force source. Here we use the two-flange Force
with flange_b connected to a Fixed ground, which is equivalent to a grounded
one-flange Force.
"""
example component Oscillator
"Sinusoidal force signal at resonance frequency"
sine1 = BlockComponents.Sources.Sine(amplitude = 1, frequency = 15.9155) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 80, "y1": 30, "x2": 180, "y2": 130, "rot": 0}
},
"tags": []
}
}
"Force source for system 1"
force1 = TranslationalComponents.Sources.Force() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 210, "y1": 210, "x2": 310, "y2": 310, "rot": 0}
},
"tags": []
}
}
"Ground for force source 1"
force1_ground = TranslationalComponents.Components.Fixed() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 90, "y1": 440, "x2": 190, "y2": 340, "rot": 180}
},
"tags": []
}
}
"Mass for system 1 (undamped)"
mass1 = TranslationalComponents.Components.Mass(L = 1, m = 1, s = initial -0.5, v = initial 0) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 400, "y1": 210, "x2": 500, "y2": 310, "rot": 0}
},
"tags": []
}
}
"Spring for system 1"
spring1 = TranslationalComponents.Components.Spring(s_rel0 = 1, c = 10000) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 640, "y1": 210, "x2": 740, "y2": 310, "rot": 0}
},
"tags": []
}
}
"Wall for system 1"
fixed1 = TranslationalComponents.Components.Fixed(s0 = 1) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 830, "y1": 340, "x2": 930, "y2": 440, "rot": 0}
},
"tags": []
}
}
"Sinusoidal force signal at resonance frequency"
sine2 = BlockComponents.Sources.Sine(amplitude = 1, frequency = 15.9155) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 80, "y1": 500, "x2": 180, "y2": 600, "rot": 0}
},
"tags": []
}
}
"Force source for system 2"
force2 = TranslationalComponents.Sources.Force() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 220, "y1": 620, "x2": 320, "y2": 720, "rot": 0}
},
"tags": []
}
}
"Ground for force source 2"
force2_ground = TranslationalComponents.Components.Fixed() {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 70, "y1": 770, "x2": 170, "y2": 870, "rot": 0}
},
"tags": []
}
}
"Mass for system 2 (damped)"
mass2 = TranslationalComponents.Components.Mass(L = 1, m = 1, s = initial -0.5, v = initial 0) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 400, "y1": 620, "x2": 500, "y2": 720, "rot": 0}
},
"tags": []
}
}
"Spring for system 2"
spring2 = TranslationalComponents.Components.Spring(s_rel0 = 1, c = 10000) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 620, "y1": 770, "x2": 720, "y2": 870, "rot": 0}
},
"tags": []
}
}
"Damper for system 2"
damper1 = TranslationalComponents.Components.Damper(d = 10) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 610, "y1": 620, "x2": 710, "y2": 720, "rot": 0}
},
"tags": []
}
}
"Wall for system 2"
fixed2 = TranslationalComponents.Components.Fixed(s0 = 1) {
"Dyad": {
"placement": {
"diagram": {"iconName": "default", "x1": 830, "y1": 770, "x2": 930, "y2": 870, "rot": 0}
},
"tags": []
}
}
relations
# System 1: force → mass → spring → fixed
connect(sine1.y, force1.f) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 260, "y": 80}], "E": 2}],
"renderStyle": "standard"
}
}
connect(force1.flange_b, mass1.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(force1.flange_a, force1_ground.flange) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 122.5, "y": 260}, {"x": 122.5, "y": 340}], "E": 2}],
"renderStyle": "standard"
}
}
connect(mass1.flange_b, spring1.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(spring1.flange_b, fixed1.flange) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 880, "y": 260}], "E": 2}],
"renderStyle": "standard"
}
}
# System 2: force → mass → [spring ‖ damper] → fixed
connect(sine2.y, force2.f) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 270, "y": 550}], "E": 2}],
"renderStyle": "standard"
}
}
connect(force2.flange_b, mass2.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(force2.flange_a, force2_ground.flange) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 120, "y": 670}], "E": 2}],
"renderStyle": "standard"
}
}
connect(mass2.flange_b, spring2.flange_a) {
"Dyad": {
"edges": [
{"S": 1, "M": [], "E": -1},
{"S": -1, "M": [{"x": 560, "y": 670}, {"x": 560, "y": 820}], "E": 2}
],
"junctions": [{"x": 610, "y": 670}],
"renderStyle": "standard"
}
}
connect(spring2.flange_b, fixed2.flange) {
"Dyad": {
"edges": [
{"S": 1, "M": [{"x": 750, "y": 820}], "E": -1},
{"S": -1, "M": [{"x": 880, "y": 670}], "E": 2}
],
"junctions": [{"x": 750, "y": 670}],
"renderStyle": "standard"
}
}
connect(mass2.flange_b, damper1.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
connect(damper1.flange_b, fixed2.flange) {
"Dyad": {
"edges": [{"S": 1, "M": [{"x": 880, "y": 670}], "E": 2}],
"renderStyle": "standard"
}
}
metadata {
"Dyad": {
"icons": {"default": "dyad://TranslationalComponents/Example.svg"},
"tests": {
"case1": {
"stop": 1,
"atol": {
"damper1.s_rel": 0.001,
"damper1.v_rel": 0.001,
"mass1.s": 0.001,
"mass1.v": 0.01
},
"expect": {
"final": {
"damper1.s_rel": 1.00086,
"damper1.v_rel": 0.0502,
"mass1.s": -0.50433,
"mass1.v": -0.25276
},
"signals": ["damper1.s_rel", "damper1.v_rel", "mass1.s", "mass1.v"]
}
}
}
}
}
endTest Cases
using TranslationalComponents
using DyadInterface: TransientAnalysis, rebuild_sol, ODEAlg
using ModelingToolkit: toggle_namespacing, get_initial_conditions, @named
using CSV, DataFrames, Plots
snapshotsdir = joinpath(dirname(dirname(pathof(TranslationalComponents))), "test", "snapshots")<< @setup-block not executed in draft mode >>Test Case case1
@named model_case1 = TranslationalComponents.Examples.Oscillator()
model_case1 = toggle_namespacing(model_case1, false)
model_case1 = toggle_namespacing(model_case1, true)
result_case1 = TransientAnalysis(; model = model_case1, alg = ODEAlg.Auto(), start = 0e+0, stop = 1e+0, abstol=1e-6, reltol=1e-6)
sol_case1 = rebuild_sol(result_case1)<< @setup-block not executed in draft mode >>df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.damper1.s_rel])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "TranslationalComponents.Examples.Oscillator_case1_sig0.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.damper1.s_rel], width=2, label="Actual value of damper1.s_rel")
if !isnothing(dfr_case1)
scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of damper1.s_rel")
end
scatter!(plt, [df_case1.t[end]], [1.00086], label="Final Condition for `damper1.s_rel`")<< @setup-block not executed in draft mode >>plt<< @example-block not executed in draft mode >>df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.damper1.v_rel])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "TranslationalComponents.Examples.Oscillator_case1_sig1.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.damper1.v_rel], width=2, label="Actual value of damper1.v_rel")
if !isnothing(dfr_case1)
scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of damper1.v_rel")
end
scatter!(plt, [df_case1.t[end]], [0.0502], label="Final Condition for `damper1.v_rel`")<< @setup-block not executed in draft mode >>plt<< @example-block not executed in draft mode >>df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.mass1.s])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "TranslationalComponents.Examples.Oscillator_case1_sig2.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.mass1.s], width=2, label="Actual value of mass1.s")
if !isnothing(dfr_case1)
scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of mass1.s")
end
scatter!(plt, [df_case1.t[end]], [-0.50433], label="Final Condition for `mass1.s`")<< @setup-block not executed in draft mode >>plt<< @example-block not executed in draft mode >>df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.mass1.v])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "TranslationalComponents.Examples.Oscillator_case1_sig3.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.mass1.v], width=2, label="Actual value of mass1.v")
if !isnothing(dfr_case1)
scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of mass1.v")
end
scatter!(plt, [df_case1.t[end]], [-0.25276], label="Final Condition for `mass1.v`")<< @setup-block not executed in draft mode >>plt<< @example-block not executed in draft mode >>Related
Examples
Experiments
Analyses