In [7]:
from IPython.display import Latex, display
from TSatPy.State import Quaternion, Identity
def show(latex):
    display(Latex(r'\begin{equation}%s\end{equation}' % latex))

In [2]:
# from IPython.display import Latex, display
# from IPython.core.display import Image
# from TSatPy.State import Quaternion, Identity

Quaternion

A quaternion is a 4-tuple invented by William Rowan Hamilton. His goal was to extend the concept of complex numbers into higher diminsions. The commonly know complex number is a sum of one real number and one imaginary number. Converting an imaginary number to a real can be accomplished by taking the square of the value. $(1\textbf{i} + 0)\times(1\textbf{i} + 0) = -1$

Hamilton was unable to extend the concept into three dimensions, but was able to define a 4-tuple that behaved similarly to the common complex number such that $ \textbf{i} \otimes \textbf{i} = \textbf{j} \otimes \textbf{j} = \textbf{k} \otimes \textbf{k} = \textbf{i} \otimes \textbf{j} \otimes \textbf{k} = -1 $.

The 4-tuple Hamilton discribed also follows the following definitions under multiplication.

$$\begin{align} \textbf{i} \otimes \textbf{j} &= \textbf{k} \\ \textbf{j} \otimes \textbf{k} &= \textbf{i} \\ \textbf{k} \otimes \textbf{i} &= \textbf{j} \end{align}$$


In [9]:
q = Quaternion([1, 4, 3], 4)
show('q=%s' % q.latex())


\begin{equation}q=1 \boldsymbol{i} +4 \boldsymbol{j} +3 \boldsymbol{k} +4\end{equation}
$$\begin{align} \textbf{i} \otimes \textbf{i} &= \textbf{j} \otimes \textbf{j} = \textbf{k} \otimes \textbf{k} = \textbf{i} \otimes \textbf{j} \otimes \textbf{k} = -1 \\ \textbf{i} \otimes \textbf{j} &= \textbf{k} \\ \textbf{j} \otimes \textbf{k} &= \textbf{i} \\ \textbf{k} \otimes \textbf{i} &= \textbf{j} \end{align}$$

Multiplication


In [10]:
qi = Quaternion([1, 0, 0], 0)
qj = Quaternion([0, 1, 0], 0)
qk = Quaternion([0, 0, 1], 0)

In [11]:
q_defs = [[qi, qi],
          [qj, qj],
          [qk, qk],
          [qi, qj, qk],
          [qi, qj],
          [qj, qk],
          [qk, qi]]
eqs = []
for q_def in q_defs:
    if len(q_def) == 2:
        prod = q_def[0] * q_def[1]
    elif len(q_def) == 3:
        prod = q_def[0] * q_def[1] * q_def[2]
    eqs.append(' %s &= %s ' % (' \otimes '.join(['(%s)' % q.latex() for q in q_def]), prod.latex()))

display(Latex(r'\begin{align} %s \end{align}' % r' \\ '.join(eqs)))


\begin{align} (1 \boldsymbol{i} +0 \boldsymbol{j} +0 \boldsymbol{k} +0) \otimes (1 \boldsymbol{i} +0 \boldsymbol{j} +0 \boldsymbol{k} +0) &= 0 \boldsymbol{i} +0 \boldsymbol{j} +0 \boldsymbol{k} -1 \\ (0 \boldsymbol{i} +1 \boldsymbol{j} +0 \boldsymbol{k} +0) \otimes (0 \boldsymbol{i} +1 \boldsymbol{j} +0 \boldsymbol{k} +0) &= 0 \boldsymbol{i} +0 \boldsymbol{j} +0 \boldsymbol{k} -1 \\ (0 \boldsymbol{i} +0 \boldsymbol{j} +1 \boldsymbol{k} +0) \otimes (0 \boldsymbol{i} +0 \boldsymbol{j} +1 \boldsymbol{k} +0) &= 0 \boldsymbol{i} +0 \boldsymbol{j} +0 \boldsymbol{k} -1 \\ (1 \boldsymbol{i} +0 \boldsymbol{j} +0 \boldsymbol{k} +0) \otimes (0 \boldsymbol{i} +1 \boldsymbol{j} +0 \boldsymbol{k} +0) \otimes (0 \boldsymbol{i} +0 \boldsymbol{j} +1 \boldsymbol{k} +0) &= 0 \boldsymbol{i} +0 \boldsymbol{j} +0 \boldsymbol{k} -1 \\ (1 \boldsymbol{i} +0 \boldsymbol{j} +0 \boldsymbol{k} +0) \otimes (0 \boldsymbol{i} +1 \boldsymbol{j} +0 \boldsymbol{k} +0) &= 0 \boldsymbol{i} +0 \boldsymbol{j} +1 \boldsymbol{k} +0 \\ (0 \boldsymbol{i} +1 \boldsymbol{j} +0 \boldsymbol{k} +0) \otimes (0 \boldsymbol{i} +0 \boldsymbol{j} +1 \boldsymbol{k} +0) &= 1 \boldsymbol{i} +0 \boldsymbol{j} +0 \boldsymbol{k} +0 \\ (0 \boldsymbol{i} +0 \boldsymbol{j} +1 \boldsymbol{k} +0) \otimes (1 \boldsymbol{i} +0 \boldsymbol{j} +0 \boldsymbol{k} +0) &= 0 \boldsymbol{i} +1 \boldsymbol{j} +0 \boldsymbol{k} +0 \end{align}

Rotational Quaternion

Since a quaternion has 4 scalar quantities, there are an infinite number of quaternions that can be used to represent a single attitude. For example, starting with a standard orientation with the body's axes aligned with the global coorinate axes and rotating 90 degrees about the z-axis is the same orientation as rotating 450 degrees and any $90 + n (360) \deg$ for all integers n. Depending on the situation this project attempts to keep the angle representation between $0 \le x < 2\pi$ or $-\pi \le x < \pi$.

An additional restriction that is placed on rotational quaternions is that the norm of the quaternion is equal to one for any attitude representation.

$$ \begin{equation} \left\| \boldsymbol{q} \right\| = \sqrt{\boldsymbol{q_v} \cdot \boldsymbol{q_v} + q_0^2} = 1 \end{equation} $$

Creating a Rotational Quaternion

For a rotation of $\theta$ radians about the axis $[x, y, z]^T$, the corresponding rotation quaternion is defined as

$$ \begin{equation} \begin{bmatrix} \boldsymbol{q_v} \\ q_0 \end{bmatrix} = \begin{bmatrix} [x, y, z]^T \sin(-\theta/2) \\ \cos(-\theta/2) \end{bmatrix} \end{equation} $$

The negative $\theta$ value for the angle is chosen to rotate the satellite's body instead of the standard positive usage which would rotate the global axes by the specified angle and in simulations with a fixed global reference frame would make TSat appear to be rotating in the opposite direction.


In [ ]: