Skip to content

Forced Toda oscillator

The forced Toda oscillator x'' + d x' + e^x - 1 = a sin(omega t), a passive asymmetric oscillator.

  • Name: forced_toda
  • Field: physics/nonlinear_oscillators
  • Formalism: ordinary differential equations
  • References: Toda 1967; Kurz and Lauterborn 1988; Datseris and Parlitz 2022

Select this system

from skcomplex.systems import create_simulation, create_system, describe

system = create_system('forced_toda')
entry = describe('forced_toda')
trajectory = create_simulation('forced_toda').prepare().run().trajectory_

Factory

@register_system(
    field='physics/nonlinear_oscillators',
    tags=('chaos', 'ode', 'second order', 'forcing', 'resonance'),
    references=('Toda 1967', 'Kurz and Lauterborn 1988', 'Datseris and Parlitz 2022'),
    defaults={'until': 300.0, 'dt': 0.05},
)
def forced_toda(
    x: float = 0.0,
    v: float = 0.0,
    *,
    d: float = 0.1,
    a: float = 0.88,
    omega: float = 1.0,
) -> System:
    """Return the forced Toda oscillator `x'' + d x' + e^x - 1 = a sin(omega t)`, a passive asymmetric oscillator.

    The exponential spring is stiff for `x > 0` and soft for `x < 0`, unlike the symmetric spring of the Duffing
    oscillator. Its free frequency falls from 1 as the amplitude grows, so the resonance curve bends to low driving
    frequencies and the response swings far to the soft side. Stronger driving gives coexisting responses and period
    doubling cascades to chaos as the driving period `2π / ω` changes.

    Args:
        x:
            The initial displacement.

        v:
            The initial velocity.

        d:
            The damping.

        a:
            The amplitude of the forcing.

        omega:
            The angular frequency of the forcing.

    Returns:
        system:
            The system, with the displacement `toda.x` of order 2 and its velocity `toda.x_d1`.

    Examples:
        >>> from skcomplex.systems.physics.nonlinear_oscillators import forced_toda
        >>> forced_toda(a=1.2).elements[0].a
        1.2
    """
    return System(elements=[TodaElement('toda', x=x, x_d1=v, d=d, a=a, omega=omega)])

Components

Elements:

  • TodaElement, from Element
class TodaElement(Element):
    """Displacement and parameters of the forced Toda oscillator, whose exponential spring is stiff on one side only.

    The acceleration is `x'' = -d x' - (e^x - 1) + a sin(omega t)`. The restoring force `e^x - 1` grows exponentially
    for `x > 0` and saturates at `-1` for `x < 0`, so the oscillator is passive and asymmetric, and its resonance curve
    bends towards low frequencies.

    Args:
        label:
            The label of the oscillator.

        visual:
            How the oscillator is drawn, or `None` for `default_visual_`.

        x:
            The initial displacement.

        x_d1:
            The initial velocity.

        d:
            The damping.

        a:
            The amplitude of the forcing.

        omega:
            The frequency of the forcing.

    Attributes:
        default_visual_:
            The visual of the oscillator when it sets none.

    Examples:
        >>> from skcomplex.systems.physics.nonlinear_oscillators import TodaElement
        >>> TodaElement('toda').d
        0.1
    """

    def __init__(
        self,
        label: str,
        visual: VisualSpec | None = None,
        *,
        x: Annotated[float, StateSpec(order=2)] = 0.0,
        x_d1: float = 0.0,
        d: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 0.1,
        a: Annotated[float, ParameterSpec()] = 0.88,
        omega: Annotated[float, ParameterSpec()] = 1.0,
    ) -> None:
        super().__init__(label, visual=visual)
        self.x = x
        self.x_d1 = x_d1
        self.d = d
        self.a = a
        self.omega = omega

    def _get_laws(self, namespace: SimpleNamespace) -> list[BaseLaw]:
        """Return the acceleration of the oscillator.

        Args:
            namespace:
                The namespace of the symbols the laws can use.

        Returns:
            laws:
                The rate of the second derivative of `x`.
        """
        s = namespace
        return [RateLaw(s.x, -s.d * derivative(s.x, 1) - (exp(s.x) - 1) + s.a * sin(s.omega * s.t))]

Equations

toda.x: diff(x_toda(t), t, t) == a_toda*sin(omega_toda*t) - d_toda*diff(x_toda(t), t) - e^x_toda(t) + 1