BodyOrientation#
- class BodyOrientation(rotation_vector: ndarray | None = None, body_fixed_frame: str | None = None, rotation: Callable | None = None, frame_class_id: int = 3000, base_frame: str = 'J2000', interpolation_frame: str = 'ECLIPJ2000', max_interval: float = 21600.0, description: str = 'User-supplied absolute body orientation', pole_x: float | None = None, pole_y: float | None = None, tai_minus_ut1: float | None = None, model: str = 'EOP1', celestial_pole_dx: float = 0.0, celestial_pole_dy: float = 0.0, nutation_delta_psi: float = 0.0, nutation_delta_epsilon: float = 0.0, ut1_time_scale: str = 'TAI')#
Bases:
objectA body-frame correction or an absolute planetary orientation model.
Use the constructor for a small active rotation,
earth_correction()for Earth-convention deltas,earth_eop()for absolute Earth inputs, andfrom_rotation()for another body’s absolute orientation law. An instance has exactly one of these modes.dataclasses.replacemakes an independent instance with revised inputs, e.g. for an EOP comparison.- Parameters:
- rotation_vectorarray_like, shape (3,), optional
Active right-hand body-fixed X/Y/Z correction in radians. Surface displacement is \(\delta r = \varepsilon \times r\) to first order.
- body_fixed_framestr, optional
SPICE axes of the correction. Required for a correction instance.
- rotationcallable, optional
Absolute inertial-to-body rotation callback; see
from_rotation().- frame_class_idint, optional
Binary PCK class ID; Earth ITRF93 uses 3000. See
from_rotation().- base_frame, interpolation_framestr, optional
Inertial callback axes and PCK interpolation axes. Defaults to J2000 and ECLIPJ2000 respectively.
- max_intervalfloat, optional
Maximum Chebyshev record length, seconds; default 21600.
- descriptionstr, optional
Provenance for a user-supplied rotation law.
- pole_x, pole_y, tai_minus_ut1, modeloptional
Absolute Earth EOPs and convention; see
earth_eop().- ut1_time_scalestr, optional
Which time scale UT1 is formed from; see
earth_eop().- celestial_pole_dx, celestial_pole_dyfloat, optional
Modern CPOs in radians; see
earth_eop().- nutation_delta_psi, nutation_delta_epsilonfloat, optional
Legacy nutation corrections in radians; see
earth_eop().
- Attributes:
- body_fixed_frame
conventionThe complete convention for report labels and PCK provenance.
eop_optionSelected Earth convention: EOP1 (ITRF93), EOP2 (IERS2010), or None.
- pole_x
- pole_y
- rotation
- rotation_vector
- tai_minus_ut1
Methods
celestial_pole_correction([delta_x, delta_y])Return the J2000 rotation vector of a celestial-pole-offset correction.
Return the rotation-vector column of each celestial pole offset.
displacement(position_body_fixed[, epoch, ...])Displacement of a body-fixed point caused by the correction.
earth_correction([delta_pole_x, ...])Construct a small Earth correction relative to the nominal kernel.
Return the rotation-vector column of each Earth EOP delta.
earth_eop(pole_x, pole_y, tai_minus_ut1[, ...])Construct absolute, constant Earth EOPs independently of a loaded PCK.
from_rotation(rotation, frame_class_id, *[, ...])Construct an absolute rotation law for any planet or other body.
iau_angles(epoch[, frame, coefficients, ...])Return the IAU pole and prime-meridian angles of a body and their rates.
iau_matrix(angles)Return the body-fixed to J2000 rotation of IAU pole angles.
iau_pole_coefficients(body)Return a body's secular IAU rotation constants from the kernel pool.
rotation_components(epoch)Return (W, R, Q), with celestial -> terrestrial = W @ R @ Q.
rotation_matrix(epoch)Return celestial -> terrestrial rotation at TDB seconds past J2000.
state_displacement(position_body_fixed, epoch)Position and velocity displacement of a body-fixed point.
write_pck(path, start, stop)Write a new type-2 PCK for this model's frame class ID.
Notes
Corrections affect station measurement geometry, including velocity, but do not replace loaded kernels or alter gravity. An absolute model can write a PCK shared by all SPICE frame consumers. A leap-second kernel is needed for absolute Earth models; generic callbacks define their own time dependence using TDB seconds past J2000. UT1 is an Earth convention.
See orientation-station-estimation for EOP signs, PCK precedence, planetary frames, cylindrical coordinates and complete estimation examples.
- classmethod earth_correction(delta_pole_x=0.0, delta_pole_y=0.0, delta_ut1=0.0)#
Construct a small Earth correction relative to the nominal kernel.
- Parameters:
- delta_pole_x, delta_pole_yfloat, optional
Intended minus nominal terrestrial xp/yp, radians. The active body-fixed rotation is (-delta_yp, -delta_xp, omega*delta_ut1). Defaults to
0..- delta_ut1float, optional
Intended minus nominal UT1, seconds. Positive advances Earth spin. Defaults to
0..
- Returns:
- BodyOrientation
First-order station correction in ITRF93. Absolute EOP numbers must not be passed here; use
earth_eop()for those.
- Raises:
- ValueError
If any of the three deltas is not finite.
- classmethod earth_eop(pole_x, pole_y, tai_minus_ut1, model='EOP1', *, celestial_pole_dx=0.0, celestial_pole_dy=0.0, nutation_delta_psi=0.0, nutation_delta_epsilon=0.0, ut1_time_scale='TAI')#
Construct absolute, constant Earth EOPs independently of a loaded PCK.
- Parameters:
- pole_x, pole_yfloat
Absolute terrestrial polar-motion coordinates in radians.
- tai_minus_ut1float
Absolute TAI-UT1 in seconds: UT1 = TAI - tai_minus_ut1.
- modelstr, optional
EOP1: ITRF93-style legacy IAU1976/1980 orientation, equinox/GMST82 + (dpsi+dPsi)cos(eps), s’=0. EOP2: IERS2010 orientation, IAU2006/2000A CIO/ERA with s06 and sp00. The descriptive names ITRF93, IERS2010, IAU1976/1980 and IAU2006/2000A are also accepted. The three EOP numbers do not determine this convention. Defaults to
"EOP1".- celestial_pole_dx, celestial_pole_dyfloat, optional
Modern observed celestial pole offsets dX/dY, radians. Supported only for IAU2006/2000A; distinct from terrestrial xp/yp. Defaults to
0..- nutation_delta_psi, nutation_delta_epsilonfloat, optional
IAU1980 nutation longitude/obliquity corrections, radians. Supported only for IAU1976/1980. dPsi also enters the equation of equinoxes. Defaults to
0..- ut1_time_scalestr, optional
Which time scale UT1 is formed from. Defaults to
"TAI", which is correct: UT1 = TAI - tai_minus_ut1, with TAI reached from the ephemeris epoch through the full TDB->TT->TAI chain."TDB"instead treats the ephemeris epoch as if it were TT, so UT1 = TDB - 32.184 - tai_minus_ut1 and the TDB-TT periodic term never reaches the spin angle.Choose
"TDB"only to reproduce another tool that omits that conversion. It is not a refinement and it is not small: TDB-TT is periodic with an amplitude of 1.66 ms, which is 0.5 m of station motion at the equator, well above the noise of a metre-class ranging system. It varies annually, so the error it causes differs between arcs at different times of year.
- Returns:
- BodyOrientation
Absolute model supporting rotation_components, rotation_matrix and write_pck. The PCK uses ITRF93 class ID 3000.
- Raises:
- ValueError
If
modelorut1_time_scaleis not recognised, an input is not finite, celestial pole offsets are given with IAU1976/1980, or nutation corrections are given with IAU2006/2000A.
Notes
EOPs/CPOs stay constant over coverage; model precession/nutation and spin vary with time. ERFA supplies SOFA-derived routines. Precession and nutation use TT; spin uses UT1. CPOs default to zero and are never inferred from observations. Load an LSK for the TDB/TT/TAI conversion. The legacy celestial axes are mean J2000; modern axes are GCRS/ICRS. SPICE calls both J2000 without converting between the conventions. EOP1/EOP2 select the rotation convention, not new station coordinates. Both export PCK class ID 3000 so existing ITRF93-referenced station SPKs use the selected orientation. EOP2 implements the IERS2010 rotation chain with the supplied constant EOPs/CPOs; no time-varying tidal EOP series is synthesized.
References
https://iers-conventions.obspm.fr/content/chapter5/icc5.pdf liberfa/erfa
- classmethod from_rotation(rotation, frame_class_id, *, base_frame='J2000', interpolation_frame='ECLIPJ2000', max_interval=21600.0, description='User-supplied absolute body orientation')#
Construct an absolute rotation law for any planet or other body.
- Parameters:
- rotationcallable
Vectorized function of TDB seconds, returning base_frame-to-body matrices with shape
epoch.shape + (3,3).- frame_class_idint
PCK frame class ID (not the body or frame ID). Load an FK mapping this ID to the intended class-2 body-fixed frame.
- base_framestr, optional
Callback inertial axes. Defaults to
"J2000".- interpolation_framestr, optional
PCK inertial base. Select axes avoiding the body’s 3-1-3 Euler pole singularity. Defaults to
"ECLIPJ2000".- max_intervalfloat, optional
Maximum Chebyshev record length, seconds. Use a shorter interval for fast rotation. Interpolation is checked. Defaults to
21600..- descriptionstr, optional
Provenance recorded in the PCK comments. Defaults to
"User-supplied absolute body orientation".
- Returns:
- BodyOrientation
Absolute model supporting rotation_matrix and write_pck. The callback supplies the physics; no Earth rotation law is assumed.
- Raises:
- ValueError
If
frame_class_idis not an integer,max_intervalis not positive and finite, orbase_frameorinterpolation_frameis not inertial.- TypeError
If
rotationis not callable.
- static celestial_pole_correction(delta_x=0.0, delta_y=0.0)#
Return the J2000 rotation vector of a celestial-pole-offset correction.
- Parameters:
- delta_x, delta_yfloat, optional
Intended minus nominal celestial pole offsets \(\delta X\), \(\delta Y\), radians. Defaults to
0..
- Returns:
- numpy.ndarray
Rotation vector \((-\delta Y, \delta X, 0)\), rad, shape (3,), in J2000 axes and held fixed there. Unlike
earth_correction()it does not turn with the Earth; apply it withinertial_rotation_partials().
- Raises:
- NonFiniteOffsetError
If either offset is not finite. It is also a ValueError.
Notes
To first order the CIP matrix \(Q(X, Y)\) of IERS Conventions (2010) eq. 5.10 is \(I + [\omega\times]\) with this \(\omega\). Frame bias and \(Q \ne I\) change the column by about 3e-3 of itself, far below what a measurement can see.
The same rotation corrects the IAU 1980 nutation of a
model="EOP1"kernel, with \(\delta X = \delta\psi\sin\varepsilon_A\) and \(\delta Y = \delta\varepsilon\) (IERS Conventions (2010) eq. 5.26 without its precession cross terms, which are about 6e-3 of the offsets).
- static celestial_pole_correction_partials()#
Return the rotation-vector column of each celestial pole offset.
- Returns:
- dict
Keyword accepted by
celestial_pole_correction()mapped to the constant \(\partial\omega/\partial p\), shape (3,), in radians per radian, J2000 axes. Exact, since the correction is linear in both offsets.
- static earth_correction_partials()#
Return the rotation-vector column of each Earth EOP delta.
- Returns:
- dict
Keyword accepted by
earth_correction()mapped to the constant \(\partial\varepsilon/\partial p\), shape (3,), in radians per radian for the pole terms and radians per second for UT1.
Notes
earth_correction()is linear in its three inputs, so these columns are exact rather than a linearization, and a station partial chains them straight intorotation_partials(). Keying by the constructor’s own argument names keeps the two from drifting apart.
- static iau_angles(epoch, frame=None, coefficients=None, *, pole_ra=None, pole_dec=None, pole_pm=None, pole_w0=None)#
Return the IAU pole and prime-meridian angles of a body and their rates.
- Parameters:
- epochfloat
TDB seconds past J2000.
- framestr, optional
The body’s SPICE body-fixed frame, e.g.
"IAU_MARS". Used when no angle is replaced. Defaults toNone.- coefficientsarray_like, shape (3, 3), optional
Secular constants as returned by
iau_pole_coefficients(); shorter rows are padded with zeros. Needed when an angle is replaced orframeisNone. Defaults toNone.- pole_ra, pole_decfloat, optional
Estimated pole right ascension and declination, rad. Each replaces its secular polynomial and is constant in time. Defaults to
None.- pole_pmfloat, optional
Estimated prime-meridian rate, deg/day. Gives \(W = W_0 + \mathrm{PM}\,d\) without the quadratic term. Defaults to
None.- pole_w0float, optional
Estimated prime-meridian angle at J2000, rad. Replaces \(W_0\). Defaults to
None.
- Returns:
- anglesnumpy.ndarray
\((\alpha, \delta, W)\), rad, shape (3,).
- ratesnumpy.ndarray
\((\dot\alpha, \dot\delta, \dot W)\), rad/s, shape (3,).
- Raises:
- MissingPoleCoefficientsError
If the secular path is needed and
coefficientsisNone. It is also a ValueError.
Notes
With
framegiven and nothing replaced, the angles are SPICE’s full model, read back fromsxform("J2000", frame)as the 3-1-3 Euler angles \((\alpha + 90^\circ, 90^\circ - \delta, W)\), so the nutation-precession terms and the time derivatives are included and \(W\) is reduced to \([-\pi, \pi]\).Otherwise the secular model of the kernel is used, \(\alpha = \alpha_0 + \alpha_1 T + \alpha_2 T^2\), likewise \(\delta\), and \(W = W_0 + W_1 d + W_2 d^2\), with \(d\) days and \(T\) Julian centuries past J2000, and each estimated value replaces its term as described above. This is the estimated-pole model of
SphericalHarmonicsGravity, so gravity and the optical measurement models see one body orientation.
- static iau_matrix(angles)#
Return the body-fixed to J2000 rotation of IAU pole angles.
- Parameters:
- anglesarray_like, shape (3,)
\((\alpha, \delta, W)\), rad, e.g. from
iau_angles().
- Returns:
- numpy.ndarray
Shape (3, 3), \(R_z(\alpha + \pi/2)\,R_x(\pi/2 - \delta)\, R_z(W)\) with active rotations, so \(r_{J2000} = R\,r_{body}\). It equals SPICE’s
pxform(frame, "J2000")for the angles ofiau_angles().
- static iau_pole_coefficients(body)#
Return a body’s secular IAU rotation constants from the kernel pool.
- Parameters:
- bodystr or int
SPICE body name or ID, e.g.
"MARS"or499.
- Returns:
- numpy.ndarray
Shape (3, 3). Rows are
POLE_RA,POLE_DEC(deg, deg per Julian century, deg per century squared) andPM(deg, deg/day, deg/day squared). A term missing from the kernel is zero.
Notes
A text PCK such as
pck00010.tpcmust be loaded. Only the secular terms are read; the nutation-precession series of the full model are left to SPICE.
- displacement(position_body_fixed, epoch: float = None, frame_from: str = None, frame_to: str = None) ArrayWUnits#
Displacement of a body-fixed point caused by the correction.
- Parameters:
- position_body_fixedArrayWUnits, ArrayWFrame or array_like
Position in the body-fixed frame, shape (3,). Bare numbers are km.
- epochfloat, optional
TDB seconds past J2000. Required only when
frame_tois given and differs fromframe_from. Defaults toNone.- frame_fromstr, optional
The body-fixed frame
position_body_fixedis expressed in. Defaults toNone, meaningbody_fixed_frame.- frame_tostr, optional
Rotate the displacement into this frame before returning it. Defaults to
None, keeping it inframe_from.
- Returns:
- ArrayWUnits
Displacement, km, shape (3,).
- Raises:
- ValueError
If this instance is not a correction model, or
frame_todiffers fromframe_fromandepochis not given.- RuntimeError
If SPICE cannot resolve the rotation from
frame_fromtoframe_to.
- rotation_components(epoch)#
Return (W, R, Q), with celestial -> terrestrial = W @ R @ Q.
Each component has shape (3, 3), or epoch.shape + (3, 3) for arrays. For IAU1976/1980, Q maps mean-J2000 to the true equator/equinox of date and R uses GAST. For IAU2006/2000A, Q maps GCRS/ICRS to CIRS and R uses ERA. SPICE names the inertial base J2000 in both cases; it does not itself convert the legacy model’s mean-J2000 axes to ICRS. The loaded Earth PCK is never consulted or decomposed. Its three rotation angles do not uniquely supply xp, yp, UT1 and two CPOs.
- Parameters:
- epochfloat or array_like
TDB seconds past J2000.
- Returns:
- polar_motionnp.ndarray
W, the polar-motion matrix built from
pole_x,pole_yand s’ (zero for IAU1976/1980).- rotationnp.ndarray
R, the spin about the pole of date by GAST (IAU1976/1980) or ERA (IAU2006/2000A).
- celestialnp.ndarray
Q, precession-nutation from the celestial axes to the true equator and equinox of date (IAU1976/1980) or to CIRS (IAU2006/2000A).
- Raises:
- ValueError
If this instance has no absolute Earth EOPs,
epochis not finite, or the corrected celestial pole has X^2 + Y^2 >= 1.- SpiceyError
If no leap-second kernel is loaded.
- rotation_matrix(epoch)#
Return celestial -> terrestrial rotation at TDB seconds past J2000.
See
rotation_components()for the celestial axes of each Earth convention.- Parameters:
- epochfloat or array_like
TDB seconds past J2000.
- Returns:
- np.ndarray
Rotation from the inertial base frame to the body-fixed frame, shape (3, 3) for a scalar epoch or
epoch.shape + (3, 3).
- Raises:
- ValueError
If this instance is a correction model or
epochis not finite, or as raised byrotation_components().
- state_displacement(position_body_fixed, epoch: float, frame_from: str = None, frame_to: str = 'J2000', velocity_body_fixed=None) ArrayWUnits#
Position and velocity displacement of a body-fixed point.
A station is static in the body-fixed frame, so the correction moves it by \(\varepsilon \times r\) there and leaves its body-fixed velocity at zero. Its inertial velocity still changes, by \(\Omega \times \delta r\) — the moved point sits on a different radius from the spin axis. That term is small but not negligible for Doppler: 23 m of displacement is 1.7 mm/s, against measurement noise often quoted at 1 mm/s.
The state transformation carries both terms, so the body-fixed six-vector
[delta_r, delta_v](delta_vis zero for a static station) is rotated withsxformrather than the position alone.- Parameters:
- position_body_fixedArrayWUnits, ArrayWFrame or array_like
Position in the body-fixed frame, shape (3,). Bare numbers are km.
- epochfloat
TDB seconds past J2000.
- frame_fromstr, optional
The body-fixed frame
position_body_fixedis expressed in. Defaults toNone, meaningbody_fixed_frame.- frame_tostr, optional
Frame to express the displacement in. Defaults to
"J2000".- velocity_body_fixedArrayWUnits, ArrayWFrame or array_like, optional
Nominal body-fixed velocity, shape (3,); bare numbers are km/s. Its cross product with the correction supplies the body-fixed velocity delta. Defaults to
None, a zero velocity.
- Returns:
- ArrayWUnits
[dx, dy, dz, dvx, dvy, dvz]in km and km/s, shape (6,).
- Raises:
- ValueError
If this instance is not a correction model.
- RuntimeError
If SPICE cannot resolve the state transformation from
frame_fromtoframe_to.
- write_pck(path, start, stop)#
Write a new type-2 PCK for this model’s frame class ID.
start/stop are TDB seconds past J2000. The caller must explicitly load the returned file after competing PCKs to select it within this interval. Existing files are not overwritten or unloaded. Outside this interval SPICE may use another loaded PCK.
Degree-12 Chebyshev records span at most
max_interval(six hours by default). Euler angles useinterpolation_frame(ECLIPJ2000 by default) as their base to avoid the near-J2000-pole singularity. Their interpolation is checked against directrotation_matrix()values at independent points, including every record boundary, before writing.- Parameters:
- pathstr or pathlib.Path
Output PCK file. It must not exist yet.
- start, stopfloat
Coverage interval, TDB seconds past J2000, with
stop > start.
- Returns:
- pathlib.Path
The written PCK file.
- Raises:
- ValueError
If this instance is a correction model;
startorstopis not finite orstop <= start;rotation_matrix()does not return proper orthogonal matrices; or the checked interpolation error exceeds 5e-11.- FileExistsError
If
pathalready exists.
- IAU_POLE_PARAMETERS = ('pole_ra', 'pole_dec', 'pole_pm', 'pole_w0')#
State keys of an estimated IAU body orientation.
Pole right ascension and declination (rad), prime-meridian rate (deg/day) and prime-meridian angle at J2000 (rad). Each replaces its term of the body’s secular PCK model, as
iau_angles()describes.
- IAU_POLE_UNITS = {'pole_dec': rad, 'pole_pm': [(8.64E+04 sec^-1) (1.75E-02 rad^1)], 'pole_ra': rad, 'pole_w0': rad}#
Units of each of
IAU_POLE_PARAMETERS.
- IAU_ROTATION_ITEMS = ('POLE_RA', 'POLE_DEC', 'PM')#
Kernel-pool names of the IAU secular rotation constants, in the row order of
iau_pole_coefficients().
- STATE_UNITS = (km, km, km, km/sec, km/sec, km/sec)#
Row units of
state_displacement().
- property convention#
The complete convention for report labels and PCK provenance.
- property eop_option#
Selected Earth convention: EOP1 (ITRF93), EOP2 (IERS2010), or None.
The option names identify the legacy and IERS rotation conventions. They do not perform a change of terrestrial station-coordinate datum.
- exception MissingPoleCoefficientsError#
Bases:
ValueErroriau_angles()needed the secular PCK coefficients of a body but was given none.
- exception NonFiniteOffsetError#
Bases:
ValueErrorA celestial pole offset given to
celestial_pole_correction()was not finite.