DC shunt motor

A DC motor has a fixed outer part, called stator, and a rotating inner part, called rotor. Both parts contain a coil of wire through which current flows. In the case of a shunt motor, these two inductors are connected in parallel to a source of electric energy.

First, we model the stator and then the rotor. Finally, we combine them into the motor model.

Stator

First and foremost, the stator has a coil, which generates a magnetic field. We use the methods linear_inductor and thermal_capacity from the ComponentLibrary to define storage components that model its inductance and thermal capacity:

coil = linear_inductor(1.0)
tc = thermal_capacity(1.0, 2.0);

To define the stator model, we further use the reversible component emc that models the coupling between the electric and the magnetic energy domain, and we use the method magnetic_resistor to define an irreversible component that models the resistance of the coil.

stator = CompositeSystem(
  Dtry(
    :b => Dtry(Junction(magnetic_flux, Position(2, 3), exposed=true, power=false)),
    :q => Dtry(Junction(charge, Position(2, 1), exposed=true)),
    :s => Dtry(Junction(entropy, Position(2, 5))),
  ),
  Dtry(
    :emc => Dtry(
      InnerBox(
        Dtry(
          :q => Dtry(InnerPort(■.q)),
          :b => Dtry(InnerPort(■.b)),
        ),
        emc,
        Position(2, 2)
      ),
    ),
    :coil => Dtry(
      InnerBox(
        Dtry(
          :b => Dtry(InnerPort(■.b)),
        ),
        coil,
        Position(1, 3)
      ),
    ),
    :res => Dtry(
      InnerBox(
        Dtry(
          :b => Dtry(InnerPort(■.b)),
          :s => Dtry(InnerPort(■.s))
        ),
        magnetic_resistor(0.01),
        Position(2, 4)
      ),
    ),
    :tc => Dtry(
      InnerBox(
        Dtry(
          :s => Dtry(InnerPort(■.s))
        ),
        tc,
        Position(1, 5)
      ),
    ),
  )
)

Rotor

For simplicity, we reuse the primitive subsystems coil and tc of the stator model. Further, we use the method angular_mass from the library to define a component that models storage of kinetic energy:

mass = angular_mass(1.0);

As the central coupling component of the motor model, we use the component mkc from the library:

EPHS.ComponentLibrary.ReversibleComponentLibrary.mkcConstant

Magnetic-kinetic coupling: Reversible coupling of of a magnetic energy domain at port $\mathtt{b}$ (magnetic flux) and a kinetic energy domain at port $\mathtt{p}$ (angular momentum) based on the Lorentz force. The strength of the coupling is proportional to the magnetic flux at the state port $\mathtt{b_s}$. The Dirac structure is given by

\[\begin{bmatrix} \mathtt{b.f} \\ \mathtt{p.f} \end{bmatrix} \: = \: \begin{bmatrix} 0 & +\mathtt{b_s.x} \\ -\mathtt{b_s.x} & 0 \end{bmatrix} \, \begin{bmatrix} \mathtt{b.e} \\ \mathtt{p.e} \end{bmatrix} \,.\]

source

To define the rotor model, we additionally use the library method rotational_friction to describe the mechanical friction of the rotor.

rotor = CompositeSystem(
  Dtry(
    :q => Dtry(Junction(charge, Position(2, 1), exposed=true)),
    :b => Dtry(Junction(magnetic_flux, Position(2, 3))),
    :bₛ => Dtry(Junction(magnetic_flux, Position(1, 4), exposed=true, power=false)),
    :p => Dtry(Junction(angular_momentum, Position(2, 5), exposed=true)),
    :s => Dtry(Junction(entropy, Position(3, 4))),
  ),
  Dtry(
    :emc => Dtry(
      InnerBox(
        Dtry(
          :q => Dtry(InnerPort(■.q)),
          :b => Dtry(InnerPort(■.b)),
        ),
        emc,
        Position(2, 2)
      ),
    ),
    :coil => Dtry(
      InnerBox(
        Dtry(
          :b => Dtry(InnerPort(■.b)),
        ),
        coil,
        Position(1, 3)
      ),
    ),
    :mkc => Dtry(
      InnerBox(
        Dtry(
          :b => Dtry(InnerPort(■.b)),
          :p => Dtry(InnerPort(■.p)),
          :bₛ => Dtry(InnerPort(■.bₛ, power=false)),
        ),
        mkc,
        Position(2, 4)
      ),
    ),
    :mass => Dtry(
      InnerBox(
        Dtry(
          :p => Dtry(InnerPort(■.p)),
        ),
        mass,
        Position(1, 5)
      ),
    ),
    :res => Dtry(
      InnerBox(
        Dtry(
          :b => Dtry(InnerPort(■.b)),
          :s => Dtry(InnerPort(■.s))
        ),
        magnetic_resistor(0.01),
        Position(3, 3)
      ),
    ),
    :mf => Dtry(
      InnerBox(
        Dtry(
          :p => Dtry(InnerPort(■.p)),
          :s => Dtry(InnerPort(■.s))
        ),
        rotational_friction(0.01),
        Position(3, 5)
      ),
    ),
    :tc => Dtry(
      InnerBox(
        Dtry(
          :s => Dtry(InnerPort(■.s))
        ),
        tc,
        Position(4, 4)
      ),
    ),
  )
)

Motor

Now we interconnect the stator and rotor:

motor = CompositeSystem(
  Dtry(
    :q => Dtry(Junction(charge, Position(2, 1), exposed=true)),
    :bₛ => Dtry(Junction(magnetic_flux, Position(2, 2), power=false)),
    :p => Dtry(Junction(angular_momentum, Position(3, 3), exposed=true)),
  ),
  Dtry(
    :stator => Dtry(
      InnerBox(
        Dtry(
          :q => Dtry(InnerPort(■.q)),
          :b => Dtry(InnerPort(■.bₛ, power=false)),
        ),
        stator,
        Position(1, 2)
      ),
    ),
    :rotor => Dtry(
      InnerBox(
        Dtry(
          :q => Dtry(InnerPort(■.q)),
          :bₛ => Dtry(InnerPort(■.bₛ, power=false)),
          :p => Dtry(InnerPort(■.p)),
        ),
        rotor,
        Position(3, 2)
      ),
    ),
  )
)

Evolution equations

As the implementation does not yet support the simulation of open systems with 'boundary conditions', we can merely assemble the equations:

assemble(motor)
Flows:
rotor.coil.b.f = q.e + -1.0 * stator.coil.b.x * rotor.mass.p.e + -1.0 * rotor.res.r * rotor.coil.b.e
rotor.mass.p.f = -1.0 * rotor.mf.d * rotor.mass.p.e + stator.coil.b.x * rotor.coil.b.e + p.f
rotor.tc.s.f = rotor.mf.d * (rotor.mass.p.e^2.0) * ((ENV.θ + rotor.tc.s.e)^-1.0) + rotor.res.r * (rotor.coil.b.e^2.0) * ((ENV.θ + rotor.tc.s.e)^-1.0)
stator.coil.b.f = q.e + -1.0 * stator.res.r * stator.coil.b.e
stator.tc.s.f = stator.res.r * (stator.coil.b.e^2.0) * ((ENV.θ + stator.tc.s.e)^-1.0)
Efforts:
rotor.coil.b.e = rotor.coil.b.x * (rotor.coil.l^-1.0)
rotor.mass.p.e = rotor.mass.p.x * (rotor.mass.m^-1.0)
rotor.tc.s.e = rotor.tc.c₁ * (exp(rotor.tc.s.x * (rotor.tc.c₂^-1.0))) * (rotor.tc.c₂^-1.0) + -1.0 * ENV.θ
stator.coil.b.e = stator.coil.b.x * (stator.coil.l^-1.0)
stator.tc.s.e = stator.tc.c₁ * (exp(stator.tc.s.x * (stator.tc.c₂^-1.0))) * (stator.tc.c₂^-1.0) + -1.0 * ENV.θ