Skip to content
LIBRARY
Sources.Tests.Speed.md

Sources.Tests.Speed

Test for SpeedSource with Filtered and Exact modes, matching MSL ModelicaTest.Rotational.TestSpeed.

Two SpeedSource instances are driven by different reference signals and each drives an Inertia (J=1):

  1. speed_filtered: Filtered mode (f_crit=5 Hz), step input at t=0.5 The first-order filter smooths the step — w tracks the step with a time constant of 1/(2π·5) ≈ 0.0318s. At t=1.1, w should be ≈1.0 (fully settled).

  2. speed_exact: Exact mode, sine input (f=1 Hz) w tracks sin(2πt) exactly. At t=1.1: w = sin(2π·1.1) = sin(0.2π) ≈ 0.5878.

Usage

RotationalComponents.Sources.Tests.Speed()

Behavior

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

Source

dyad
"""
Test for SpeedSource with Filtered and Exact modes, matching MSL ModelicaTest.Rotational.TestSpeed.

Two SpeedSource instances are driven by different reference signals and each
drives an Inertia (J=1):

1. speed_filtered: Filtered mode (f_crit=5 Hz), step input at t=0.5
   The first-order filter smooths the step — w tracks the step with a time constant
   of 1/(2π·5) ≈ 0.0318s. At t=1.1, w should be ≈1.0 (fully settled).

2. speed_exact: Exact mode, sine input (f=1 Hz)
   w tracks sin(2πt) exactly. At t=1.1: w = sin(2π·1.1) = sin(0.2π) ≈ 0.5878.
"""
test component Speed
  "Fixed ground for all supports"
  fixed = RotationalComponents.Components.Fixed()
  "Step signal for filtered speed source (step at t=0.5)"
  step = BlockComponents.Sources.Step(height = 1.0, start_time = 0.5)
  "SpeedSource — Filtered mode with low f_crit=5 Hz"
  speed_filtered = RotationalComponents.Sources.SpeedSource(ref_type = RotationalComponents.Sources.ReferenceType.Filtered(f_crit = 5.0))
  "Inertia driven by filtered speed source"
  inertia_filtered = RotationalComponents.Components.Inertia(J = 1)
  "Sine signal for exact speed source (f=1 Hz)"
  sine = BlockComponents.Sources.Sine(amplitude = 1, frequency = 1)
  "SpeedSource — Exact mode"
  speed_exact = RotationalComponents.Sources.SpeedSource(ref_type = RotationalComponents.Sources.ReferenceType.Exact())
  "Inertia driven by exact speed source"
  inertia_exact = RotationalComponents.Components.Inertia(J = 1)
relations
  initial inertia_exact.phi = 0
  initial inertia_filtered.phi = 0
  connect(step.y, speed_filtered.w_ref)
  connect(speed_filtered.spline, inertia_filtered.spline_a)
  connect(speed_filtered.support, fixed.spline)
  connect(sine.y, speed_exact.w_ref)
  connect(speed_exact.spline, inertia_exact.spline_a)
  connect(speed_exact.support, fixed.spline)
metadata {
  "Dyad": {
    "icons": {"default": "dyad://RotationalComponents/Example.svg"},
    "tests": {
      "case1": {
        "stop": 1.1,
        "atol": {"inertia_filtered.w": 0.01, "inertia_exact.w": 0.001},
        "expect": {
          "initial": {
            "inertia_filtered.phi": 0,
            "inertia_exact.phi": 0,
            "inertia_filtered.w": 0,
            "inertia_exact.w": 0
          },
          "final": {"inertia_exact.w": 0.5878},
          "signals": [
            "inertia_filtered.w",
            "inertia_exact.w",
            "inertia_filtered.phi",
            "inertia_exact.phi"
          ]
        }
      }
    }
  }
}
end
Flattened Source
dyad
"""
Test for SpeedSource with Filtered and Exact modes, matching MSL ModelicaTest.Rotational.TestSpeed.

Two SpeedSource instances are driven by different reference signals and each
drives an Inertia (J=1):

1. speed_filtered: Filtered mode (f_crit=5 Hz), step input at t=0.5
   The first-order filter smooths the step — w tracks the step with a time constant
   of 1/(2π·5) ≈ 0.0318s. At t=1.1, w should be ≈1.0 (fully settled).

2. speed_exact: Exact mode, sine input (f=1 Hz)
   w tracks sin(2πt) exactly. At t=1.1: w = sin(2π·1.1) = sin(0.2π) ≈ 0.5878.
"""
test component Speed
  "Fixed ground for all supports"
  fixed = RotationalComponents.Components.Fixed()
  "Step signal for filtered speed source (step at t=0.5)"
  step = BlockComponents.Sources.Step(height = 1.0, start_time = 0.5)
  "SpeedSource — Filtered mode with low f_crit=5 Hz"
  speed_filtered = RotationalComponents.Sources.SpeedSource(ref_type = RotationalComponents.Sources.ReferenceType.Filtered(f_crit = 5.0))
  "Inertia driven by filtered speed source"
  inertia_filtered = RotationalComponents.Components.Inertia(J = 1)
  "Sine signal for exact speed source (f=1 Hz)"
  sine = BlockComponents.Sources.Sine(amplitude = 1, frequency = 1)
  "SpeedSource — Exact mode"
  speed_exact = RotationalComponents.Sources.SpeedSource(ref_type = RotationalComponents.Sources.ReferenceType.Exact())
  "Inertia driven by exact speed source"
  inertia_exact = RotationalComponents.Components.Inertia(J = 1)
relations
  initial inertia_exact.phi = 0
  initial inertia_filtered.phi = 0
  connect(step.y, speed_filtered.w_ref)
  connect(speed_filtered.spline, inertia_filtered.spline_a)
  connect(speed_filtered.support, fixed.spline)
  connect(sine.y, speed_exact.w_ref)
  connect(speed_exact.spline, inertia_exact.spline_a)
  connect(speed_exact.support, fixed.spline)
metadata {
  "Dyad": {
    "icons": {"default": "dyad://RotationalComponents/Example.svg"},
    "tests": {
      "case1": {
        "stop": 1.1,
        "atol": {"inertia_filtered.w": 0.01, "inertia_exact.w": 0.001},
        "expect": {
          "initial": {
            "inertia_filtered.phi": 0,
            "inertia_exact.phi": 0,
            "inertia_filtered.w": 0,
            "inertia_exact.w": 0
          },
          "final": {"inertia_exact.w": 0.5878},
          "signals": [
            "inertia_filtered.w",
            "inertia_exact.w",
            "inertia_filtered.phi",
            "inertia_exact.phi"
          ]
        }
      }
    }
  }
}
end


Test Cases

julia
using RotationalComponents
using DyadInterface: TransientAnalysis, rebuild_sol, ODEAlg
using ModelingToolkit: toggle_namespacing, get_initial_conditions, @named
using CSV, DataFrames, Plots

snapshotsdir = joinpath(dirname(dirname(pathof(RotationalComponents))), "test", "snapshots")
<< @setup-block not executed in draft mode >>

Test Case case1

julia
@named model_case1 = RotationalComponents.Sources.Tests.Speed()
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.inertia_filtered.w])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "RotationalComponents.Sources.Tests.Speed_case1_sig0.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.inertia_filtered.w], width=2, label="Actual value of inertia_filtered.w")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of inertia_filtered.w")
end
scatter!(plt, [df_case1.t[1]], [0], label="Initial Condition for `inertia_filtered.w`")
<< @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.inertia_exact.w])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "RotationalComponents.Sources.Tests.Speed_case1_sig1.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.inertia_exact.w], width=2, label="Actual value of inertia_exact.w")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of inertia_exact.w")
end
scatter!(plt, [df_case1.t[1]], [0], label="Initial Condition for `inertia_exact.w`")
scatter!(plt, [df_case1.t[end]], [0.5878], label="Final Condition for `inertia_exact.w`")
<< @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.inertia_filtered.phi])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "RotationalComponents.Sources.Tests.Speed_case1_sig2.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.inertia_filtered.phi], width=2, label="Actual value of inertia_filtered.phi")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of inertia_filtered.phi")
end
scatter!(plt, [df_case1.t[1]], [0], label="Initial Condition for `inertia_filtered.phi`")
<< @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.inertia_exact.phi])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "RotationalComponents.Sources.Tests.Speed_case1_sig3.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.inertia_exact.phi], width=2, label="Actual value of inertia_exact.phi")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of inertia_exact.phi")
end
scatter!(plt, [df_case1.t[1]], [0], label="Initial Condition for `inertia_exact.phi`")
<< @setup-block not executed in draft mode >>
julia
plt
<< @example-block not executed in draft mode >>