Skip to content
LIBRARY
Sources.Tests.Position.md

Sources.Tests.Position

Test of the Position source component with all ReferenceType enum variants.

Replicates the structure of ModelicaTest.Translational.AllComponents (Position portion) and ModelicaTest.Translational.TestFrictionPosition.

Three Position instances are driven by a common Sine reference (amplitude=1, frequency=1 Hz) and each drives a Mass (m=1 kg) with support grounded to Fixed:

  • pos_filtered: default Filtered mode (f_crit=50 Hz, af=1.3617, bf=0.6180)

  • pos_exact: Exact mode — flange position equals input directly

  • pos_filtered_low: Filtered mode with low critical frequency (f_crit=5 Hz) to show visible filtering

Usage

TranslationalComponents.Sources.Tests.Position()

Behavior

julia
using TranslationalComponents #hide
using ModelingToolkit #hide
@named sys = TranslationalComponents.Sources.Tests.Position() #hide
full_equations(sys) #hide
<< @example-block not executed in draft mode >>

Source

dyad
"""
Test of the Position source component with all ReferenceType enum variants.

Replicates the structure of ModelicaTest.Translational.AllComponents (Position portion)
and ModelicaTest.Translational.TestFrictionPosition.

Three Position instances are driven by a common Sine reference (amplitude=1, frequency=1 Hz)
and each drives a Mass (m=1 kg) with support grounded to Fixed:

- pos_filtered: default Filtered mode (f_crit=50 Hz, af=1.3617, bf=0.6180)
- pos_exact: Exact mode — flange position equals input directly
- pos_filtered_low: Filtered mode with low critical frequency (f_crit=5 Hz) to show visible filtering
"""
test component Position
  "Sine reference position signal (amplitude=1 m, frequency=1 Hz)"
  sine = BlockComponents.Sources.Sine(amplitude = 1.0, frequency = 1.0) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 30, "y1": 450, "x2": 130, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Position source — Filtered with default Bessel filter (f_crit=50 Hz)"
  pos_filtered = TranslationalComponents.Sources.Position() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 340, "y1": 640, "x2": 440, "y2": 740, "rot": 0}
      },
      "tags": []
    }
  }
  "Mass driven by filtered position source"
  mass_filtered = TranslationalComponents.Components.Mass(m = 1.0) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 590, "y1": 640, "x2": 690, "y2": 740, "rot": 0}
      },
      "tags": []
    }
  }
  "Position source — Exact (flange tracks input directly)"
  pos_exact = TranslationalComponents.Sources.Position(ref_type = TranslationalComponents.Sources.ReferenceType.Exact()) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 330, "y1": 210, "x2": 430, "y2": 310, "rot": 0}
      },
      "tags": []
    }
  }
  "Mass driven by exact position source"
  mass_exact = TranslationalComponents.Components.Mass(m = 1.0) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 590, "y1": 210, "x2": 690, "y2": 310, "rot": 0}
      },
      "tags": []
    }
  }
  "Position source — Filtered with low critical frequency (f_crit=5 Hz)"
  pos_filtered_low = TranslationalComponents.Sources.Position(ref_type = TranslationalComponents.Sources.ReferenceType.Filtered(f_crit = 5.0)) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 320, "y1": 450, "x2": 420, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Mass driven by low-f_crit filtered position source"
  mass_filtered_low = TranslationalComponents.Components.Mass(m = 1.0) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 600, "y1": 450, "x2": 700, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Fixed ground for all supports"
  ground = TranslationalComponents.Components.Fixed() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 890, "y1": 450, "x2": 990, "y2": 550, "rot": 270}
      },
      "tags": []
    }
  }
relations
  # --- Filtered (default) ---
  connect(sine.y, pos_filtered.s_ref) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 140, "y": 500}, {"x": 140, "y": 690}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(pos_filtered.flange, mass_filtered.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  initial pos_filtered.v = 0
  # --- Exact ---
  connect(sine.y, pos_exact.s_ref) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 140, "y": 500}, {"x": 140, "y": 260}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(pos_exact.flange, mass_exact.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  # --- Filtered low f_crit ---
  connect(sine.y, pos_filtered_low.s_ref) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(pos_filtered_low.flange, mass_filtered_low.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  initial pos_filtered_low.v = 0
  connect(pos_exact.support, ground.flange) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 380, "y": 400}, {"x": 850, "y": 400}, {"x": 850, "y": 500}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(pos_filtered_low.support, ground.flange) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 370, "y": 600}, {"x": 850, "y": 600}, {"x": 850, "y": 500}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(pos_filtered.support, ground.flange) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 390, "y": 830}, {"x": 850, "y": 830}, {"x": 850, "y": 500}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
metadata {
  "Dyad": {
    "icons": {"default": "dyad://TranslationalComponents/Example.svg"},
    "tests": {
      "case1": {
        "stop": 1.1,
        "atol": {
          "mass_filtered.s": 0.001,
          "mass_filtered.v": 0.01,
          "mass_exact.s": 0.001,
          "mass_exact.v": 0.01,
          "mass_filtered_low.s": 0.01,
          "mass_filtered_low.v": 0.1
        },
        "expect": {
          "final": {
            "mass_exact.s": 0.5877852522924736,
            "mass_filtered.s": 0.565467313786633,
            "mass_filtered.v": 5.1812448946651894,
            "mass_filtered_low.s": 0.3442052973660629
          },
          "signals": [
            "mass_filtered.s",
            "mass_filtered.v",
            "mass_exact.s",
            "mass_exact.v",
            "mass_filtered_low.s",
            "mass_filtered_low.v"
          ]
        }
      }
    }
  }
}
end
Flattened Source
dyad
"""
Test of the Position source component with all ReferenceType enum variants.

Replicates the structure of ModelicaTest.Translational.AllComponents (Position portion)
and ModelicaTest.Translational.TestFrictionPosition.

Three Position instances are driven by a common Sine reference (amplitude=1, frequency=1 Hz)
and each drives a Mass (m=1 kg) with support grounded to Fixed:

- pos_filtered: default Filtered mode (f_crit=50 Hz, af=1.3617, bf=0.6180)
- pos_exact: Exact mode — flange position equals input directly
- pos_filtered_low: Filtered mode with low critical frequency (f_crit=5 Hz) to show visible filtering
"""
test component Position
  "Sine reference position signal (amplitude=1 m, frequency=1 Hz)"
  sine = BlockComponents.Sources.Sine(amplitude = 1.0, frequency = 1.0) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 30, "y1": 450, "x2": 130, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Position source — Filtered with default Bessel filter (f_crit=50 Hz)"
  pos_filtered = TranslationalComponents.Sources.Position() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 340, "y1": 640, "x2": 440, "y2": 740, "rot": 0}
      },
      "tags": []
    }
  }
  "Mass driven by filtered position source"
  mass_filtered = TranslationalComponents.Components.Mass(m = 1.0) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 590, "y1": 640, "x2": 690, "y2": 740, "rot": 0}
      },
      "tags": []
    }
  }
  "Position source — Exact (flange tracks input directly)"
  pos_exact = TranslationalComponents.Sources.Position(ref_type = TranslationalComponents.Sources.ReferenceType.Exact()) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 330, "y1": 210, "x2": 430, "y2": 310, "rot": 0}
      },
      "tags": []
    }
  }
  "Mass driven by exact position source"
  mass_exact = TranslationalComponents.Components.Mass(m = 1.0) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 590, "y1": 210, "x2": 690, "y2": 310, "rot": 0}
      },
      "tags": []
    }
  }
  "Position source — Filtered with low critical frequency (f_crit=5 Hz)"
  pos_filtered_low = TranslationalComponents.Sources.Position(ref_type = TranslationalComponents.Sources.ReferenceType.Filtered(f_crit = 5.0)) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 320, "y1": 450, "x2": 420, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Mass driven by low-f_crit filtered position source"
  mass_filtered_low = TranslationalComponents.Components.Mass(m = 1.0) {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 600, "y1": 450, "x2": 700, "y2": 550, "rot": 0}
      },
      "tags": []
    }
  }
  "Fixed ground for all supports"
  ground = TranslationalComponents.Components.Fixed() {
    "Dyad": {
      "placement": {
        "diagram": {"iconName": "default", "x1": 890, "y1": 450, "x2": 990, "y2": 550, "rot": 270}
      },
      "tags": []
    }
  }
relations
  # --- Filtered (default) ---
  connect(sine.y, pos_filtered.s_ref) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 140, "y": 500}, {"x": 140, "y": 690}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(pos_filtered.flange, mass_filtered.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  initial pos_filtered.v = 0
  # --- Exact ---
  connect(sine.y, pos_exact.s_ref) {
    "Dyad": {
      "edges": [{"S": 1, "M": [{"x": 140, "y": 500}, {"x": 140, "y": 260}], "E": 2}],
      "renderStyle": "standard"
    }
  }
  connect(pos_exact.flange, mass_exact.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  # --- Filtered low f_crit ---
  connect(sine.y, pos_filtered_low.s_ref) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  connect(pos_filtered_low.flange, mass_filtered_low.flange_a) {"Dyad": {"edges": [{"S": 1, "M": [], "E": 2}], "renderStyle": "standard"}}
  initial pos_filtered_low.v = 0
  connect(pos_exact.support, ground.flange) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 380, "y": 400}, {"x": 850, "y": 400}, {"x": 850, "y": 500}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(pos_filtered_low.support, ground.flange) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 370, "y": 600}, {"x": 850, "y": 600}, {"x": 850, "y": 500}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
  connect(pos_filtered.support, ground.flange) {
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [{"x": 390, "y": 830}, {"x": 850, "y": 830}, {"x": 850, "y": 500}],
          "E": 2
        }
      ],
      "renderStyle": "standard"
    }
  }
metadata {
  "Dyad": {
    "icons": {"default": "dyad://TranslationalComponents/Example.svg"},
    "tests": {
      "case1": {
        "stop": 1.1,
        "atol": {
          "mass_filtered.s": 0.001,
          "mass_filtered.v": 0.01,
          "mass_exact.s": 0.001,
          "mass_exact.v": 0.01,
          "mass_filtered_low.s": 0.01,
          "mass_filtered_low.v": 0.1
        },
        "expect": {
          "final": {
            "mass_exact.s": 0.5877852522924736,
            "mass_filtered.s": 0.565467313786633,
            "mass_filtered.v": 5.1812448946651894,
            "mass_filtered_low.s": 0.3442052973660629
          },
          "signals": [
            "mass_filtered.s",
            "mass_filtered.v",
            "mass_exact.s",
            "mass_exact.v",
            "mass_filtered_low.s",
            "mass_filtered_low.v"
          ]
        }
      }
    }
  }
}
end


Test Cases

julia
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

julia
@named model_case1 = TranslationalComponents.Sources.Tests.Position()
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 = 1.1e+0, abstol=1e-6, reltol=1e-6)
sol_case1 = rebuild_sol(result_case1)
<< @setup-block not executed in draft mode >>
julia
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.mass_filtered.s])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "TranslationalComponents.Sources.Tests.Position_case1_sig0.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.mass_filtered.s], width=2, label="Actual value of mass_filtered.s")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of mass_filtered.s")
end
scatter!(plt, [df_case1.t[end]], [0.565467313786633], label="Final Condition for `mass_filtered.s`")
<< @setup-block not executed in draft mode >>
julia
plt
<< @example-block not executed in draft mode >>
julia
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.mass_filtered.v])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "TranslationalComponents.Sources.Tests.Position_case1_sig1.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.mass_filtered.v], width=2, label="Actual value of mass_filtered.v")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of mass_filtered.v")
end
scatter!(plt, [df_case1.t[end]], [5.1812448946651894], label="Final Condition for `mass_filtered.v`")
<< @setup-block not executed in draft mode >>
julia
plt
<< @example-block not executed in draft mode >>
julia
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.mass_exact.s])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "TranslationalComponents.Sources.Tests.Position_case1_sig2.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.mass_exact.s], width=2, label="Actual value of mass_exact.s")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of mass_exact.s")
end
scatter!(plt, [df_case1.t[end]], [0.5877852522924736], label="Final Condition for `mass_exact.s`")
<< @setup-block not executed in draft mode >>
julia
plt
<< @example-block not executed in draft mode >>
julia
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.mass_exact.v])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "TranslationalComponents.Sources.Tests.Position_case1_sig3.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.mass_exact.v], width=2, label="Actual value of mass_exact.v")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of mass_exact.v")
end
<< @setup-block not executed in draft mode >>
julia
plt
<< @example-block not executed in draft mode >>
julia
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.mass_filtered_low.s])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "TranslationalComponents.Sources.Tests.Position_case1_sig4.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.mass_filtered_low.s], width=2, label="Actual value of mass_filtered_low.s")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of mass_filtered_low.s")
end
scatter!(plt, [df_case1.t[end]], [0.3442052973660629], label="Final Condition for `mass_filtered_low.s`")
<< @setup-block not executed in draft mode >>
julia
plt
<< @example-block not executed in draft mode >>
julia
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.mass_filtered_low.v])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "TranslationalComponents.Sources.Tests.Position_case1_sig5.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.mass_filtered_low.v], width=2, label="Actual value of mass_filtered_low.v")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of mass_filtered_low.v")
end
<< @setup-block not executed in draft mode >>
julia
plt
<< @example-block not executed in draft mode >>