Skip to content
RotationalEMFTest.md

RotationalEMFTest

A test circuit for a rotational electromechanical transducer (RotationalEMF) driven by a sinusoidal voltage and connected to an inertial load.

This model simulates a rotational electromechanical device (RotationalEMF) whose electrical terminals are excited by a sinusoidal voltage. The housing of the RotationalEMF is mechanically fixed, while its rotor is connected to a rotational Inertia. A Sine signal generator provides the input for a VoltageSource, which in turn applies voltage to the RotationalEMF. This setup allows for testing the dynamic response of the RotationalEMF and the connected inertia to electrical stimulation. The primary behavior demonstrated is the conversion of electrical energy (sinusoidal voltage) into mechanical motion (rotation of the inertia) and the generation of torque.

Usage

RotationalEMFTest()

Behavior

[input_signal.y(t)=sine_voltage.V(t)connect(fixed+spline,rotemf+housing)connect(rotemf+p,sinevoltage+p)connect(sinevoltage+n,rotemf+n)connect(rotemf+rotor,inertia+splinea)rot_emf.v(t)=rot_emf.n.v(t)+rot_emf.p.v(t)0=rot_emf.n.i(t)+rot_emf.p.i(t)rot_emf.i(t)=rot_emf.p.i(t)rot_emf.phi(t)=rot_emf.rotor.phi(t)rot_emf.housing.phi(t)rot_emf.w(t)=drot_emf.phi(t)dtrot_emf.krot_emf.w(t)=rot_emf.v(t)rot_emf.tau(t)=rot_emf.krot_emf.i(t)rot_emf.tau(t)=rot_emf.rotor.tau(t)fixed.spline.phi(t)=fixed.phi0input_signal.y(t)=ifelse(input_signal.start_time<t,input_signal.offset+input_signal.amplitudesin(input_signal.phase+6.2832input_signal.frequency(input_signal.start_time+t)),input_signal.offset)sine_voltage.v(t)=sine_voltage.p.v(t)sine_voltage.n.v(t)sine_voltage.i(t)=sine_voltage.p.i(t)sine_voltage.p.i(t)+sine_voltage.n.i(t)=0sine_voltage.v(t)=sine_voltage.uVsine_voltage.V(t)inertia.phi(t)=inertia.spline_a.phi(t)inertia.phi(t)=inertia.spline_b.phi(t)dinertia.phi(t)dt=inertia.w(t)dinertia.w(t)dt=inertia.a(t)inertia.Jinertia.a(t)=inertia.spline_a.tau(t)+inertia.spline_b.tau(t)]

Source

dyad
# A test circuit for a rotational electromechanical transducer (RotationalEMF) driven by a sinusoidal voltage and connected to an inertial load.
#
# This model simulates a rotational electromechanical device (`RotationalEMF`) whose electrical terminals are excited by a sinusoidal voltage. The housing of the `RotationalEMF` is mechanically fixed, while its rotor is connected to a rotational `Inertia`. A `Sine` signal generator provides the input for a `VoltageSource`, which in turn applies voltage to the `RotationalEMF`. This setup allows for testing the dynamic response of the `RotationalEMF` and the connected inertia to electrical stimulation. The primary behavior demonstrated is the conversion of electrical energy (sinusoidal voltage) into mechanical motion (rotation of the inertia) and the generation of torque.
test component RotationalEMFTest
  # Electromechanical transducer converting electrical to rotational energy and vice-versa, with coupling constant k=1.
  rot_emf = RotationalEMF(k=1) [{
    "Dyad": {"placement": {"icon": {"x1": 300, "y1": 700, "x2": 500, "y2": 900, "rot": 0}}}
  }]
  # Represents a mechanically fixed point, providing a stationary reference for the EMF housing.
  fixed = RotationalComponents.Fixed() [{
    "Dyad": {"placement": {"icon": {"x1": 0, "y1": 700, "x2": 200, "y2": 900, "rot": 180}}}
  }]
  # Generates a sinusoidal signal (amplitude=1, frequency=1 rad/s, offset=0, start_time=0) to define the voltage source's behavior.
  input_signal = BlockComponents.Sine(amplitude=1, frequency=1, offset=0, start_time=0) [{
    "Dyad": {"placement": {"icon": {"x1": 300, "y1": 100, "x2": 500, "y2": 300, "rot": 0}}}
  }]
  # Ideal voltage source whose output voltage is driven by the input_signal.
  sine_voltage = VoltageSource() [{
    "Dyad": {"placement": {"icon": {"x1": 500, "y1": 400, "x2": 700, "y2": 600, "rot": 0}}}
  }]
  # Rotational inertia with moment of inertia J=100 kg.m^2, representing the mechanical load.
  inertia = RotationalComponents.Inertia(J=100) [{
    "Dyad": {"placement": {"icon": {"x1": 600, "y1": 700, "x2": 800, "y2": 900, "rot": 0}}}
  }]
relations
  connect(input_signal.y, sine_voltage.V) [{"Dyad": {"edges": [{"S": 1, "M": [{"x": 600, "y": 200}], "E": 2}]}}]
  connect(fixed.spline, rot_emf.housing) [{"Dyad": {"edges": [{"S": 1, "E": 2}]}}]
  connect(rot_emf.p, sine_voltage.p) [{"Dyad": {"edges": [{"S": 1, "M": [{"x": 400, "y": 500}], "E": 2}]}}]
  connect(sine_voltage.n, rot_emf.n) [{
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [
            {"x": 750, "y": 500},
            {"x": 750, "y": 650},
            {"x": 550, "y": 650},
            {"x": 550, "y": 950},
            {"x": 400, "y": 950}
          ],
          "E": 2
        }
      ]
    }
  }]
  connect(rot_emf.rotor, inertia.spline_a) [{"Dyad": {"edges": [{"S": 1, "E": 2}]}}]
metadata {
  "Dyad": {
    "tests": {"case1": {"stop": 10, "expect": {"signals": ["rot_emf.tau", "rot_emf.phi"]}}}
  }
}
end
Flattened Source
dyad
# A test circuit for a rotational electromechanical transducer (RotationalEMF) driven by a sinusoidal voltage and connected to an inertial load.
#
# This model simulates a rotational electromechanical device (`RotationalEMF`) whose electrical terminals are excited by a sinusoidal voltage. The housing of the `RotationalEMF` is mechanically fixed, while its rotor is connected to a rotational `Inertia`. A `Sine` signal generator provides the input for a `VoltageSource`, which in turn applies voltage to the `RotationalEMF`. This setup allows for testing the dynamic response of the `RotationalEMF` and the connected inertia to electrical stimulation. The primary behavior demonstrated is the conversion of electrical energy (sinusoidal voltage) into mechanical motion (rotation of the inertia) and the generation of torque.
test component RotationalEMFTest
  # Electromechanical transducer converting electrical to rotational energy and vice-versa, with coupling constant k=1.
  rot_emf = RotationalEMF(k=1) [{
    "Dyad": {"placement": {"icon": {"x1": 300, "y1": 700, "x2": 500, "y2": 900, "rot": 0}}}
  }]
  # Represents a mechanically fixed point, providing a stationary reference for the EMF housing.
  fixed = RotationalComponents.Fixed() [{
    "Dyad": {"placement": {"icon": {"x1": 0, "y1": 700, "x2": 200, "y2": 900, "rot": 180}}}
  }]
  # Generates a sinusoidal signal (amplitude=1, frequency=1 rad/s, offset=0, start_time=0) to define the voltage source's behavior.
  input_signal = BlockComponents.Sine(amplitude=1, frequency=1, offset=0, start_time=0) [{
    "Dyad": {"placement": {"icon": {"x1": 300, "y1": 100, "x2": 500, "y2": 300, "rot": 0}}}
  }]
  # Ideal voltage source whose output voltage is driven by the input_signal.
  sine_voltage = VoltageSource() [{
    "Dyad": {"placement": {"icon": {"x1": 500, "y1": 400, "x2": 700, "y2": 600, "rot": 0}}}
  }]
  # Rotational inertia with moment of inertia J=100 kg.m^2, representing the mechanical load.
  inertia = RotationalComponents.Inertia(J=100) [{
    "Dyad": {"placement": {"icon": {"x1": 600, "y1": 700, "x2": 800, "y2": 900, "rot": 0}}}
  }]
relations
  connect(input_signal.y, sine_voltage.V) [{"Dyad": {"edges": [{"S": 1, "M": [{"x": 600, "y": 200}], "E": 2}]}}]
  connect(fixed.spline, rot_emf.housing) [{"Dyad": {"edges": [{"S": 1, "E": 2}]}}]
  connect(rot_emf.p, sine_voltage.p) [{"Dyad": {"edges": [{"S": 1, "M": [{"x": 400, "y": 500}], "E": 2}]}}]
  connect(sine_voltage.n, rot_emf.n) [{
    "Dyad": {
      "edges": [
        {
          "S": 1,
          "M": [
            {"x": 750, "y": 500},
            {"x": 750, "y": 650},
            {"x": 550, "y": 650},
            {"x": 550, "y": 950},
            {"x": 400, "y": 950}
          ],
          "E": 2
        }
      ]
    }
  }]
  connect(rot_emf.rotor, inertia.spline_a) [{"Dyad": {"edges": [{"S": 1, "E": 2}]}}]
metadata {
  "Dyad": {
    "tests": {"case1": {"stop": 10, "expect": {"signals": ["rot_emf.tau", "rot_emf.phi"]}}}
  }
}
end


Test Cases

This is setup code, that must be run before each test case.

julia
using ElectricalComponents
using ModelingToolkit, OrdinaryDiffEqDefault
using Plots
using CSV, DataFrames

snapshotsdir = joinpath(dirname(dirname(pathof(ElectricalComponents))), "test", "snapshots")
"/home/actions-runner-10/.julia/packages/ElectricalComponents/bmmPM/test/snapshots"

Test Case case1

julia
@mtkbuild model_case1 = RotationalEMFTest()
u0_case1 = []
prob_case1 = ODEProblem(model_case1, u0_case1, (0, 10))
sol_case1 = solve(prob_case1)
retcode: Success
Interpolation: 3rd order Hermite
t: 45-element Vector{Float64}:
  0.0
  9.999999999999999e-5
  0.0010999999999999998
  0.011099999999999997
  0.050784137892691775
  0.1133829487424738
  0.191644891105999
  0.2936084163925959
  0.4184983331005152
  0.5751396248233639

  7.684915529389811
  7.986681414428846
  8.25722721731883
  8.521456194377711
  8.83549189247025
  9.099472757655487
  9.470267466874974
  9.7314070007879
 10.0
u: 45-element Vector{Vector{Float64}}:
 [-0.0]
 [3.1415925502355376e-8]
 [3.801311978771164e-6]
 [0.00038691875723072223]
 [0.008033745377996374]
 [0.03870786249505734]
 [0.10209857892095617]
 [0.20221973172562124]
 [0.29789384703539257]
 [0.3008998580674771]

 [0.2224942357005495]
 [0.0006192398610979312]
 [0.16643016111145612]
 [0.31691653962136546]
 [0.07779740893221518]
 [0.03016362779826914]
 [0.3155524352589041]
 [0.1777265823640727]
 [2.234751943810411e-5]
julia
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.rot_emf.tau])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "RotationalEMFTest_case1_sig0.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.rot_emf.tau], width=2, label="Actual value of rot_emf.tau")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of rot_emf.tau")
end

plt

julia
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.rot_emf.phi])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "RotationalEMFTest_case1_sig1.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.rot_emf.phi], width=2, label="Actual value of rot_emf.phi")
if !isnothing(dfr_case1)
  scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of rot_emf.phi")
end

plt