A Python wrapper for the NAIF CSPICE Toolkit providing essential tools for spacecraft navigation and planetary science calculations
Spacecraft and instrument attitude/pointing data management using C-kernels. CK files store time-ordered orientation information that describes how spacecraft, instruments, and reference frames are oriented in space, enabling precise pointing calculations for observations and navigation.
Create, open, and manage CK files containing orientation data.
def ckopn(fname: str, ifname: str, ncomch: int) -> int:
"""
Open new CK file for writing.
Parameters:
- fname: str, CK file name
- ifname: str, internal file name
- ncomch: int, number of comment characters
Returns:
int: file handle
"""
def ckcls(handle: int) -> None:
"""
Close CK file.
Parameters:
- handle: int, file handle
Returns:
None
"""Get spacecraft and instrument pointing information from CK files.
def ckgp(inst: int, sclkdp: float, tol: float, ref: str) -> Tuple[ndarray, float, bool]:
"""
Get pointing (attitude matrix) from CK file.
Parameters:
- inst: int, instrument ID code
- sclkdp: float, spacecraft clock time
- tol: float, time tolerance
- ref: str, reference frame
Returns:
Tuple[ndarray, float, bool]: (c_matrix, clkout, found)
"""
def ckgpav(inst: int, sclkdp: float, tol: float, ref: str) -> Tuple[ndarray, ndarray, float, bool]:
"""
Get pointing and angular velocity from CK file.
Parameters:
- inst: int, instrument ID code
- sclkdp: float, spacecraft clock time
- tol: float, time tolerance
- ref: str, reference frame
Returns:
Tuple[ndarray, ndarray, float, bool]: (c_matrix, av, clkout, found)
"""Compute orientation transformations between reference frames.
def ckfrot(inst: int, et: float) -> Tuple[ndarray, str, bool]:
"""
Get frame rotation from CK file using ET.
Parameters:
- inst: int, instrument ID code
- et: float, ephemeris time
Returns:
Tuple[ndarray, str, bool]: (rotate, ref, found)
"""
def ckfxfm(inst: int, et: float) -> Tuple[ndarray, str, bool]:
"""
Get frame transformation (6x6 state matrix) from CK file.
Parameters:
- inst: int, instrument ID code
- et: float, ephemeris time
Returns:
Tuple[ndarray, str, bool]: (xform, ref, found)
"""Write various types of CK segments for different attitude parameterizations.
def ckw01(handle: int, begtim: float, endtim: float, inst: int, ref: str, avflag: bool, segid: str, nrec: int, sclkdp: ndarray, quats: ndarray, avvs: ndarray) -> None:
"""
Write Type 1 CK segment (discrete pointing).
Parameters:
- handle: int, file handle
- begtim: float, segment begin time
- endtim: float, segment end time
- inst: int, instrument ID
- ref: str, reference frame
- avflag: bool, angular velocity flag
- segid: str, segment identifier
- nrec: int, number of records
- sclkdp: ndarray, spacecraft clock times
- quats: ndarray, quaternions (4 x nrec)
- avvs: ndarray, angular velocities (3 x nrec)
Returns:
None
"""
def ckw02(handle: int, begtim: float, endtim: float, inst: int, ref: str, segid: str, nrec: int, start: ndarray, stop: ndarray, quats: ndarray, avvs: ndarray, rates: ndarray) -> None:
"""
Write Type 2 CK segment (linearly interpolated pointing).
Parameters:
- handle: int, file handle
- begtim: float, segment begin time
- endtim: float, segment end time
- inst: int, instrument ID
- ref: str, reference frame
- segid: str, segment identifier
- nrec: int, number of records
- start: ndarray, interval start times
- stop: ndarray, interval stop times
- quats: ndarray, quaternions
- avvs: ndarray, angular velocities
- rates: ndarray, angular acceleration
Returns:
None
"""
def ckw03(handle: int, begtim: float, endtim: float, inst: int, ref: str, avflag: bool, segid: str, nrec: int, sclkdp: ndarray, quats: ndarray, avvs: ndarray, nints: int, starts: ndarray) -> None:
"""
Write Type 3 CK segment (Chebyshev polynomials).
Parameters:
- handle: int, file handle
- begtim: float, segment begin time
- endtim: float, segment end time
- inst: int, instrument ID
- ref: str, reference frame
- avflag: bool, angular velocity flag
- segid: str, segment identifier
- nrec: int, number of records
- sclkdp: ndarray, spacecraft clock times
- quats: ndarray, quaternions
- avvs: ndarray, angular velocities
- nints: int, number of intervals
- starts: ndarray, interval start indices
Returns:
None
"""
def ckw05(handle: int, subtype: int, degree: int, begtim: float, endtim: float, inst: int, ref: str, avflag: bool, segid: str, n: int, sclkdp: ndarray, packts: ndarray, rate: float, nints: int, starts: ndarray) -> None:
"""
Write Type 5 CK segment (MEX/Rosetta format).
Parameters:
- handle: int, file handle
- subtype: int, subtype code
- degree: int, polynomial degree
- begtim: float, segment begin time
- endtim: float, segment end time
- inst: int, instrument ID
- ref: str, reference frame
- avflag: bool, angular velocity flag
- segid: str, segment identifier
- n: int, number of packets
- sclkdp: ndarray, spacecraft clock times
- packts: ndarray, data packets
- rate: float, nominal tick rate
- nints: int, number of intervals
- starts: ndarray, interval start indices
Returns:
None
"""Analyze time coverage and data availability in CK files.
def ckcov(ck: str, idcode: int, needav: bool, level: str, tol: float, timsys: str, cover: SpiceCell) -> None:
"""
Find time coverage windows for CK object.
Parameters:
- ck: str, CK file name
- idcode: int, instrument/spacecraft ID
- needav: bool, require angular velocity data
- level: str, coverage level ("SEGMENT" or "INTERVAL")
- tol: float, time tolerance
- timsys: str, time system ("SCLK" or "TDB")
- cover: SpiceCell, coverage window (modified)
Returns:
None (coverage window updated in place)
"""
def ckobj(ck: str) -> List[int]:
"""
Get object ID codes for all objects in CK file.
Parameters:
- ck: str, CK file name
Returns:
List[int]: object ID codes
"""Access raw CK data at the segment level.
def cklpf(fname: str) -> int:
"""
Load CK file, return handle.
Parameters:
- fname: str, CK file name
Returns:
int: file handle
"""
def ckupf(handle: int) -> None:
"""
Unload CK file.
Parameters:
- handle: int, file handle
Returns:
None
"""Query metadata and structure of CK segments.
def cknr02(handle: int, descr: SpiceDLADescr) -> int:
"""
Get number of records in Type 2 CK segment.
Parameters:
- handle: int, CK file handle
- descr: SpiceDLADescr, segment descriptor
Returns:
int: number of records
"""
def cknr03(handle: int, descr: SpiceDLADescr) -> int:
"""
Get number of records in Type 3 CK segment.
Parameters:
- handle: int, CK file handle
- descr: SpiceDLADescr, segment descriptor
Returns:
int: number of records
"""
def ckgr02(handle: int, descr: SpiceDLADescr, recno: int) -> Tuple[float, float, ndarray, ndarray, float]:
"""
Get record from Type 2 CK segment.
Parameters:
- handle: int, CK file handle
- descr: SpiceDLADescr, segment descriptor
- recno: int, record number
Returns:
Tuple[float, float, ndarray, ndarray, float]: (start, stop, quat, av, rate)
"""
def ckgr03(handle: int, descr: SpiceDLADescr, recno: int) -> Tuple[float, ndarray, ndarray]:
"""
Get record from Type 3 CK segment.
Parameters:
- handle: int, CK file handle
- descr: SpiceDLADescr, segment descriptor
- recno: int, record number
Returns:
Tuple[float, ndarray, ndarray]: (sclkdp, quat, av)
"""Get information about loaded CK files and instruments.
def ckmeta(ckid: int, meta: str) -> Union[str, int]:
"""
Get metadata for CK instrument.
Parameters:
- ckid: int, CK instrument ID
- meta: str, metadata item ("SPK_ID", "FRAME_ID", "FRAME_NAME", etc.)
Returns:
Union[str, int]: metadata value
"""import spiceypy as spice
import numpy as np
# Load CK file and other kernels
spice.furnsh("spacecraft_attitude.bc")
spice.furnsh("spacecraft_sclk.tsc")
# Convert time to spacecraft clock
et = spice.str2et("2023-01-01T12:00:00")
spacecraft_id = -123
sclk = spice.sce2s(spacecraft_id, et)
# Get spacecraft pointing matrix
inst_id = -123000 # instrument ID
tolerance = 1.0 # 1 second tolerance
ref_frame = "J2000"
c_matrix, clkout, found = spice.ckgp(inst_id, sclk, tolerance, ref_frame)
if found:
print(f"Attitude matrix at SCLK {clkout}:")
print(c_matrix)
# Convert to Euler angles if needed
angles = spice.m2eul(c_matrix, 3, 1, 3) # Z-X-Z sequence
print(f"Euler angles (Z-X-Z): {np.degrees(angles)} degrees")# Get both attitude and angular velocity
c_matrix, av, clkout, found = spice.ckgpav(inst_id, sclk, tolerance, ref_frame)
if found:
print(f"Attitude matrix:\n{c_matrix}")
print(f"Angular velocity: {av} rad/sec")
# Angular velocity magnitude
av_magnitude = spice.vnorm(av)
print(f"Angular velocity magnitude: {av_magnitude} rad/sec")import numpy as np
# Open new CK file
handle = spice.ckopn("spacecraft_attitude.bc", "Spacecraft Attitude Data", 0)
# Define attitude data
inst_id = -123000
ref_frame = "J2000"
segment_id = "Attitude Segment 1"
# Time range and data
begin_time = spice.str2et("2023-01-01T00:00:00")
end_time = spice.str2et("2023-01-02T00:00:00")
# Convert times to spacecraft clock
sclk_times = []
for i in range(24): # hourly data points
et = begin_time + i * 3600.0 # hours to seconds
sclk = spice.sce2s(spacecraft_id, et)
sclk_times.append(sclk)
sclk_array = np.array(sclk_times)
# Generate quaternions (example: slow rotation about Z-axis)
quaternions = []
angular_velocities = []
for i, sclk in enumerate(sclk_times):
# Rotation angle increases linearly with time
angle = 2 * np.pi * i / len(sclk_times) # one full rotation per day
# Quaternion for rotation about Z-axis
quat = np.array([
np.cos(angle/2), 0, 0, np.sin(angle/2) # [w, x, y, z]
])
quaternions.append(quat)
# Angular velocity (constant rotation about Z)
av = np.array([0, 0, 2*np.pi/(24*3600)]) # rad/sec
angular_velocities.append(av)
quats_array = np.array(quaternions).T # 4 x N
avs_array = np.array(angular_velocities).T # 3 x N
# Write Type 1 CK segment
spice.ckw01(
handle, begin_time, end_time, inst_id, ref_frame,
True, # include angular velocity
segment_id, len(sclk_times), sclk_array, quats_array, avs_array
)
# Close CK file
spice.ckcls(handle)# Create time window for coverage analysis
coverage = spice.cell_double(1000)
# Find coverage for specific instrument
ck_file = "spacecraft_attitude.bc"
spice.ckcov(
ck_file,
inst_id,
False, # don't require angular velocity
"INTERVAL", # interval-level coverage
0.0, # no tolerance
"SCLK", # spacecraft clock time
coverage
)
# Display coverage intervals
num_intervals = spice.wncard(coverage)
print(f"Found {num_intervals} coverage intervals:")
for i in range(num_intervals):
start_sclk, stop_sclk = spice.wnfetd(coverage, i)
# Convert back to ET for display
start_et = spice.scs2e(spacecraft_id, start_sclk)
stop_et = spice.scs2e(spacecraft_id, stop_sclk)
start_utc = spice.et2utc(start_et, "C", 0)
stop_utc = spice.et2utc(stop_et, "C", 0)
print(f" Interval {i}: {start_utc} to {stop_utc}")# Get all objects in CK file
object_ids = spice.ckobj("spacecraft_attitude.bc")
print(f"Objects in CK file: {object_ids}")
# Get metadata for each object
for obj_id in object_ids:
try:
frame_name = spice.ckmeta(obj_id, "FRAME_NAME")
frame_id = spice.ckmeta(obj_id, "FRAME_ID")
print(f"Object {obj_id}: Frame {frame_name} (ID {frame_id})")
except:
print(f"Object {obj_id}: Unable to retrieve metadata")Install with Tessl CLI
npx tessl i tessl/pypi-spiceypydocs