Skip to content

Faraday-disk charger

A battery charger driven by a Faraday disk generator whose own current strengthens its field.

  • Name: faraday_disk
  • Field: engineering/power_systems
  • Formalism: ordinary differential equations
  • References: Trzaska 2023

Factory

@register_model(
    field='engineering/power_systems',
    tags=('energy', 'electromechanics', 'batteries', 'ode'),
    references=('Trzaska 2023',),
    defaults={'until': 50.0, 'dt': 0.1},
)
def faraday_disk(
    I: float = 0.0,
    U: float = 0.0,
    omega: float = 0.0,
    *,
    B: float = 1.5,
    M: float = 4.8,
    N: float = 250.0,
    R1: float = 2.3,
    R2: float = 109.0,
    L: float = 0.2,
    C: float = 0.75,
) -> System:
    """Return a battery charger driven by a Faraday disk generator whose own current strengthens its field.

    A motor turns the conducting disk of radii `r1` and `r2` with a constant torque `M` in the field `B` of a magnet
    plus the field `μ N I / l` of a coil that the generated current flows through. With `a = B (r2^2 - r1^2) / 2` and
    `b = μ N (r2^2 - r1^2) / (2 l)`, the current, the polarization voltage of the battery, and the angular speed follow
    `L I' = -R1 I - U + (a + b I) ω - E(I)`, `C U' = I - U / R2`, and
    `J ω' = M - alpha sign(ω) - β r2 ω - (a + b I) I`, where the battery voltage is `E(I) = a0 + a1 I + a3 I^3` and the
    last term is the braking torque of the Lorentz force.

    The generator charges the battery only when its voltage `a ω` exceeds the open-circuit voltage `a0 = 8` of the
    battery, at `ω` above 35 for the default field. Below that speed the steady current is a small negative current,
    the battery discharges through the disk and helps the motor, and the steady speed grows linearly with the torque,
    as `(M - alpha) / (β r2)` up to the small Lorentz torque: with the defaults the current settles at -0.040 and the
    speed at 15.7. The coil acts as a negative resistance `b ω` against `R1 + a1`, so above `ω = (R1 + a1) / b`, about
    32 or a torque near 9.5 for the defaults, the steady state loses its stability and the current oscillates around
    zero, swinging between charging and discharging, while the mean braking torque `b <I²>` bends the speed below the
    linear trend. A stronger magnet charges at the default torque: `B = 4` gives a steady current of 0.013.

    Args:
        I:
            The initial charging current.

        U:
            The initial polarization voltage of the battery.

        omega:
            The initial angular speed of the disk.

        B:
            The field of the permanent magnet.

        M:
            The torque of the drive motor.

        N:
            The number of turns of the feedback coil.

        R1:
            The series resistance of the coil, the disk, and the battery.

        R2:
            The polarization resistance of the battery.

        L:
            The inductance of the coil.

        C:
            The polarization capacitance of the battery.

    Returns:
        system:
            The model, with the current `charger.I`, the polarization voltage `charger.U`, and the angular speed
            `charger.omega`.

    Examples:
        >>> from skcomplex.models.engineering.power_systems import faraday_disk
        >>> faraday_disk(M=6.0).elements[0].M
        6.0
    """
    charger = FaradayDiskElement('charger', I=I, U=U, omega=omega, B=B, M=M, N=N, R1=R1, R2=R2, L=L, C=C)
    return System(elements=[charger])

Components

class FaradayDiskElement(Element):
    """Homopolar generator, a spinning conducting disk in a field that charges a load."""

    def __init__(
        self,
        label: str,
        visual: VisualSpec | None = None,
        *,
        I: Annotated[object, StateSpec()] = 0.0,
        U: Annotated[object, StateSpec()] = 0.0,
        omega: Annotated[object, StateSpec()] = 0.0,
        B: Annotated[object, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 1.5,
        r1: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 0.025,
        r2: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 0.55,
        L: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 0.2,
        C: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 0.75,
        R1: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 2.3,
        R2: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 109.0,
        alpha: Annotated[object, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 0.5,
        beta: Annotated[object, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 0.5,
        J: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 0.5,
        mu: Annotated[object, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 0.00012566370614359174,
        N: Annotated[object, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 250.0,
        l: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 0.05,
        M: Annotated[object, ParameterSpec()] = 4.8,
        a0: Annotated[object, ParameterSpec()] = 8.0,
        a1: Annotated[object, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 0.75,
        a3: Annotated[object, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 0.5,
    ) -> None:
        super().__init__(label, visual=visual)
        self.I = I
        self.U = U
        self.omega = omega
        self.B = B
        self.r1 = r1
        self.r2 = r2
        self.L = L
        self.C = C
        self.R1 = R1
        self.R2 = R2
        self.alpha = alpha
        self.beta = beta
        self.J = J
        self.mu = mu
        self.N = N
        self.l = l
        self.M = M
        self.a0 = a0
        self.a1 = a1
        self.a3 = a3

    def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
        """Return the rates of the spin, the current, and the charge of the disk."""
        return [
            RateLaw(
                s.I,
                (
                    -s.R1 * s.I
                    - s.U
                    + (s.B + s.mu * s.N * s.I / s.l) * (s.r2**2 - s.r1**2) * s.omega / 2
                    - (s.a0 + s.a1 * s.I + s.a3 * s.I**3)
                )
                / s.L,
            ),
            RateLaw(s.U, (s.I - s.U / s.R2) / s.C),
            RateLaw(
                s.omega,
                (
                    s.M
                    - s.alpha * sign(s.omega)
                    - s.beta * s.r2 * s.omega
                    - s.I * (s.B + s.mu * s.N * s.I / s.l) * (s.r2**2 - s.r1**2) / 2
                )
                / s.J,
            ),
        ]

Equations

charger.I: diff(I_charger(t), t) == -1/2*(2*a3_charger*I_charger(t)^3 + (r1_charger^2 - r2_charger^2)*(N_charger*mu_charger*I_charger(t)/l_charger + B_charger)*omega_charger(t) + 2*R1_charger*I_charger(t) + 2*a1_charger*I_charger(t) + 2*a0_charger + 2*U_charger(t))/L_charger
charger.U: diff(U_charger(t), t) == -(U_charger(t)/R2_charger - I_charger(t))/C_charger
charger.omega: diff(omega_charger(t), t) == 1/2*((r1_charger^2 - r2_charger^2)*(N_charger*mu_charger*I_charger(t)/l_charger + B_charger)*I_charger(t) - 2*beta_charger*r2_charger*omega_charger(t) - 2*alpha_charger*where(omega_charger(t) > 0, 1, where(omega_charger(t) < 0, -1, 0)) + 2*M_charger)/J_charger