Skip to content

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