Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MNT: Encapsulate quaternion conversions #537

Merged
merged 3 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ disable=raw-checker-failed,
no-else-return,
inconsistent-return-statements,
unspecified-encoding,
no-member, # because we use funcify_method decorator

# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ straightforward as possible.
- MNT: Add repr method to Parachute class [#490](https://github.com/RocketPy-Team/RocketPy/pull/490)
- ENH: Function Reverse Arithmetic Priority [#488](https://github.com/RocketPy-Team/RocketPy/pull/488)
- DOC: Update Header Related Docs
- MNT: Encapsulate quaternion conversions [#537](https://github.com/RocketPy-Team/RocketPy/pull/537)
- MNT: improve the low pass filter and document an example [#538](https://github.com/RocketPy-Team/RocketPy/pull/538)

### Fixed
Expand Down
36 changes: 16 additions & 20 deletions rocketpy/simulation/flight.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@
from ..mathutils.vector_matrix import Matrix, Vector
from ..plots.flight_plots import _FlightPlots
from ..prints.flight_prints import _FlightPrints
from ..tools import find_closest
from ..tools import (
find_closest,
quaternions_to_spin,
quaternions_to_precession,
quaternions_to_nutation,
)


class Flight:
Expand Down Expand Up @@ -2295,33 +2300,24 @@ def lateral_attitude_angle(self):
@funcify_method("Time (s)", "Precession Angle - ψ (°)", "spline", "constant")
def psi(self):
"""Precession angle as a Function of time."""
psi = (180 / np.pi) * (
np.arctan2(self.e3[:, 1], self.e0[:, 1])
+ np.arctan2(-self.e2[:, 1], -self.e1[:, 1])
) # Precession angle
psi = np.column_stack([self.time, psi]) # Precession angle
return psi
psi = quaternions_to_precession(
self.e0.y_array, self.e1.y_array, self.e2.y_array, self.e3.y_array
)
return np.column_stack([self.time, psi])

@funcify_method("Time (s)", "Spin Angle - φ (°)", "spline", "constant")
def phi(self):
"""Spin angle as a Function of time."""
phi = (180 / np.pi) * (
np.arctan2(self.e3[:, 1], self.e0[:, 1])
- np.arctan2(-self.e2[:, 1], -self.e1[:, 1])
) # Spin angle
phi = np.column_stack([self.time, phi]) # Spin angle
return phi
phi = quaternions_to_spin(
self.e0.y_array, self.e1.y_array, self.e2.y_array, self.e3.y_array
)
return np.column_stack([self.time, phi])

@funcify_method("Time (s)", "Nutation Angle - θ (°)", "spline", "constant")
def theta(self):
"""Nutation angle as a Function of time."""
theta = (
(180 / np.pi)
* 2
* np.arcsin(-((self.e1[:, 1] ** 2 + self.e2[:, 1] ** 2) ** 0.5))
) # Nutation angle
theta = np.column_stack([self.time, theta]) # Nutation angle
return theta
theta = quaternions_to_nutation(self.e1.y_array, self.e2.y_array)
return np.column_stack([self.time, theta])

# Fluid Mechanics variables
# Freestream Velocity
Expand Down
64 changes: 64 additions & 0 deletions rocketpy/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import re
from bisect import bisect_left

import numpy as np
import pytz
from cftime import num2pydate
from packaging import version as packaging_version
Expand Down Expand Up @@ -381,6 +382,69 @@ def check_requirement_version(module_name, version):
return True


# Flight


def quaternions_to_precession(e0, e1, e2, e3):
"""Calculates the Precession angle
Parameters
----------
e0 : float
Euler parameter 0, must be between -1 and 1
e1 : float
Euler parameter 1, must be between -1 and 1
e2 : float
Euler parameter 2, must be between -1 and 1
e3 : float
Euler parameter 3, must be between -1 and 1
Returns
-------
float
Euler Precession angle in degrees
"""
return (180 / np.pi) * (np.arctan2(e3, e0) + np.arctan2(-e2, -e1))


def quaternions_to_spin(e0, e1, e2, e3):
"""Calculates the Spin angle from quaternions.
Parameters
----------
e0 : float
Euler parameter 0, must be between -1 and 1
e1 : float
Euler parameter 1, must be between -1 and 1
e2 : float
Euler parameter 2, must be between -1 and 1
e3 : float
Euler parameter 3, must be between -1 and 1
Returns
-------
float
Euler Spin angle in degrees
"""
return (180 / np.pi) * (np.arctan2(e3, e0) - np.arctan2(-e2, -e1))


def quaternions_to_nutation(e1, e2):
"""Calculates the Nutation angle from quaternions.
Parameters
----------
e1 : float
Euler parameter 1, must be between -1 and 1
e2 : float
Euler parameter 2, must be between -1 and 1
Returns
-------
float
Euler Nutation angle in degrees
"""
return (180 / np.pi) * 2 * np.arcsin(-((e1**2 + e2**2) ** 0.5))


if __name__ == "__main__":
import doctest

Expand Down
Loading