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