Skip to content
This repository has been archived by the owner on Aug 13, 2020. It is now read-only.

Commit

Permalink
* Changed repo structure from src/ to src/pyfme
Browse files Browse the repository at this point in the history
* Added aricraft folder with an empty file that will contain the test aircraft.
* Added some functions in utils/coordinates to change from body to local horizon coords and from local horizon coords to body (tested).
  • Loading branch information
AlexS12 committed Dec 24, 2015
1 parent 6a1d1e2 commit 19a4b0c
Show file tree
Hide file tree
Showing 12 changed files with 259 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
__pycache__
.cache

*.py[cod]
2 changes: 2 additions & 0 deletions src/pyfme/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@


File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Empty file added src/pyfme/utils/__init__.py
Empty file.
161 changes: 161 additions & 0 deletions src/pyfme/utils/coordinates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# -*- coding: utf-8 -*-
"""
Frames of Reference orientation functions
"""

import numpy as np

# Reassing for readability
sin = np.sin
cos = np.cos


def check_theta_phi_psi_range(theta, phi, psi):
"""Check theta, phi, psi values are inside the defined range. This
comprobation can also detect if the value of the angle is in degrees in
some cases.
"""

theta_min, theta_max = (-np.pi/2, np.pi/2)
phi_min, phi_max = (-np.pi, np.pi)
psi_min, psi_max = (0, 2 * np.pi)

if not (theta_min <= theta <= theta_max):
raise ValueError('Theta value is not inside correct range')
elif not (phi_min <= phi <= phi_max):
raise ValueError('Phi value is not inside correct range')
elif not (psi_min <= phi <= psi_max):
raise ValueError('Psi value is not inside correct range')



def body2hor(body_coords, theta, phi, psi):
"""Transforms the vector coordinates in body frame of reference to local
horizon frame of reference.
Parameters
----------
body_coords : array_like
3 dimensional vector with (x,y,z) coordinates in body axes.
theta : float
Pitch (or elevation) angle (rad).
phi : float
Bank angle (rad).
psi : float
Yaw (or azimuth) angle (rad)
Returns
-------
hor_coords : array_like
3 dimensional vector with (x,y,z) coordinates in local horizon axes.
Raises
------
ValueError
If the values of the euler angles are outside the proper ranges.
See Also
--------
`hor2body` function.
Notes
-----
See [1] or [2] for frame of reference definition.
Note that in order to avoid ambiguities ranges in angles are limited to:
* -pi/2 <= theta <= pi/2
* -pi <= phi <= pi
* 0 <= psi <= 2*pi
References
----------
.. [1] B. Etkin, "Dynamics of Atmospheric Flight," Courier Corporation,
pp. 104-120, 2012.
.. [2] Gómez Tierno, M.A. et al, "Mecánica del Vuelo," Garceta, pp. 1-12,
2012
"""

check_theta_phi_psi_range(theta, phi, psi)

# Transformation matrix from body to local horizon
Lhb = np.array([
[cos(theta) * cos(psi),
sin(phi) * sin(theta) * cos(psi) - cos(phi) * sin(psi),
cos(phi) * sin(theta) * cos(psi) + sin(phi) * sin(psi)],
[cos(theta) * sin(psi),
sin(phi) * sin(theta) * sin(psi) + cos(phi) * cos(psi),
cos(phi) * sin(theta) * sin(psi) - sin(phi) * cos(psi)],
[- sin(theta),
sin(phi) * cos(theta),
cos(phi) * cos(theta)]
])

hor_coords = Lhb.dot(body_coords)

return hor_coords


def hor2body(hor_coords, theta, phi, psi):
"""Transforms the vector coordinates in local horizon frame of reference
to body frame of reference.
Parameters
----------
hor_coords : array_like
3 dimensional vector with (x,y,z) coordinates in local horizon axes.
theta : float
Pitch (or elevation) angle (rad).
phi : float
Bank angle (rad).
psi : float
Yaw (or azimuth) angle (rad)
Returns
-------
body_coords : array_like
3 dimensional vector with (x,y,z) coordinates in body axes.
Raises
------
ValueError
If the values of the euler angles are outside the proper ranges.
See Also
--------
`body2hor` function.
Notes
-----
See [1] or [2] for frame of reference definition.
Note that in order to avoid ambiguities ranges in angles are limited to:
* -pi/2 <= theta <= pi/2
* -pi <= phi <= pi
* 0 <= psi <= 2*pi
References
----------
.. [1] B. Etkin, "Dynamics of Atmospheric Flight," Courier Corporation,
pp. 104-120, 2012.
.. [2] Gómez Tierno, M.A. et al, "Mecánica del Vuelo," Garceta, pp. 1-12,
2012
"""

check_theta_phi_psi_range(theta, phi, psi)

# Transformation matrix local horizon to body
Lbh = np.array([
[cos(theta) * cos(psi),
cos(theta) * sin(psi),
- sin(theta)],
[sin(phi) * sin(theta) * cos(psi) - cos(phi) * sin(psi),
sin(phi) * sin(theta) * sin(psi) + cos(phi) * cos(psi),
sin(phi) * cos(theta)],
[cos(phi) * sin(theta) * cos(psi) + sin(phi) * sin(psi),
cos(phi) * sin(theta) * sin(psi) - sin(phi) * cos(psi),
cos(phi) * cos(theta)]
])

body_coords = Lbh.dot(hor_coords)

return body_coords
Empty file.
92 changes: 92 additions & 0 deletions src/pyfme/utils/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
"""
Frames of Reference orientation test functions
"""
import pytest

import numpy as np
from numpy.testing import (assert_equal, assert_almost_equal,
assert_array_equal, assert_array_almost_equal)


from pyfme.utils.coordinates import (body2hor, hor2body,
check_theta_phi_psi_range)


def test_check_theta_phi_psi_range():

wrong_values = (3 * np.pi, - 3 * np.pi)

for value in wrong_values:
# 0 is always a correct value
angles = [0, 0, 0]
for ii in range(3):
angles[ii] = value
with pytest.raises(ValueError):
check_theta_phi_psi_range(*angles)


def test_body2hor():

# Test with a pitch rotation
vector_body = np.array([1, 1, 1])
theta, phi, psi = np.deg2rad(45), 0, 0

vector_hor = body2hor(vector_body, theta, phi, psi)

vector_hor_expected = np.array([2 * 0.70710678118654757, 1, 0])

assert_array_almost_equal(vector_hor, vector_hor_expected)

# Test with a roll rotation
vector_body = np.array([1, 1, 1])
theta, phi, psi = 0, np.deg2rad(45), 0

vector_hor = body2hor(vector_body, theta, phi, psi)

vector_hor_expected = np.array([1, 0, 2 * 0.70710678118654757])

assert_array_almost_equal(vector_hor, vector_hor_expected)

# Test with a yaw rotation
vector_body = np.array([1, 1, 1])
theta, phi, psi = 0, 0, np.deg2rad(45)

vector_hor = body2hor(vector_body, theta, phi, psi)

vector_hor_expected = np.array([0, 2 * 0.70710678118654757, 1])

assert_array_almost_equal(vector_hor, vector_hor_expected)


def test_hor2body():

# Test with a pitch rotation
vector_hor = np.array([2 * 0.70710678118654757, 1, 0])
theta, phi, psi = np.deg2rad(45), 0, 0

vector_body_expected = np.array([1, 1, 1])

vector_body = hor2body(vector_hor, theta, phi, psi)

assert_array_almost_equal(vector_body, vector_body_expected)

# Test with a roll rotation
vector_hor = np.array([1, 0, 2 * 0.70710678118654757])
theta, phi, psi = 0, np.deg2rad(45), 0

vector_body_expected = np.array([1, 1, 1])

vector_body = hor2body(vector_hor, theta, phi, psi)

assert_array_almost_equal(vector_body, vector_body_expected)

# Test with a yaw rotation
vector_hor = np.array([0, 2 * 0.70710678118654757, 1])
theta, phi, psi = 0, 0, np.deg2rad(45)

vector_body_expected = np.array([1, 1, 1])

vector_body = hor2body(vector_hor, theta, phi, psi)

assert_array_almost_equal(vector_body, vector_body_expected)

0 comments on commit 19a4b0c

Please sign in to comment.