SKD version: v435_20231205_001
Creation: 2023-12-05T10:35:29 by ESA SPICE Service (ESAC/ESA).
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 | FAIL! |
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! |
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.
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')
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.
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-11-26T23:59:30' # Start time
finish_time ='2023-12-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
Ensure that frame changes operations can be performed at any time (incl. instrument frames), meaning all frames are connected.
plan_mk = '/home/esaspice/juice/kernels/mk/juice_ops_local.tm'.replace('ops', 'plan')
spiops.load(plan_mk)
frm_start_time = '2023-11-26T23:59:30' # Start time
frm_finish_time ='2023-12-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)
Check that all TK frames defined with matrices are defined with proper rotation matrices.
all_matrices_ok = spiops.check_rotation_matrices()
test_history.set_test_result('XM-C3', all_matrices_ok)
Check that all instruments fields of view are defined properly.
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
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)
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
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
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm')
target_ck = '/home/esaspice/juice/kernels/ck/juice_sc_meas_231201_231203_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
The following plot shows the drift of the S/C Clock.
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
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:
the second letter defines the reference period of the data:
the third letter indicates the type of data
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
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
Comparison of spacecraft orientation (quaternion) between source AEM Quaternions and generated CK
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm'.replace('ops', 'plan'))
target_ck = '/home/esaspice/juice/kernels/ck/juice_sc_attc_000052_230414_231228_v02.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
Comparison of spacecraft orientation (quaternion) between source AOCS Measured Quaternions and generated CK
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm')
target_ck = '/home/esaspice/juice/kernels/ck/juice_sc_meas_231201_231203_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
Comparison of spacecraft position and velocity between source OEM and generated SPK
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm')
target_spk = '/home/esaspice/juice/kernels/spk/juice_orbc_000052_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
Comparison of JUICE SADM Angle from HK TM and SPICE CK
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
Comparison of +Z axis orientation between predicted and measured attitude in arcseconds
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm')
measured_ck = '/home/esaspice/juice/kernels/ck/juice_sc_meas_231201_231203_s231127_v01.bc'
predicted_ck = '/home/esaspice/juice/kernels/ck/juice_sc_attc_000052_230414_231228_v02.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
Quaternions, JUICE Solar Array Orientation and Solar Aspect Angle, Medium Gain Antenna Orientation and MGA boresight-Earth Angle.
spiops.load('/home/esaspice/juice/kernels/mk/juice_ops_local.tm')
juice.Plot('quaternions', notebook=True)
test_history.set_test_result('XM-Q4', True)
juice.Plot('sa_ang', notebook=True)
test_history.set_test_result('XM-Q5-MPO', True)
juice.Plot('saa_sa', notebook=True)
test_history.set_test_result('XM-Q1-MPO', True)
juice.Plot('mga_angles', notebook=True)
test_history.set_test_result('BC-Q2', True)
juice.Plot('mga_earth', notebook=True)
test_history.set_test_result('BC-Q8', True)
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)
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))
# Unload ops MK
spiceypy.kclear() # Avoid any plan kernel in the kernel pool
# Show validation results
test_history.show_tests()