JUICE SPICE Kernel Dataset Status

SKD version: v440_20240109_001
Creation: 2024-01-11T19:20:10 by ESA SPICE Service (ESAC/ESA).

Validation Results

ID Description Level Threshold Result
XM-C1 Metakernel is valid Consistency OK!
XM-C2 Frame chain Consistency OK!
XM-C3 Rotation matrices Consistency OK!
XM-C4 Fields of view Consistency OK!
XM-V1 Time deviation Validity/Error 50ms OK!
XM-V1-BIS Time correlation Validity/Error 500ms OK!
XM-Q2 S/C Clock Drift Quality/Evolution OK!
XM-V3 Predicted Quaternions to CK error Validity/Warning 5 mdeg OK!
XM-V4 Measured Quaternions to CK error Validity/Warning 5 mdeg OK!
XM-V5 OEM to SPK error Validity/Error 100 m & 250 m/s OK!
XM-V7-JUICE JUICE Solar Array (SA) Angles Validity/Error 100 mdeg OK!
XM-Q3 Attitude Error Quality/Data 500 mdeg OK!
XM-Q4 JUICE Orientation (quaternions w.r.. J2000) Quality/Data OK!
XM-Q5-MPO JUICE Solar Array (SA) Angles Quality/Data OK!
XM-Q1-MPO JUICE SA Solar Aspect Angle Quality/Data OK!
BC-Q2 JUICE Medium Gain Antenna Angles Quality/Data OK!
BC-Q8 JUICE Medium Gain Antenna - Earth Angle Quality/Data OK!
XM-V9 Gap report Validity/Warning OK!
XM-V10 Diff of latest orbit w.r.t. previous orbit Quality/Evolution OK!

Startup

Prepare the testing environment at first stage, so if any validation step fails stopping the execution, the tests are already defined and in fail state.

In [1]:
from spival.classes.history import TestHistory

test_history = TestHistory()
test_history.add_test('XM-C1', 'Metakernel is valid', 'Consistency')
test_history.add_test('XM-C2', 'Frame chain', 'Consistency')
test_history.add_test('XM-C3', 'Rotation matrices', 'Consistency')
test_history.add_test('XM-C4', 'Fields of view', 'Consistency')
test_history.add_test('XM-V1', 'Time deviation', 'Validity/Error', threshold='50ms')
test_history.add_test('XM-V1-BIS', 'Time correlation', 'Validity/Error', threshold='500ms')
test_history.add_test('XM-Q2', 'S/C Clock Drift', 'Quality/Evolution')
test_history.add_test('XM-V3', 'Predicted Quaternions to CK error', 'Validity/Warning', threshold='5 mdeg')
test_history.add_test('XM-V4', 'Measured Quaternions to CK error', 'Validity/Warning', threshold='5 mdeg')
test_history.add_test('XM-V5', 'OEM to SPK error', 'Validity/Error', threshold='100 m & 250 m/s')
test_history.add_test('XM-V7-JUICE', 'JUICE Solar Array (SA) Angles', 'Validity/Error', threshold='100 mdeg')
test_history.add_test('XM-Q3', 'Attitude Error', 'Quality/Data', threshold='500 mdeg')
test_history.add_test('XM-Q4', 'JUICE Orientation (quaternions w.r.. J2000)', 'Quality/Data')
test_history.add_test('XM-Q5-MPO', 'JUICE Solar Array (SA) Angles', 'Quality/Data')
test_history.add_test('XM-Q1-MPO', 'JUICE SA Solar Aspect Angle', 'Quality/Data')
test_history.add_test('BC-Q2', 'JUICE Medium Gain Antenna Angles', 'Quality/Data')
test_history.add_test('BC-Q8', 'JUICE Medium Gain Antenna - Earth Angle', 'Quality/Data')
test_history.add_test('XM-V9', 'Gap report', 'Validity/Warning')
test_history.add_test('XM-V10', 'Diff of latest orbit w.r.t. previous orbit', 'Quality/Evolution')

XM-C1 - Test Metakernel is valid

The metakernel is loaded, the scenario covers a week with a finish time set by the end of coverage of the latest Predicted Attitude Kernel.

In [2]:
from spiops import spiops
import spiceypy

spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm')               
mission_config = spiops.load_config('/home/esaspice/juice/spival.json')               

test_history.set_test_result('XM-C1', True)

start_time = '2023-12-27T23:59:30'                                # Start time
finish_time ='2024-01-03T23:59:30'                               # End time
resolution = 60                                           # Resolution

interval = spiops.TimeWindow(start_time, finish_time, resolution=resolution) # spiops object TimeWindow generated
sun = spiops.Target('SUN', time=interval, frame='IAU_SUN')                   # spiops object Target Sun generated
juice = spiops.Observer('JUICE', time=interval, target=sun, mission_config=mission_config)  # spiops object Observer JUICE generated
spiceypy.kclear()  # Avoid any plan kernel in the kernel pool

Metakernel loaded successfully.

XM-C2 - Frame chain

Ensure that frame changes operations can be performed at any time (incl. instrument frames), meaning all frames are connected.

In [3]:
plan_mk = '/home/esaspice/juice/kernels/mk/juice_ops_local.tm'.replace('ops', 'plan')
spiops.load(plan_mk)
frm_start_time = '2023-12-27T23:59:30'                                # Start time
frm_finish_time ='2024-01-03T23:59:30'                               # End time
num_samples = 100

all_frames_ok = spiops.check_frame_chain(frm_start_time, frm_finish_time, num_samples, ignore_frames=['@EW@_PLAN', '@EW@_MEAS', 'JUICE_RIME'])
test_history.set_test_result('XM-C2', all_frames_ok)

XM-C3 - Rotation matrices

Check that all TK frames defined with matrices are defined with proper rotation matrices.

In [4]:
all_matrices_ok = spiops.check_rotation_matrices()
test_history.set_test_result('XM-C3', all_matrices_ok)
-28881 - JUICE_HAA_UOAF -> OK!
-28750 - JUICE_RPWI_SCM -> OK!
-28740 - JUICE_RPWI_RWI -> OK!
-28310 - JUICE_JMAG_MAGOBS -> OK!
-28300 - JUICE_JMAG_MAGIBS -> OK!
-28044 - JUICE_MGA_EL_ZERO -> OK!
-28040 - JUICE_MGA_APM -> OK!
1502010 - HCI -> OK!
1502301 - LME2000 -> OK!
1503299 - VME2000 -> OK!
1503499 - MME2000 -> OK!
ALL ROTATION MATRICES OK!

XM-C4 - Fields of view

Check that all instruments fields of view are defined properly.

In [5]:
all_fovs_ok = spiops.check_fovs(max_angle_deg=89.99994)
test_history.set_test_result('XM-C4', all_fovs_ok)
spiceypy.kclear()  # Avoid any plan kernel in the kernel pool

XM-V1 - Time deviation

Downloads the time deviation files for a given time range and computes the time difference between the UTC timestamp of packet calculated with SPICE (1st column) and the UTC timestamp of packet calculated from SCOS2K header (3rd column)

In [6]:
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm')
max_time_diff = spiops.time_deviation('JUICE', start_time, finish_time, plot_style='line', notebook=True)
test_history.set_test_result('XM-V1', (max_time_diff != None) and (max_time_diff < 50)) # 50 milliseconds
spiceypy.kclear()  # Avoid any plan kernel in the kernel pool
Avg time difference [ms]: 7.152579251735929
Max time difference [ms]: 9.000062942504883
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead

XM-V1-BIS - Time correlation

Downloads a telemetry file of a given CK and computes the time difference between the UTC time (1st column) and the clock string (2nd column) in milliseconds

In [7]:
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm')
target_ck = '/home/esaspice/juice/kernels/ck/juice_sc_meas_240101_240103_s231127_v01.bc'
max_time_diff = spiops.time_correlation('JUICE', target_ck, plot_style='line', notebook=True)
test_history.set_test_result('XM-V1-BIS', (max_time_diff != None) and (max_time_diff < 500)) # 500 milliseconds
spiceypy.kclear()  # Avoid any plan kernel in the kernel pool
AOCS tab file: juice_raw_hk_aocs_measured_attitude_20240103.tab
Avg time difference [ms]: 0.4982422623369429
Max time difference [ms]: 0.9998083114624023
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead

XM-Q2 - S/C Clock Drift

The following plot shows the drift of the S/C Clock.

In [8]:
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm')
juice.Plot('clock_drift', notebook=True)
test_history.set_test_result('XM-Q2', True)
spiceypy.kclear()  # Avoid any plan kernel in the kernel pool
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead

Coverage

The coverage provided by the SPK and CK files is displayed for the Operational and the Planning meta-kernels.

The Data type designation includes a reference to the originator of the data, the type of data and the reference period is provided. This is a three letter acronym. The first letter defines the file originator:

  • s: Science Operation
  • m: Mission Analysis
  • f: Flight Dynamic

the second letter defines the reference period of the data:

  • c: Cruise phase reference
  • l: Science phase Long term reference
  • m: Science phase Medium term reference
  • s: Science phase Short term reference
  • o: Undefined reference

the third letter indicates the type of data

  • p: Predicted data
  • r: Reconstructed data
  • t: Test data
  • c: Commanded data (from Housekeeping Telemetry)
  • m: Measured data (from Housekeeping Telemetry)
In [9]:
spiops.ck_coverage_timeline('/home/esaspice/juice/kernels/mk/juice_ops_local.tm', ['JUICE_SPACECRAFT_PLAN', 'JUICE_SPACECRAFT_MEAS'])
spiops.ck_coverage_timeline('/home/esaspice/juice/kernels/mk/juice_ops_local.tm'.replace('ops', 'plan'), ['JUICE_SPACECRAFT_PLAN', 'JUICE_SPACECRAFT_MEAS'])
spiceypy.kclear()  # Avoid any plan kernel in the kernel pool
Loading BokehJS ...
Loading BokehJS ...
In [10]:
spiops.spk_coverage_timeline('/home/esaspice/juice/kernels/mk/juice_ops_local.tm', ['JUICE'])
spiops.spk_coverage_timeline('/home/esaspice/juice/kernels/mk/juice_ops_local.tm'.replace('ops', 'plan'), ['JUICE'])
spiceypy.kclear()  # Avoid any plan kernel in the kernel pool
Loading BokehJS ...
Loading BokehJS ...

XM-V3 - Predicted Quaternions to CK error

Comparison of spacecraft orientation (quaternion) between source AEM Quaternions and generated CK

In [11]:
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm'.replace('ops', 'plan'))
target_ck = '/home/esaspice/juice/kernels/ck/juice_sc_attc_000054_230414_240301_v01.bc'
max_err = spiops.ckVsAEM('JUICE', target_ck, mission_config, plot_style='line', notebook=True)
test_history.set_test_result('XM-V3', (max_err != None) and (max_err < 5)) # 5mdeg
spiceypy.kclear()  # Avoid any plan kernel in the kernel pool
AEM file: ATTC__000054.jui
Excluded intervals:
   2023-May-17 11:56:40 - 2023-May-17 11:56:50
   2023-May-17 11:59:55 - 2023-May-17 12:00:05
   2023-May-26 13:03:00 - 2023-May-26 13:03:30
   2023-Dec-28 08:00:00 - 2023-Dec-28 16:00:00
Avg QX error:  3.3685632001291147e-12
Avg QY error:  2.7919854321219854e-12
Avg QZ error:  5.174329569035104e-12
Avg QW error:  3.949209175778781e-12
Max angular error [mdeg]: 0.00025617909246514783 at 2023-04-25T11:20:10.00
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead

XM-V4 - Measured Quaternions to CK error

Comparison of spacecraft orientation (quaternion) between source AOCS Measured Quaternions and generated CK

In [12]:
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm')
target_ck = '/home/esaspice/juice/kernels/ck/juice_sc_meas_240101_240103_s231127_v01.bc'
max_err = spiops.ckVsAocs('JUICE', target_ck, mission_config, plot_style='circle', notebook=True)
test_history.set_test_result('XM-V4', (max_err != None) and (max_err < 5)) # 5mdeg
spiceypy.kclear()  # Avoid any plan kernel in the kernel pool
AOCS tab file: juice_raw_hk_aocs_measured_attitude_20240103.tab
Avg QX error:  5.944660928944488e-09
Avg QY error:  6.533083607664457e-09
Avg QZ error:  1.0073176680261573e-08
Avg QW error:  9.651168810465354e-09
Max angular error [mdeg]: 0.037200205848408455 at 2024-01-03T00:49:30.15
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead

XM-V5 - OEM to SPK error

Comparison of spacecraft position and velocity between source OEM and generated SPK

In [13]:
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm')
target_spk = '/home/esaspice/juice/kernels/spk/juice_orbc_000054_230414_310721_v01.bsp'
max_pos_err, max_vel_err = spiops.spkVsOem('JUICE', target_spk, mission_config, plot_style='line', notebook=True)
test_history.set_test_result('XM-V5', (max_pos_err != None) and (max_pos_err < 0.1) and (max_vel_err < 0.25))
spiceypy.kclear()  # Avoid any plan kernel in the kernel pool
OEM file: ORBC__000054.jui
Warning: using previous segment boundary point at 2023-05-28T05:52:10.76500099
Excluded intervals:
   2023-Jul-05 04:52:30 - 2023-Jul-05 04:53:00
Avg position error [km]: 4.6972725152980645e-07 , max position error [km]: 5.076641319044152e-06 at 2025-08-31T06:47:34.71743743
Avg velocity error [km/s]: 5.6821378060235165e-06 , max velocity error [km/s]: 0.09674924704079924 at 2023-05-26T14:02:52.47502024
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead

XM-V7-JUICE - JUICE Solar Array (SA) Angles

Comparison of JUICE SADM Angle from HK TM and SPICE CK

In [14]:
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm')
max_err = spiops.saa_vs_hk_sa_position('JUICE', plot_style='circle', notebook=True)
test_history.set_test_result('XM-V7-JUICE', (max_err != None) and (max_err < 100)) # 100mdeg
spiceypy.kclear()  # Avoid any plan kernel in the kernel pool
Max angular error [mdeg]: 1.4210854715202004e-11
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead

XM-Q3 - Attitude Error

Comparison of +Z axis orientation between predicted and measured attitude in arcseconds

In [15]:
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm')
measured_ck = '/home/esaspice/juice/kernels/ck/juice_sc_meas_240101_240103_s231127_v01.bc'
predicted_ck = '/home/esaspice/juice/kernels/ck/juice_sc_attc_000054_230414_240301_v01.bc'
resolution = 30

res = spiops.ckdiff_error(measured_ck, predicted_ck, ['JUICE_SPACECRAFT_MEAS', 'JUICE_SPACECRAFT_PLAN'], 'J2000', resolution, 0.001, 
                    plot_style='circle', utc_start=start_time, utc_finish=finish_time, notebook=True, mission_config=mission_config)
test_history.set_test_result('XM-Q3', (res != None) and (res < 500)) # 500mdeg
spiceypy.kclear()  # Avoid any plan kernel in the kernel pool
Removed 0 datapoints from excluded intervals
Excluded intervals:
   2023-Oct-26 19:16:09 - 2023-Oct-26 20:16:09
   2023-Nov-17 15:01:09 - 2023-Nov-17 17:01:09
Max angular error [mdeg]: 17.025415120782174
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead

S/C Structures Orientation

Quaternions, JUICE Solar Array Orientation and Solar Aspect Angle, Medium Gain Antenna Orientation and MGA boresight-Earth Angle.

XM-Q4 - JUICE Orientation (quaternions w.r.. J2000)

In [16]:
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm')
juice.Plot('quaternions', notebook=True)
test_history.set_test_result('XM-Q4', True)
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead

XM-Q5-MPO - JUICE Solar Array (SA) Angles

In [17]:
juice.Plot('sa_ang', notebook=True)
test_history.set_test_result('XM-Q5-MPO', True)
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead

XM-Q1-MPO - JUICE SA Solar Aspect Angle

In [18]:
juice.Plot('saa_sa', notebook=True)
test_history.set_test_result('XM-Q1-MPO', True)
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead

BC-Q2 - JUICE Medium Gain Antenna Angles

In [19]:
juice.Plot('mga_angles', notebook=True)
test_history.set_test_result('BC-Q2', True)
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead

BC-Q8 - JUICE Medium Gain Antenna - Earth Angle

In [20]:
juice.Plot('mga_earth', notebook=True)
test_history.set_test_result('BC-Q8', True)
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead

XM-V9 - Gap Report

In [21]:
frames = ['JUICE_SPACECRAFT_MEAS','JUICE_SA+Y_MEAS', 'JUICE_MGA_AZ_MEAS']
spiops.ck_gap_report('/home/esaspice/juice/kernels/mk/juice_ops_local.tm', frames)
test_history.set_test_result('XM-V9', True)
Loading BokehJS ...

XM-V10 - Diff of latest orbit w.r.t. previous orbit

In [22]:
spk_expression = 'juice_orbc_??????_??????_??????_v??.bsp'
num_samples = 5000
max_position_error = spiops.spk_diff('JUICE', spk_expression, num_samples, notebook=True)
test_history.set_test_result('XM-V10', (max_position_error != None))
Loaded: juice_orbc_000053_230414_310721_v01.bsp
Loaded: juice_orbc_000054_230414_310721_v01.bsp
Avg position difference [Km]: 69.08734305170027
Max position difference [Km]: 193.3084543254628
Avg velocity difference [Km/s]: 5.956706725449317e-06
Max velocity difference [Km/s]: 0.00040418571895070175
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
Loading BokehJS ...
BokehDeprecationWarning: 'legend' keyword is deprecated, use explicit 'legend_label', 'legend_field', or 'legend_group' keywords instead
In [23]:
# Unload ops MK
spiceypy.kclear()  # Avoid any plan kernel in the kernel pool
In [24]:
# Show validation results
test_history.show_tests()