imap-processing 0.9.0__py3-none-any.whl → 0.11.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.

Files changed (243) hide show
  1. imap_processing/_version.py +2 -2
  2. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +749 -442
  3. imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +7 -0
  4. imap_processing/cdf/config/imap_glows_l1a_variable_attrs.yaml +8 -2
  5. imap_processing/cdf/config/imap_glows_l1b_variable_attrs.yaml +0 -1
  6. imap_processing/cdf/config/imap_glows_l2_variable_attrs.yaml +358 -0
  7. imap_processing/cdf/config/imap_hi_variable_attrs.yaml +59 -25
  8. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +22 -0
  9. imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +32 -8
  10. imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml +94 -5
  11. imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +65 -37
  12. imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +16 -1
  13. imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +7 -0
  14. imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +14 -14
  15. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +25 -24
  16. imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +238 -0
  17. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +100 -92
  18. imap_processing/cdf/utils.py +2 -2
  19. imap_processing/cli.py +45 -9
  20. imap_processing/codice/codice_l1a.py +104 -58
  21. imap_processing/codice/constants.py +111 -155
  22. imap_processing/codice/data/esa_sweep_values.csv +256 -256
  23. imap_processing/codice/data/lo_stepping_values.csv +128 -128
  24. imap_processing/ena_maps/ena_maps.py +519 -0
  25. imap_processing/ena_maps/utils/map_utils.py +145 -0
  26. imap_processing/ena_maps/utils/spatial_utils.py +226 -0
  27. imap_processing/glows/__init__.py +3 -0
  28. imap_processing/glows/ancillary/imap_glows_pipeline_settings_v001.json +52 -0
  29. imap_processing/glows/l1a/glows_l1a.py +72 -14
  30. imap_processing/glows/l1b/glows_l1b.py +2 -1
  31. imap_processing/glows/l1b/glows_l1b_data.py +25 -1
  32. imap_processing/glows/l2/glows_l2.py +324 -0
  33. imap_processing/glows/l2/glows_l2_data.py +156 -51
  34. imap_processing/hi/l1a/science_direct_event.py +57 -51
  35. imap_processing/hi/l1b/hi_l1b.py +43 -28
  36. imap_processing/hi/l1c/hi_l1c.py +225 -42
  37. imap_processing/hi/utils.py +20 -3
  38. imap_processing/hit/l0/constants.py +2 -2
  39. imap_processing/hit/l0/decom_hit.py +1 -1
  40. imap_processing/hit/l1a/hit_l1a.py +94 -13
  41. imap_processing/hit/l1b/hit_l1b.py +158 -9
  42. imap_processing/ialirt/l0/process_codicehi.py +156 -0
  43. imap_processing/ialirt/l0/process_codicelo.py +5 -2
  44. imap_processing/ialirt/packet_definitions/ialirt.xml +28 -20
  45. imap_processing/ialirt/packet_definitions/ialirt_codicehi.xml +241 -0
  46. imap_processing/ialirt/packet_definitions/ialirt_swapi.xml +170 -0
  47. imap_processing/ialirt/packet_definitions/ialirt_swe.xml +258 -0
  48. imap_processing/ialirt/process_ephemeris.py +72 -40
  49. imap_processing/idex/decode.py +241 -0
  50. imap_processing/idex/idex_l1a.py +143 -81
  51. imap_processing/idex/idex_l1b.py +244 -10
  52. imap_processing/lo/l0/lo_science.py +61 -0
  53. imap_processing/lo/l1a/lo_l1a.py +98 -10
  54. imap_processing/lo/l1b/lo_l1b.py +2 -2
  55. imap_processing/lo/l1c/lo_l1c.py +2 -2
  56. imap_processing/lo/packet_definitions/lo_xtce.xml +1082 -9178
  57. imap_processing/mag/l0/decom_mag.py +2 -2
  58. imap_processing/mag/l1a/mag_l1a.py +7 -7
  59. imap_processing/mag/l1a/mag_l1a_data.py +62 -30
  60. imap_processing/mag/l1b/mag_l1b.py +11 -6
  61. imap_processing/quality_flags.py +18 -3
  62. imap_processing/spice/geometry.py +149 -177
  63. imap_processing/spice/kernels.py +26 -26
  64. imap_processing/spice/spin.py +233 -0
  65. imap_processing/spice/time.py +96 -31
  66. imap_processing/swapi/l1/swapi_l1.py +60 -31
  67. imap_processing/swapi/packet_definitions/swapi_packet_definition.xml +363 -384
  68. imap_processing/swe/l1a/swe_l1a.py +8 -3
  69. imap_processing/swe/l1a/swe_science.py +24 -24
  70. imap_processing/swe/l1b/swe_l1b.py +2 -1
  71. imap_processing/swe/l1b/swe_l1b_science.py +181 -122
  72. imap_processing/swe/l2/swe_l2.py +337 -70
  73. imap_processing/swe/utils/swe_utils.py +28 -0
  74. imap_processing/tests/cdf/test_utils.py +2 -2
  75. imap_processing/tests/codice/conftest.py +20 -17
  76. imap_processing/tests/codice/data/validation/imap_codice_l1a_hskp_20241110193622_v0.0.0.cdf +0 -0
  77. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-aggregated_20241110193700_v0.0.0.cdf +0 -0
  78. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-counters-singles_20241110193700_v0.0.0.cdf +0 -0
  79. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-angular_20241110193700_v0.0.0.cdf +0 -0
  80. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-priority_20241110193700_v0.0.0.cdf +0 -0
  81. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-nsw-species_20241110193700_v0.0.0.cdf +0 -0
  82. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-angular_20241110193700_v0.0.0.cdf +0 -0
  83. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-priority_20241110193700_v0.0.0.cdf +0 -0
  84. imap_processing/tests/codice/data/validation/imap_codice_l1a_lo-sw-species_20241110193700_v0.0.0.cdf +0 -0
  85. imap_processing/tests/codice/test_codice_l0.py +55 -121
  86. imap_processing/tests/codice/test_codice_l1a.py +147 -59
  87. imap_processing/tests/conftest.py +81 -22
  88. imap_processing/tests/ena_maps/test_ena_maps.py +309 -0
  89. imap_processing/tests/ena_maps/test_map_utils.py +286 -0
  90. imap_processing/tests/ena_maps/test_spatial_utils.py +161 -0
  91. imap_processing/tests/glows/conftest.py +7 -1
  92. imap_processing/tests/glows/test_glows_l1a_cdf.py +3 -7
  93. imap_processing/tests/glows/test_glows_l1a_data.py +34 -6
  94. imap_processing/tests/glows/test_glows_l1b_data.py +29 -17
  95. imap_processing/tests/glows/test_glows_l2.py +101 -0
  96. imap_processing/tests/hi/conftest.py +3 -3
  97. imap_processing/tests/hi/data/l1/imap_hi_l1b_45sensor-de_20250415_v999.cdf +0 -0
  98. imap_processing/tests/hi/data/l1/imap_his_pset-calibration-prod-config_20240101_v001.csv +31 -0
  99. imap_processing/tests/hi/test_hi_l1b.py +14 -9
  100. imap_processing/tests/hi/test_hi_l1c.py +136 -36
  101. imap_processing/tests/hi/test_l1a.py +0 -2
  102. imap_processing/tests/hi/test_science_direct_event.py +18 -14
  103. imap_processing/tests/hi/test_utils.py +16 -11
  104. imap_processing/tests/hit/helpers/__init__.py +0 -0
  105. imap_processing/tests/hit/helpers/l1_validation.py +405 -0
  106. imap_processing/tests/hit/test_data/sci_sample.ccsds +0 -0
  107. imap_processing/tests/hit/test_decom_hit.py +8 -10
  108. imap_processing/tests/hit/test_hit_l1a.py +117 -180
  109. imap_processing/tests/hit/test_hit_l1b.py +149 -55
  110. imap_processing/tests/hit/validation_data/hit_l1b_standard_sample2_nsrl_v4_3decimals.csv +62 -0
  111. imap_processing/tests/hit/validation_data/sci_sample_raw.csv +62 -0
  112. imap_processing/tests/ialirt/test_data/l0/20240827095047_SWE_IALIRT_packet.bin +0 -0
  113. imap_processing/tests/ialirt/test_data/l0/BinLog CCSDS_FRAG_TLM_20240826_152323Z_IALIRT_data_for_SDC.bin +0 -0
  114. imap_processing/tests/ialirt/test_data/l0/eu_SWP_IAL_20240826_152033.csv +644 -0
  115. imap_processing/tests/ialirt/test_data/l0/hi_fsw_view_1_ccsds.bin +0 -0
  116. imap_processing/tests/ialirt/test_data/l0/idle_export_eu.SWE_IALIRT_20240827_093852.csv +914 -0
  117. imap_processing/tests/ialirt/test_data/l0/imap_codice_l1a_hi-ialirt_20240523200000_v0.0.0.cdf +0 -0
  118. imap_processing/tests/ialirt/unit/test_process_codicehi.py +106 -0
  119. imap_processing/tests/ialirt/unit/test_process_ephemeris.py +33 -5
  120. imap_processing/tests/ialirt/unit/test_process_swapi.py +85 -0
  121. imap_processing/tests/ialirt/unit/test_process_swe.py +106 -0
  122. imap_processing/tests/idex/conftest.py +29 -1
  123. imap_processing/tests/idex/test_data/compressed_2023_102_14_24_55.pkts +0 -0
  124. imap_processing/tests/idex/test_data/non_compressed_2023_102_14_22_26.pkts +0 -0
  125. imap_processing/tests/idex/test_idex_l0.py +6 -3
  126. imap_processing/tests/idex/test_idex_l1a.py +151 -1
  127. imap_processing/tests/idex/test_idex_l1b.py +124 -2
  128. imap_processing/tests/lo/test_lo_l1a.py +62 -2
  129. imap_processing/tests/lo/test_lo_science.py +85 -0
  130. imap_processing/tests/lo/validation_data/Instrument_FM1_T104_R129_20240803_ILO_SPIN_EU.csv +2 -0
  131. imap_processing/tests/mag/conftest.py +16 -0
  132. imap_processing/tests/mag/test_mag_decom.py +6 -4
  133. imap_processing/tests/mag/test_mag_l1a.py +36 -7
  134. imap_processing/tests/mag/test_mag_l1b.py +55 -4
  135. imap_processing/tests/mag/test_mag_validation.py +148 -0
  136. imap_processing/tests/mag/validation/L1a/T001/all_p_ones.txt +19200 -0
  137. imap_processing/tests/mag/validation/L1a/T001/mag-l0-l1a-t001-in.bin +0 -0
  138. imap_processing/tests/mag/validation/L1a/T001/mag-l0-l1a-t001-out.csv +17 -0
  139. imap_processing/tests/mag/validation/L1a/T002/all_n_ones.txt +19200 -0
  140. imap_processing/tests/mag/validation/L1a/T002/mag-l0-l1a-t002-in.bin +0 -0
  141. imap_processing/tests/mag/validation/L1a/T002/mag-l0-l1a-t002-out.csv +17 -0
  142. imap_processing/tests/mag/validation/L1a/T003/field_like.txt +19200 -0
  143. imap_processing/tests/mag/validation/L1a/T003/mag-l0-l1a-t003-in.bin +0 -0
  144. imap_processing/tests/mag/validation/L1a/T003/mag-l0-l1a-t003-out.csv +17 -0
  145. imap_processing/tests/mag/validation/L1a/T004/field_like.txt +19200 -0
  146. imap_processing/tests/mag/validation/L1a/T004/mag-l0-l1a-t004-in.bin +0 -0
  147. imap_processing/tests/mag/validation/L1a/T004/mag-l0-l1a-t004-out.csv +17 -0
  148. imap_processing/tests/mag/validation/L1a/T005/field_like_range_change.txt +19200 -0
  149. imap_processing/tests/mag/validation/L1a/T005/mag-l0-l1a-t005-in.bin +0 -0
  150. imap_processing/tests/mag/validation/L1a/T005/mag-l0-l1a-t005-out.csv +17 -0
  151. imap_processing/tests/mag/validation/L1a/T006/hdr_field.txt +19200 -0
  152. imap_processing/tests/mag/validation/L1a/T006/mag-l0-l1a-t006-in.bin +0 -0
  153. imap_processing/tests/mag/validation/L1a/T006/mag-l0-l1a-t006-out.csv +17 -0
  154. imap_processing/tests/mag/validation/L1a/T007/hdr_field_and_range_change.txt +19200 -0
  155. imap_processing/tests/mag/validation/L1a/T007/mag-l0-l1a-t007-in.bin +0 -0
  156. imap_processing/tests/mag/validation/L1a/T007/mag-l0-l1a-t007-out.csv +17 -0
  157. imap_processing/tests/mag/validation/L1a/T008/field_like_range_change.txt +19200 -0
  158. imap_processing/tests/mag/validation/L1a/T008/mag-l0-l1a-t008-in.bin +0 -0
  159. imap_processing/tests/mag/validation/L1a/T008/mag-l0-l1a-t008-out.csv +17 -0
  160. imap_processing/tests/mag/validation/L1b/T009/data.bin +0 -0
  161. imap_processing/tests/mag/validation/L1b/T009/field_like_all_ranges.txt +19200 -0
  162. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-in.csv +17 -0
  163. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-magi-out.csv +17 -0
  164. imap_processing/tests/mag/validation/L1b/T009/mag-l1a-l1b-t009-mago-out.csv +17 -0
  165. imap_processing/tests/mag/validation/L1b/T010/data.bin +0 -0
  166. imap_processing/tests/mag/validation/L1b/T010/field_like_all_ranges.txt +19200 -0
  167. imap_processing/tests/mag/validation/L1b/T010/mag-l1a-l1b-t010-in.csv +17 -0
  168. imap_processing/tests/mag/validation/L1b/T010/mag-l1a-l1b-t010-magi-out.csv +17 -0
  169. imap_processing/tests/mag/validation/L1b/T010/mag-l1a-l1b-t010-mago-out.csv +17 -0
  170. imap_processing/tests/mag/validation/L1b/T011/data.bin +0 -0
  171. imap_processing/tests/mag/validation/L1b/T011/field_like_all_ranges.txt +19200 -0
  172. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-in.csv +17 -0
  173. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-magi-out.csv +17 -0
  174. imap_processing/tests/mag/validation/L1b/T011/mag-l1a-l1b-t011-mago-out.csv +17 -0
  175. imap_processing/tests/spice/test_geometry.py +128 -133
  176. imap_processing/tests/spice/test_kernels.py +37 -37
  177. imap_processing/tests/spice/test_spin.py +184 -0
  178. imap_processing/tests/spice/test_time.py +43 -20
  179. imap_processing/tests/swapi/test_swapi_l1.py +11 -10
  180. imap_processing/tests/swapi/test_swapi_l2.py +13 -3
  181. imap_processing/tests/swe/test_swe_l1a.py +1 -1
  182. imap_processing/tests/swe/test_swe_l1b.py +20 -3
  183. imap_processing/tests/swe/test_swe_l1b_science.py +54 -35
  184. imap_processing/tests/swe/test_swe_l2.py +148 -5
  185. imap_processing/tests/test_cli.py +39 -7
  186. imap_processing/tests/test_quality_flags.py +19 -19
  187. imap_processing/tests/test_utils.py +3 -2
  188. imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_ultrarawimg_withFSWcalcs_FM45_40P_Phi28p5_BeamCal_LinearScan_phi2850_theta-000_20240207T102740.csv +3314 -3314
  189. imap_processing/tests/ultra/test_data/mock_data.py +161 -0
  190. imap_processing/tests/ultra/unit/conftest.py +73 -0
  191. imap_processing/tests/ultra/unit/test_badtimes.py +58 -0
  192. imap_processing/tests/ultra/unit/test_cullingmask.py +87 -0
  193. imap_processing/tests/ultra/unit/test_de.py +61 -60
  194. imap_processing/tests/ultra/unit/test_ultra_l1a.py +3 -3
  195. imap_processing/tests/ultra/unit/test_ultra_l1b.py +51 -77
  196. imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +5 -5
  197. imap_processing/tests/ultra/unit/test_ultra_l1b_culling.py +114 -0
  198. imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +86 -26
  199. imap_processing/tests/ultra/unit/test_ultra_l1c.py +1 -1
  200. imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +3 -3
  201. imap_processing/ultra/constants.py +11 -1
  202. imap_processing/ultra/l1a/ultra_l1a.py +2 -2
  203. imap_processing/ultra/l1b/badtimes.py +22 -5
  204. imap_processing/ultra/l1b/cullingmask.py +31 -5
  205. imap_processing/ultra/l1b/de.py +32 -37
  206. imap_processing/ultra/l1b/extendedspin.py +44 -20
  207. imap_processing/ultra/l1b/ultra_l1b.py +21 -22
  208. imap_processing/ultra/l1b/ultra_l1b_culling.py +190 -0
  209. imap_processing/ultra/l1b/ultra_l1b_extended.py +81 -30
  210. imap_processing/ultra/l1c/histogram.py +6 -2
  211. imap_processing/ultra/l1c/pset.py +6 -2
  212. imap_processing/ultra/l1c/ultra_l1c.py +2 -3
  213. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +4 -3
  214. imap_processing/ultra/utils/ultra_l1_utils.py +70 -14
  215. imap_processing/utils.py +2 -2
  216. {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/METADATA +7 -2
  217. {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/RECORD +235 -152
  218. imap_processing/tests/codice/data/eu_unit_lookup_table.csv +0 -101
  219. imap_processing/tests/codice/data/idle_export_eu.COD_NHK_20230822_122700 2.csv +0 -100
  220. imap_processing/tests/codice/data/idle_export_raw.COD_NHK_20230822_122700.csv +0 -100
  221. imap_processing/tests/codice/data/imap_codice_l0_raw_20241110_v001.pkts +0 -0
  222. imap_processing/tests/hi/test_data/l1a/imap_hi_l1a_45sensor-de_20250415_v000.cdf +0 -0
  223. imap_processing/tests/hit/test_data/sci_sample1.ccsds +0 -0
  224. imap_processing/tests/ultra/unit/test_spatial_utils.py +0 -125
  225. imap_processing/ultra/utils/spatial_utils.py +0 -221
  226. /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_APP_NHK.bin +0 -0
  227. /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_APP_NHK.csv +0 -0
  228. /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_SCI_CNT.bin +0 -0
  229. /imap_processing/tests/hi/{test_data → data}/l0/20231030_H45_SCI_DE.bin +0 -0
  230. /imap_processing/tests/hi/{test_data → data}/l0/H90_NHK_20241104.bin +0 -0
  231. /imap_processing/tests/hi/{test_data → data}/l0/H90_sci_cnt_20241104.bin +0 -0
  232. /imap_processing/tests/hi/{test_data → data}/l0/H90_sci_de_20241104.bin +0 -0
  233. /imap_processing/tests/hi/{test_data → data}/l0/README.txt +0 -0
  234. /imap_processing/tests/idex/{imap_idex_l0_raw_20231214_v001.pkts → test_data/imap_idex_l0_raw_20231214_v001.pkts} +0 -0
  235. /imap_processing/tests/idex/{impact_14_tof_high_data.txt → test_data/impact_14_tof_high_data.txt} +0 -0
  236. /imap_processing/tests/mag/{imap_mag_l1a_norm-magi_20251017_v001.cdf → validation/imap_mag_l1a_norm-magi_20251017_v001.cdf} +0 -0
  237. /imap_processing/tests/mag/{mag_l0_test_data.pkts → validation/mag_l0_test_data.pkts} +0 -0
  238. /imap_processing/tests/mag/{mag_l0_test_output.csv → validation/mag_l0_test_output.csv} +0 -0
  239. /imap_processing/tests/mag/{mag_l1_test_data.pkts → validation/mag_l1_test_data.pkts} +0 -0
  240. /imap_processing/tests/mag/{mag_l1a_test_output.csv → validation/mag_l1a_test_output.csv} +0 -0
  241. {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/LICENSE +0 -0
  242. {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/WHEEL +0 -0
  243. {imap_processing-0.9.0.dist-info → imap_processing-0.11.0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,241 @@
1
+ """
2
+ Decompress IDEX raw wavelength data.
3
+
4
+ Originally written by Corinne Wuerthner.
5
+ A compressed data frame starts on a byte boundary, and begins with the 8-bit sequence
6
+ 0xF5 to indicate the start of a frame.
7
+ A frame contains one or more subframes of compressed data. Subframes are packed as
8
+ tightly as possible, and are not aligned to any byte or word boundary. The compression
9
+ parameters are varied for each subframe to optimize the data compression. Within a
10
+ subframe the same predictor, and the same Rice parameter is used for all the
11
+ samples in that subframe. The predictor and rice parameter is allowed to vary
12
+ from subframe to subframe.
13
+
14
+ The start of each subframe consists of the following bits:
15
+ 00: Constant value
16
+ The predictor assumes that every sample in the frame is equal to the
17
+ first sample in the frame. In this case, the first sample is stored as
18
+ the original NBIT binary value and no other samples are included in the
19
+ frame. The constant value predictor will only be selected for a
20
+ subframe where every sample is the same value.
21
+
22
+ 01: Verbatim
23
+ The predictor assumes that the data is not well correlated, and simply
24
+ stores every sample in the frame using the original NBIT binary
25
+ representation. This predictor minimizes the impact of data expansion
26
+ for uncorrelated data samples where the golomb-rice coding would
27
+ actually make the encoded data significantly larger than the original
28
+ data set.
29
+
30
+ 10: Linear predictor #1
31
+ This predictor assumes that each sample will have the same value as the
32
+ sample immediately before it (sample X(n) = sampleX(n-1)). The predicted
33
+ value is subtracted from the actual value of the sample and only the
34
+ error (residual) between the actual value, and the predicted value is
35
+ stored. This predictor requires a single uncompressed sample as a
36
+ “warmup sample” to be used in predicting the other samples in the
37
+ subframe.
38
+
39
+ 11: Linear Predictor #2
40
+ This predictor assumes that sample X(n) = 2*X(n-1)-X(n-2). This
41
+ predictor calculates the slope of the signal based on the two previous
42
+ values (slope = X(n-1)-X(n-2)) and predicts the value of X(n) will
43
+ follow on a straight line drawn between the two previous points.
44
+ X(n) = X(n-1) + (X(n-1)-X(n-2)) = 2*X(n-1)-X(n-2).
45
+
46
+ M bits for the rice parameter k. The bit width of k is equal to ceiling(log2(NBITS)).
47
+ For 10 bits, the bit width of k is 4 because log2(10) = 3.32 and ceiling(3.32) = 4.
48
+ The rice parameter k is stored in the bit stream as an unsigned binary value. The rice
49
+ parameter is omitted from the bit stream if the predictor type is set to “00” or '01'.
50
+ The next NBITS contain the raw binary value of the first sample in the subframe.
51
+ """
52
+
53
+ # sub_frame_size is the compression block size
54
+ SUB_FRAME_SIZE = 64
55
+
56
+
57
+ def _decode_sub_frame(
58
+ bits: str,
59
+ bp: int,
60
+ psel: int,
61
+ k: int,
62
+ n_bits: int,
63
+ ) -> tuple[list[int], int]:
64
+ """
65
+ Decode a subframe of compressed data.
66
+
67
+ Parameters
68
+ ----------
69
+ bits : str
70
+ Raw waveform binary string.
71
+ bp : int
72
+ Current position to start reading from bits.
73
+ psel : int
74
+ Predictor select value.
75
+ k : int
76
+ Rice parameter used to divide each re-mapped residual value into two parts.
77
+ n_bits : int
78
+ Expected number of bits per sample. Either 10 or 12.
79
+
80
+ Returns
81
+ -------
82
+ tuple[list, int]
83
+ Decompressed subframe as a list of integers and the bit position.
84
+ """
85
+ sample_count = 0
86
+ sub_frame_data = []
87
+
88
+ while (sample_count < SUB_FRAME_SIZE) and bp < len(bits):
89
+ if sample_count == 0:
90
+ # For every subframe, the first sample is always uncompressed.
91
+ # Read warmup sample
92
+ d1, bp = read_bits(bits, bp, n_bits)
93
+
94
+ sub_frame_data.append(d1)
95
+ sample_count += 1
96
+
97
+ # A 'psel' value of zero assumes that every sample in the frame is equal
98
+ # to the first sample in the frame. In this case, the first sample is
99
+ # stored as the original NBIT binary value
100
+ if psel == 0:
101
+ sub_frame_data.extend([d1] * (SUB_FRAME_SIZE - 1))
102
+ sample_count = SUB_FRAME_SIZE
103
+
104
+ # A 'psel' value of 1 assumes that the data is not well correlated, and
105
+ # simply stores every sample in the frame using the original NBIT binary
106
+ # representation.
107
+ # A 'psel' value of 3 requires two uncompressed 'warm-up' samples.
108
+ elif (psel == 1) or ((sample_count == 1) and (psel == 3)):
109
+ d1, bp = read_bits(bits, bp, n_bits)
110
+ sub_frame_data.append(d1)
111
+ sample_count += 1
112
+
113
+ else:
114
+ # The rice parameter (k) is used to divide each re-mapped residual value
115
+ # into two parts. The least significant k bits of the value are called
116
+ # the remainder (r). The other part of the value (not included in the
117
+ # remainder) is called the quotient (q).
118
+ # The remapped quotient is unary encoded by including a number of 0 bits
119
+ # equal to the value of the quotient, followed by a single '1' bit.
120
+ q = bits[bp:].find("1")
121
+ bp += q + 1
122
+ # If the value of the quotient is equal to or larger than 47, then a
123
+ # special symbol is used to denote that this particular residual value
124
+ # is not rice encoded, but that this special symbol is followed by the
125
+ # raw binary representation of the residual value using a (N_BITS+2)
126
+ # bit binary number. This special symbol is simply 47 zeros followed
127
+ # by a one.
128
+ if q == 47:
129
+ d1, bp = read_bits(bits, bp, n_bits + 2, True)
130
+ else:
131
+ if q % 2 == 1:
132
+ q = int(-((q + 1) / 2))
133
+ else:
134
+ q = int(q / 2)
135
+
136
+ r, bp = read_bits(bits, bp, k + 1)
137
+ d1 = (q << (k + 1)) + r
138
+
139
+ if psel == 2:
140
+ d1 = d1 + sub_frame_data[sample_count - 1]
141
+ elif (sample_count > 1) and (psel == 3):
142
+ d1 = (
143
+ d1
144
+ + 2 * sub_frame_data[(sample_count - 1)]
145
+ - sub_frame_data[(sample_count - 2)]
146
+ )
147
+
148
+ if (d1 > 2**n_bits) or (d1 < -(2**n_bits)):
149
+ raise ValueError(
150
+ f"Overflow Error while decoding subframe "
151
+ f"{k=}, {q=}, {r=}, {d1=}\n"
152
+ f"DataOut = {sub_frame_data}"
153
+ )
154
+
155
+ sub_frame_data.append(d1)
156
+ sample_count += 1
157
+
158
+ return sub_frame_data, bp
159
+
160
+
161
+ def rice_decode(compressed_data: str, nbit10: bool, sample_count: int) -> list[int]:
162
+ """
163
+ Decode compressed IDEX wavelength data using linear prediction and Golomb-RICE.
164
+
165
+ Parameters
166
+ ----------
167
+ compressed_data : str
168
+ Binary string representation of the raw waveform.
169
+ nbit10 : bool
170
+ If nbit10 is true, then the samples are expected to be 10 bits each, and if
171
+ nbit10 is false, then the samples are expected to be 12 bits each.
172
+ sample_count : int
173
+ The total number of samples to be decompressed.
174
+
175
+ Returns
176
+ -------
177
+ list
178
+ Decompressed data as a list of integers.
179
+ """
180
+ # Constants:
181
+ k_bits = 4
182
+ n_bits = 10 if nbit10 else 12
183
+
184
+ # frame_size is the expected amount of data
185
+ frame_size = sample_count
186
+ sub_frame_per_frame = frame_size / SUB_FRAME_SIZE
187
+
188
+ bits = compressed_data
189
+ out_data = []
190
+ sub_frame_count = 0
191
+ bp = 0
192
+ # Decode all subframes
193
+ while bp < len(bits) and (sub_frame_count < sub_frame_per_frame):
194
+ # The next two bits are the predictor select bits
195
+ psel, bp = read_bits(bits, bp, 2)
196
+ if psel > 1:
197
+ k, bp = read_bits(bits, bp, k_bits)
198
+ else:
199
+ k = 0
200
+
201
+ sub_frame_data, bp = _decode_sub_frame(bits, bp, psel, k, n_bits)
202
+
203
+ out_data.extend(sub_frame_data)
204
+ sub_frame_count += 1
205
+
206
+ if bp < len(bits) and (len(out_data) < frame_size):
207
+ raise ValueError("End of file reached before", frame_size, "samples decoded")
208
+
209
+ return out_data
210
+
211
+
212
+ def read_bits(
213
+ bits: str, bit_pointer: int, read_num: int, signed: bool = False
214
+ ) -> tuple[int, int]:
215
+ """
216
+ Read bits from a binary string and convert to an int.
217
+
218
+ Parameters
219
+ ----------
220
+ bits : str
221
+ Binary string to read from.
222
+ bit_pointer : int
223
+ Current position in binary string.
224
+ read_num : int
225
+ Number of bits to read.
226
+ signed : bool
227
+ If signed is True, convert bits to a signed int. Default is False.
228
+
229
+ Returns
230
+ -------
231
+ value : int
232
+ Value of bits read.
233
+ bit_pointer : int
234
+ Bit position after reading.
235
+ """
236
+ value = int(bits[bit_pointer : bit_pointer + read_num], 2)
237
+ if signed and bits[bit_pointer] == "1":
238
+ # If signed and is negative convert value
239
+ value = value - 2**read_num
240
+ bit_pointer += read_num
241
+ return value, bit_pointer
@@ -25,8 +25,9 @@ import space_packet_parser
25
25
  import xarray as xr
26
26
 
27
27
  from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
28
+ from imap_processing.idex.decode import rice_decode
28
29
  from imap_processing.idex.idex_l0 import decom_packets
29
- from imap_processing.spice.time import met_to_j2000ns
30
+ from imap_processing.spice.time import met_to_ttj2000ns
30
31
  from imap_processing.utils import convert_to_binary_string
31
32
 
32
33
  logger = logging.getLogger(__name__)
@@ -76,7 +77,6 @@ class PacketParser:
76
77
  Currently assumes one L0 file will generate exactly one L1a file.
77
78
  """
78
79
  decom_packet_list = decom_packets(packet_file)
79
-
80
80
  dust_events = {}
81
81
  for packet in decom_packet_list:
82
82
  if "IDX__SCI0TYPE" in packet:
@@ -105,24 +105,88 @@ class PacketParser:
105
105
  idex_attrs = get_idex_attrs(data_version)
106
106
  self.data.attrs = idex_attrs.get_global_attributes("imap_idex_l1a_sci")
107
107
 
108
+ # Add high and low sample rate coords
109
+ self.data["time_low_sample_rate_index"] = xr.DataArray(
110
+ np.arange(len(self.data["time_low_sample_rate"][0])),
111
+ name="time_low_sample_rate_index",
112
+ dims=["time_low_sample_rate_index"],
113
+ attrs=idex_attrs.get_variable_attributes("time_low_sample_rate_index"),
114
+ )
115
+
116
+ self.data["time_high_sample_rate_index"] = xr.DataArray(
117
+ np.arange(len(self.data["time_high_sample_rate"][0])),
118
+ name="time_high_sample_rate_index",
119
+ dims=["time_high_sample_rate_index"],
120
+ attrs=idex_attrs.get_variable_attributes("time_high_sample_rate_index"),
121
+ )
108
122
  # NOTE: LABL_PTR_1 should be CDF_CHAR.
109
- self.data["time_low_sr_label"] = xr.DataArray(
110
- self.data.time_low_sr_dim.values.astype(str),
111
- name="time_low_sr_label",
112
- dims=["time_low_sr_label"],
113
- attrs=idex_attrs.get_variable_attributes("time_low_sr_label"),
123
+ self.data["time_low_sample_rate_label"] = xr.DataArray(
124
+ self.data.time_low_sample_rate_index.values.astype(str),
125
+ name="time_low_sample_rate_label",
126
+ dims=["time_low_sample_rate_index"],
127
+ attrs=idex_attrs.get_variable_attributes("time_low_sample_rate_label"),
114
128
  )
115
129
 
116
- self.data["time_high_sr_label"] = xr.DataArray(
117
- self.data.time_high_sr_dim.values.astype(str),
118
- name="time_high_sr_label",
119
- dims=["time_high_sr_label"],
120
- attrs=idex_attrs.get_variable_attributes("time_high_sr_label"),
130
+ self.data["time_high_sample_rate_label"] = xr.DataArray(
131
+ self.data.time_high_sample_rate_index.values.astype(str),
132
+ name="time_high_sample_rate_label",
133
+ dims=["time_high_sample_rate_index"],
134
+ attrs=idex_attrs.get_variable_attributes("time_high_sample_rate_label"),
121
135
  )
122
136
 
123
137
  logger.info("IDEX L1A science data processing completed.")
124
138
 
125
139
 
140
+ def _read_waveform_bits(waveform_raw: str, high_sample: bool = True) -> list[int]:
141
+ """
142
+ Convert the raw waveform binary string to ints.
143
+
144
+ Parse a binary string representing a waveform.
145
+ If the data is a high sample waveform:
146
+ - Data arrives in 32-bit chunks, divided up into:
147
+ * 2 bits of padding
148
+ * 3x10 bits of integer data.
149
+ - The very last four numbers are usually bad, so remove those.
150
+ If the data is a low sample waveform:
151
+ - Data arrives in 32-bit chunks, divided up into:
152
+ * 8 bits of padding
153
+ * 2x12 bits of integer data.
154
+
155
+ Parameters
156
+ ----------
157
+ waveform_raw : str
158
+ The binary string representing the waveform.
159
+ high_sample : bool
160
+ If true, parse the waveform according to the high sample pattern,
161
+ otherwise use the low sample pattern.
162
+
163
+ Returns
164
+ -------
165
+ ints : list
166
+ List of the waveform.
167
+ """
168
+ ints = []
169
+ if high_sample:
170
+ for i in range(0, len(waveform_raw), 32):
171
+ # 32-bit chunks, divided up into 2, 10, 10, 10
172
+ # skip first two bits
173
+ ints += [
174
+ int(waveform_raw[i + 2 : i + 12], 2),
175
+ int(waveform_raw[i + 12 : i + 22], 2),
176
+ int(waveform_raw[i + 22 : i + 32], 2),
177
+ ]
178
+ ints = ints[:-4] # Remove last 4 numbers
179
+ else:
180
+ for i in range(0, len(waveform_raw), 32):
181
+ # 32-bit chunks, divided up into 8, 12, 12
182
+ # skip first eight bits
183
+ ints += [
184
+ int(waveform_raw[i + 8 : i + 20], 2),
185
+ int(waveform_raw[i + 20 : i + 32], 2),
186
+ ]
187
+ return ints
188
+
189
+
126
190
  class RawDustEvent:
127
191
  """
128
192
  Encapsulate IDEX Raw Dust Event.
@@ -147,6 +211,10 @@ class RawDustEvent:
147
211
  The number of samples in a "block" of low sample data.
148
212
  NUMBER_SAMPLES_PER_HIGH_SAMPLE_BLOCK: int
149
213
  The number of samples in a "block" of high sample data.
214
+ MAX_HIGH_BLOCKS: int
215
+ The maximum number of "blocks" for high sample data.
216
+ MAX_LOW_BLOCKS: int
217
+ The maximum number of "blocks" for low sample data.
150
218
 
151
219
  Methods
152
220
  -------
@@ -180,6 +248,9 @@ class RawDustEvent:
180
248
  NUMBER_SAMPLES_PER_HIGH_SAMPLE_BLOCK = (
181
249
  512 # The number of samples in a "block" of high sample data
182
250
  )
251
+ # Maximum amount of data
252
+ MAX_HIGH_BLOCKS = 16
253
+ MAX_LOW_BLOCKS = 64
183
254
 
184
255
  def __init__(
185
256
  self, header_packet: space_packet_parser.packets.CCSDSPacket, data_version: str
@@ -229,6 +300,7 @@ class RawDustEvent:
229
300
  self.Target_High_bits = ""
230
301
  self.Ion_Grid_bits = ""
231
302
 
303
+ self.compressed = self.telemetry_items["idx__sci0comp"]
232
304
  self.cdf_attrs = get_idex_attrs(data_version)
233
305
 
234
306
  def _append_raw_data(self, scitype: Scitype, bits: str) -> None:
@@ -287,7 +359,7 @@ class RawDustEvent:
287
359
  # Get the datetime of Jan 1 2012 as the start date
288
360
  met = seconds_since_launch + microseconds_since_last_second * 1e-6
289
361
 
290
- self.impact_time = met_to_j2000ns(met)
362
+ self.impact_time = met_to_ttj2000ns(met)
291
363
 
292
364
  def _set_sample_trigger_times(
293
365
  self, packet: space_packet_parser.packets.CCSDSPacket
@@ -361,11 +433,7 @@ class RawDustEvent:
361
433
  Will process the high sample waveform.
362
434
 
363
435
  Parse a binary string representing a high sample waveform.
364
- Data arrives in 32 bit chunks, divided up into:
365
- * 2 bits of padding
366
- * 3x10 bits of integer data.
367
-
368
- The very last 4 numbers are bad usually, so remove those.
436
+ If the data has been compressed, decompress using the RICE Golomb algorithm.
369
437
 
370
438
  Parameters
371
439
  ----------
@@ -377,25 +445,20 @@ class RawDustEvent:
377
445
  ints : list
378
446
  List of the high sample waveform.
379
447
  """
380
- ints = []
381
- for i in range(0, len(waveform_raw), 32):
382
- # 32 bit chunks, divided up into 2, 10, 10, 10
383
- # skip first two bits
384
- ints += [
385
- int(waveform_raw[i + 2 : i + 12], 2),
386
- int(waveform_raw[i + 12 : i + 22], 2),
387
- int(waveform_raw[i + 22 : i + 32], 2),
388
- ]
389
- return ints[:-4] # Remove last 4 numbers
448
+ samples = self.MAX_HIGH_BLOCKS * self.NUMBER_SAMPLES_PER_HIGH_SAMPLE_BLOCK
449
+ if self.compressed.raw_value == 1:
450
+ ints = rice_decode(waveform_raw, nbit10=True, sample_count=samples)
451
+ ints = ints[:-3]
452
+ else:
453
+ ints = _read_waveform_bits(waveform_raw, high_sample=True)
454
+ return ints
390
455
 
391
456
  def _parse_low_sample_waveform(self, waveform_raw: str) -> list[int]:
392
457
  """
393
458
  Will process the low sample waveform.
394
459
 
395
460
  Parse a binary string representing a low sample waveform
396
- Data arrives in 32-bit chunks, divided up into:
397
- * 8 bits of padding
398
- * 2x12 bits of integer data.
461
+ If the data has been compressed, decompress using the RICE Golomb algorithm.
399
462
 
400
463
  Parameters
401
464
  ----------
@@ -407,12 +470,11 @@ class RawDustEvent:
407
470
  ints : list
408
471
  List of processed low sample waveform.
409
472
  """
410
- ints = []
411
- for i in range(0, len(waveform_raw), 32):
412
- ints += [
413
- int(waveform_raw[i + 8 : i + 20], 2),
414
- int(waveform_raw[i + 20 : i + 32], 2),
415
- ]
473
+ samples = self.MAX_LOW_BLOCKS * self.NUMBER_SAMPLES_PER_LOW_SAMPLE_BLOCK
474
+ if self.compressed.raw_value == 1:
475
+ ints = rice_decode(waveform_raw, nbit10=False, sample_count=samples)
476
+ else:
477
+ ints = _read_waveform_bits(waveform_raw, high_sample=False)
416
478
  return ints
417
479
 
418
480
  def _calc_low_sample_resolution(self, num_samples: int) -> npt.NDArray:
@@ -432,14 +494,15 @@ class RawDustEvent:
432
494
 
433
495
  Returns
434
496
  -------
435
- time_low_sr_data : numpy.ndarray
497
+ time_low_sample_rate_data : numpy.ndarray
436
498
  Low time sample data array.
437
499
  """
438
- time_low_sr_init = np.linspace(0, num_samples, num_samples)
439
- time_low_sr_data = (
440
- self.LOW_SAMPLE_RATE * time_low_sr_init - self.low_sample_trigger_time
500
+ time_low_sample_rate_init = np.linspace(0, num_samples, num_samples)
501
+ time_low_sample_rate_data = (
502
+ self.LOW_SAMPLE_RATE * time_low_sample_rate_init
503
+ - self.low_sample_trigger_time
441
504
  )
442
- return time_low_sr_data
505
+ return time_low_sample_rate_data
443
506
 
444
507
  def _calc_high_sample_resolution(self, num_samples: int) -> npt.NDArray:
445
508
  """
@@ -458,14 +521,15 @@ class RawDustEvent:
458
521
 
459
522
  Returns
460
523
  -------
461
- time_high_sr_data : numpy.ndarray
524
+ time_high_sample_rate_data : numpy.ndarray
462
525
  High sample time data array.
463
526
  """
464
- time_high_sr_init = np.linspace(0, num_samples, num_samples)
465
- time_high_sr_data = (
466
- self.HIGH_SAMPLE_RATE * time_high_sr_init - self.high_sample_trigger_time
527
+ time_high_sample_rate_init = np.linspace(0, num_samples, num_samples)
528
+ time_high_sample_rate_data = (
529
+ self.HIGH_SAMPLE_RATE * time_high_sample_rate_init
530
+ - self.high_sample_trigger_time
467
531
  )
468
- return time_high_sr_data
532
+ return time_high_sample_rate_data
469
533
 
470
534
  def _populate_bit_strings(
471
535
  self, packet: space_packet_parser.packets.CCSDSPacket
@@ -510,81 +574,79 @@ class RawDustEvent:
510
574
  )
511
575
 
512
576
  # Process the 6 primary data variables
513
- tof_high_xr = xr.DataArray(
577
+ tof_high = xr.DataArray(
514
578
  name="TOF_High",
515
579
  data=[self._parse_high_sample_waveform(self.TOF_High_bits)],
516
- dims=("epoch", "time_high_sr_dim"),
580
+ dims=("epoch", "time_high_sample_rate_index"),
517
581
  attrs=idex_attrs.get_variable_attributes("tof_high_attrs"),
518
582
  )
519
- tof_low_xr = xr.DataArray(
583
+ tof_low = xr.DataArray(
520
584
  name="TOF_Low",
521
585
  data=[self._parse_high_sample_waveform(self.TOF_Low_bits)],
522
- dims=("epoch", "time_high_sr_dim"),
586
+ dims=("epoch", "time_high_sample_rate_index"),
523
587
  attrs=idex_attrs.get_variable_attributes("tof_low_attrs"),
524
588
  )
525
- tof_mid_xr = xr.DataArray(
589
+ tof_mid = xr.DataArray(
526
590
  name="TOF_Mid",
527
591
  data=[self._parse_high_sample_waveform(self.TOF_Mid_bits)],
528
- dims=("epoch", "time_high_sr_dim"),
592
+ dims=("epoch", "time_high_sample_rate_index"),
529
593
  attrs=idex_attrs.get_variable_attributes("tof_mid_attrs"),
530
594
  )
531
- target_high_xr = xr.DataArray(
595
+ target_high = xr.DataArray(
532
596
  name="Target_High",
533
597
  data=[self._parse_low_sample_waveform(self.Target_High_bits)],
534
- dims=("epoch", "time_low_sr_dim"),
598
+ dims=("epoch", "time_low_sample_rate_index"),
535
599
  attrs=idex_attrs.get_variable_attributes("target_high_attrs"),
536
600
  )
537
- target_low_xr = xr.DataArray(
601
+ target_low = xr.DataArray(
538
602
  name="Target_Low",
539
603
  data=[self._parse_low_sample_waveform(self.Target_Low_bits)],
540
- dims=("epoch", "time_low_sr_dim"),
604
+ dims=("epoch", "time_low_sample_rate_index"),
541
605
  attrs=idex_attrs.get_variable_attributes("target_low_attrs"),
542
606
  )
543
- ion_grid_xr = xr.DataArray(
607
+ ion_grid = xr.DataArray(
544
608
  name="Ion_Grid",
545
609
  data=[self._parse_low_sample_waveform(self.Ion_Grid_bits)],
546
- dims=("epoch", "time_low_sr_dim"),
610
+ dims=("epoch", "time_low_sample_rate_index"),
547
611
  attrs=idex_attrs.get_variable_attributes("ion_grid_attrs"),
548
612
  )
549
613
 
550
614
  # Determine the 3 coordinate variables
551
- epoch_xr = xr.DataArray(
615
+ epoch = xr.DataArray(
552
616
  name="epoch",
553
617
  data=[self.impact_time],
554
618
  dims=("epoch"),
555
619
  attrs=idex_attrs.get_variable_attributes("epoch"),
556
620
  )
557
621
 
558
- time_low_sr_xr = xr.DataArray(
559
- name="time_low_sr",
560
- data=[self._calc_low_sample_resolution(len(target_low_xr[0]))],
561
- dims=("epoch", "time_low_sr_dim"),
562
- attrs=idex_attrs.get_variable_attributes("low_sr_attrs"),
622
+ time_low_sample_rate = xr.DataArray(
623
+ name="time_low_sample_rate",
624
+ data=[self._calc_low_sample_resolution(len(target_low[0]))],
625
+ dims=("epoch", "time_low_sample_rate_index"),
626
+ attrs=idex_attrs.get_variable_attributes("low_sample_rate_attrs"),
563
627
  )
564
628
 
565
- time_high_sr_xr = xr.DataArray(
566
- name="time_high_sr",
567
- data=[self._calc_high_sample_resolution(len(tof_low_xr[0]))],
568
- dims=("epoch", "time_high_sr_dim"),
569
- attrs=idex_attrs.get_variable_attributes("high_sr_attrs"),
629
+ time_high_sample_rate = xr.DataArray(
630
+ name="time_high_sample_rate",
631
+ data=[self._calc_high_sample_resolution(len(tof_low[0]))],
632
+ dims=("epoch", "time_high_sample_rate_index"),
633
+ attrs=idex_attrs.get_variable_attributes("high_sample_rate_attrs"),
570
634
  )
571
635
 
572
636
  # Combine to return a dataset object
573
637
  dataset = xr.Dataset(
574
638
  data_vars={
575
- "TOF_Low": tof_low_xr,
576
- "TOF_High": tof_high_xr,
577
- "TOF_Mid": tof_mid_xr,
578
- "Target_High": target_high_xr,
579
- "Target_Low": target_low_xr,
580
- "Ion_Grid": ion_grid_xr,
639
+ "TOF_Low": tof_low,
640
+ "TOF_High": tof_high,
641
+ "TOF_Mid": tof_mid,
642
+ "Target_High": target_high,
643
+ "Target_Low": target_low,
644
+ "Ion_Grid": ion_grid,
645
+ "time_low_sample_rate": time_low_sample_rate,
646
+ "time_high_sample_rate": time_high_sample_rate,
581
647
  }
582
648
  | trigger_vars,
583
- coords={
584
- "epoch": epoch_xr,
585
- "time_low_sr": time_low_sr_xr,
586
- "time_high_sr": time_high_sr_xr,
587
- },
649
+ coords={"epoch": epoch},
588
650
  )
589
651
 
590
652
  return dataset