Skip to content

Right Ascension / Declination Coordinates

Functions for converting between right ascension/declination (RA/Dec) and Cartesian inertial coordinates, propagating catalog positions with proper motion, and converting between topocentric RA/Dec and azimuth-elevation.

Position Conversions

position_radec_to_inertial builtin

position_radec_to_inertial(x_radec: Union[ndarray, Sequence], angle_format: AngleFormat, axis: int = -1) -> ndarray

Convert a right ascension, declination, and range into the equivalent Cartesian inertial position.

Parameters:

Name Type Description Default
x_radec ndarray or list

Right ascension, declination, and range [ra, dec, range] where right ascension and declination are in radians or degrees, and range is in meters. Also accepts a batch of vectors with the 3 components along axis (for example shape (n, 3)).

required
angle_format AngleFormat

Angle format for angular elements (RADIANS or DEGREES).

required
axis int

The axis of x_radec along which the 3 components of a single vector lie; the remaining axes enumerate the batch. For a batch of shape (n, 3) the components lie along the last axis, so the default -1 applies; a (3, n) column layout uses axis=0.

-1

Returns:

Type Description
ndarray

numpy.ndarray: Cartesian inertial position [x, y, z] in meters. For batched input the output takes the batch layout of x_radec.

Example
1
2
3
4
5
6
import brahe as bh
import numpy as np

x_radec = np.array([0.0, 0.0, 1.0])
x_inertial = bh.position_radec_to_inertial(x_radec, bh.AngleFormat.DEGREES)
print(f"Inertial position: {x_inertial}")

position_inertial_to_radec builtin

position_inertial_to_radec(x_inertial: Union[ndarray, Sequence], angle_format: AngleFormat, axis: int = -1) -> ndarray

Convert a Cartesian inertial position into the equivalent right ascension, declination, and range.

Right ascension is normalized to the range [0, 360) degrees (or [0, 2*pi) radians). At the polar singularity (x = y = 0) right ascension is indeterminate from position alone and is returned as 0; use state_inertial_to_radec to resolve it from velocity instead.

Parameters:

Name Type Description Default
x_inertial ndarray or list

Cartesian inertial position [x, y, z] in meters. Also accepts a batch of vectors with the 3 components along axis (for example shape (n, 3)).

required
angle_format AngleFormat

Angle format for angular output (RADIANS or DEGREES).

required
axis int

The axis of x_inertial along which the 3 components of a single vector lie; the remaining axes enumerate the batch. For a batch of shape (n, 3) the components lie along the last axis, so the default -1 applies; a (3, n) column layout uses axis=0.

-1

Returns:

Type Description
ndarray

numpy.ndarray: Right ascension, declination, and range [ra, dec, range] where right ascension and declination are in radians or degrees, and range is in meters. For batched input the output takes the batch layout of x_inertial.

Example
1
2
3
4
5
6
import brahe as bh
import numpy as np

x_inertial = np.array([1.0, 0.0, 0.0])
x_radec = bh.position_inertial_to_radec(x_inertial, bh.AngleFormat.DEGREES)
print(f"RA/Dec: {x_radec}")

State Conversions

state_radec_to_inertial builtin

state_radec_to_inertial(x_radec: Union[ndarray, Sequence], angle_format: AngleFormat, axis: int = -1) -> ndarray

Convert a right ascension, declination, range, and their rates into the equivalent Cartesian inertial position and velocity.

Parameters:

Name Type Description Default
x_radec ndarray or list

Right ascension, declination, range, and rates [ra, dec, range, ra_rate, dec_rate, range_rate] where right ascension, declination, and their rates are in radians (or radians/s) or degrees (or degrees/s), and range/range_rate are in meters and meters/s. Also accepts a batch of vectors with the 6 components along axis (for example shape (n, 6)).

required
angle_format AngleFormat

Angle format for angular elements and rates (RADIANS or DEGREES).

required
axis int

The axis of x_radec along which the 6 components of a single vector lie; the remaining axes enumerate the batch. For a batch of shape (n, 6) the components lie along the last axis, so the default -1 applies; a (6, n) column layout uses axis=0.

-1

Returns:

Type Description
ndarray

numpy.ndarray: Cartesian inertial position and velocity [x, y, z, vx, vy, vz] in meters and meters per second. For batched input the output takes the batch layout of x_radec.

Example
1
2
3
4
5
6
import brahe as bh
import numpy as np

x_radec = np.array([0.0, 0.0, 7000e3, 0.0, 0.0, 0.0])
x_inertial = bh.state_radec_to_inertial(x_radec, bh.AngleFormat.DEGREES)
print(f"Inertial state: {x_inertial}")

state_inertial_to_radec builtin

state_inertial_to_radec(x_inertial: Union[ndarray, Sequence], angle_format: AngleFormat, axis: int = -1) -> ndarray

Convert a Cartesian inertial position and velocity into the equivalent right ascension, declination, range, and their rates.

Right ascension is normalized to the range [0, 360) degrees (or [0, 2*pi) radians). At the polar singularity (x = y = 0), where right ascension is indeterminate from position alone, it is instead resolved from the velocity components.

Parameters:

Name Type Description Default
x_inertial ndarray or list

Cartesian inertial position and velocity [x, y, z, vx, vy, vz] in meters and meters per second. Also accepts a batch of vectors with the 6 components along axis (for example shape (n, 6)).

required
angle_format AngleFormat

Angle format for angular output and rates (RADIANS or DEGREES).

required
axis int

The axis of x_inertial along which the 6 components of a single vector lie; the remaining axes enumerate the batch. For a batch of shape (n, 6) the components lie along the last axis, so the default -1 applies; a (6, n) column layout uses axis=0.

-1

Returns:

Type Description
ndarray

numpy.ndarray: Right ascension, declination, range, and rates [ra, dec, range, ra_rate, dec_rate, range_rate] where right ascension, declination, and their rates are in radians (or radians/s) or degrees (or degrees/s), and range/range_rate are in meters and meters/s. For batched input the output takes the batch layout of x_inertial.

Example
1
2
3
4
5
6
import brahe as bh
import numpy as np

x_inertial = np.array([7000e3, 0.0, 0.0, 0.0, 0.0, 0.0])
x_radec = bh.state_inertial_to_radec(x_inertial, bh.AngleFormat.DEGREES)
print(f"RA/Dec state: {x_radec}")

Proper Motion

apply_proper_motion builtin

apply_proper_motion(ra: float, dec: float, pm_ra: float, pm_dec: float, parallax: Union[float, None], radial_velocity: Union[float, None], epoch_from: Epoch, epoch_to: Epoch, angle_format: AngleFormat) -> tuple[float, float]

Propagate a star's catalog position from one epoch to another using IAU SOFA's iauPmsafe space-motion transformation.

iauPmsafe reconstructs the star's full barycentric position/velocity state from the catalog (ra, dec), proper motion, parallax, and radial velocity; advances it assuming straight-line motion at constant velocity (including a light-time correction and the special-relativistic Doppler treatment of Stumpff, 1985); and reduces the result back to catalog (ra, dec) at epoch_to. To first order this is the rigorous direction-only epoch transformation of ESA SP-1200 (Vol. 1, §1.5.5): a tangential proper-motion displacement plus a radial "perspective acceleration" term that is significant for high radial-velocity, high-parallax stars such as Barnard's Star.

pm_ra follows the standard catalog convention: it is mu_alpha* = mu_alpha * cos(dec), not the raw coordinate rate mu_alpha. This matches the pmra/pmdec columns of Hipparcos, Gaia, and most other star catalogs. If parallax or radial_velocity is None it is treated as zero; iauPmsafe additionally applies a proper-motion-scaled minimum-parallax guard so a star with a missing or tiny parallax still propagates correctly rather than being clamped to a no-op.

Parameters:

Name Type Description Default
ra float

Right ascension at epoch_from. Units: (radians or degrees)

required
dec float

Declination at epoch_from. Units: (radians or degrees)

required
pm_ra float

Proper motion in right ascension, mu_alpha* = mu_alpha * cos(dec). Units: (mas/yr)

required
pm_dec float

Proper motion in declination, mu_delta. Units: (mas/yr)

required
parallax float or None

Annual parallax, or None if unknown/unavailable. Units: (mas)

required
radial_velocity float or None

Radial velocity, or None if unknown/unavailable. Units: (km/s)

required
epoch_from Epoch

Epoch of the input (ra, dec).

required
epoch_to Epoch

Epoch to propagate the position to.

required
angle_format AngleFormat

Angle format for ra/dec input and output (RADIANS or DEGREES).

required

Returns:

Type Description
tuple[float, float]

tuple[float, float]: Right ascension and declination propagated to epoch_to.

Example
import brahe as bh

# Barnard's Star (HIP 87937), J1991.25 Hipparcos catalog values.
epoch_from = bh.Epoch.from_mjd(48348.5625, bh.TimeSystem.TT)
epoch_to = bh.Epoch.from_mjd(48348.5625 + 10.0 * 365.25, bh.TimeSystem.TT)

ra, dec = bh.apply_proper_motion(
    269.45402305,
    4.66828815,
    -797.84,
    10326.93,
    549.30,
    -106.8,
    epoch_from,
    epoch_to,
    bh.AngleFormat.DEGREES,
)

Azimuth-Elevation Conversions

position_radec_to_azel builtin

position_radec_to_azel(x_radec: Union[ndarray, Sequence], site_geodetic: Union[ndarray, Sequence], epc: Union[Epoch, Sequence[Epoch]], angle_format: AngleFormat, axis: int = -1) -> ndarray

Convert a topocentric right ascension, declination, and range into the equivalent azimuth, elevation, and range as seen from a given site.

This is a direction-only rotation of the line-of-sight unit vector: no parallax translation between the geocenter and the site is applied, and range passes through unchanged. The input (ra, dec) must already be the direction from the site: for stars (effectively at infinite distance) this is the same as the geocentric catalog (ra, dec), but for satellites or other nearby objects the caller must first compute the topocentric right ascension/declination before calling this function.

Requires a global Earth orientation parameter (EOP) provider to be initialized, as with all frame conversions between inertial and Earth-fixed frames.

Parameters:

Name Type Description Default
x_radec ndarray or list

Topocentric right ascension, declination, and range [ra, dec, range] where right ascension and declination are in radians or degrees, and range is in meters. Also accepts a batch of vectors with the 3 components along axis (for example shape (n, 3)).

required
site_geodetic ndarray or list

Geodetic coordinates of the observing site [lon, lat, alt] where longitude and latitude are in radians or degrees, and altitude is in meters.

required
epc Epoch or Sequence[Epoch]

Epoch of the observation, used to rotate between the inertial and Earth-fixed frames. A sequence evaluates one epoch per vector (or broadcasts a single vector across all epochs).

required
angle_format AngleFormat

Angle format for angular elements (RADIANS or DEGREES).

required
axis int

The axis of x_radec along which the 3 components of a single vector lie; the remaining axes enumerate the batch. For a batch of shape (n, 3) the components lie along the last axis, so the default -1 applies; a (3, n) column layout uses axis=0.

-1

Returns:

Type Description
ndarray

numpy.ndarray: Azimuth (clockwise from North), elevation, and range [az, el, range] where azimuth and elevation are in radians or degrees, and range is in meters. For batched input the output takes the batch layout of x_radec (shape (n, 3) for a single vector with a sequence of n epochs).

Example
import brahe as bh
import numpy as np

bh.initialize_eop()

epc = bh.Epoch.from_datetime(2024, 3, 20, 12, 0, 0.0, 0.0, bh.UTC)
site = np.array([-122.17, 37.43, 100.0])  # Stanford, deg/deg/m
x_radec = np.array([101.28, -16.72, 1.0])

# Requires a global EOP provider to be initialized first.
x_azel = bh.position_radec_to_azel(x_radec, site, epc, bh.AngleFormat.DEGREES)

position_azel_to_radec builtin

position_azel_to_radec(x_azel: Union[ndarray, Sequence], site_geodetic: Union[ndarray, Sequence], epc: Union[Epoch, Sequence[Epoch]], angle_format: AngleFormat, axis: int = -1) -> ndarray

Convert an azimuth, elevation, and range as seen from a given site into the equivalent topocentric right ascension, declination, and range.

This is the inverse of position_radec_to_azel and is likewise a direction-only rotation: no parallax translation between the site and the geocenter is applied, and range passes through unchanged. The returned (ra, dec) is the topocentric direction as seen from the site, which for stars is the same as the geocentric catalog (ra, dec).

Requires a global Earth orientation parameter (EOP) provider to be initialized, as with all frame conversions between inertial and Earth-fixed frames.

Parameters:

Name Type Description Default
x_azel ndarray or list

Azimuth (clockwise from North), elevation, and range [az, el, range] where azimuth and elevation are in radians or degrees, and range is in meters. Also accepts a batch of vectors with the 3 components along axis (for example shape (n, 3)).

required
site_geodetic ndarray or list

Geodetic coordinates of the observing site [lon, lat, alt] where longitude and latitude are in radians or degrees, and altitude is in meters.

required
epc Epoch or Sequence[Epoch]

Epoch of the observation, used to rotate between the Earth-fixed and inertial frames. A sequence evaluates one epoch per vector (or broadcasts a single vector across all epochs).

required
angle_format AngleFormat

Angle format for angular elements (RADIANS or DEGREES).

required
axis int

The axis of x_azel along which the 3 components of a single vector lie; the remaining axes enumerate the batch. For a batch of shape (n, 3) the components lie along the last axis, so the default -1 applies; a (3, n) column layout uses axis=0.

-1

Returns:

Type Description
ndarray

numpy.ndarray: Topocentric right ascension, declination, and range [ra, dec, range] where right ascension and declination are in radians or degrees, and range is in meters. For batched input the output takes the batch layout of x_azel (shape (n, 3) for a single vector with a sequence of n epochs).

Example
import brahe as bh
import numpy as np

bh.initialize_eop()

epc = bh.Epoch.from_datetime(2024, 3, 20, 12, 0, 0.0, 0.0, bh.UTC)
site = np.array([-122.17, 37.43, 100.0])  # Stanford, deg/deg/m
x_azel = np.array([180.0, 45.0, 1.0])

# Requires a global EOP provider to be initialized first.
x_radec = bh.position_azel_to_radec(x_azel, site, epc, bh.AngleFormat.DEGREES)

See Also