Skip to content

Attitude Dynamics

Rigid-body attitude dynamics for spacecraft attitude propagation.

Provides torque models and a configurable dynamics factory for propagating the attitude state (quaternion + angular velocity) of a rigid spacecraft:

  • Euler dynamics: Quaternion kinematics and Euler's rotational equation
  • Gravity gradient: Gravity gradient torque model
  • Factory: Composable dynamics function compatible with all integrators
  • Utilities: State normalization helpers

AttitudeDynamicsConfig dataclass

Configuration for composable attitude dynamics.

Selects which torque models to include in the dynamics closure returned by :func:~astrojax.attitude_dynamics.factory.create_attitude_dynamics.

Parameters:

Name Type Description Default
inertia SpacecraftInertia

Spacecraft inertia tensor.

SpacecraftInertia()
gravity_gradient bool

Enable gravity gradient torque.

False
mu float

Gravitational parameter [m3/s2] for gravity gradient.

GM_EARTH

Examples:

from astrojax.attitude_dynamics.config import AttitudeDynamicsConfig
config = AttitudeDynamicsConfig.torque_free(
    SpacecraftInertia.from_principal(10.0, 20.0, 30.0)
)
config.gravity_gradient

torque_free(inertia) staticmethod

Preset: torque-free rigid body rotation.

Parameters:

Name Type Description Default
inertia SpacecraftInertia

Spacecraft inertia tensor.

required

Returns:

Name Type Description
AttitudeDynamicsConfig AttitudeDynamicsConfig

Configuration with no external torques.

Examples:

config = AttitudeDynamicsConfig.torque_free(
    SpacecraftInertia.from_principal(10.0, 20.0, 30.0)
)
config.gravity_gradient

with_gravity_gradient(inertia, mu=GM_EARTH) staticmethod

Preset: rigid body with gravity gradient torque.

Parameters:

Name Type Description Default
inertia SpacecraftInertia

Spacecraft inertia tensor.

required
mu float

Gravitational parameter [m3/s2].

GM_EARTH

Returns:

Name Type Description
AttitudeDynamicsConfig AttitudeDynamicsConfig

Configuration with gravity gradient enabled.

Examples:

config = AttitudeDynamicsConfig.with_gravity_gradient(
    SpacecraftInertia.from_principal(10.0, 20.0, 30.0)
)
config.gravity_gradient

SpacecraftInertia dataclass

Rigid-body inertia tensor of the spacecraft.

Stores the 3x3 inertia tensor in the body frame. For most spacecraft the tensor is diagonal (principal axes aligned with body axes) and can be constructed with :meth:from_principal.

Parameters:

Name Type Description Default
I Array

3x3 inertia tensor [kg m^2].

(lambda: eye(3, dtype=get_dtype()))()

Examples:

from astrojax.attitude_dynamics.config import SpacecraftInertia
inertia = SpacecraftInertia.from_principal(100.0, 200.0, 300.0)
inertia.I.shape

from_principal(Ixx, Iyy, Izz) staticmethod

Create an inertia tensor from principal moments.

Parameters:

Name Type Description Default
Ixx float

Moment of inertia about the body x-axis [kg m^2].

required
Iyy float

Moment of inertia about the body y-axis [kg m^2].

required
Izz float

Moment of inertia about the body z-axis [kg m^2].

required

Returns:

Name Type Description
SpacecraftInertia SpacecraftInertia

Diagonal inertia tensor.

Examples:

inertia = SpacecraftInertia.from_principal(10.0, 20.0, 30.0)
float(inertia.I[0, 0])

create_attitude_dynamics(config, position_fn)

Create a configurable attitude dynamics function.

Returns a closure dynamics(t, state) -> derivative that computes the time-derivative of a 7-element attitude state vector, composing the selected torque models from config.

The returned function is compatible with all astrojax integrators (rk4_step, rkf45_step, dp54_step).

Parameters:

Name Type Description Default
config AttitudeDynamicsConfig

Attitude dynamics configuration.

required
position_fn Callable[[ArrayLike], Array]

Callable position_fn(t) -> Array(3,) returning the spacecraft ECI position at time t [m]. Required even for torque-free motion (not called if unused).

required

Returns:

Type Description
Callable[[ArrayLike, ArrayLike], Array]

A callable dynamics(t, state) -> derivative where:

Callable[[ArrayLike, ArrayLike], Array]
  • t: time (scalar), typically seconds since a reference epoch.
Callable[[ArrayLike, ArrayLike], Array]
  • state: [q_w, q_x, q_y, q_z, omega_x, omega_y, omega_z], shape (7,).
Callable[[ArrayLike, ArrayLike], Array]
  • derivative: [dq_w, dq_x, dq_y, dq_z, domega_x, domega_y, domega_z], shape (7,).

Examples:

import jax.numpy as jnp
from astrojax.attitude_dynamics.config import (
    AttitudeDynamicsConfig, SpacecraftInertia,
)
from astrojax.attitude_dynamics.factory import create_attitude_dynamics
from astrojax.integrators import rk4_step
inertia = SpacecraftInertia.from_principal(10.0, 20.0, 30.0)
config = AttitudeDynamicsConfig.torque_free(inertia)
pos_fn = lambda t: jnp.array([7000e3, 0.0, 0.0])
dynamics = create_attitude_dynamics(config, pos_fn)
x0 = jnp.array([1.0, 0.0, 0.0, 0.0, 0.1, 0.0, 0.0])
result = rk4_step(dynamics, 0.0, x0, 1.0)

euler_equation(omega, I, tau)

Compute angular acceleration from Euler's rotational equation.

Euler's equation for a rigid body::

I @ omega_dot = -omega x (I @ omega) + tau
omega_dot = I^{-1} @ (-omega x (I @ omega) + tau)

Uses jnp.linalg.solve instead of an explicit inverse for numerical stability.

Parameters:

Name Type Description Default
omega ArrayLike

Angular velocity in the body frame [wx, wy, wz] of shape (3,) [rad/s].

required
I ArrayLike

Inertia tensor of shape (3, 3) [kg m^2].

required
tau ArrayLike

Total external torque in the body frame [tx, ty, tz] of shape (3,) [N m].

required

Returns:

Type Description
Array

Angular acceleration [dwx, dwy, dwz] of shape (3,) [rad/s^2].

Examples:

import jax.numpy as jnp
omega = jnp.array([0.1, 0.0, 0.0])
I = jnp.diag(jnp.array([10.0, 20.0, 30.0]))
tau = jnp.zeros(3)
omega_dot = euler_equation(omega, I, tau)
omega_dot.shape

normalize_attitude_state(state)

Renormalize the quaternion portion of an attitude state vector.

Numerical integration causes the quaternion norm to drift from unity. This function normalizes the quaternion [w, x, y, z] (elements 0--3) while leaving the angular velocity (elements 4--6) unchanged.

Parameters:

Name Type Description Default
state ArrayLike

Attitude state [q_w, q_x, q_y, q_z, wx, wy, wz] of shape (7,).

required

Returns:

Type Description
Array

State with normalized quaternion, shape (7,).

Examples:

import jax.numpy as jnp
state = jnp.array([1.001, 0.0, 0.0, 0.0, 0.1, 0.0, 0.0])
normed = normalize_attitude_state(state)
float(jnp.linalg.norm(normed[:4]))

quaternion_derivative(q, omega)

Compute the quaternion time-derivative from angular velocity.

Uses the 4x4 Omega matrix form::

q_dot = 0.5 * Omega(omega) @ q

where the Omega matrix for scalar-first [w, x, y, z] quaternions is::

    [  0   -wx  -wy  -wz ]
O = [ wx    0    wz  -wy ]
    [ wy  -wz    0    wx ]
    [ wz   wy  -wx    0  ]

Parameters:

Name Type Description Default
q ArrayLike

Unit quaternion [w, x, y, z] of shape (4,).

required
omega ArrayLike

Angular velocity in the body frame [wx, wy, wz] of shape (3,) [rad/s].

required

Returns:

Type Description
Array

Quaternion derivative of shape (4,).

Examples:

import jax.numpy as jnp
q = jnp.array([1.0, 0.0, 0.0, 0.0])  # identity
omega = jnp.array([0.0, 0.0, 0.1])    # yaw rate
q_dot = quaternion_derivative(q, omega)
q_dot.shape

torque_gravity_gradient(q, r_eci, I, mu=GM_EARTH)

Compute the gravity gradient torque in the body frame.

Parameters:

Name Type Description Default
q ArrayLike

Unit quaternion [w, x, y, z] of shape (4,) representing the body-to-inertial rotation.

required
r_eci ArrayLike

Spacecraft position in ECI of shape (3,) [m].

required
I ArrayLike

Inertia tensor of shape (3, 3) [kg m^2].

required
mu float

Gravitational parameter [m3/s2].

GM_EARTH

Returns:

Type Description
Array

Gravity gradient torque in the body frame of shape (3,) [N m].

Examples:

import jax.numpy as jnp
q = jnp.array([1.0, 0.0, 0.0, 0.0])
r_eci = jnp.array([7000e3, 0.0, 0.0])
I = jnp.diag(jnp.array([10.0, 20.0, 30.0]))
tau = torque_gravity_gradient(q, r_eci, I)
tau.shape