Skip to content

API

Reference Frames

Reference Frames module.

This module provides utilities for computing various reference frames used in the Perseo framework, including:

  • Geocentric Reference Frame
  • Geodetic Reference Frame
  • ZeroDoppler Reference Frame

The main function compute_sensor_local_axis computes the local reference frame for a sensor based on its position, velocity, and the specified reference frame type.

The module also includes functions for computing pointing directions from ARF and antenna angles

Attributes

ReferenceFrame module-attribute

Python
ReferenceFrame = Literal['GEOCENTRIC', 'GEODETIC', 'ZERODOPPLER']

__all__ module-attribute

Python
__all__ = ['ReferenceFrame', 'compute_sensor_local_axis']

Functions:

compute_zerodoppler_reference_frame

Python
compute_zerodoppler_reference_frame(sensor_positions: NDArray[floating], sensor_velocities: NDArray[floating]) -> npt.NDArray[np.floating]

Compute the axes of the ZeroDoppler reference frame.

Sensor positions and velocities are assumed to be expressed in ECEF coordinates.

Reference frame

  • x-unit vector: oriented as sensor non-inertial velocity
  • y-unit vector: given by the cross product between x and sensor position corrected with Earth eccentricity
  • z-unit vector: completing the reference frame

Output frame has x as first column, y as second one and z as the last one. e.g. ux = zero_doppler_frame[..., 0], uy = zero_doppler_frame[..., 1], uz = zero_doppler_frame[..., 2]

Parameters:

Name Type Description Default
sensor_positions NDArray[floating]

sensor positions, with shape (3,) or (N, 3)

required
sensor_velocities NDArray[floating]

sensor velocities, with shape (3,) or (N, 3)

required

Returns:

Type Description
NDArray[floating]

zero doppler axes for each sensor position, with shape (3, 3) or (N, 3, 3) stored as columns of the output array.

Raises:

Type Description
ValueError

in case of invalid input

compute_geocentric_reference_frame

Python
compute_geocentric_reference_frame(sensor_positions: NDArray[floating], sensor_velocities: NDArray[floating]) -> npt.NDArray[np.floating]

Compute the axes of the geocentric reference frame.

Sensor positions and velocities are assumed to be expressed in ECEF coordinates.

Reference frame

  • x-unit vector: completing the reference frame
  • y-unit vector: given by the cross product between z and sensor inertial velocity
  • z-unit vector: oriented as -sat_pos

Output frame has x as first column, y as second one and z as the last one. e.g. ux = geocentric_frame[..., 0], uy = geocentric_frame[..., 1], uz = geocentric_frame[..., 2]

Parameters:

Name Type Description Default
sensor_positions NDArray[floating]

sensor positions, with shape (3,) or (N, 3)

required
sensor_velocities NDArray[floating]

sensor velocities, with shape (3,) or (N, 3)

required

Returns:

Type Description
NDArray[floating]

geocentric reference frame for each sensor position, with shape (3, 3) or (N, 3, 3) stored as columns of the output array.

compute_geodetic_reference_frame

Python
compute_geodetic_reference_frame(sensor_positions: NDArray[floating], sensor_velocities: NDArray[floating]) -> npt.NDArray[np.floating]

Compute the axes of the geodetic reference frame.

Sensor positions and velocities are assumed to be expressed in ECEF coordinates.

Output frame has x as first column, y as second one and z as the last one. e.g. ux = geodetic_frame[..., 0], uy = geodetic_frame[..., 1], uz = geodetic_frame[..., 2]

Parameters:

Name Type Description Default
sensor_positions NDArray[floating]

sensor positions, with shape (3,) or (N, 3)

required
sensor_velocities NDArray[floating]

sensor velocities, with shape (3,) or (N, 3)

required

Returns:

Type Description
NDArray[floating]

geodetic reference frame for each sensor position, with shape (3, 3) or (N, 3, 3) stored as columns of the output array.

compute_sensor_local_axis

Python
compute_sensor_local_axis(sensor_positions: NDArray[floating], sensor_velocities: NDArray[floating], reference_frame: ReferenceFrame) -> npt.NDArray[np.floating]

Compute the axes of the sensor reference frame.

Sensor positions and velocities are assumed to be expressed in ECEF coordinates. Reference frame is one of "GEOCENTRIC", "GEODETIC", or "ZERODOPPLER".

Output frame has x as first column, y as second one and z as the last one. e.g. for "ZERODOPPLER" reference frame: ux = zero_doppler_frame[..., 0], uy = zero_doppler_frame[..., 1], uz = zero_doppler_frame[..., 2]

Parameters:

Name Type Description Default
sensor_positions NDArray[floating]

sensor positions, with shape (3,) or (N, 3)

required
sensor_velocities NDArray[floating]

sensor velocities, with shape (3,) or (N, 3)

required
reference_frame ReferenceFrame

reference frame, one of "GEOCENTRIC", "GEODETIC", or "ZERODOPPLER"

required

Returns:

Type Description
NDArray[floating]

sensor local axis as a numpy array with shape (3, 3) or (N, 3, 3)

Examples:

single position and velocity

Python Console Session
>>> print(position.shape)
(3,)
>>> axis = compute_sensor_local_axis(position, velocity, "ZERODOPPLER")
>>> print(axis.shape)
(3, 3)

multiple position and velocity

Python Console Session
>>> print(positions.shape)
(10, 3)
>>> axes = compute_sensor_local_axis(positions, velocities, "ZERODOPPLER")
>>> print(axes.shape)
(10, 3, 3)

compute_inertial_velocity

Python
compute_inertial_velocity(sensor_positions: NDArray[floating], sensor_velocities: NDArray[floating]) -> npt.NDArray[np.floating]

Compute the sensor inertial velocity.

Parameters:

Name Type Description Default
sensor_positions NDArray[floating]

sensor positions, with shape (3,) or (N, 3)

required
sensor_velocities NDArray[floating]

sensor velocities, with shape (3,) or (N, 3)

required

Returns:

Type Description
NDArray[floating]

inertial velocity, one for each sensor position, with shape (3,) or (N, 3)

Raises:

Type Description
ValueError

in case of invalid input

compute_geodetic_point

Python
compute_geodetic_point(sensor_positions: NDArray[floating]) -> npt.NDArray[np.floating]

Compute the geodetic point that corresponds to a sensor position.

Parameters:

Name Type Description Default
sensor_positions NDArray[floating]

sensor positions, with shape (3,) or (N, 3)

required

Returns:

Type Description
NDArray[floating]

geodetic points, with shape (3,) or (N, 3)

Raises:

Type Description
ValueError

sensor positions invalid shape

Rotations

Rotation transformation utilities.

Attributes

RotationOrder module-attribute

Python
RotationOrder = Literal['YPR', 'YRP', 'PRY', 'PYR', 'RYP', 'RPY']

__all__ module-attribute

Python
__all__ = ['RotationOrder', 'euler_angles_to_rotation', 'rotation_to_euler_angles']

Functions:

euler_angles_to_rotation

Python
euler_angles_to_rotation(ypr_rad: NDArray[floating], order: RotationOrder) -> Rotation

Convert input Euler angles in radians to a SciPy Rotation object.

This is the reverse operation of rotation_to_euler_angles.

Parameters:

Name Type Description Default
ypr_rad NDArray[floating]

euler angles in radians with shape (3,) or (N, 3) with yaw, pitch, roll order.

required
order ('YPR', 'YRP', 'PRY', 'PYR', 'RYP', 'RPY')

order of application of the rotations corresponding to the provided euler angles.

required

Returns:

Type Description
Rotation

a SciPy rotation object equivalent to the input euler angles matrix with the specified order

Examples:

single rotation

Python Console Session
>>> rotation = euler_angles_to_rotation(order="YPR", ypr_rad=[[0, 0, np.deg2rad(30.0)]])
>>> print(rotation.as_matrix())
[[ 1.         0.         0.       ]
 [ 0.         0.8660254 -0.5      ]
 [ 0.         0.5        0.8660254]]

multiple rotation

Python Console Session
>>> roll = np.deg2rad(np.arange(10, 26, 5, dtype=float))
>>> euler_angles = np.stack([np.zeros_like(roll), np.zeros_like(roll), roll], axis=-1)
>>> rotation = euler_angles_to_rotation(order="YPR", ypr_rad=euler_angles)
>>> print(rotation.as_matrix().shape)
 (4, 3, 3)

rotation order as string

Python Console Session
>>> euler_angles_to_rotation("YPR", ypr_rad=[[0, 0, np.deg2rad(30.0)]])

rotation_to_euler_angles

Python
rotation_to_euler_angles(rotation: Rotation, order: RotationOrder) -> npt.NDArray[np.floating]

Compute euler angles array from the Rotation object and its rotation order.

This is the reverse operation of euler_angles_to_rotation.

Parameters:

Name Type Description Default
rotation Rotation

rotation matrix from which compute the euler angles

required
order ('YPR', 'YRP', 'PRY', 'PYR', 'RYP', 'RPY')

rotation order corresponding to the provided rotation

required

Returns:

Type Description
NDArray[floating]

euler angles array, (N, 3) with yaw, pitch, roll order.

Antenna Reference Frame

Antenna Reference Frame (ARF) module.

This module provides functions to compute the Antenna Reference Frame (ARF) from rotations and Euler angles, and to extract Euler angles from a given ARF.

Note

The Antenna Reference Frame (ARF) is a 3x3 matrix that represents the orientation of the antenna reference frame.

ARF Matrix Structure

Each column of the ARF matrix represents one axis of the antenna frame expressed in the local frame's coordinates:

\[ ARF = [X_{antenna} | Y_{antenna} | Z_{antenna}] \]

Where:

  • X_antenna: X-axis of the antenna frame (usually along-track direction)
  • Y_antenna: Y-axis of the antenna frame (cross-track direction)
  • Z_antenna: Z-axis of the antenna frame (boresight direction)

Accessing Antenna Reference Frame unit vectors

Individual axes (columns) can be accessed with:

Python
X_antenna = arf[..., 0]  # First column (X-axis)
Y_antenna = arf[..., 1]  # Second column (Y-axis)
Z_antenna = arf[..., 2]  # Third column (Z-axis)

Construction via Euler Angles

The ARF is typically constructed from three sequential rotations (Euler angles):

  1. Yaw (Z-axis rotation): Rotation around the local Z-axis
  2. Pitch (Y-axis rotation): Rotation around the local Y-axis
  3. Roll (X-axis rotation): Rotation around the local X-axis

These rotations are applied in certain order (usually YPR order (Yaw-Pitch-Roll)) to progressively rotate the initial reference frame into the antenna reference frame.

Vector Transformation

To rotate a vector v from the local frame to the antenna frame:

\[ v_{antenna} = ARF \, @ \, v_{local} \]

To rotate back from the antenna frame to the local frame (using transpose/inverse):

\[ v_{local} = ARF.T \, @ \, v_{antenna} \]

This is crucial for SAR processing where understanding antenna orientation relative to satellite motion and Earth's surface is essential.

Examples

Basic usage:

Python
import numpy as np

from perseo_core.geometry.pointing import (
    compute_antenna_reference_frame_from_euler_angles,
    compute_sensor_local_axis,
)

# Define rotation angles
ypr_deg = np.array([5, 1, 30])  # yaw, pitch, roll in degrees
ypr_rad = np.deg2rad(ypr_deg)

# Sensor parameters in ECEF
sensor_positions = np.array([26512.279931507, 1064819.379506800, -7083173.555337110])
sensor_velocities = np.array([7529.609430015988, -342.978175622686, -23.376907795264])

# Compute local axis (ZERODOPPLER reference frame in ECEF)
local_axis = compute_sensor_local_axis(
    sensor_positions=sensor_positions,
    sensor_velocities=sensor_velocities,
    reference_frame="ZERODOPPLER",
)

# Compute antenna reference frame (ARF) from Euler angles
arf = compute_antenna_reference_frame_from_euler_angles(
    rotation_order="YPR",
    ypr_rad=ypr_rad,
    initial_reference_frame=local_axis,
)

# Access individual axes
print("Antenna Reference Frame:")
print("  X-axis:", arf[..., 0])
print("  Y-axis:", arf[..., 1])
print("  Z-axis (boresight):", arf[..., 2])

Attributes

__all__ module-attribute

Python
__all__ = ['compute_antenna_reference_frame_from_euler_angles', 'compute_euler_angles_from_antenna_reference_frame', 'compute_pointing_directions']

Functions:

compute_antenna_reference_frame_from_rotation

Python
compute_antenna_reference_frame_from_rotation(rotation: Rotation, initial_reference_frame: NDArray[floating] | None = None) -> npt.NDArray[np.floating]

Compute the Antenna Reference Frame (ARF) from a given rotation.

The ARF is obtained by rotating the initial reference frame with the given rotation. The rotation is assumed to be defined along the initial reference frame axes.

Parameters:

Name Type Description Default
rotation Rotation

the rotation axes implicitely defined inside the rotation are the initial_reference_frame axes.

required
initial_reference_frame NDArray[floating]

initial reference frame axes with shape (3, 3) or (N, 3, 3). If None, the initial reference frame is assumed to be the identity matrix.

None

Returns:

Type Description
NDArray[floating]

antenna reference frame axes as a numpy array with shape (3, 3) or (N, 3, 3)

compute_rotation_from_antenna_reference_frame

Python
compute_rotation_from_antenna_reference_frame(antenna_reference_frame: NDArray[floating], initial_reference_frame: NDArray[floating] | None = None) -> Rotation

Compute the rotation from a given Antenna Reference Frame (ARF).

Parameters:

Name Type Description Default
antenna_reference_frame NDArray[floating]

antenna reference frame of the sensor, with shape (3, 3) or (N, 3, 3)

required
initial_reference_frame NDArray[floating]

reference frame of the sensor, with shape (3, 3) or (N, 3, 3). If None, the initial reference frame is assumed to be the identity matrix.

None

Returns:

Type Description
Rotation

rotation from the initial reference frame to the antenna reference frame

compute_antenna_reference_frame_from_euler_angles

Python
compute_antenna_reference_frame_from_euler_angles(ypr_rad: NDArray[floating], rotation_order: RotationOrder, initial_reference_frame: NDArray[floating]) -> npt.NDArray[np.floating]

Compute the Antenna Reference Frame (ARF) from Euler angles (Yaw, Pitch and Roll).

Parameters:

Name Type Description Default
ypr_rad NDArray[floating]

euler angles in radians with shape (3,) or (N, 3) with yaw, pitch, roll order.

required
rotation_order RotationOrder

order of applications of the rotations

required
initial_reference_frame NDArray[floating]

reference frame of the sensor, with shape (3, 3) or (N, 3, 3)

required

Returns:

Type Description
NDArray[floating]

antenna reference frame as a numpy array with shape (3, 3) or (N, 3, 3)

compute_euler_angles_from_antenna_reference_frame

Python
compute_euler_angles_from_antenna_reference_frame(antenna_reference_frame: NDArray[floating], initial_reference_frame: NDArray[floating], rotation_order: RotationOrder) -> npt.NDArray[np.floating]

Compute euler angles (Yaw, Pitch and Roll) from Antenna Reference Frame (ARF).

Parameters:

Name Type Description Default
antenna_reference_frame NDArray[floating]

antenna reference frame of the sensor, with shape (3, 3) or (N, 3, 3)

required
initial_reference_frame NDArray[floating]

reference frame of the sensor, with shape (3, 3) or (N, 3, 3)

required
rotation_order RotationOrder

order of applications of the output euler angles

required

Returns:

Type Description
NDArray[floating]

euler angles in radians with shape (3,) or (N, 3) with yaw, pitch, roll order.

compute_pointing_directions

Python
compute_pointing_directions(antenna_reference_frame: NDArray[floating], azimuth_antenna_angles: float | NDArray[floating], elevation_antenna_angles: float | NDArray[floating]) -> npt.NDArray[np.floating]

Compute the pointing directions corresponding to the given antenna angles.

Parameters:

Name Type Description Default
antenna_reference_frame NDArray[floating]

antenna reference frame for the sensor as a numpy array with shape (3, 3) or (N, 3, 3)

required
azimuth_antenna_angles float | NDArray[floating]

scalar or (N,) array like, in radians

required
elevation_antenna_angles float | NDArray[floating]

scalar or (N,) array like, in radians

required

Returns:

Type Description
NDArray[floating]

pointing directions, with shape (3,) or (N, 3)