Source code for coupled_oscillator.phase

import numpy as np
import coupled_oscillator as co


[docs] class Phase:
[docs] def __init__(self, osc_prop: co.OscillatorProperties, angle: float = 0, displacement: float = 0, angle_momentum: float = 0, displacement_momentum: float = 0, arr: np.ndarray | None = None): self._osc_prop = osc_prop # check if the array is given, if so then set the array and return if arr is not None: self._arr = arr return # otherwise, set the values of the phase from the given arguments self._arr = np.zeros(4, dtype=np.float64) self.angle = angle self.displacement = displacement self.angle_momentum = angle_momentum self.displacement_momentum = displacement_momentum
# ================================================================ # Coordinate Transformation # ================================================================
[docs] def to_cartesian_coordinates(self) -> np.ndarray: """ Converts the phase to cartesian coordinates. Returns: np.ndarray: The cartesian coordinates of the phase (x, y). """ angle = self.angle pendulum_length = self._osc_prop.length + self.displacement x = np.sin(angle) * pendulum_length y = -np.cos(angle) * pendulum_length return np.array([x, y], dtype=np.float64)
# ================================================================ # Representation # ================================================================ def __repr__(self) -> str: prop = f"ϕ: {self.angle:.2f}, " prop += f"ξ: {self.displacement:.2f}, " prop += f"p_ϕ: {self.angle_momentum:.2f}, " prop += f"p_ξ: {self.displacement_momentum:.2f}" return f"Phase({prop})" # ================================================================ # Properties # ================================================================ @property def angle(self) -> float: """The angle of the pendulum.""" return self._arr[0] @angle.setter def angle(self, value: float): self._arr[0] = value @property def displacement(self) -> float: """The displacement of the spring.""" return self._arr[1] @displacement.setter def displacement(self, value: float): self._arr[1] = value @property def angle_momentum(self) -> float: """The angular momentum of the pendulum.""" return self._arr[2] @angle_momentum.setter def angle_momentum(self, value: float): self._arr[2] = value @property def displacement_momentum(self) -> float: """The displacement momentum of the spring.""" return self._arr[3] @displacement_momentum.setter def displacement_momentum(self, value: float): self._arr[3] = value # ================================================================ # Operator Overloads # ================================================================
[docs] @staticmethod def get_value(value): """ Returns the value of the given object. If the given object is a Phase object, then the array containing the values of the phase is returned. Otherwise, the given object is returned as is. """ if isinstance(value, Phase): return value._arr return value
def __add__(self, other): return Phase(self._osc_prop, arr=self._arr + self.get_value(other)) def __radd__(self, other): return Phase(self._osc_prop, arr=self._arr + self.get_value(other)) def __sub__(self, other): return Phase(self._osc_prop, arr=self._arr - self.get_value(other)) def __rsub__(self, other): return Phase(self._osc_prop, arr=self.get_value(other) - self._arr) def __mul__(self, other): return Phase(self._osc_prop, arr=self._arr * self.get_value(other)) def __rmul__(self, other): return Phase(self._osc_prop, arr=self._arr * self.get_value(other)) def __truediv__(self, other): return Phase(self._osc_prop, arr=self._arr / self.get_value(other)) def __rtruediv__(self, other): return Phase(self._osc_prop, arr=self.get_value(other) / self._arr) def __neg__(self): return Phase(self._osc_prop, arr=-self._arr) def __pos__(self): return Phase(self._osc_prop, arr=+self._arr)