JUICE SPICE Kernel Dataset Status

SKD version: v441_20240321_001
Creation: 2024-03-21T14:50:44 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 FAIL!
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 FAIL!
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 = '2024-02-27T08:21:28'                                # Start time
finish_time ='2024-03-05T08:21:28'                               # 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 = '2024-02-27T08:21:28'                                # Start time
frm_finish_time ='2024-03-05T08:21:28'                               # 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]: 1.0820438701008994
Max time difference [ms]: 2.000093460083008
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_240301_240305_s240214_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_20240305.tab
Avg time difference [ms]: 0.5128146167770326
Max time difference [ms]: 0.9963512420654297
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_000057_230414_240503_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__000057.jui
AEM file cannot be downloaded!

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_240301_240305_s240214_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_20240305.tab
Avg QX error:  3.2937189783219276e-11
Avg QY error:  4.5293425979154156e-11
Avg QZ error:  1.7230092961072212e-11
Avg QW error:  1.1318468738613751e-11
Max angular error [mdeg]: 2.789347545130205e-05 at 2024-03-05T02:00:28.97
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_000057_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__000057.jui
OEM file cannot be downloaded!

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]: 0
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_240301_240305_s240214_v01.bc'
predicted_ck = '/home/esaspice/juice/kernels/ck/juice_sc_attc_000057_230414_240503_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]: 6.54173022407728
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_000055_230414_310721_v01.bsp
Loaded: juice_orbc_000056_230414_310721_v01.bsp
Avg position difference [Km]: 165.70260544768973
Max position difference [Km]: 1687.6821767582703
Avg velocity difference [Km/s]: 2.453536401408963e-05
Max velocity difference [Km/s]: 0.00309571426147151
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()