Adler equation
The Adler equation Δφ' = Δω + ε sin Δφ for the phase difference of an oscillator and its drive.
- Name:
adler_equation - Field:
physics/nonlinear_oscillators - Formalism: ordinary differential equations
- References: Adler 1946; Datseris and Parlitz 2022
Factory
@register_model(
field='physics/nonlinear_oscillators',
tags=('synchronization', 'ode', 'phase', 'oscillation'),
references=('Adler 1946', 'Datseris and Parlitz 2022'),
defaults={'until': 50.0, 'dt': 0.1},
)
def adler_equation(phi: float = 0.0, *, detuning: float = 0.5, epsilon: float = 1.0) -> System:
"""Return the Adler equation `Δφ' = Δω + ε sin Δφ` for the phase difference of an oscillator and its drive.
The phase difference locks at a fixed point when `|Δω| < ε`, inside the Arnold tongue. Outside it, the phase slips
by `2π` every `2π / sqrt(Δω² - ε²)`.
Args:
phi:
The initial phase difference.
detuning:
The frequency difference `Δω`.
epsilon:
The strength of the coupling.
Returns:
system:
The model, with the phase difference `difference.phi`.
Examples:
>>> from skcomplex.models.physics.nonlinear_oscillators import adler_equation
>>> adler_equation(detuning=2.0).elements[0].detuning
2.0
"""
return System(elements=[AdlerPhaseElement('difference', phi=phi, detuning=detuning, epsilon=epsilon)])
Components
class AdlerPhaseElement(Element):
"""Phase difference of a forced oscillator, `phi' = detuning + epsilon sin(phi)`, the Adler equation.
The phase locks at a fixed point when `|detuning| <= epsilon`, and slips with the period
`2 pi / sqrt(detuning^2 - epsilon^2)` otherwise.
Args:
label:
The label of the phase difference.
visual:
How the phase difference is drawn, or `None` for `default_visual_`.
phi:
The initial phase difference.
detuning:
The detuning of the natural frequency from the forcing.
epsilon:
The strength of the forcing.
Attributes:
default_visual_:
The visual of the phase difference when it sets none.
Examples:
>>> from skcomplex.models.physics.nonlinear_oscillators import AdlerPhaseElement
>>> AdlerPhaseElement('difference').detuning
0.5
"""
def __init__(
self,
label: str,
visual: VisualSpec | None = None,
*,
phi: Annotated[float, StateSpec()] = 0.0,
detuning: Annotated[float, ParameterSpec()] = 0.5,
epsilon: Annotated[float, ParameterSpec()] = 1.0,
) -> None:
super().__init__(label, visual=visual)
self.phi = phi
self.detuning = detuning
self.epsilon = epsilon
def _get_laws(self, namespace: SimpleNamespace) -> list[BaseLaw]:
"""Return the rate of the phase difference.
Args:
namespace:
The namespace of the symbols the laws can use.
Returns:
laws:
The rate of `phi`.
"""
return [RateLaw(namespace.phi, namespace.detuning + namespace.epsilon * sin(namespace.phi))]
Equations
difference.phi: diff(phi_difference(t), t) == epsilon_difference*sin(phi_difference(t)) + detuning_difference