Skip to content

Quaternion Math Module Documentation

This module provides functions to work in the quaternion representation of rotations, as the double cover of the special orthogonal group SO(3).

Functions:

Name Description
left_qmatrix

Compute the left quaternion product matrix for a quaternion.

right_qmatrix

Compute the right quaternion product matrix for a quaternion.

quat_conj

Compute the conjugate of a quaternion.

quat_inv

Compute the inverse of a quaternion.

quat_normalize

Normalize a quaternion to unit norm.

quat_positive_scalar

Ensure a quaternion has a positive scalar component.

Compute the left quaternion product matrix for a given quaternion, such that q * p = L(q) * p. For a quaternion q = (x, y, z, w) under the JPL convention, the left quaternion product matrix is defined as:

\[ L(q) = \begin{bmatrix} w & -z & y & x \\ z & w & -x & y \\ -y & x & w & z \\ -x & -y & -z & w \end{bmatrix} \]

Parameters:

Name Type Description Default
quat Union[ndarray, Iterable[float]]

The quaternion as a numpy array or as a list in the order (x, y, z, w).

required

Returns:

Name Type Description
left_quat_product_matrix ndarray

The left quaternion product matrix as a (4, 4) numpy array.

Raises:

Type Description
ValueError

If the input quaternion is not a 4-element numpy array or list.

ValueError

If the input quaternion is not normalized.

TypeError

If the input quaternion is not a numpy array or list.

Source code in navlib/math/quaternion.py
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
def left_qmatrix(quat: Union[np.ndarray, Iterable[float]]) -> np.ndarray:
    """
    Compute the left quaternion product matrix for a given quaternion, such that
    q * p = L(q) * p. For a quaternion q = (x, y, z, w)  under the JPL convention,
    the left quaternion product matrix is defined as:

    $$
    L(q) =
    \\begin{bmatrix}
        w & -z & y & x \\\\
        z & w & -x & y \\\\
        -y & x & w & z \\\\
        -x & -y & -z & w
    \\end{bmatrix}
    $$

    Args:
        quat (Union[np.ndarray, Iterable[float]]): The quaternion as a numpy array or as a list in the order
            (x, y, z, w).

    Returns:
        left_quat_product_matrix (np.ndarray): The left quaternion product matrix as a (4, 4) numpy array.

    Raises:
        ValueError: If the input quaternion is not a 4-element numpy array or list.
        ValueError: If the input quaternion is not normalized.
        TypeError: If the input quaternion is not a numpy array or list.
    """
    # Convert to numpy array if input is a list
    if isinstance(quat, list):
        quat = np.array(quat)

    # Check if the input is a numpy array
    if not isinstance(quat, np.ndarray):
        raise TypeError("The quaternion must be a numpy array or a list.")

    # Check if the input quaternion has 4 elements
    quat = quat.squeeze()
    if quat.shape[0] != 4:
        raise ValueError("The quaternion must have 4 elements.")
    if quat.ndim != 1:
        raise ValueError("The quaternion must be a 1-dimensional numpy array or list.")

    # Check if the quaternion is normalized
    if abs(np.linalg.norm(quat) - 1.0) >= 1e-6:
        raise ValueError("The quaternion must be normalized.")

    # Extract quaternion components
    x, y, z, w = quat[0], quat[1], quat[2], quat[3]

    # Construct the left quaternion product matrix
    left_quat_product_matrix = np.array(
        [
            [w, -z, y, x],
            [z, w, -x, y],
            [-y, x, w, z],
            [-x, -y, -z, w],
        ]
    )
    return left_quat_product_matrix

Compute the conjugate of a quaternion under the JPL convention (x, y, z, w).

Parameters:

Name Type Description Default
q Union[ndarray, Iterable[float]]

Input quaternion as a list or numpy array (x, y, z, w).

required

Returns:

Type Description
ndarray

np.ndarray: The conjugated quaternion.

Source code in navlib/math/quaternion.py
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
def quat_conj(q: Union[np.ndarray, Iterable[float]]) -> np.ndarray:
    """
    Compute the conjugate of a quaternion under the JPL convention (x, y, z, w).

    Args:
        q (Union[np.ndarray, Iterable[float]]): Input quaternion as a list or numpy array (x, y, z, w).

    Returns:
        np.ndarray: The conjugated quaternion.
    """
    if isinstance(q, list):
        q = np.array(q)
    if not isinstance(q, np.ndarray):
        raise TypeError("The quaternion must be a numpy array or list.")
    q = q.squeeze()
    if q.shape[0] != 4:
        raise ValueError("The quaternion must have 4 elements.")
    if q.ndim != 1:
        raise ValueError("The quaternion must be a 1-dimensional array.")

    return np.array([-q[0], -q[1], -q[2], q[3]])

Compute the inverse of a quaternion under the JPL convention (x, y, z, w).

Parameters:

Name Type Description Default
q Union[ndarray, Iterable[float]]

Input quaternion as a list or numpy array (x, y, z, w).

required

Returns:

Type Description
ndarray

np.ndarray: The inverted quaternion.

Source code in navlib/math/quaternion.py
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
def quat_inv(q: Union[np.ndarray, Iterable[float]]) -> np.ndarray:
    """
    Compute the inverse of a quaternion under the JPL convention (x, y, z, w).

    Args:
        q (Union[np.ndarray, Iterable[float]]): Input quaternion as a list or numpy array (x, y, z, w).

    Returns:
        np.ndarray: The inverted quaternion.
    """
    if isinstance(q, list):
        q = np.array(q)
    if not isinstance(q, np.ndarray):
        raise TypeError("The quaternion must be a numpy array or list.")
    q = q.squeeze()
    if q.shape[0] != 4:
        raise ValueError("The quaternion must have 4 elements.")
    if q.ndim != 1:
        raise ValueError("The quaternion must be a 1-dimensional array.")

    return quat_conj(q) / np.dot(q, q)

Normalize a quaternion to unit norm under the JPL convention (x, y, z, w).

Parameters:

Name Type Description Default
q Union[ndarray, Iterable[float]]

Input quaternion as a list or numpy array (x, y, z, w).

required

Returns:

Type Description
ndarray

np.ndarray: The normalized quaternion.

Source code in navlib/math/quaternion.py
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
def quat_normalize(q: Union[np.ndarray, Iterable[float]]) -> np.ndarray:
    """
    Normalize a quaternion to unit norm under the JPL convention (x, y, z, w).

    Args:
        q (Union[np.ndarray, Iterable[float]]): Input quaternion as a list or numpy array (x, y, z, w).

    Returns:
        np.ndarray: The normalized quaternion.
    """
    if isinstance(q, list):
        q = np.array(q)
    if not isinstance(q, np.ndarray):
        raise TypeError("The quaternion must be a numpy array or list.")
    q = q.squeeze()
    if q.shape[0] != 4:
        raise ValueError("The quaternion must have 4 elements.")
    if q.ndim != 1:
        raise ValueError("The quaternion must be a 1-dimensional array.")

    norm_q = np.linalg.norm(q)
    if norm_q < 1e-8:
        raise ValueError("The quaternion norm is too close to zero to normalize.")
    return q / norm_q

Ensure that a quaternion has a positive scalar component (w > 0), flipping its sign if needed. This removes ambiguity from double coverage.

Parameters:

Name Type Description Default
q Union[ndarray, Iterable[float]]

Input quaternion (x, y, z, w).

required

Returns:

Type Description
ndarray

np.ndarray: Quaternion with positive scalar part.

Source code in navlib/math/quaternion.py
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
def quat_positive_scalar(q: Union[np.ndarray, Iterable[float]]) -> np.ndarray:
    """
    Ensure that a quaternion has a positive scalar component (w > 0),
    flipping its sign if needed. This removes ambiguity from double coverage.

    Args:
        q (Union[np.ndarray, Iterable[float]]): Input quaternion (x, y, z, w).

    Returns:
        np.ndarray: Quaternion with positive scalar part.
    """
    if isinstance(q, list):
        q = np.array(q)
    if not isinstance(q, np.ndarray):
        raise TypeError("The quaternion must be a numpy array or list.")
    q = q.squeeze()
    if q.shape[0] != 4:
        raise ValueError("The quaternion must have 4 elements.")
    if q.ndim != 1:
        raise ValueError("The quaternion must be a 1-dimensional array.")

    return q if q[3] >= 0.0 else -q

Compute the right quaternion product matrix for a given quaternion, such that q * p = R(p) * q For a quaternion q = (x, y, z, w) under the JPL convention, the right quaternion product matrix is defined as:

\[ R(q) = \begin{bmatrix} w & z & -y & x \\ -z & w & x & y \\ y & -x & w & z \\ -x & -y & -z & w \end{bmatrix} \]

Parameters:

Name Type Description Default
quat Union[ndarray, Iterable[float]]

The quaternion as a numpy array or as a list in the order (x, y, z, w).

required

Returns:

Name Type Description
right_quat_product_matrix ndarray

The right quaternion product matrix as a (4, 4) numpy array.

Raises:

Type Description
ValueError

If the input quaternion is not a 4-element numpy array or list.

ValueError

If the input quaternion is not normalized.

TypeError

If the input quaternion is not a numpy array or list.

Source code in navlib/math/quaternion.py
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
def right_qmatrix(quat: Union[np.ndarray, Iterable[float]]) -> np.ndarray:
    """
    Compute the right quaternion product matrix for a given quaternion, such that
    q * p = R(p) * q For a quaternion q = (x, y, z, w) under the JPL convention,
    the right quaternion product matrix is defined as:

    $$
    R(q) =
    \\begin{bmatrix}
        w & z & -y & x \\\\
        -z & w & x & y \\\\
        y & -x & w & z \\\\
        -x & -y & -z & w
    \\end{bmatrix}
    $$

    Args:
        quat (Union[np.ndarray, Iterable[float]]): The quaternion as a numpy array or as a list in the order
            (x, y, z, w).

    Returns:
        right_quat_product_matrix (np.ndarray): The right quaternion product matrix as a (4, 4) numpy array.

    Raises:
        ValueError: If the input quaternion is not a 4-element numpy array or list.
        ValueError: If the input quaternion is not normalized.
        TypeError: If the input quaternion is not a numpy array or list.
    """
    # Convert to numpy array if input is a list
    if isinstance(quat, list):
        quat = np.array(quat)

    # Check if the input is a numpy array
    if not isinstance(quat, np.ndarray):
        raise TypeError("The quaternion must be a numpy array or a list.")

    # Check if the input quaternion has 4 elements
    quat = quat.squeeze()
    if quat.shape[0] != 4:
        raise ValueError("The quaternion must have 4 elements.")
    if quat.ndim != 1:
        raise ValueError("The quaternion must be a 1-dimensional numpy array or list.")

    # Check if the quaternion is normalized
    if abs(np.linalg.norm(quat) - 1.0) >= 1e-6:
        raise ValueError("The quaternion must be normalized.")

    # Extract quaternion components
    x, y, z, w = quat[0], quat[1], quat[2], quat[3]

    # Construct the right quaternion product matrix
    right_quat_product_matrix = np.array(
        [
            [w, z, -y, x],
            [-z, w, x, y],
            [y, -x, w, z],
            [-x, -y, -z, w],
        ]
    )
    return right_quat_product_matrix