Space is huge - our entire solar system is about 9.09 billion kilometers in diameter, and at those scales even the radius of the sun at 695,508 seems tiny in comparison. So how is it that we can communicate with probes like New Horizons, 4.5 light-hours away, with unerring accuracy?

During my work with Mars 2020, I was able to play around with SPICE, a NASA toolkit that has become the standard for positioning and timing in space. SPICE is also used by ESA, JAXA, ISRO, and KARI. The best part is, it’s open source and the toolkit is open for anyone to download! However, the concepts took a while to understand. That’s why I thought it would be a good idea to document the “big ideas” used in the toolkit, which I found extremely interesting. Let’s start with time.

When you are

Time in SPICE is specified in multiple different systems, all of which revolve around epochs, which are events we can set a time to. For example, an epoch may be set to the oscillations of a quartz crystal, or Earth’s rotation around it’s axis. Multiple systems exist since we have different ways to represent time, and different epochs we can set our time to.

Everyone uses Coordinated Universal Time (UTC) in everyday life. We specify it as a string like this: 1999-03-21T12:28:29.702. It’s not the best representation for space missions however, as UTC noon often does not match perfectly with astronomical noon (in the UT1 format, where the sun is directly over the Greenwich zenith meridian) as the Earth’s rotation is not uniform, so leap seconds need to be added at the end of either June 30 or December 31. Having a non-uniform time system is a recipe for disaster, which is where International Atomic Time (TAI) comes in.

The format of International Atomic Time is similar to the UNIX epoch. TAI measures atomic seconds from UTC midnight on 1 Jan 1958 (in UNIX it’s from midnight on 1 Jan 1970). As it uses an atomic clock for timekeeping, our epochs are fully uniform, which lets us calculate time without worrying too much about offsets like UTC. We specify it similarly to a UNIX timestamp you can get with date +%s.

The most basic system for counting time in SPICE is the Barycentric Dynamical Time (TDB), which is also known as Ephemeris Time (ET). This is set with an offset and a scale to Barycentric Coordinate Time (TCB), a clock at rest but outside the Solar system’s gravity well. This means that TCB ticks about 490 milliseconds faster per year than TAI. However, ET advances on average at almost the same rate as TAI, which is good enough for navigation in the solar system. This is also specified in the same way as a UNIX timestamp.

The spacecraft also contains clocks to schedule operations, which is a count of clock-dependent “ticks” from some reference tick. Since these clocks aren’t very stable, we have to account for drift in the duration of the “tick.” In SPICE, spacecraft time (SCLK) is encoded as a double-precision number called “ticks” for ease of conversion, but it’s often expressed as a character string that differs by mission, and is specified in kernels. That’s because each clock may have a “tick” that denotes different amounts of time passing, or varying accuracy of ticks. That’s why Cassini’s SCLK format (1/4294967295.255) is completely different from that of Galileo’s (1/16777215:90:09:07).

SPICE contains a utility (chronos) to convert between UTC, ET, and SCLK. But how would we store all the offsets, or how much time each “tick” actually is?

LSK and SCLK Kernels

A leapsecond kernel (LSK) is a file listing every leap second that has ever occurred, and gets updated whenever a new one is announced. It contains the dates on which a leap second occurred. For example, here’s the LSK used by Mars Science Laboratory (MSL):

DELTET/DELTA_AT        = ( 10,   @1972-JAN-1
                           11,   @1972-JUL-1     
                           12,   @1973-JAN-1     
                           13,   @1974-JAN-1     
                           14,   @1975-JAN-1          
                           15,   @1976-JAN-1          
                           16,   @1977-JAN-1          
                           17,   @1978-JAN-1          
                           18,   @1979-JAN-1          
                           19,   @1980-JAN-1          
                           20,   @1981-JUL-1          
                           21,   @1982-JUL-1          
                           22,   @1983-JUL-1          
                           23,   @1985-JUL-1          
                           24,   @1988-JAN-1 
                           25,   @1990-JAN-1
                           26,   @1991-JAN-1 
                           27,   @1992-JUL-1
                           28,   @1993-JUL-1
                           29,   @1994-JUL-1
                           30,   @1996-JAN-1 
                           31,   @1997-JUL-1
                           32,   @1999-JAN-1
                           33,   @2006-JAN-1
                           34,   @2009-JAN-1
                           35,   @2012-JUL-1
                           36,   @2015-JUL-1 
                           37,   @2017-JAN-1 )

SCLK kernels allow us to translate from a spacecraft clock to other time systems. You can find one of MSL’s here:

SCLK_PARTITION_START_76900  = ( 0.00000000000000E+00 )

SCLK_PARTITION_END_76900    = ( 3.15576000000000E+14 )

SCLK01_COEFFICIENTS_76900   = (
   0.0000000000000E+00     397446666.183    88775.24400000
                         )

The partitions mentioned in the kernel are the time when the spacecraft clock rolls over, at which point the SCLK would go from 1/** to 2/**. The coefficients are the interesting part. 88775.24400000 is the number of ET seconds per Martian day (or Sol). 397446666.183 is the exact landing time of MSL on Mars in seconds from midnight at GMT on Jan 1 2000 - 2012-08-06T05:17:55 in UTC.

Where you are

To know your position, you’ll need two things:

  • Another object to measure your position from (an origin)
  • A way to measure how far you are from that object (a unit of distance)

In SPICE, this translates to a reference frame and a coordinate system. A reference frame can be an inertial frame, where the origin is the barycenter of the Solar system. The most common inertial reference frame used is ICRF, which is defined by extragalactic radio sources, and coincides closely with the J2000 frame, which is based on Earth’s equator and equinox at 2000-01-01T12:00:00. This is useful for travel through the Solar system.

A body-fixed frame, on the other hand, is tied to a celestial body and rotates with it, which is useful to position parts on a spacecraft.

Then there are topocentric frames, which are attached to the surface of a celestial body. This is useful for landers and rovers.

Finally, we have dynamic frames, where the orientations change with time. This is useful for knowing where to point antennas to communicate with probes.

SPICE also supports multiple coordinate systems, including planetocentric, planetodetic, and planetographic ones. Our Longitude/Latitude system is an example of a planetocentric system, where we assume the planet is spherical and measure using the Prime Meridian and the Equator. A planetodetic system, however, keeps longitude but the latitude becomes the angle measured from the X-Y plane to the surface normal at the point of interest. A planetographic system is similar to a planetodetic system, but longitude increases against the direction of the planet’s rotation, except for the earth, moon and sun, where longitude is positive east by default. The planetographic system is only fixed for planets and satellites, as there are conflicting standards for dwarf planets, asteroids and comets. SPICE comes with utilities to convert between these systems.

Each spacecraft often has multiple body-fixed frames for its instruments, in addition to an inertial frame or topocentric frame to locate the spacecraft. For example, a high-gain antenna may have it’s own frame and orientation data. Data for these frames are stored in spk, ck, and fk files. How do these files work?

SPK, CK, FK, and PCK files

An spk file contains position and velocity data for objects. Each spk kernel can contain multiple objects. When resolving the position of an object, SPICE can also look through all its loadeded kernels to compute the vectors needed. You can find one used for MSL here. Each object is stored in a simple binary format:

Target, Ref Frame ID, Center of Motion, T_start, T_stop
epoch_1,  x1,  y1,  z1,  vx1,  vy1,  vz1
...
epoch_n,  xn,  yn,  zn,  vxn,  vyn,  vzn

A pck file contains orientation and shape models for natural celestial bodies. It can be in text form, or a binary form if high accuracy data is available. Polynomials are used to describe the declination and rotation of the pole, as well as the prime meridian. You can find one used by MSL here. An entry in a text-based PCK file would look like this:

BODY610_POLE_RA       = (  40.58    -0.036       0. )
BODY610_POLE_DEC      = (  83.52    -0.004       0. )
BODY610_PM            = (  58.83   518.2359876   0. )
BODY610_LONG_AXIS     = (   0.                      )

BODY610_NUT_PREC_RA   = ( 0. -1.623  0. 0. 0. 0. 0. 0.  0.023 )
BODY610_NUT_PREC_DEC  = ( 0. -0.183  0. 0. 0. 0. 0. 0.  0.001 )
BODY610_NUT_PREC_PM   = ( 0.  1.613  0. 0. 0. 0. 0. 0. -0.023 )

A ck file contains orientation data for a spacecraft or a component on that spacecraft. It’s stored in a rather complicated binary format, so I won’t go into detail on it.

A fk file contains frame data that allows for easy translation between each frame’s coordinate system. Here’s what an entry looks like:

FRAME_DAWN_SPACECRAFT  = -203000
FRAME_-203000_NAME     = 'DAWN_SPACECRAFT’
FRAME_-203000_CLASS    =  3
FRAME_-203000_CLASS_ID = -203000
FRAME_-203000_CENTER   = -203

These entries note that frame ID -203000 has name DAWN_SPACECRAFT, with class 3, which means it is a CK-based frame. The CLASS_ID tells us that the ID of the CK structure of this entry is -203000, and is centered at the object -203.

Aberration Corrections

Positions can now be determined given a state vector and a reference frame. SPICE provides many features relating to positioning, including conversion between coordinate systems and reference frames, as well as a cool feature called aberration corrections. These are corrections made to state vectors to account for the travel time of light and stellar aberration.

For example, let’s say our spacecraft is trying to image a moving object 8 light seconds away. SPICE would show that the object is 8 light-seconds away, but is also moving in another direction. However, in order to take a picture with the planet centered, we would need to point our camera at the object as it was 8 seconds ago. There is one problem though: we’re assuming that our spacecraft is not moving at the same time (stellar aberration). We can correct this by pointing our cameras slightly away from the spacecraft’s direction of travel.

SPICE provides a utility for this, called STATES. Usage is simple:

~
⟩ ./cspice/exe/states

                Welcome to STATES

This program demonstrates the use of NAIF S- and P-
Kernel (SPK) files and subroutines by computing the
state of a target body as seen from an observing
body at a number of epochs within a given time
interval.


Enter the name of a leapseconds kernel file: naif0012.tls

Enter the name of a binary SPK ephemeris file: de425s.bsp

Enter the name of the observing body: Mars

Enter the name of a target body: Earth

Enter the number of states to be calculated: 24

Enter the beginning UTC time: 1 jan 2020

Enter the ending UTC time: 5 jan 2020

Enter the inertial reference frame (e.g.:J2000): J2000

Type of correction                              Type of state
-------------------------------------------------------------
'LT+S'    Light-time and stellar aberration    Apparent state
'LT'      Light-time only                      True state
'NONE'    No correction                        Geometric state

Enter LT+S, LT, or NONE: LT+S

Working ... Please wait

For time 1 of 24, the state of:
Body            : Earth
Relative to body: Mars
In Frame        : J2000
At UTC time     : 2020 JAN 01 00:00:00

                 Position (km)              Velocity (km/s)
            -----------------------     -----------------------
          X:  1.7264994106068176e+08        -4.4257725250749800e+01
          Y:  2.5540840124038413e+08         1.1538086331635352e+01
          Z:  1.0847062666574109e+08         5.8006544004475851e+00
  MAGNITUDE:  3.2681390793796480e+08      4.6103375928890053e+01


Continue? (Enter Y or N): y

Here’s the results without abberation correction:

For time 1 of 24, the state of:
Body            : Earth
Relative to body: Mars
In Frame        : J2000
At UTC time     : 2020 JAN 01 00:00:00

                 Position (km)              Velocity (km/s)
            -----------------------     -----------------------
          X:  1.7259725326375243e+08        -4.4256182271235772e+01
          Y:  2.5541439777498752e+08         1.1529246064486195e+01
          Z:  1.0847415490990619e+08         5.7967956829135803e+00
  MAGNITUDE:  3.2679193488880628e+08      4.6099197652776560e+01

Remember that J2000 is actually ICRF here. Also, because SPICE uses vectors for the location of each planet, the choice of reference frame won’t change our final answer since the component of the vector in the direction of the origin cancels out. We also see very minimal changes due to aberration since Earth and Mars are closer together, but if we look at the state of an object farther away, like Pluto, we’ll get a much more noticable distortion.

I was actually surprised and very impressed at the amount of thought put into something as simple as knowing your position and time in space. Even this post only scratches the surface of what SPICE does. Aside from command-line utilities, it also includes APIs for C, FORTRAN, IDL, Java, and MATLAB. Bindings are also available for other languages, including Python. If you’re interested in playing around with it, you can download the toolkit as well as existing mission data and try it out yourself!