imap-processing 0.11.0__py3-none-any.whl → 0.12.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of imap-processing might be problematic. Click here for more details.
- imap_processing/__init__.py +10 -11
- imap_processing/_version.py +2 -2
- imap_processing/ccsds/excel_to_xtce.py +65 -16
- imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +6 -28
- imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +365 -42
- imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +0 -5
- imap_processing/cdf/config/imap_hi_global_cdf_attrs.yaml +10 -11
- imap_processing/cdf/config/imap_hi_variable_attrs.yaml +17 -19
- imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +26 -13
- imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +106 -116
- imap_processing/cdf/config/imap_hit_l1b_variable_attrs.yaml +120 -145
- imap_processing/cdf/config/imap_hit_l2_variable_attrs.yaml +14 -0
- imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +6 -9
- imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +1 -1
- imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +0 -12
- imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +1 -1
- imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +9 -21
- imap_processing/cdf/config/imap_mag_l1a_variable_attrs.yaml +361 -0
- imap_processing/cdf/config/imap_mag_l1b_variable_attrs.yaml +160 -0
- imap_processing/cdf/config/imap_mag_l1c_variable_attrs.yaml +160 -0
- imap_processing/cdf/config/imap_spacecraft_global_cdf_attrs.yaml +18 -0
- imap_processing/cdf/config/imap_spacecraft_variable_attrs.yaml +40 -0
- imap_processing/cdf/config/imap_swapi_global_cdf_attrs.yaml +1 -5
- imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +12 -4
- imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +16 -2
- imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +48 -52
- imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +71 -47
- imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +2 -14
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +51 -2
- imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +29 -14
- imap_processing/cdf/utils.py +13 -7
- imap_processing/cli.py +23 -8
- imap_processing/codice/codice_l1a.py +207 -85
- imap_processing/codice/constants.py +1322 -568
- imap_processing/codice/decompress.py +2 -6
- imap_processing/ena_maps/ena_maps.py +480 -116
- imap_processing/ena_maps/utils/coordinates.py +19 -0
- imap_processing/ena_maps/utils/map_utils.py +14 -17
- imap_processing/ena_maps/utils/spatial_utils.py +45 -47
- imap_processing/hi/l1a/hi_l1a.py +24 -18
- imap_processing/hi/l1a/histogram.py +0 -1
- imap_processing/hi/l1a/science_direct_event.py +6 -8
- imap_processing/hi/l1b/hi_l1b.py +31 -39
- imap_processing/hi/l1c/hi_l1c.py +405 -17
- imap_processing/hi/utils.py +58 -12
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt0-factors_20250219_v002.csv +205 -0
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt1-factors_20250219_v002.csv +205 -0
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt2-factors_20250219_v002.csv +205 -0
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-standard-dt3-factors_20250219_v002.csv +205 -0
- imap_processing/hit/ancillary/imap_hit_l1b-to-l2-summed-dt0-factors_20250219_v002.csv +68 -0
- imap_processing/hit/hit_utils.py +173 -1
- imap_processing/hit/l0/constants.py +20 -11
- imap_processing/hit/l0/decom_hit.py +18 -4
- imap_processing/hit/l1a/hit_l1a.py +45 -54
- imap_processing/hit/l1b/constants.py +317 -0
- imap_processing/hit/l1b/hit_l1b.py +367 -18
- imap_processing/hit/l2/constants.py +281 -0
- imap_processing/hit/l2/hit_l2.py +614 -0
- imap_processing/hit/packet_definitions/hit_packet_definitions.xml +1323 -71
- imap_processing/ialirt/l0/mag_l0_ialirt_data.py +155 -0
- imap_processing/ialirt/l0/parse_mag.py +246 -0
- imap_processing/ialirt/l0/process_swe.py +252 -0
- imap_processing/ialirt/packet_definitions/ialirt.xml +7 -3
- imap_processing/ialirt/packet_definitions/ialirt_mag.xml +115 -0
- imap_processing/ialirt/utils/grouping.py +114 -0
- imap_processing/ialirt/utils/time.py +29 -0
- imap_processing/idex/atomic_masses.csv +22 -0
- imap_processing/idex/decode.py +2 -2
- imap_processing/idex/idex_constants.py +25 -0
- imap_processing/idex/idex_l1a.py +6 -7
- imap_processing/idex/idex_l1b.py +4 -31
- imap_processing/idex/idex_l2a.py +789 -0
- imap_processing/idex/idex_variable_unpacking_and_eu_conversion.csv +39 -33
- imap_processing/lo/l0/lo_science.py +6 -0
- imap_processing/lo/l1a/lo_l1a.py +0 -1
- imap_processing/lo/l1b/lo_l1b.py +177 -25
- imap_processing/mag/constants.py +8 -0
- imap_processing/mag/imap_mag_sdc-configuration_v001.yaml +6 -0
- imap_processing/mag/l0/decom_mag.py +10 -3
- imap_processing/mag/l1a/mag_l1a.py +22 -11
- imap_processing/mag/l1a/mag_l1a_data.py +28 -3
- imap_processing/mag/l1b/mag_l1b.py +190 -48
- imap_processing/mag/l1c/interpolation_methods.py +211 -0
- imap_processing/mag/l1c/mag_l1c.py +447 -9
- imap_processing/quality_flags.py +1 -0
- imap_processing/spacecraft/packet_definitions/scid_x252.xml +538 -0
- imap_processing/spacecraft/quaternions.py +123 -0
- imap_processing/spice/geometry.py +16 -19
- imap_processing/spice/repoint.py +120 -0
- imap_processing/swapi/l1/swapi_l1.py +4 -0
- imap_processing/swapi/l2/swapi_l2.py +0 -1
- imap_processing/swe/l1a/swe_l1a.py +47 -8
- imap_processing/swe/l1a/swe_science.py +5 -2
- imap_processing/swe/l1b/swe_l1b_science.py +103 -56
- imap_processing/swe/l2/swe_l2.py +60 -65
- imap_processing/swe/packet_definitions/swe_packet_definition.xml +1121 -1
- imap_processing/swe/utils/swe_constants.py +63 -0
- imap_processing/swe/utils/swe_utils.py +85 -28
- imap_processing/tests/ccsds/test_data/expected_output.xml +40 -1
- imap_processing/tests/ccsds/test_excel_to_xtce.py +23 -20
- imap_processing/tests/cdf/test_data/imap_instrument2_global_cdf_attrs.yaml +0 -2
- imap_processing/tests/codice/conftest.py +1 -1
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-counters-singles_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-ialirt_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-omni_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-pha_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-priorities_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_hi-sectored_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-singles_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-ialirt_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-angular_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-priority_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-species_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-pha_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-angular_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-priority_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-species_20241110193700_v0.0.0.cdf +0 -0
- imap_processing/tests/codice/test_codice_l1a.py +110 -46
- imap_processing/tests/codice/test_decompress.py +4 -4
- imap_processing/tests/conftest.py +166 -10
- imap_processing/tests/ena_maps/conftest.py +51 -0
- imap_processing/tests/ena_maps/test_ena_maps.py +638 -109
- imap_processing/tests/ena_maps/test_map_utils.py +66 -43
- imap_processing/tests/ena_maps/test_spatial_utils.py +16 -20
- imap_processing/tests/hi/data/l0/H45_diag_fee_20250208.bin +0 -0
- imap_processing/tests/hi/data/l0/H45_diag_fee_20250208_verify.csv +205 -0
- imap_processing/tests/hi/test_hi_l1b.py +12 -15
- imap_processing/tests/hi/test_hi_l1c.py +234 -6
- imap_processing/tests/hi/test_l1a.py +30 -0
- imap_processing/tests/hi/test_science_direct_event.py +1 -1
- imap_processing/tests/hi/test_utils.py +24 -2
- imap_processing/tests/hit/helpers/l1_validation.py +39 -39
- imap_processing/tests/hit/test_data/hskp_sample.ccsds +0 -0
- imap_processing/tests/hit/test_data/imap_hit_l0_raw_20100105_v001.pkts +0 -0
- imap_processing/tests/hit/test_decom_hit.py +4 -0
- imap_processing/tests/hit/test_hit_l1a.py +24 -28
- imap_processing/tests/hit/test_hit_l1b.py +304 -40
- imap_processing/tests/hit/test_hit_l2.py +454 -0
- imap_processing/tests/hit/test_hit_utils.py +112 -2
- imap_processing/tests/hit/validation_data/hskp_sample_eu_3_6_2025.csv +89 -0
- imap_processing/tests/hit/validation_data/hskp_sample_raw.csv +89 -88
- imap_processing/tests/ialirt/test_data/l0/461971383-404.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971384-405.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971385-406.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971386-407.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971387-408.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971388-409.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971389-410.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971390-411.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/461971391-412.bin +0 -0
- imap_processing/tests/ialirt/test_data/l0/sample_decoded_i-alirt_data.csv +383 -0
- imap_processing/tests/ialirt/unit/test_grouping.py +81 -0
- imap_processing/tests/ialirt/unit/test_parse_mag.py +168 -0
- imap_processing/tests/ialirt/unit/test_process_swe.py +208 -3
- imap_processing/tests/ialirt/unit/test_time.py +16 -0
- imap_processing/tests/idex/conftest.py +62 -6
- imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231218_v001.pkts +0 -0
- imap_processing/tests/idex/test_data/impact_14_tof_high_data.txt +4508 -4508
- imap_processing/tests/idex/test_idex_l1a.py +48 -4
- imap_processing/tests/idex/test_idex_l1b.py +3 -3
- imap_processing/tests/idex/test_idex_l2a.py +383 -0
- imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20241022_v002.cdf +0 -0
- imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20241022_v002.cdf +0 -0
- imap_processing/tests/lo/test_lo_l1b.py +148 -4
- imap_processing/tests/lo/test_lo_science.py +1 -0
- imap_processing/tests/mag/conftest.py +69 -0
- imap_processing/tests/mag/test_mag_decom.py +1 -1
- imap_processing/tests/mag/test_mag_l1a.py +38 -0
- imap_processing/tests/mag/test_mag_l1b.py +34 -53
- imap_processing/tests/mag/test_mag_l1c.py +251 -20
- imap_processing/tests/mag/test_mag_validation.py +109 -25
- imap_processing/tests/mag/validation/L1b/T009/MAGScience-normal-(2,2)-8s-20250204-16h39.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-magi-out.csv +16 -16
- imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-mago-out.csv +16 -16
- imap_processing/tests/mag/validation/L1b/T010/MAGScience-normal-(2,2)-8s-20250206-12h05.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T011/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-magi-out.csv +16 -16
- imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-mago-out.csv +16 -16
- imap_processing/tests/mag/validation/L1b/T012/MAGScience-normal-(2,2)-8s-20250204-16h08.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T012/data.bin +0 -0
- imap_processing/tests/mag/validation/L1b/T012/field_like_all_ranges.txt +19200 -0
- imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-cal.cdf +0 -0
- imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-in.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-magi-out.csv +17 -0
- imap_processing/tests/mag/validation/L1b/T012/mag-l1a-l1b-t012-mago-out.csv +17 -0
- imap_processing/tests/mag/validation/imap_calibration_mag_20240229_v01.cdf +0 -0
- imap_processing/tests/spacecraft/__init__.py +0 -0
- imap_processing/tests/spacecraft/data/SSR_2024_190_20_08_12_0483851794_2_DA_apid0594_1packet.pkts +0 -0
- imap_processing/tests/spacecraft/test_quaternions.py +71 -0
- imap_processing/tests/spice/test_data/fake_repoint_data.csv +5 -0
- imap_processing/tests/spice/test_geometry.py +6 -9
- imap_processing/tests/spice/test_repoint.py +111 -0
- imap_processing/tests/swapi/test_swapi_l1.py +7 -3
- imap_processing/tests/swe/l0_data/2024051010_SWE_HK_packet.bin +0 -0
- imap_processing/tests/swe/l0_data/2024051011_SWE_CEM_RAW_packet.bin +0 -0
- imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_APP_HK_20240510_092742.csv +49 -0
- imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_CEM_RAW_20240510_092742.csv +593 -0
- imap_processing/tests/swe/test_swe_l1a.py +18 -0
- imap_processing/tests/swe/test_swe_l1a_cem_raw.py +52 -0
- imap_processing/tests/swe/test_swe_l1a_hk.py +68 -0
- imap_processing/tests/swe/test_swe_l1b_science.py +23 -4
- imap_processing/tests/swe/test_swe_l2.py +112 -30
- imap_processing/tests/test_cli.py +2 -2
- imap_processing/tests/test_utils.py +138 -16
- imap_processing/tests/ultra/data/l0/FM45_UltraFM45_Functional_2024-01-22T0105_20240122T010548.CCSDS +0 -0
- imap_processing/tests/ultra/data/l0/ultra45_raw_sc_ultraimgrates_20220530_00.csv +164 -0
- imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultrarawimg_withFSWcalcs_FM45_40P_Phi28p5_BeamCal_LinearScan_phi2850_theta-000_20240207T102740.csv +3243 -3243
- imap_processing/tests/ultra/data/mock_data.py +341 -0
- imap_processing/tests/ultra/unit/conftest.py +69 -26
- imap_processing/tests/ultra/unit/test_badtimes.py +2 -0
- imap_processing/tests/ultra/unit/test_cullingmask.py +4 -0
- imap_processing/tests/ultra/unit/test_de.py +12 -4
- imap_processing/tests/ultra/unit/test_decom_apid_881.py +44 -0
- imap_processing/tests/ultra/unit/test_spacecraft_pset.py +78 -0
- imap_processing/tests/ultra/unit/test_ultra_l1a.py +28 -12
- imap_processing/tests/ultra/unit/test_ultra_l1b.py +34 -6
- imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +22 -26
- imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +86 -51
- imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +94 -52
- imap_processing/ultra/l0/decom_tools.py +6 -5
- imap_processing/ultra/l1a/ultra_l1a.py +28 -56
- imap_processing/ultra/l1b/de.py +72 -28
- imap_processing/ultra/l1b/extendedspin.py +12 -14
- imap_processing/ultra/l1b/ultra_l1b.py +34 -9
- imap_processing/ultra/l1b/ultra_l1b_culling.py +65 -29
- imap_processing/ultra/l1b/ultra_l1b_extended.py +64 -19
- imap_processing/ultra/l1c/spacecraft_pset.py +86 -0
- imap_processing/ultra/l1c/ultra_l1c.py +7 -4
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +112 -61
- imap_processing/ultra/lookup_tables/ultra_90_dps_exposure_compressed.cdf +0 -0
- imap_processing/ultra/utils/ultra_l1_utils.py +20 -2
- imap_processing/utils.py +68 -28
- {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/METADATA +8 -5
- {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/RECORD +250 -199
- imap_processing/cdf/config/imap_mag_l1_variable_attrs.yaml +0 -237
- imap_processing/hi/l1a/housekeeping.py +0 -27
- imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-aggregated_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-singles_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_hi-omni_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_hi-sectored_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_hskp_20100101_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-aggregated_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-singles_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-angular_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-priority_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-species_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-angular_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-priority_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-species_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-aggregated_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-singles_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hi-omni_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hi-sectored_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_hskp_20100101_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-aggregated_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-singles_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-angular_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-priority_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-species_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-angular_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-priority_20240429_v001.cdf +0 -0
- imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-species_20240429_v001.cdf +0 -0
- imap_processing/tests/hi/data/l1/imap_hi_l1b_45sensor-de_20250415_v999.cdf +0 -0
- imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1251.pkts +0 -0
- imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1252.pkts +0 -0
- imap_processing/tests/hit/validation_data/hskp_sample_eu.csv +0 -89
- imap_processing/tests/hit/validation_data/sci_sample_raw1.csv +0 -29
- imap_processing/tests/idex/test_data/imap_idex_l0_raw_20231214_v001.pkts +0 -0
- imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20100101_v001.cdf +0 -0
- imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20100101_v001.cdf +0 -0
- imap_processing/tests/ultra/test_data/mock_data.py +0 -161
- imap_processing/ultra/l1c/pset.py +0 -40
- /imap_processing/tests/ultra/{test_data → data}/l0/FM45_40P_Phi28p5_BeamCal_LinearScan_phi28.50_theta-0.00_20240207T102740.CCSDS +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/FM45_7P_Phi0.0_BeamCal_LinearScan_phi0.04_theta-0.01_20230821T121304.CCSDS +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.CCSDS +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.CCSDS +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_auxdata_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_enaphxtofhangimg_FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.csv +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultraimgrates_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l0/ultra45_raw_sc_ultrarawimgevent_FM45_7P_Phi00_BeamCal_LinearScan_phi004_theta-001_20230821T121304.csv +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E1.cdf +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E12.cdf +0 -0
- /imap_processing/tests/ultra/{test_data → data}/l1/dps_exposure_helio_45_E24.cdf +0 -0
- {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/LICENSE +0 -0
- {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/WHEEL +0 -0
- {imap_processing-0.11.0.dist-info → imap_processing-0.12.0.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""Classes for Level 0 MAG I-ALiRT data."""
|
|
2
|
+
|
|
3
|
+
# Science samples are split across 4 sequential packets so
|
|
4
|
+
# several packets need to be processed before a single science
|
|
5
|
+
# sample can be processed. The packets are as follows:
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Packet0:
|
|
11
|
+
"""
|
|
12
|
+
Class for packet 0.
|
|
13
|
+
|
|
14
|
+
Parameters
|
|
15
|
+
----------
|
|
16
|
+
status : int
|
|
17
|
+
24-bit integer value.
|
|
18
|
+
|
|
19
|
+
Notes
|
|
20
|
+
-----
|
|
21
|
+
Bits 23-22 → Packet Number (2-bit value)
|
|
22
|
+
Bits 21-17 → hk1v5_warn, hk1v5_danger, hk1v5c_warn, hk1v5c_danger,
|
|
23
|
+
hk1v8_warn (5-bit value)
|
|
24
|
+
Bits 16-13 → hk1v8_danger, hk1v8c_warn, hk1v8c_danger (4-bit value)
|
|
25
|
+
Bit 5 → fob_saturated (1-bit value)
|
|
26
|
+
Bit 4 → fib_saturated (1-bit value)
|
|
27
|
+
Bits 3-0 → mode (4-bit value)
|
|
28
|
+
Bits 12-6 → icu_temp (7-bit value)
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, status: int) -> None:
|
|
32
|
+
# +1.5v voltage warning flag raised
|
|
33
|
+
self.hk1v5_warn = (status >> 20) & 0x01
|
|
34
|
+
# +1.5v voltage danger flag raised
|
|
35
|
+
self.hk1v5_danger = (status >> 19) & 0x01
|
|
36
|
+
# +1.5v current warning flag raised
|
|
37
|
+
self.hk1v5c_warn = (status >> 18) & 0x01
|
|
38
|
+
# +1.5v current danger flag raised
|
|
39
|
+
self.hk1v5c_danger = (status >> 17) & 0x01
|
|
40
|
+
# +1.8v voltage warning flag raised
|
|
41
|
+
self.hk1v8_warn = (status >> 16) & 0x01
|
|
42
|
+
# +1.8v voltage danger flag raised
|
|
43
|
+
self.hk1v8_danger = (status >> 15) & 0x01
|
|
44
|
+
# +1.8v current warning flag raised
|
|
45
|
+
self.hk1v8c_warn = (status >> 14) & 0x01
|
|
46
|
+
# +1.8v current danger flag raised
|
|
47
|
+
self.hk1v8c_danger = (status >> 13) & 0x01
|
|
48
|
+
# Outboard (MAGo) sensor is saturated (danger)
|
|
49
|
+
self.fob_saturated = (status >> 5) & 0x01
|
|
50
|
+
# Inboard (MAGi) sensor is saturated (danger)
|
|
51
|
+
self.fib_saturated = (status >> 4) & 0x01
|
|
52
|
+
# Instrument mode
|
|
53
|
+
self.mode = (status >> 0) & 0x0F
|
|
54
|
+
# instrument control unit temperature (top 7/16 bits, eng. units)
|
|
55
|
+
self.icu_temp = ((status >> 6) & 0x7F) << 5
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class Packet1:
|
|
59
|
+
"""
|
|
60
|
+
Class for packet 1.
|
|
61
|
+
|
|
62
|
+
Parameters
|
|
63
|
+
----------
|
|
64
|
+
status : int
|
|
65
|
+
24-bit integer value.
|
|
66
|
+
|
|
67
|
+
Notes
|
|
68
|
+
-----
|
|
69
|
+
Bit 5 → pri_isvalid (1-bit value)
|
|
70
|
+
Bits 4-1 → hk2v5_warn, hk2v5_danger, hk2v5c_warn, hk2v5c_danger (4-bit value)
|
|
71
|
+
Bits 16-9 → hk3v3 (8-bit value)
|
|
72
|
+
Bits 8-0 → hk3v3_current (9-bit value)
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
def __init__(self, status: int) -> None:
|
|
76
|
+
# +2.5v voltage warning flag raised
|
|
77
|
+
self.hk2v5_warn = (status >> 20) & 0x01
|
|
78
|
+
# +2.5v voltage danger flag raised
|
|
79
|
+
self.hk2v5_danger = (status >> 19) & 0x01
|
|
80
|
+
# +2.5v current warning flag raised
|
|
81
|
+
self.hk2v5c_warn = (status >> 18) & 0x01
|
|
82
|
+
# +2.5v current warning flag raised
|
|
83
|
+
self.hk2v5c_danger = (status >> 17) & 0x01
|
|
84
|
+
# +3.3v voltage (top 8/16 bits, in eng. units)
|
|
85
|
+
self.hk3v3 = ((status >> 9) & 0xFF) << 4
|
|
86
|
+
# +3.3v current (top 9/16 bits, in eng. units)
|
|
87
|
+
self.hk3v3_current = ((status >> 0) & 0x1FF) << 3
|
|
88
|
+
# Primary sensor (typically MAGo) science data is valid
|
|
89
|
+
self.pri_isvalid = (status >> 21) & 0x01
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class Packet2:
|
|
93
|
+
"""
|
|
94
|
+
Class for packet 2.
|
|
95
|
+
|
|
96
|
+
Parameters
|
|
97
|
+
----------
|
|
98
|
+
status : int
|
|
99
|
+
24-bit integer value.
|
|
100
|
+
|
|
101
|
+
Notes
|
|
102
|
+
-----
|
|
103
|
+
Bits 23-22 → Packet Number (2-bit value)
|
|
104
|
+
Bits 21-17 → Various warning/danger flags (5-bit value)
|
|
105
|
+
Bits 16-9 → hkn8v5 (8-bit value)
|
|
106
|
+
Bits 8-0 → hkn8v5_current (9-bit value)
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
def __init__(self, status: int) -> None:
|
|
110
|
+
# +8.5v voltage warning flag raised
|
|
111
|
+
self.hkp8v5_warn = (status >> 20) & 0x01
|
|
112
|
+
# +8.5v voltage danger flag raised
|
|
113
|
+
self.hkp8v5_danger = (status >> 19) & 0x01
|
|
114
|
+
# +8.5v current warning flag raised
|
|
115
|
+
self.hkp8v5c_warn = (status >> 18) & 0x01
|
|
116
|
+
# +8.5v current danger flag raised
|
|
117
|
+
self.hkp8v5c_danger = (status >> 17) & 0x01
|
|
118
|
+
# -8.5v voltage (top 8/16 bits, in eng. units)
|
|
119
|
+
self.hkn8v5 = ((status >> 9) & 0xFF) << 4
|
|
120
|
+
# -8.5v current (top 9/16 bits, in eng. units)
|
|
121
|
+
self.hkn8v5_current = ((status >> 0) & 0x1FF) << 3
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class Packet3:
|
|
125
|
+
"""
|
|
126
|
+
Class for packet 3.
|
|
127
|
+
|
|
128
|
+
Parameters
|
|
129
|
+
----------
|
|
130
|
+
status : int
|
|
131
|
+
24-bit integer value.
|
|
132
|
+
|
|
133
|
+
Notes
|
|
134
|
+
-----
|
|
135
|
+
Bits 20-13 → fob_temp (8-bit value, shifted left by 4)
|
|
136
|
+
Bits 12-5 → fib_temp (8-bit value, shifted left by 4)
|
|
137
|
+
Bits 4-3 → fob_range (2-bit value)
|
|
138
|
+
Bits 2-1 → fib_range (2-bit value)
|
|
139
|
+
Bit 0 → multbit_errs (1-bit value)
|
|
140
|
+
Bit 5 → sec_isvalid (1-bit value, overlapping with fib_temp extraction)
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
def __init__(self, status: int) -> None:
|
|
144
|
+
# Temp of outboard (MAGo) sensor (top 8/16 bits, in eng. units)
|
|
145
|
+
self.fob_temp = ((status >> 13) & 0xFF) << 4
|
|
146
|
+
# Temp of outboard (MAGo) sensor (top 8/16 bits, in eng. units)
|
|
147
|
+
self.fib_temp = ((status >> 5) & 0xFF) << 4
|
|
148
|
+
# Outboard (MAGo) sensor range [0-3]
|
|
149
|
+
self.fob_range = (status >> 3) & 0x03
|
|
150
|
+
# Inboard (MAGi) sensor range [0-3]
|
|
151
|
+
self.fib_range = (status >> 1) & 0x03
|
|
152
|
+
# Multiple (SEU) memory error bits danger flag raised
|
|
153
|
+
self.multbit_errs = (status >> 0) & 0x01
|
|
154
|
+
# Secondary sensor (typically MAGi) science data is valid
|
|
155
|
+
self.sec_isvalid = (status >> 21) & 0x01
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"""Functions to support I-ALiRT MAG packet parsing."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import xarray as xr
|
|
7
|
+
|
|
8
|
+
from imap_processing.ialirt.l0.mag_l0_ialirt_data import (
|
|
9
|
+
Packet0,
|
|
10
|
+
Packet1,
|
|
11
|
+
Packet2,
|
|
12
|
+
Packet3,
|
|
13
|
+
)
|
|
14
|
+
from imap_processing.ialirt.utils.grouping import find_groups
|
|
15
|
+
from imap_processing.ialirt.utils.time import calculate_time
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_pkt_counter(status_values: xr.DataArray) -> xr.DataArray:
|
|
21
|
+
"""
|
|
22
|
+
Get the packet counters.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
status_values : xr.DataArray
|
|
27
|
+
Status data.
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
pkt_counters : xr.DataArray
|
|
32
|
+
Packet counters.
|
|
33
|
+
"""
|
|
34
|
+
# mag_status is a 24 bit unsigned field
|
|
35
|
+
# The leading 2 bits of STATUS are a 2 bit 0-3 counter
|
|
36
|
+
pkt_counter = (status_values >> 22) & 0x03
|
|
37
|
+
|
|
38
|
+
return pkt_counter
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_status_data(status_values: xr.DataArray, pkt_counters: xr.DataArray) -> dict:
|
|
42
|
+
"""
|
|
43
|
+
Get the status data.
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
status_values : xr.DataArray
|
|
48
|
+
Status data.
|
|
49
|
+
pkt_counters : xr.DataArray
|
|
50
|
+
Packet counters.
|
|
51
|
+
|
|
52
|
+
Returns
|
|
53
|
+
-------
|
|
54
|
+
combined_packets : dict
|
|
55
|
+
Decoded packets.
|
|
56
|
+
"""
|
|
57
|
+
decoders = {
|
|
58
|
+
0: Packet0,
|
|
59
|
+
1: Packet1,
|
|
60
|
+
2: Packet2,
|
|
61
|
+
3: Packet3,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
combined_packets = {}
|
|
65
|
+
|
|
66
|
+
for pkt_num, decoder in decoders.items():
|
|
67
|
+
status_subset = status_values[pkt_counters == pkt_num]
|
|
68
|
+
decoded_packet = decoder(int(status_subset))
|
|
69
|
+
combined_packets.update(vars(decoded_packet))
|
|
70
|
+
|
|
71
|
+
return combined_packets
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def get_bytes(val: int) -> list[int]:
|
|
75
|
+
"""
|
|
76
|
+
Extract three bytes from a 24-bit integer.
|
|
77
|
+
|
|
78
|
+
Parameters
|
|
79
|
+
----------
|
|
80
|
+
val : int
|
|
81
|
+
24-bit integer value.
|
|
82
|
+
|
|
83
|
+
Returns
|
|
84
|
+
-------
|
|
85
|
+
list[int]
|
|
86
|
+
List of three extracted bytes.
|
|
87
|
+
"""
|
|
88
|
+
return [
|
|
89
|
+
(val >> 16) & 0xFF, # Most significant byte (Byte2)
|
|
90
|
+
(val >> 8) & 0xFF, # Middle byte (Byte1)
|
|
91
|
+
(val >> 0) & 0xFF, # Least significant byte (Byte0)
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def extract_magnetic_vectors(science_values: xr.DataArray) -> dict:
|
|
96
|
+
"""
|
|
97
|
+
Extract the magnetic vectors.
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
science_values : xr.DataArray
|
|
102
|
+
Science data.
|
|
103
|
+
|
|
104
|
+
Returns
|
|
105
|
+
-------
|
|
106
|
+
vectors : dict
|
|
107
|
+
Magnetic vectors.
|
|
108
|
+
"""
|
|
109
|
+
# Primary sensor:
|
|
110
|
+
pri_x = (int(science_values[0]) >> 8) & 0xFFFF
|
|
111
|
+
pri_y = ((int(science_values[0]) << 8) & 0xFF00) | (
|
|
112
|
+
(int(science_values[1]) >> 16) & 0xFF
|
|
113
|
+
)
|
|
114
|
+
pri_z = int(science_values[1]) & 0xFFFF
|
|
115
|
+
|
|
116
|
+
# Secondary sensor:
|
|
117
|
+
sec_x = (int(science_values[2]) >> 8) & 0xFFFF
|
|
118
|
+
sec_y = ((int(science_values[2]) << 8) & 0xFF00) | (
|
|
119
|
+
(int(science_values[3]) >> 16) & 0xFF
|
|
120
|
+
)
|
|
121
|
+
sec_z = int(science_values[3]) & 0xFFFF
|
|
122
|
+
|
|
123
|
+
vectors = {
|
|
124
|
+
"pri_x": pri_x,
|
|
125
|
+
"pri_y": pri_y,
|
|
126
|
+
"pri_z": pri_z,
|
|
127
|
+
"sec_x": sec_x,
|
|
128
|
+
"sec_y": sec_y,
|
|
129
|
+
"sec_z": sec_z,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return vectors
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def get_time(grouped_data: xr.Dataset, group: int, pkt_counter: xr.DataArray) -> dict:
|
|
136
|
+
"""
|
|
137
|
+
Get the time for the grouped data.
|
|
138
|
+
|
|
139
|
+
Parameters
|
|
140
|
+
----------
|
|
141
|
+
grouped_data : xr.Dataset
|
|
142
|
+
Grouped data.
|
|
143
|
+
group : int
|
|
144
|
+
Group number.
|
|
145
|
+
pkt_counter : xr.DataArray
|
|
146
|
+
Packet counter.
|
|
147
|
+
|
|
148
|
+
Returns
|
|
149
|
+
-------
|
|
150
|
+
time_data : dict
|
|
151
|
+
Coarse and fine time for Primary and Secondary Sensors.
|
|
152
|
+
"""
|
|
153
|
+
pri_coarsetm = grouped_data["mag_acq_tm_coarse"][
|
|
154
|
+
(grouped_data["group"] == group).values
|
|
155
|
+
][pkt_counter == 0]
|
|
156
|
+
|
|
157
|
+
pri_fintm = grouped_data["mag_acq_tm_fine"][
|
|
158
|
+
(grouped_data["group"] == group).values
|
|
159
|
+
][pkt_counter == 0]
|
|
160
|
+
|
|
161
|
+
sec_coarsetm = grouped_data["mag_acq_tm_coarse"][
|
|
162
|
+
(grouped_data["group"] == group).values
|
|
163
|
+
][pkt_counter == 2]
|
|
164
|
+
|
|
165
|
+
sec_fintm = grouped_data["mag_acq_tm_fine"][
|
|
166
|
+
(grouped_data["group"] == group).values
|
|
167
|
+
][pkt_counter == 2]
|
|
168
|
+
|
|
169
|
+
time_data = {
|
|
170
|
+
"pri_coarsetm": int(pri_coarsetm),
|
|
171
|
+
"pri_fintm": int(pri_fintm),
|
|
172
|
+
"sec_coarsetm": int(sec_coarsetm),
|
|
173
|
+
"sec_fintm": int(sec_fintm),
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return time_data
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def parse_packet(accumulated_data: xr.Dataset) -> list[dict]:
|
|
180
|
+
"""
|
|
181
|
+
Parse the MAG packets.
|
|
182
|
+
|
|
183
|
+
Parameters
|
|
184
|
+
----------
|
|
185
|
+
accumulated_data : xr.Dataset
|
|
186
|
+
Packets dataset accumulated over 1 min.
|
|
187
|
+
|
|
188
|
+
Returns
|
|
189
|
+
-------
|
|
190
|
+
mag_data : list[dict]
|
|
191
|
+
Dictionaries of the parsed data product.
|
|
192
|
+
"""
|
|
193
|
+
logger.info(
|
|
194
|
+
f"Parsing MAG for time: {accumulated_data['mag_acq_tm_coarse'].min().values} - "
|
|
195
|
+
f"{accumulated_data['mag_acq_tm_coarse'].max().values}."
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Note that the fine time second is split into 65535.
|
|
199
|
+
time_seconds = calculate_time(
|
|
200
|
+
accumulated_data["mag_acq_tm_coarse"],
|
|
201
|
+
accumulated_data["mag_acq_tm_fine"],
|
|
202
|
+
65535,
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
# Add required parameters.
|
|
206
|
+
accumulated_data["time_seconds"] = time_seconds
|
|
207
|
+
sorted_data = accumulated_data.sortby("time_seconds", ascending=True)
|
|
208
|
+
pkt_counter = get_pkt_counter(sorted_data["mag_status"])
|
|
209
|
+
sorted_data["pkt_counter"] = pkt_counter
|
|
210
|
+
|
|
211
|
+
grouped_data = find_groups(sorted_data, (0, 3), "pkt_counter", "time_seconds")
|
|
212
|
+
|
|
213
|
+
unique_groups = np.unique(grouped_data["group"])
|
|
214
|
+
mag_data = []
|
|
215
|
+
|
|
216
|
+
for group in unique_groups:
|
|
217
|
+
# Get status values for each group.
|
|
218
|
+
status_values = grouped_data["mag_status"][
|
|
219
|
+
(grouped_data["group"] == group).values
|
|
220
|
+
]
|
|
221
|
+
pkt_counter = grouped_data["pkt_counter"][
|
|
222
|
+
(grouped_data["group"] == group).values
|
|
223
|
+
]
|
|
224
|
+
|
|
225
|
+
if not np.array_equal(pkt_counter, np.arange(4)):
|
|
226
|
+
logger.warning(
|
|
227
|
+
f"Group {group} does not contain all values from 0 to "
|
|
228
|
+
f"3 without duplicates."
|
|
229
|
+
)
|
|
230
|
+
continue
|
|
231
|
+
|
|
232
|
+
# Get decoded status data.
|
|
233
|
+
status_data = get_status_data(status_values, pkt_counter)
|
|
234
|
+
|
|
235
|
+
# Get science values for each group.
|
|
236
|
+
science_values = grouped_data["mag_data"][
|
|
237
|
+
(grouped_data["group"] == group).values
|
|
238
|
+
]
|
|
239
|
+
science_data = extract_magnetic_vectors(science_values)
|
|
240
|
+
|
|
241
|
+
# Get time values for each group.
|
|
242
|
+
time_data = get_time(grouped_data, group, pkt_counter)
|
|
243
|
+
|
|
244
|
+
mag_data.append({**status_data, **science_data, **time_data})
|
|
245
|
+
|
|
246
|
+
return mag_data
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"""Functions to support I-ALiRT SWE packet parsing."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
7
|
+
import xarray as xr
|
|
8
|
+
from numpy.typing import NDArray
|
|
9
|
+
|
|
10
|
+
from imap_processing.ialirt.utils.grouping import find_groups
|
|
11
|
+
from imap_processing.swe.l1a.swe_science import decompressed_counts
|
|
12
|
+
from imap_processing.swe.l1b.swe_l1b_science import (
|
|
13
|
+
deadtime_correction,
|
|
14
|
+
read_in_flight_cal_data,
|
|
15
|
+
)
|
|
16
|
+
from imap_processing.swe.utils.swe_constants import (
|
|
17
|
+
ESA_VOLTAGE_ROW_INDEX_DICT,
|
|
18
|
+
GEOMETRIC_FACTORS,
|
|
19
|
+
N_CEMS,
|
|
20
|
+
)
|
|
21
|
+
from imap_processing.swe.utils.swe_utils import combine_acquisition_time
|
|
22
|
+
|
|
23
|
+
logger = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def decompress_counts(raw_counts: NDArray) -> NDArray:
|
|
27
|
+
"""
|
|
28
|
+
Perform decompression of raw counts using a predefined decompression table.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
raw_counts : np.ndarray
|
|
33
|
+
Array of raw compressed counts with shape (n_energy, n_cem, n_phi).
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
-------
|
|
37
|
+
counts : np.ndarray
|
|
38
|
+
Array of decompressed counts with the same shape as raw_counts.
|
|
39
|
+
"""
|
|
40
|
+
decompression_table = np.array([decompressed_counts(i) for i in range(256)])
|
|
41
|
+
|
|
42
|
+
# Decompress using the precomputed table
|
|
43
|
+
counts = decompression_table[raw_counts]
|
|
44
|
+
|
|
45
|
+
return counts
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def phi_to_bin(phi_values: NDArray) -> NDArray:
|
|
49
|
+
"""
|
|
50
|
+
Convert phi values to corresponding bin indices.
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
phi_values : NDArray
|
|
55
|
+
Array of phi values.
|
|
56
|
+
|
|
57
|
+
Returns
|
|
58
|
+
-------
|
|
59
|
+
bin_indices : NDArray
|
|
60
|
+
Array of bin indices.
|
|
61
|
+
"""
|
|
62
|
+
# Ensure it wraps correctly within 0-29 bins
|
|
63
|
+
return ((phi_values - 12) // 12) % 30
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def prepare_raw_counts(grouped: xr.Dataset, cem_number: int = N_CEMS) -> NDArray:
|
|
67
|
+
"""
|
|
68
|
+
Reformat raw counts into a 3D array binned by phi.
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
grouped : xr.Dataset
|
|
73
|
+
Dataset containing grouped i-ALiRT packet data for 30 seconds.
|
|
74
|
+
cem_number : int
|
|
75
|
+
Number of CEMs (default 7).
|
|
76
|
+
|
|
77
|
+
Returns
|
|
78
|
+
-------
|
|
79
|
+
raw_counts : NDArray
|
|
80
|
+
Raw counts with shape (8, 7, 30).
|
|
81
|
+
|
|
82
|
+
Notes
|
|
83
|
+
-----
|
|
84
|
+
Array of raw counts with shape (n_energy, n_cem, n_phi), where:
|
|
85
|
+
- 8 corresponds to the 8 energy steps.
|
|
86
|
+
- 7 corresponds to the 7 CEM detectors.
|
|
87
|
+
- 30 corresponds to the 30 phi bins.
|
|
88
|
+
"""
|
|
89
|
+
raw_counts = np.zeros((8, cem_number, 30), dtype=np.uint8)
|
|
90
|
+
|
|
91
|
+
# Compute phi values and their corresponding bins
|
|
92
|
+
# Example: energy steps 0-1 have the same phi;
|
|
93
|
+
# energy steps 2-3 have the same phi, etc.
|
|
94
|
+
# A depiction of this is shown in Figure 7 of the SWE Algorithm Document.
|
|
95
|
+
phi_values = np.array(
|
|
96
|
+
[
|
|
97
|
+
(12 + 24 * grouped["swe_seq"].values) % 360, # Energy steps 0 and 1
|
|
98
|
+
(24 + 24 * grouped["swe_seq"].values) % 360, # Energy steps 2 and 3
|
|
99
|
+
]
|
|
100
|
+
)
|
|
101
|
+
phi_bins = phi_to_bin(phi_values).astype(int) # Get phi bin indices
|
|
102
|
+
|
|
103
|
+
# Energy bin lookup table (indexed by quarter cycle)
|
|
104
|
+
energy_bins = np.array(
|
|
105
|
+
[
|
|
106
|
+
[1, 5, 7, 3], # 0-14 (first quarter cycle)
|
|
107
|
+
[2, 6, 4, 0], # 15-29 (second quarter cycle)
|
|
108
|
+
[3, 7, 5, 1], # 30-44 (third quarter cycle)
|
|
109
|
+
[0, 4, 6, 2], # 45-59 (fourth quarter cycle)
|
|
110
|
+
]
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# The first 15 seconds is the first quarter cycle, etc.
|
|
114
|
+
quarter_cycles = np.floor(grouped["swe_seq"] / 15).astype(int)
|
|
115
|
+
e_bins = energy_bins[quarter_cycles]
|
|
116
|
+
|
|
117
|
+
# Populate raw_counts
|
|
118
|
+
for cem in range(1, cem_number + 1): # 7 CEMs
|
|
119
|
+
e1 = grouped[f"swe_cem{cem}_e1"].values
|
|
120
|
+
e2 = grouped[f"swe_cem{cem}_e2"].values
|
|
121
|
+
e3 = grouped[f"swe_cem{cem}_e3"].values
|
|
122
|
+
e4 = grouped[f"swe_cem{cem}_e4"].values
|
|
123
|
+
|
|
124
|
+
# Phi bins 0, 2...(12, 36, ...)
|
|
125
|
+
raw_counts[e_bins[:, 0], cem - 1, phi_bins[0]] = e1
|
|
126
|
+
raw_counts[e_bins[:, 1], cem - 1, phi_bins[0]] = e2
|
|
127
|
+
# Phi bins 1, 3...(24, 48, ...)
|
|
128
|
+
raw_counts[e_bins[:, 2], cem - 1, phi_bins[1]] = e3
|
|
129
|
+
raw_counts[e_bins[:, 3], cem - 1, phi_bins[1]] = e4
|
|
130
|
+
|
|
131
|
+
return raw_counts
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def get_ialirt_energies() -> list:
|
|
135
|
+
"""
|
|
136
|
+
Get the ESA voltages for I-ALiRT.
|
|
137
|
+
|
|
138
|
+
Returns
|
|
139
|
+
-------
|
|
140
|
+
energy : list
|
|
141
|
+
List of ESA voltage for I-ALiRT.
|
|
142
|
+
|
|
143
|
+
Notes
|
|
144
|
+
-----
|
|
145
|
+
This is a subset of the ESA_VOLTAGE_ROW_INDEX_DICT.
|
|
146
|
+
"""
|
|
147
|
+
energy = [k for k, v in ESA_VOLTAGE_ROW_INDEX_DICT.items() if 11 <= v <= 18]
|
|
148
|
+
|
|
149
|
+
return energy
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def normalize_counts(counts: NDArray, latest_cal: pd.Series) -> NDArray:
|
|
153
|
+
"""
|
|
154
|
+
Normalize the counts using the latest calibration factor.
|
|
155
|
+
|
|
156
|
+
Parameters
|
|
157
|
+
----------
|
|
158
|
+
counts : np.ndarray
|
|
159
|
+
Array of counts.
|
|
160
|
+
latest_cal : pd.Series
|
|
161
|
+
Array of latest calibration factors.
|
|
162
|
+
|
|
163
|
+
Returns
|
|
164
|
+
-------
|
|
165
|
+
norm_counts : np.ndarray
|
|
166
|
+
Array of normalized counts.
|
|
167
|
+
"""
|
|
168
|
+
latest_cal = latest_cal.to_numpy()
|
|
169
|
+
|
|
170
|
+
# Norm counts where counts are non-negative
|
|
171
|
+
# TODO: confirm fv is counts with Ruth
|
|
172
|
+
norm_counts = counts * (latest_cal / GEOMETRIC_FACTORS)[:, np.newaxis]
|
|
173
|
+
norm_counts[norm_counts < 0] = 0
|
|
174
|
+
|
|
175
|
+
return norm_counts
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def process_swe(accumulated_data: xr.Dataset) -> list[dict]:
|
|
179
|
+
"""
|
|
180
|
+
Create L1 data dictionary..
|
|
181
|
+
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
accumulated_data : xr.Dataset
|
|
185
|
+
Packets dataset accumulated over 1 min.
|
|
186
|
+
|
|
187
|
+
Returns
|
|
188
|
+
-------
|
|
189
|
+
swe_data : list[dict]
|
|
190
|
+
Dictionaries of the parsed data product.
|
|
191
|
+
"""
|
|
192
|
+
logger.info("Processing SWE.")
|
|
193
|
+
|
|
194
|
+
# Calculate time in seconds
|
|
195
|
+
time_seconds = combine_acquisition_time(
|
|
196
|
+
accumulated_data["swe_acq_sec"], accumulated_data["swe_acq_sub"]
|
|
197
|
+
)
|
|
198
|
+
accumulated_data["time_seconds"] = time_seconds
|
|
199
|
+
|
|
200
|
+
# Get total full cycle data available for processing.
|
|
201
|
+
# There are 60 packets in a set so (0, 59) is the range.
|
|
202
|
+
grouped_data = find_groups(accumulated_data, (0, 59), "swe_seq", "time_seconds")
|
|
203
|
+
unique_groups = np.unique(grouped_data["group"])
|
|
204
|
+
swe_data: list[dict] = []
|
|
205
|
+
|
|
206
|
+
for group in unique_groups:
|
|
207
|
+
# Sequence values for the group should be 0-59 with no duplicates.
|
|
208
|
+
seq_values = grouped_data["swe_seq"][(grouped_data["group"] == group).values]
|
|
209
|
+
|
|
210
|
+
# Ensure no duplicates and all values from 0 to 59 are present
|
|
211
|
+
if not np.array_equal(seq_values, np.arange(60)):
|
|
212
|
+
logger.warning(
|
|
213
|
+
f"Group {group} does not contain all values from 0 to "
|
|
214
|
+
f"59 without duplicates."
|
|
215
|
+
)
|
|
216
|
+
continue
|
|
217
|
+
# Prepare raw counts array just for this group
|
|
218
|
+
# (8 energy steps, 7 CEMs, 30 phi bins)
|
|
219
|
+
group_mask = grouped_data["group"] == group
|
|
220
|
+
grouped = grouped_data.sel(epoch=group_mask)
|
|
221
|
+
|
|
222
|
+
# Split into Q1 & Q2 (swe_seq 0-29) and Q3 & Q4 (swe_seq 30-59)
|
|
223
|
+
first_half = grouped.where(grouped["swe_seq"] < 30, drop=True)
|
|
224
|
+
second_half = grouped.where(grouped["swe_seq"] >= 30, drop=True)
|
|
225
|
+
|
|
226
|
+
# Prepare raw counts separately for both halves
|
|
227
|
+
raw_counts_first_half = prepare_raw_counts(first_half)
|
|
228
|
+
raw_counts_second_half = prepare_raw_counts(second_half)
|
|
229
|
+
|
|
230
|
+
# Decompress the raw counts
|
|
231
|
+
counts_first_half = decompress_counts(raw_counts_first_half)
|
|
232
|
+
counts_second_half = decompress_counts(raw_counts_second_half)
|
|
233
|
+
|
|
234
|
+
# Apply the deadtime correction
|
|
235
|
+
# acq_duration = 80 milliseconds
|
|
236
|
+
corrected_first_half = deadtime_correction(counts_first_half, 80 * 10**3)
|
|
237
|
+
corrected_second_half = deadtime_correction(counts_second_half, 80 * 10**3)
|
|
238
|
+
|
|
239
|
+
# Grab the latest calibration factor
|
|
240
|
+
in_flight_cal_df = read_in_flight_cal_data()
|
|
241
|
+
latest_cal = in_flight_cal_df.sort_values("met_time").iloc[-1][1::]
|
|
242
|
+
|
|
243
|
+
normalized_first_half = normalize_counts(corrected_first_half, latest_cal)
|
|
244
|
+
normalized_second_half = normalize_counts(corrected_second_half, latest_cal)
|
|
245
|
+
|
|
246
|
+
# Sum over the 7 detectors
|
|
247
|
+
summed_first_half = np.sum(normalized_first_half, axis=1) # noqa: F841
|
|
248
|
+
summed_second_half = np.sum(normalized_second_half, axis=1) # noqa: F841
|
|
249
|
+
|
|
250
|
+
# TODO: will continue here
|
|
251
|
+
|
|
252
|
+
return swe_data
|
|
@@ -428,8 +428,11 @@
|
|
|
428
428
|
</xtce:Parameter>
|
|
429
429
|
<!-- SWE -->
|
|
430
430
|
<!-- MAG -->
|
|
431
|
-
<xtce:Parameter name="
|
|
432
|
-
<xtce:LongDescription>MAG Acquisition Time</xtce:LongDescription>
|
|
431
|
+
<xtce:Parameter name="MAG_ACQ_TM_COARSE" parameterTypeRef="uint32">
|
|
432
|
+
<xtce:LongDescription>MAG Coarse Acquisition Time</xtce:LongDescription>
|
|
433
|
+
</xtce:Parameter>
|
|
434
|
+
<xtce:Parameter name="MAG_ACQ_TM_FINE" parameterTypeRef="uint16">
|
|
435
|
+
<xtce:LongDescription>MAG Fine Acquisition Time</xtce:LongDescription>
|
|
433
436
|
</xtce:Parameter>
|
|
434
437
|
<xtce:Parameter name="MAG_STATUS" parameterTypeRef="uint24">
|
|
435
438
|
<xtce:LongDescription>MAG Status</xtce:LongDescription>
|
|
@@ -674,7 +677,8 @@
|
|
|
674
677
|
<xtce:ParameterRefEntry parameterRef="SC_SPARE_3"/>
|
|
675
678
|
<!-- Spacecraft -->
|
|
676
679
|
<!-- MAG -->
|
|
677
|
-
<xtce:ParameterRefEntry parameterRef="
|
|
680
|
+
<xtce:ParameterRefEntry parameterRef="MAG_ACQ_TM_COARSE"/>
|
|
681
|
+
<xtce:ParameterRefEntry parameterRef="MAG_ACQ_TM_FINE"/>
|
|
678
682
|
<xtce:ParameterRefEntry parameterRef="MAG_STATUS"/>
|
|
679
683
|
<xtce:ParameterRefEntry parameterRef="MAG_DATA"/>
|
|
680
684
|
<!-- MAG -->
|