angutils

angutils provides routines for operating on 3D Euclidean vectors and computing a variety of angles and projections. The majority of the routines provided by this package are numerical versions of the equivalent symbolic routines provided by package sympyhelpers (https://sympyhelpers.readthedocs.io/en/latest/).

Installation

To install from PyPI:

pip install angutils

To install from source, clone or download the code repository, and, in the top level directory run:

pip install .

Notational Conventions

The following notational conventions are adopted throughout the code and documentation:

  • All matrices are represented by uppercase unbolded letters (\(A\))

  • All vectors are represented by lowercase bolded letters (\(\mathbf v\)). All vectors are assumed to be Euclidean (\(\mathbb{R}^3\))

  • Unit vectors are represented by lowercase bolded letters with hats (\({\hat{\mathbf{v}}}\) is the unit vector of \(\mathbf v\))

  • Vector norms are denoted by \(\Vert \mathbf v \Vert\) such that \(\mathbf v = \Vert \mathbf v \Vert {\hat{\mathbf{v}}}\)

  • Reference frames are represented by calligraphic capital letters (\(\mathcal A\)) and defined by a set of three mutually orthogonal unit vectors such that \(\mathcal A = ({\hat{\mathbf{a}}}_1, {\hat{\mathbf{a}}}_2, {\hat{\mathbf{a}}}_3)\) implies that \({\hat{\mathbf{a}}}_1\times {\hat{\mathbf{a}}}_2 = {\hat{\mathbf{a}}_3}\). All reference frames are dextral

  • The component representation of any vector \(\mathbf v\) in reference frame \(\mathcal I\) is given by \([\mathbf v]_\mathcal I\) and is assumed to be a (3x1) column matrix

  • Direction cosine matrices (DCMs) are defined as \({{\vphantom{C}}^{\mathcal{B}}\!{C}^{\mathcal{A}}}\) such that:

    \[[\mathbf v]_\mathcal B = {{\vphantom{C}}^{\mathcal{B}}\!{C}^{\mathcal{A}}}[\mathbf v]_\mathcal A\]
  • The inverse of a direction cosine matrix is its transpose and is denoted by switching the order of the superscripts:

    \[\left({{\vphantom{C}}^{\mathcal{B}}\!{C}^{\mathcal{A}}}\right)^{-1} \equiv \left({{\vphantom{C}}^{\mathcal{B}}\!{C}^{\mathcal{A}}}\right)^T = {{\vphantom{C}}^{\mathcal{A}}\!{C}^{\mathcal{B}}}\]

Relationship Between DCMs and Rotation Matrices

This often causes a lot of confusion, as DCMs and 3D rotation matrices have essentially the same form and content, but serve different purposes. A DCM maps the components of a vector expressed in one reference frame to components of the same vector expressed in a different reference frame (this is equivalent to a change of basis). A rotation matrix operates on the components of a vector in one reference frames to return the components of a different vector in the same frame (the new vector is rotated from the original vector by the angle encoded by the rotation matrix and has the same magnitude as the original vector).

The action of the DCM is encoded in the notational conventions, above. The rotation matrix can best be understood by positing a dyadic (second-order tensor) \(\mathbb{R}\) such that:

\[\mathbf{b} = \mathbb{R} \cdot \mathbf{a}\]

where \(\mathbf{b}\) is \(\mathbf{a}\), rotated by some angle \(\theta\) about an axis \(\mathbf{\hat{n}}\). If we express \(\mathbb{R}\) in components of some frame \(\mathcal{A}\), then we get a matrix whose contents match the DCM \({{\vphantom{C}}^{\mathcal{A}}\!{C}^{\mathcal{B}}}\). Thus, rotation matrices and DCMs are essentially transposes of one another.

Error Quantification

As we have two methods that are effective inverses of one another (calcDCM() and DCM2axang()), we can check the numerical errors associated with conversions between axis/angle and DCM representations of the same rotations.

pic1 pic2

These figures show the absolute error in angle (left) and maximum absolute error in axis component when converting from an initial axis/angle representation to a DCM and then inverting the process. As expected, errors are functions of the angle, and peak around multiples of \(\pi\).

The other pair of methods that serve as mutual inverses are EulerAng2DCM() and DCM2EulerAng(). Here, however, a direct comparison is more difficult, as Euler angle sets are not guaranteed to be unique (e.g., there is a \(\pi\) radian ambiguity in all terms of an Euler angle set associated with a specific rotation order. Instead of directly comparing angle inputs to EulerAng2DCM() to the angle outputs of DCM2EulerAng(), we can instead use those outputs to re-compute the DCM, and then compare the entries of the two DCMs. Carrying out this exercise (which is implemented in the unit tests for the package) shows that all pairs of DCM entries produced in this fashion have a guaranteed maximum error of 1e-15.