SPICE Kernels¶
Brahe includes a native reader for NASA JPL NAIF SPICE kernels: binary SPK ephemeris kernels (Chebyshev position/velocity, Types 2 and 3) and binary PCK orientation kernels (Chebyshev Euler angles, Type 2). Kernels are parsed directly by brahe — there is no dependency on the CSPICE toolkit or another SPICE binding at runtime.
Two ways to query loaded kernels are available:
- Generic queries (
spk_position/spk_velocity/spk_state/spk_acceleration,pck_euler_angles/pck_rotation_matrix) take NAIF IDs or frame class IDs directly and resolve against a process-wide kernel registry. - Per-body convenience functions (
sun_position_spice,moon_state_spice, ...) wrap the same registry for the ten most commonly used bodies.
For downloading and caching the underlying kernel files, see NAIF Ephemeris Kernels.
Loading Kernels¶
load_spice_kernel accepts either a known kernel name or a filesystem path, and auto-detects SPK vs. binary PCK from the file header:
Output
Known kernel names — the eight planetary DE kernels (de430, de432s, de435, de438, de440, de440s, de442, de442s), the seven satellite ephemeris kernels (mar099, mar099s, jup365, sat441, ura184, nep097, plu060), and the binary PCK moon_pa_de440 — are downloaded and cached automatically; any other string is treated as a path to a local .bsp or .bpc file (bring-your-own kernels). The moon_pa_de440 binary PCK is derived from the same DE440 integration as de440.bsp but is distributed by NAIF as a separate file — SPK kernels carry only translational states. See NAIF Ephemeris Kernels for caching details.
Downloadable Kernels¶
| Name | File | Size | Coverage | Contents |
|---|---|---|---|---|
de440s | de440s.bsp | ~33 MB | 1849–2150 | Sun, Moon, all planets and planetary-system barycenters (default for spk_*/*_spice auto-init) |
de440 | de440.bsp | ~120 MB | 1550–2650 | Same content as de440s, wider time span |
de430 | de430.bsp | ~120 MB | — | Standard precision, extended time span |
de432s | de432s.bsp | ~11 MB | — | Small variant tuned for New Horizons Pluto targeting |
de435 | de435.bsp | ~120 MB | — | Higher accuracy for inner planets |
de438 | de438.bsp | ~120 MB | — | Standard precision |
de442 | de442.bsp | ~120 MB | — | Intended for the MESSENGER mission to Mercury |
de442s | de442s.bsp | ~33 MB | — | Small variant of de442 |
mar099s | mar099s.bsp | ~68 MB | 1995–2050 | Mars, Phobos, Deimos (default Mars satellite kernel for body-center auto-download) |
mar099 | mar099.bsp | ~1.1 GB | 1600–2600 | Mars, Phobos, Deimos, wider time span |
jup365 | jup365.bsp | ~1.1 GB | 1600–2200 | Jupiter, Io, Europa, Ganymede, Callisto |
sat441 | sat441.bsp | ~662 MB | 1750–2250 | Saturn, Titan and the mid-size moons |
ura184 | ura184_part-3.bsp | ~387 MB | 1600–2399 | Uranus, Miranda, Ariel, Umbriel, Titania, Oberon |
nep097 | nep097.bsp | ~105 MB | 1600–2400 | Neptune, Triton |
plu060 | plu060.bsp | ~135 MB | 1800–2200 | Pluto, Charon |
moon_pa_de440 | moon_pa_de440_200625.bpc | ~13 MB | matches de440/de440s | Lunar principal-axis orientation (binary PCK, not an SPK) |
Any string that does not match a name in this table is treated as a filesystem path to a local .bsp or .bpc file.
Registry behavior:
- Idempotent: calling
load_spice_kernelwith a name/path that is already loaded is a no-op. - Persistent: kernels stay resident until
unload_spice_kernelorclear_spice_kernelsis called. - Precedence:
spk_*queries resolve across every loaded SPK kernel; for body pairs covered by more than one kernel, the most recently loaded kernel wins (matching SPICE's own "last loaded wins" convention).pck_*queries search loaded PCK kernels newest-first for a frame with coverage at the requested epoch. - Auto-initialization:
spk_position/spk_velocity/spk_state/spk_accelerationloadde440sautomatically if no SPK kernel has been loaded yet. Binary PCKs are never auto-loaded through this generic interface —load_spice_kernel("moon_pa_de440")(or an explicit path) must be called first. The Moon'sLFPA/LFMEframe functions (see Lunar Reference Frames) are a narrow exception: they auto-loadmoon_pa_de440on first use.
Loading Multiple Kernels at Once¶
load_common_spice_kernels and load_all_spice_kernels pre-load a curated set of kernels in one call, so a session does not pay per-kernel download latency the first time each body is queried:
| Function | Loads | Download size |
|---|---|---|
load_common_spice_kernels() | de440s, moon_pa_de440 | ~46 MB |
load_all_spice_kernels() | de440s, moon_pa_de440, mar099s, jup365, sat441, ura184, nep097, plu060 | ~2.5 GB |
Each kernel load within these calls is idempotent, so calling either alongside individual load_spice_kernel calls is safe. Prefer load_common_spice_kernels unless outer-planet body centers, their moons, or Pluto are needed — load_all_spice_kernels downloads over 2 GB on first use.
Querying Ephemeris Data¶
Generic NAIF-ID Queries¶
spk_position, spk_velocity, spk_state, and spk_acceleration take a target NAIF ID, a center NAIF ID, and an Epoch, and resolve across all loaded SPK kernels:
| Function | Returns | Units |
|---|---|---|
spk_position(target, center, epc) | Position of target rel. center | m |
spk_velocity(target, center, epc) | Velocity of target rel. center | m/s |
spk_state(target, center, epc) | [x, y, z, vx, vy, vz] of target rel. center | m, m/s |
spk_acceleration(target, center, epc) | Acceleration of target rel. center | m/s² |
Common NAIF IDs are exposed through the NAIFId enum (Python: IntEnum; Rust: enum NAIFId with an Id(i32) catch-all variant), covering the ten planetary-system barycenters, the Sun, the eight planet body centers, and the major natural satellites used elsewhere in brahe (Phobos, Deimos, the four Galilean moons, Titan, the five major Uranian moons, Triton, Charon). NAIFId values compare and pass equal to the equivalent raw integer, so either form works everywhere a NAIF ID is expected:
Any NAIF ID present in a loaded kernel but not named by the enum (e.g. a minor body or spacecraft) is passed as a raw integer (Python) or NAIFId::Id(...) (Rust). Full ID listing: NAIF Integer ID Codes.
Kernel-Scoped Queries¶
spk_position_from_kernel, spk_velocity_from_kernel, spk_state_from_kernel, and spk_acceleration_from_kernel take an additional kernel_name argument and query that kernel only — no cross-kernel chaining is performed and the registry's precedence rules do not apply. The named kernel is auto-loaded if not already resident. Use these when a query must come from a specific kernel regardless of what else is loaded.
Per-Body Functions¶
sun_position_spice, moon_position_spice, mercury_position_spice, venus_position_spice, mars_position_spice, jupiter_position_spice, saturn_position_spice, uranus_position_spice, neptune_position_spice, and solar_system_barycenter_position_spice (alias: ssb_position_spice) each have _velocity_spice and _state_spice counterparts, all queried relative to Earth (NAIFId.EARTH / NAIFId::Earth, ID 399). They take an Epoch and an ephemeris source selecting which DE kernel to query (EphemerisSource.DE440s / EphemerisSource.DE440 in Python, SPICEKernel::DE440s / SPICEKernel::DE440 in Rust). Computing the state shares a single record lookup between position and velocity, so prefer *_state_spice over separate position/velocity calls when both are needed.
The Mars/Jupiter/Saturn/Uranus/Neptune functions return the planet body center. The DE kernel only carries the planetary-system barycenter for these outer planets, so the body center is computed as a two-leg sum: the barycenter relative to Earth from the DE kernel, plus the body center relative to the barycenter from the planet's satellite ephemeris kernel. That satellite kernel is auto-downloaded and loaded on first use (mar099s ~68 MB, jup365 ~1.1 GB, sat441 ~662 MB, ura184 ~387 MB, nep097 ~105 MB).
Each of the five outer planets also has mars_barycenter_position_spice, jupiter_barycenter_position_spice, and so on (with _velocity_spice / _state_spice counterparts) that return the planetary-system barycenter using only the DE kernel — no satellite-kernel download. The barycenter and body center differ by up to a few hundred km due to large moons (e.g. ~290 km for Saturn from Titan, ~230 km for Jupiter from the Galilean moons; only ~0.2 m for Mars). Prefer the _barycenter_ variants for third-body force modeling, which uses the system barycenter with the system GM. Sun, Moon, Mercury, and Venus have no significant satellites, so their body-center and barycenter positions coincide and no barycenter variant is provided.
PCK Orientation¶
PCK queries take a frame class ID — either a raw NAIF frame class ID or a FrameId enum value. The lunar principal-axis frame from the moon_pa_de440 kernel is registered under frame class ID 31008 (FrameId.MOON_PA_DE440 / FrameId::MoonPaDe440).
| Function | Returns |
|---|---|
pck_euler_angles(frame_id, epc) | (angles, rates) as raw arrays: [phi, delta, w] (rad) and their rates (rad/s) |
pck_euler_angle(frame_id, epc) | EulerAngle (order ZXZ, radians) |
pck_euler_rates(frame_id, epc) | [phi_dot, delta_dot, w_dot] (rad/s) as a raw array |
pck_euler_angle_and_rates(frame_id, epc) | (EulerAngle, rates) from a single shared segment lookup |
pck_quaternion(frame_id, epc) | Quaternion (unit quaternion, ICRF to body-fixed) |
pck_rotation_matrix(frame_id, epc) | RotationMatrix (ICRF to body-fixed) |
pck_euler_angles (the original, tuple-of-arrays form) is unchanged and still available alongside the typed functions. pck_rotation_matrix returns a RotationMatrix object rather than a raw array — index it directly (r[(0, 0)]) or call .to_matrix() for a numpy array in Python; in Rust call .to_matrix() to get an SMatrix3<f64> indexable as r.to_matrix()[(0, 0)]. See the EulerAngle, Quaternion, and RotationMatrix references for the full type APIs.
The example below uses the original pck_euler_angles/pck_rotation_matrix pair:
Output
Reference Frame¶
SPK and PCK outputs are expressed in the kernel's inertial reference frame. For DE4xx-era kernels (DE430 and later) that frame is ICRF, even though NAIF labels it "J2000" in kernel metadata and documentation — see the NAIF Frames Required Reading for the frame-ID definitions and the historical "J2000" naming. Brahe applies no additional bias rotation between the kernel output and GCRF: values from spk_*/*_spice queries are GCRF-compatible directly.
Performance¶
SPK and PCK kernels are parsed once, at load_spice_kernel time, into an in-memory segment table. Queries take a short-lived read lock on the shared registry only to look up the relevant segment chain; the Chebyshev evaluation itself runs outside any lock. Repeated queries for the same target/center pair reuse a cached chain, so sequential access patterns (e.g. a propagator stepping through epochs) avoid re-resolving kernel coverage on every call.
See Also¶
- Ephemerides API Reference - Per-body
*_spicefunction reference - SPICE Kernels API Reference - Kernel registry and generic query reference
- NAIF Ephemeris Kernels - Downloading and caching DE/PCK kernel files
- Third-Body Perturbations - Using DE ephemerides in force models
- Epoch - Converting to SPICE ephemeris time (ET)
- NAIF Integer ID Codes - Full NAIF body ID reference
- NAIF DAF Required Reading - Double Precision Array File format underlying SPK and PCK
- NAIF SPK Required Reading - SPK ephemeris kernel format and data types
- NAIF PCK Required Reading - Binary PCK orientation kernel format
- NAIF Frames Required Reading - Reference frame definitions and the "J2000"/ICRF naming