imap-processing 0.6.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.
Files changed (398) hide show
  1. imap_processing/__init__.py +34 -0
  2. imap_processing/_version.py +3 -0
  3. imap_processing/ccsds/__init__.py +0 -0
  4. imap_processing/ccsds/ccsds_data.py +55 -0
  5. imap_processing/ccsds/excel_to_xtce.py +477 -0
  6. imap_processing/cdf/__init__.py +0 -0
  7. imap_processing/cdf/cdf_attribute_manager.py +322 -0
  8. imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +212 -0
  9. imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +1358 -0
  10. imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +391 -0
  11. imap_processing/cdf/config/imap_constant_attrs.yaml +33 -0
  12. imap_processing/cdf/config/imap_default_global_cdf_attrs.yaml +17 -0
  13. imap_processing/cdf/config/imap_glows_global_cdf_attrs.yaml +41 -0
  14. imap_processing/cdf/config/imap_glows_l1a_variable_attrs.yaml +499 -0
  15. imap_processing/cdf/config/imap_glows_l1b_variable_attrs.yaml +334 -0
  16. imap_processing/cdf/config/imap_hi_global_cdf_attrs.yaml +51 -0
  17. imap_processing/cdf/config/imap_hi_variable_attrs.yaml +435 -0
  18. imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +27 -0
  19. imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +493 -0
  20. imap_processing/cdf/config/imap_hit_l1b_variable_attrs.yaml +564 -0
  21. imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +24 -0
  22. imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml +426 -0
  23. imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +90 -0
  24. imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +487 -0
  25. imap_processing/cdf/config/imap_lo_l1b_variable_attrs.yaml +121 -0
  26. imap_processing/cdf/config/imap_lo_l1c_variable_attrs.yaml +179 -0
  27. imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +97 -0
  28. imap_processing/cdf/config/imap_mag_l1_variable_attrs.yaml +201 -0
  29. imap_processing/cdf/config/imap_swapi_global_cdf_attrs.yaml +33 -0
  30. imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +137 -0
  31. imap_processing/cdf/config/imap_swe_global_cdf_attrs.yaml +24 -0
  32. imap_processing/cdf/config/imap_swe_l1a_variable_attrs.yaml +234 -0
  33. imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +273 -0
  34. imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +100 -0
  35. imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +52 -0
  36. imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +297 -0
  37. imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +121 -0
  38. imap_processing/cdf/config/shared/default_global_cdf_attrs_schema.yaml +246 -0
  39. imap_processing/cdf/config/shared/default_variable_cdf_attrs_schema.yaml +466 -0
  40. imap_processing/cdf/imap_cdf_manager.py +64 -0
  41. imap_processing/cdf/utils.py +147 -0
  42. imap_processing/cli.py +863 -0
  43. imap_processing/codice/__init__.py +1 -0
  44. imap_processing/codice/codice_l0.py +54 -0
  45. imap_processing/codice/codice_l1a.py +558 -0
  46. imap_processing/codice/codice_l1b.py +194 -0
  47. imap_processing/codice/constants.py +986 -0
  48. imap_processing/codice/data/esa_sweep_values.csv +257 -0
  49. imap_processing/codice/data/lo_stepping_values.csv +129 -0
  50. imap_processing/codice/decompress.py +142 -0
  51. imap_processing/codice/packet_definitions/P_COD_NHK.xml +618 -0
  52. imap_processing/codice/packet_definitions/codice_packet_definition.xml +5073 -0
  53. imap_processing/codice/utils.py +95 -0
  54. imap_processing/decom.py +40 -0
  55. imap_processing/glows/__init__.py +1 -0
  56. imap_processing/glows/ancillary/l1b_conversion_table_v001.json +42 -0
  57. imap_processing/glows/l0/__init__.py +0 -0
  58. imap_processing/glows/l0/decom_glows.py +91 -0
  59. imap_processing/glows/l0/glows_l0_data.py +194 -0
  60. imap_processing/glows/l1a/glows_l1a.py +424 -0
  61. imap_processing/glows/l1a/glows_l1a_data.py +555 -0
  62. imap_processing/glows/l1b/glows_l1b.py +270 -0
  63. imap_processing/glows/l1b/glows_l1b_data.py +583 -0
  64. imap_processing/glows/packet_definitions/GLX_COMBINED.xml +254 -0
  65. imap_processing/glows/packet_definitions/P_GLX_TMSCDE.xml +97 -0
  66. imap_processing/glows/packet_definitions/P_GLX_TMSCHIST.xml +215 -0
  67. imap_processing/glows/utils/__init__.py +0 -0
  68. imap_processing/glows/utils/constants.py +105 -0
  69. imap_processing/hi/__init__.py +1 -0
  70. imap_processing/hi/l0/__init__.py +0 -0
  71. imap_processing/hi/l0/decom_hi.py +24 -0
  72. imap_processing/hi/l1a/__init__.py +0 -0
  73. imap_processing/hi/l1a/hi_l1a.py +73 -0
  74. imap_processing/hi/l1a/histogram.py +142 -0
  75. imap_processing/hi/l1a/housekeeping.py +27 -0
  76. imap_processing/hi/l1a/science_direct_event.py +341 -0
  77. imap_processing/hi/l1b/__init__.py +0 -0
  78. imap_processing/hi/l1b/hi_eng_unit_convert_table.csv +154 -0
  79. imap_processing/hi/l1b/hi_l1b.py +127 -0
  80. imap_processing/hi/l1c/__init__.py +0 -0
  81. imap_processing/hi/l1c/hi_l1c.py +228 -0
  82. imap_processing/hi/packet_definitions/__init__.py +0 -0
  83. imap_processing/hi/packet_definitions/hi_packet_definition.xml +482 -0
  84. imap_processing/hi/utils.py +27 -0
  85. imap_processing/hit/__init__.py +1 -0
  86. imap_processing/hit/l0/__init__.py +0 -0
  87. imap_processing/hit/l0/data_classes/housekeeping.py +240 -0
  88. imap_processing/hit/l0/data_classes/science_packet.py +259 -0
  89. imap_processing/hit/l0/decom_hit.py +467 -0
  90. imap_processing/hit/l0/utils/hit_base.py +57 -0
  91. imap_processing/hit/l1a/__init__.py +0 -0
  92. imap_processing/hit/l1a/hit_l1a.py +254 -0
  93. imap_processing/hit/l1b/hit_l1b.py +179 -0
  94. imap_processing/hit/packet_definitions/hit_packet_definitions.xml +1276 -0
  95. imap_processing/ialirt/__init__.py +0 -0
  96. imap_processing/ialirt/l0/__init__.py +0 -0
  97. imap_processing/ialirt/l0/process_hit.py +220 -0
  98. imap_processing/ialirt/packet_definitions/__init__.py +0 -0
  99. imap_processing/ialirt/packet_definitions/ialirt.xml +778 -0
  100. imap_processing/ialirt/packet_definitions/ialirt_hit.xml +186 -0
  101. imap_processing/idex/__init__.py +2 -0
  102. imap_processing/idex/idex_constants.py +27 -0
  103. imap_processing/idex/idex_l0.py +31 -0
  104. imap_processing/idex/idex_l1a.py +631 -0
  105. imap_processing/idex/packet_definitions/idex_packet_definition.xml +3162 -0
  106. imap_processing/lo/__init__.py +1 -0
  107. imap_processing/lo/l0/__init__.py +0 -0
  108. imap_processing/lo/l0/data_classes/science_direct_events.py +215 -0
  109. imap_processing/lo/l0/data_classes/star_sensor.py +98 -0
  110. imap_processing/lo/l0/decompression_tables/12_to_16_bit.csv +4097 -0
  111. imap_processing/lo/l0/decompression_tables/8_to_12_bit.csv +257 -0
  112. imap_processing/lo/l0/decompression_tables/8_to_16_bit.csv +257 -0
  113. imap_processing/lo/l0/decompression_tables/decompression_tables.py +75 -0
  114. imap_processing/lo/l0/lo_apid.py +15 -0
  115. imap_processing/lo/l0/lo_science.py +150 -0
  116. imap_processing/lo/l0/utils/binary_string.py +59 -0
  117. imap_processing/lo/l0/utils/bit_decompression.py +62 -0
  118. imap_processing/lo/l0/utils/lo_base.py +57 -0
  119. imap_processing/lo/l1a/__init__.py +0 -0
  120. imap_processing/lo/l1a/lo_l1a.py +157 -0
  121. imap_processing/lo/l1b/lo_l1b.py +160 -0
  122. imap_processing/lo/l1c/lo_l1c.py +180 -0
  123. imap_processing/lo/packet_definitions/lo_xtce.xml +3541 -0
  124. imap_processing/mag/__init__.py +2 -0
  125. imap_processing/mag/constants.py +108 -0
  126. imap_processing/mag/l0/decom_mag.py +170 -0
  127. imap_processing/mag/l0/mag_l0_data.py +118 -0
  128. imap_processing/mag/l1a/mag_l1a.py +317 -0
  129. imap_processing/mag/l1a/mag_l1a_data.py +1007 -0
  130. imap_processing/mag/l1b/__init__.py +0 -0
  131. imap_processing/mag/l1b/imap_calibration_mag_20240229_v01.cdf +0 -0
  132. imap_processing/mag/l1b/mag_l1b.py +125 -0
  133. imap_processing/mag/l1c/mag_l1c.py +57 -0
  134. imap_processing/mag/packet_definitions/MAG_SCI_COMBINED.xml +235 -0
  135. imap_processing/quality_flags.py +91 -0
  136. imap_processing/spice/__init__.py +1 -0
  137. imap_processing/spice/geometry.py +322 -0
  138. imap_processing/spice/kernels.py +459 -0
  139. imap_processing/spice/time.py +72 -0
  140. imap_processing/swapi/__init__.py +1 -0
  141. imap_processing/swapi/l1/__init__.py +0 -0
  142. imap_processing/swapi/l1/swapi_l1.py +685 -0
  143. imap_processing/swapi/l2/__init__.py +0 -0
  144. imap_processing/swapi/l2/swapi_l2.py +107 -0
  145. imap_processing/swapi/packet_definitions/__init__.py +0 -0
  146. imap_processing/swapi/packet_definitions/swapi_packet_definition.xml +708 -0
  147. imap_processing/swapi/swapi_utils.py +25 -0
  148. imap_processing/swe/__init__.py +1 -0
  149. imap_processing/swe/l1a/__init__.py +0 -0
  150. imap_processing/swe/l1a/swe_l1a.py +48 -0
  151. imap_processing/swe/l1a/swe_science.py +223 -0
  152. imap_processing/swe/l1b/engineering_unit_convert_table.csv +65 -0
  153. imap_processing/swe/l1b/swe_esa_lookup_table.csv +1441 -0
  154. imap_processing/swe/l1b/swe_l1b.py +49 -0
  155. imap_processing/swe/l1b/swe_l1b_science.py +557 -0
  156. imap_processing/swe/packet_definitions/__init__.py +0 -0
  157. imap_processing/swe/packet_definitions/swe_packet_definition.xml +303 -0
  158. imap_processing/swe/utils/__init__.py +0 -0
  159. imap_processing/swe/utils/swe_utils.py +9 -0
  160. imap_processing/tests/__init__.py +0 -0
  161. imap_processing/tests/ccsds/test_data/expected_output.xml +171 -0
  162. imap_processing/tests/ccsds/test_excel_to_xtce.py +285 -0
  163. imap_processing/tests/cdf/__init__.py +0 -0
  164. imap_processing/tests/cdf/imap_default_global_cdf_attrs.yaml +8 -0
  165. imap_processing/tests/cdf/shared/default_global_cdf_attrs_schema.yaml +246 -0
  166. imap_processing/tests/cdf/shared/default_variable_cdf_attrs_schema.yaml +466 -0
  167. imap_processing/tests/cdf/test_cdf_attribute_manager.py +353 -0
  168. imap_processing/tests/cdf/test_data/imap_default_global_test_cdf_attrs.yaml +7 -0
  169. imap_processing/tests/cdf/test_data/imap_instrument1_global_cdf_attrs.yaml +14 -0
  170. imap_processing/tests/cdf/test_data/imap_instrument1_level1_variable_attrs.yaml +23 -0
  171. imap_processing/tests/cdf/test_data/imap_instrument2_global_cdf_attrs.yaml +23 -0
  172. imap_processing/tests/cdf/test_data/imap_instrument2_level2_variable_attrs.yaml +30 -0
  173. imap_processing/tests/cdf/test_data/imap_test_global.yaml +26 -0
  174. imap_processing/tests/cdf/test_data/imap_test_variable.yaml +41 -0
  175. imap_processing/tests/cdf/test_imap_cdf_manager.py +62 -0
  176. imap_processing/tests/cdf/test_utils.py +109 -0
  177. imap_processing/tests/codice/__init__.py +0 -0
  178. imap_processing/tests/codice/conftest.py +56 -0
  179. imap_processing/tests/codice/data/eu_unit_lookup_table.csv +101 -0
  180. imap_processing/tests/codice/data/idle_export_eu.COD_NHK_20230822_122700 2.csv +100 -0
  181. imap_processing/tests/codice/data/idle_export_raw.COD_NHK_20230822_122700.csv +100 -0
  182. imap_processing/tests/codice/data/imap_codice_l0_hi-counters-aggregated_20240429_v001.pkts +0 -0
  183. imap_processing/tests/codice/data/imap_codice_l0_hi-counters-singles_20240429_v001.pkts +0 -0
  184. imap_processing/tests/codice/data/imap_codice_l0_hi-omni_20240429_v001.pkts +0 -0
  185. imap_processing/tests/codice/data/imap_codice_l0_hi-pha_20240429_v001.pkts +0 -0
  186. imap_processing/tests/codice/data/imap_codice_l0_hi-sectored_20240429_v001.pkts +0 -0
  187. imap_processing/tests/codice/data/imap_codice_l0_hskp_20100101_v001.pkts +0 -0
  188. imap_processing/tests/codice/data/imap_codice_l0_lo-counters-aggregated_20240429_v001.pkts +0 -0
  189. imap_processing/tests/codice/data/imap_codice_l0_lo-counters-singles_20240429_v001.pkts +0 -0
  190. imap_processing/tests/codice/data/imap_codice_l0_lo-nsw-angular_20240429_v001.pkts +0 -0
  191. imap_processing/tests/codice/data/imap_codice_l0_lo-nsw-priority_20240429_v001.pkts +0 -0
  192. imap_processing/tests/codice/data/imap_codice_l0_lo-nsw-species_20240429_v001.pkts +0 -0
  193. imap_processing/tests/codice/data/imap_codice_l0_lo-pha_20240429_v001.pkts +0 -0
  194. imap_processing/tests/codice/data/imap_codice_l0_lo-sw-angular_20240429_v001.pkts +0 -0
  195. imap_processing/tests/codice/data/imap_codice_l0_lo-sw-priority_20240429_v001.pkts +0 -0
  196. imap_processing/tests/codice/data/imap_codice_l0_lo-sw-species_20240429_v001.pkts +0 -0
  197. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-aggregated_20240429_v001.cdf +0 -0
  198. imap_processing/tests/codice/data/imap_codice_l1a_hi-counters-singles_20240429_v001.cdf +0 -0
  199. imap_processing/tests/codice/data/imap_codice_l1a_hi-omni_20240429_v001.cdf +0 -0
  200. imap_processing/tests/codice/data/imap_codice_l1a_hi-sectored_20240429_v001.cdf +0 -0
  201. imap_processing/tests/codice/data/imap_codice_l1a_hskp_20100101_v001.cdf +0 -0
  202. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-aggregated_20240429_v001.cdf +0 -0
  203. imap_processing/tests/codice/data/imap_codice_l1a_lo-counters-singles_20240429_v001.cdf +0 -0
  204. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-angular_20240429_v001.cdf +0 -0
  205. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-priority_20240429_v001.cdf +0 -0
  206. imap_processing/tests/codice/data/imap_codice_l1a_lo-nsw-species_20240429_v001.cdf +0 -0
  207. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-angular_20240429_v001.cdf +0 -0
  208. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-priority_20240429_v001.cdf +0 -0
  209. imap_processing/tests/codice/data/imap_codice_l1a_lo-sw-species_20240429_v001.cdf +0 -0
  210. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-aggregated_20240429_v001.cdf +0 -0
  211. imap_processing/tests/codice/data/imap_codice_l1b_hi-counters-singles_20240429_v001.cdf +0 -0
  212. imap_processing/tests/codice/data/imap_codice_l1b_hi-omni_20240429_v001.cdf +0 -0
  213. imap_processing/tests/codice/data/imap_codice_l1b_hi-sectored_20240429_v001.cdf +0 -0
  214. imap_processing/tests/codice/data/imap_codice_l1b_hskp_20100101_v001.cdf +0 -0
  215. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-aggregated_20240429_v001.cdf +0 -0
  216. imap_processing/tests/codice/data/imap_codice_l1b_lo-counters-singles_20240429_v001.cdf +0 -0
  217. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-angular_20240429_v001.cdf +0 -0
  218. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-priority_20240429_v001.cdf +0 -0
  219. imap_processing/tests/codice/data/imap_codice_l1b_lo-nsw-species_20240429_v001.cdf +0 -0
  220. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-angular_20240429_v001.cdf +0 -0
  221. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-priority_20240429_v001.cdf +0 -0
  222. imap_processing/tests/codice/data/imap_codice_l1b_lo-sw-species_20240429_v001.cdf +0 -0
  223. imap_processing/tests/codice/test_codice_l0.py +144 -0
  224. imap_processing/tests/codice/test_codice_l1a.py +187 -0
  225. imap_processing/tests/codice/test_codice_l1b.py +60 -0
  226. imap_processing/tests/codice/test_decompress.py +50 -0
  227. imap_processing/tests/conftest.py +372 -0
  228. imap_processing/tests/glows/direct_events_validation_data_l1a.csv +5704 -0
  229. imap_processing/tests/glows/glows_test_packet_20110921_v01.pkts +0 -0
  230. imap_processing/tests/glows/test_glows_decom.py +133 -0
  231. imap_processing/tests/glows/test_glows_l1a_cdf.py +85 -0
  232. imap_processing/tests/glows/test_glows_l1a_data.py +510 -0
  233. imap_processing/tests/glows/test_glows_l1b.py +348 -0
  234. imap_processing/tests/glows/test_glows_l1b_data.py +70 -0
  235. imap_processing/tests/hi/__init__.py +0 -0
  236. imap_processing/tests/hi/conftest.py +133 -0
  237. imap_processing/tests/hi/test_data/l0/20231030_H45_APP_NHK.bin +0 -0
  238. imap_processing/tests/hi/test_data/l0/20231030_H45_APP_NHK.csv +201 -0
  239. imap_processing/tests/hi/test_data/l0/20231030_H45_SCI_CNT.bin +0 -0
  240. imap_processing/tests/hi/test_data/l0/20231030_H45_SCI_DE.bin +0 -0
  241. imap_processing/tests/hi/test_data/l0/README.txt +54 -0
  242. imap_processing/tests/hi/test_decom.py +55 -0
  243. imap_processing/tests/hi/test_hi_l1b.py +31 -0
  244. imap_processing/tests/hi/test_hi_l1c.py +69 -0
  245. imap_processing/tests/hi/test_l1a.py +96 -0
  246. imap_processing/tests/hi/test_l1a_sci_de.py +72 -0
  247. imap_processing/tests/hi/test_utils.py +15 -0
  248. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1251.pkts +0 -0
  249. imap_processing/tests/hit/PREFLIGHT_raw_record_2023_256_15_59_04_apid1252.pkts +0 -0
  250. imap_processing/tests/hit/__init__.py +0 -0
  251. imap_processing/tests/hit/test_data/imap_hit_l0_hk_20100105_v001.pkts +0 -0
  252. imap_processing/tests/hit/test_data/sci_sample.ccsds +0 -0
  253. imap_processing/tests/hit/test_hit_decom.py +230 -0
  254. imap_processing/tests/hit/test_hit_l1a.py +224 -0
  255. imap_processing/tests/hit/test_hit_l1b.py +52 -0
  256. imap_processing/tests/hit/validation_data/hskp_sample_raw.csv +88 -0
  257. imap_processing/tests/ialirt/__init__.py +0 -0
  258. imap_processing/tests/ialirt/test_data/l0/IALiRT Raw Packet Telemetry.txt +33 -0
  259. imap_processing/tests/ialirt/test_data/l0/hit_ialirt_sample.ccsds +0 -0
  260. imap_processing/tests/ialirt/test_data/l0/hit_ialirt_sample.csv +1001 -0
  261. imap_processing/tests/ialirt/unit/__init__.py +0 -0
  262. imap_processing/tests/ialirt/unit/test_decom_ialirt.py +94 -0
  263. imap_processing/tests/ialirt/unit/test_process_hit.py +226 -0
  264. imap_processing/tests/idex/__init__.py +0 -0
  265. imap_processing/tests/idex/conftest.py +22 -0
  266. imap_processing/tests/idex/imap_idex_l0_raw_20230725_v001.pkts +0 -0
  267. imap_processing/tests/idex/impact_14_tof_high_data.txt +8189 -0
  268. imap_processing/tests/idex/test_idex_l0.py +45 -0
  269. imap_processing/tests/idex/test_idex_l1a.py +91 -0
  270. imap_processing/tests/lo/__init__.py +0 -0
  271. imap_processing/tests/lo/test_binary_string.py +21 -0
  272. imap_processing/tests/lo/test_bit_decompression.py +39 -0
  273. imap_processing/tests/lo/test_cdfs/imap_lo_l0_raw_20240627_v001.pkts +0 -0
  274. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_de_20100101_v001.cdf +0 -0
  275. imap_processing/tests/lo/test_cdfs/imap_lo_l1a_spin_20100101_v001.cdf +0 -0
  276. imap_processing/tests/lo/test_cdfs/imap_lo_l1b_de_20100101_v001.cdf +0 -0
  277. imap_processing/tests/lo/test_lo_l1a.py +66 -0
  278. imap_processing/tests/lo/test_lo_l1b.py +74 -0
  279. imap_processing/tests/lo/test_lo_l1c.py +66 -0
  280. imap_processing/tests/lo/test_science_counts.py +41 -0
  281. imap_processing/tests/lo/test_science_direct_events.py +209 -0
  282. imap_processing/tests/lo/test_star_sensor.py +35 -0
  283. imap_processing/tests/mag/imap_mag_l1a_burst-magi_20231025_v001.cdf +0 -0
  284. imap_processing/tests/mag/mag_l0_test_data.pkts +0 -0
  285. imap_processing/tests/mag/mag_l0_test_output.csv +37 -0
  286. imap_processing/tests/mag/mag_l1_test_data.pkts +0 -0
  287. imap_processing/tests/mag/mag_l1a_test_output.csv +97 -0
  288. imap_processing/tests/mag/test_mag_decom.py +117 -0
  289. imap_processing/tests/mag/test_mag_l1a.py +856 -0
  290. imap_processing/tests/mag/test_mag_l1b.py +77 -0
  291. imap_processing/tests/mag/test_mag_l1c.py +40 -0
  292. imap_processing/tests/spice/__init__.py +0 -0
  293. imap_processing/tests/spice/test_data/imap_ena_sim_metakernel.template +4 -0
  294. imap_processing/tests/spice/test_data/imap_science_0001.tf +171 -0
  295. imap_processing/tests/spice/test_data/imap_sclk_0000.tsc +156 -0
  296. imap_processing/tests/spice/test_data/imap_sim_ck_2hr_2secsampling_with_nutation.bc +0 -0
  297. imap_processing/tests/spice/test_data/imap_simple_metakernel.template +3 -0
  298. imap_processing/tests/spice/test_data/imap_spk_demo.bsp +0 -0
  299. imap_processing/tests/spice/test_data/imap_wkcp.tf +1806 -0
  300. imap_processing/tests/spice/test_data/naif0012.tls +150 -0
  301. imap_processing/tests/spice/test_data/sim_1yr_imap_attitude.bc +0 -0
  302. imap_processing/tests/spice/test_data/sim_1yr_imap_pointing_frame.bc +0 -0
  303. imap_processing/tests/spice/test_geometry.py +214 -0
  304. imap_processing/tests/spice/test_kernels.py +272 -0
  305. imap_processing/tests/spice/test_time.py +35 -0
  306. imap_processing/tests/swapi/__init__.py +0 -0
  307. imap_processing/tests/swapi/conftest.py +16 -0
  308. imap_processing/tests/swapi/l0_data/__init__.py +0 -0
  309. imap_processing/tests/swapi/l0_data/imap_swapi_l0_raw_20231012_v001.pkts +0 -0
  310. imap_processing/tests/swapi/l0_validation_data/__init__.py +0 -0
  311. imap_processing/tests/swapi/l0_validation_data/idle_export_eu.SWP_AUT_20231012_125245.csv +124 -0
  312. imap_processing/tests/swapi/l0_validation_data/idle_export_eu.SWP_HK_20231012_125245.csv +98 -0
  313. imap_processing/tests/swapi/l0_validation_data/idle_export_eu.SWP_MG_20231012_125245.csv +9 -0
  314. imap_processing/tests/swapi/l0_validation_data/idle_export_eu.SWP_SCI_20231012_125245.csv +72 -0
  315. imap_processing/tests/swapi/l0_validation_data/idle_export_raw.SWP_AUT_20231012_125245.csv +124 -0
  316. imap_processing/tests/swapi/l0_validation_data/idle_export_raw.SWP_HK_20231012_125245.csv +98 -0
  317. imap_processing/tests/swapi/l0_validation_data/idle_export_raw.SWP_MG_20231012_125245.csv +9 -0
  318. imap_processing/tests/swapi/l0_validation_data/idle_export_raw.SWP_SCI_20231012_125245.csv +72 -0
  319. imap_processing/tests/swapi/test_swapi_decom.py +135 -0
  320. imap_processing/tests/swapi/test_swapi_l1.py +354 -0
  321. imap_processing/tests/swapi/test_swapi_l2.py +21 -0
  322. imap_processing/tests/swe/__init__.py +0 -0
  323. imap_processing/tests/swe/conftest.py +35 -0
  324. imap_processing/tests/swe/decompressed/20230927173238_4th_quarter_decompressed.csv +181 -0
  325. imap_processing/tests/swe/decompressed/20230927173253_1st_quarter_decompressed.csv +181 -0
  326. imap_processing/tests/swe/decompressed/20230927173308_2nd_quarter_decompressed.csv +181 -0
  327. imap_processing/tests/swe/decompressed/20230927173323_3rd_quarter_decompressed.csv +181 -0
  328. imap_processing/tests/swe/l0_data/2024051010_SWE_SCIENCE_packet.bin +0 -0
  329. imap_processing/tests/swe/l0_validation_data/idle_export_eu.SWE_SCIENCE_20240510_092742.csv +544 -0
  330. imap_processing/tests/swe/l0_validation_data/idle_export_raw.SWE_SCIENCE_20240510_092742.csv +363 -0
  331. imap_processing/tests/swe/test_swe_l1a.py +12 -0
  332. imap_processing/tests/swe/test_swe_l1a_science.py +129 -0
  333. imap_processing/tests/swe/test_swe_l1b.py +61 -0
  334. imap_processing/tests/swe/test_swe_l1b_science.py +65 -0
  335. imap_processing/tests/test_cli.py +229 -0
  336. imap_processing/tests/test_decom.py +66 -0
  337. imap_processing/tests/test_quality_flags.py +71 -0
  338. imap_processing/tests/test_utils.py +107 -0
  339. imap_processing/tests/ultra/__init__.py +0 -0
  340. imap_processing/tests/ultra/test_data/l0/FM45_40P_Phi28p5_BeamCal_LinearScan_phi28.50_theta-0.00_20240207T102740.CCSDS +0 -0
  341. imap_processing/tests/ultra/test_data/l0/FM45_7P_Phi0.0_BeamCal_LinearScan_phi0.04_theta-0.01_20230821T121304.CCSDS +0 -0
  342. imap_processing/tests/ultra/test_data/l0/FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.CCSDS +0 -0
  343. imap_processing/tests/ultra/test_data/l0/Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.CCSDS +0 -0
  344. imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_auxdata_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +24 -0
  345. imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_enaphxtofhangimg_FM45_TV_Cycle6_Hot_Ops_Front212_20240124T063837.csv +105 -0
  346. imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_ultraimgrates_Ultra45_EM_SwRI_Cal_Run7_ThetaScan_20220530T225054.csv +24 -0
  347. imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_ultrarawimg_withFSWcalcs_FM45_40P_Phi28p5_BeamCal_LinearScan_phi2850_theta-000_20240207T102740.csv +3314 -0
  348. imap_processing/tests/ultra/test_data/l0/ultra45_raw_sc_ultrarawimgevent_FM45_7P_Phi00_BeamCal_LinearScan_phi004_theta-001_20230821T121304.csv +702 -0
  349. imap_processing/tests/ultra/unit/__init__.py +0 -0
  350. imap_processing/tests/ultra/unit/conftest.py +210 -0
  351. imap_processing/tests/ultra/unit/test_decom_apid_880.py +98 -0
  352. imap_processing/tests/ultra/unit/test_decom_apid_881.py +50 -0
  353. imap_processing/tests/ultra/unit/test_decom_apid_883.py +44 -0
  354. imap_processing/tests/ultra/unit/test_decom_apid_896.py +104 -0
  355. imap_processing/tests/ultra/unit/test_lookup_utils.py +68 -0
  356. imap_processing/tests/ultra/unit/test_ultra_l1a.py +338 -0
  357. imap_processing/tests/ultra/unit/test_ultra_l1b.py +122 -0
  358. imap_processing/tests/ultra/unit/test_ultra_l1b_annotated.py +57 -0
  359. imap_processing/tests/ultra/unit/test_ultra_l1b_extended.py +342 -0
  360. imap_processing/tests/ultra/unit/test_ultra_l1c.py +104 -0
  361. imap_processing/tests/ultra/unit/test_ultra_l1c_pset_bins.py +35 -0
  362. imap_processing/ultra/__init__.py +1 -0
  363. imap_processing/ultra/constants.py +60 -0
  364. imap_processing/ultra/l0/__init__.py +0 -0
  365. imap_processing/ultra/l0/decom_tools.py +281 -0
  366. imap_processing/ultra/l0/decom_ultra.py +278 -0
  367. imap_processing/ultra/l0/ultra_utils.py +326 -0
  368. imap_processing/ultra/l1a/__init__.py +0 -0
  369. imap_processing/ultra/l1a/ultra_l1a.py +319 -0
  370. imap_processing/ultra/l1b/badtimes.py +26 -0
  371. imap_processing/ultra/l1b/cullingmask.py +26 -0
  372. imap_processing/ultra/l1b/de.py +59 -0
  373. imap_processing/ultra/l1b/extendedspin.py +45 -0
  374. imap_processing/ultra/l1b/lookup_utils.py +165 -0
  375. imap_processing/ultra/l1b/ultra_l1b.py +65 -0
  376. imap_processing/ultra/l1b/ultra_l1b_annotated.py +54 -0
  377. imap_processing/ultra/l1b/ultra_l1b_extended.py +764 -0
  378. imap_processing/ultra/l1c/histogram.py +36 -0
  379. imap_processing/ultra/l1c/pset.py +36 -0
  380. imap_processing/ultra/l1c/ultra_l1c.py +52 -0
  381. imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +54 -0
  382. imap_processing/ultra/lookup_tables/EgyNorm.mem.csv +32769 -0
  383. imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +2 -0
  384. imap_processing/ultra/lookup_tables/ultra45_back-pos-luts.csv +4097 -0
  385. imap_processing/ultra/lookup_tables/ultra45_tdc_norm.csv +2050 -0
  386. imap_processing/ultra/lookup_tables/ultra90_back-pos-luts.csv +4097 -0
  387. imap_processing/ultra/lookup_tables/ultra90_tdc_norm.csv +2050 -0
  388. imap_processing/ultra/lookup_tables/yadjust.csv +257 -0
  389. imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +547 -0
  390. imap_processing/ultra/packet_definitions/__init__.py +0 -0
  391. imap_processing/ultra/utils/__init__.py +0 -0
  392. imap_processing/ultra/utils/ultra_l1_utils.py +50 -0
  393. imap_processing/utils.py +413 -0
  394. imap_processing-0.6.0.dist-info/LICENSE +21 -0
  395. imap_processing-0.6.0.dist-info/METADATA +107 -0
  396. imap_processing-0.6.0.dist-info/RECORD +398 -0
  397. imap_processing-0.6.0.dist-info/WHEEL +4 -0
  398. imap_processing-0.6.0.dist-info/entry_points.txt +4 -0
@@ -0,0 +1,555 @@
1
+ """Data classes to support GLOWS L1A processing."""
2
+
3
+ import struct
4
+ from dataclasses import InitVar, dataclass, field
5
+
6
+ from imap_processing.glows import __version__
7
+ from imap_processing.glows.l0.glows_l0_data import DirectEventL0, HistogramL0
8
+ from imap_processing.glows.utils.constants import DirectEvent, TimeTuple
9
+
10
+
11
+ @dataclass
12
+ class StatusData:
13
+ """
14
+ Data structure for GLOWS status data, also known as "data_every_second".
15
+
16
+ This is used to generate the housekeeping info for each direct event from the
17
+ compressed structure in the first 40 bytes of each direct event data field.
18
+
19
+ Each DirectEventL1A instance covers one second of direct events data. Each second
20
+ has metadata associated with it, which is described in this class. The first 40
21
+ bytes of each direct event grouping is used to create this class. A second of
22
+ direct events data may span multiple packets, but each second only has one set of
23
+ StatusData attributes.
24
+
25
+ Attributes must match byte_attribute_mapping in generate_status_data.
26
+
27
+ Parameters
28
+ ----------
29
+ general_data_subset : bytearray
30
+ 40 bytes containing the information for general data (data_every_second).
31
+
32
+ Attributes
33
+ ----------
34
+ imap_sclk_last_pps: int
35
+ IMAP seconds for last PPS
36
+ glows_sclk_last_pps: int
37
+ GLOWS seconds for last PPS
38
+ glows_ssclk_last_pps: int
39
+ GLOWS subseconds for last PPS
40
+ imap_sclk_next_pps: int
41
+ IMAP seconds for next PPS
42
+ catbed_heater_active: int
43
+ Flag - heater active
44
+ spin_period_valid: int
45
+ Flag - spin phase valid
46
+ spin_phase_at_next_pps_valid: int
47
+ Flag - spin phase at next PPS valid
48
+ spin_period_source: int
49
+ Flag - Spin period source
50
+ spin_period: int
51
+ Uint encoded spin period value
52
+ spin_phase_at_next_pps: int
53
+ Uint encoded next spin phase value
54
+ number_of_completed_spins: int
55
+ Number of spins, from onboard
56
+ filter_temperature: int
57
+ Uint encoded temperature
58
+ hv_voltage: int
59
+ Uint encoded voltage
60
+ glows_time_on_pps_valid: int
61
+ Flag - is glows time valid
62
+ time_status_valid: int
63
+ Flag - valid time status
64
+ housekeeping_valid: int
65
+ Flag - valid housekeeping
66
+ is_pps_autogenerated: int
67
+ Flag
68
+ hv_test_in_progress: int
69
+ Flag
70
+ pulse_test_in_progress: int
71
+ Flag
72
+ memory_error_detected: int
73
+ Flag
74
+ """
75
+
76
+ imap_sclk_last_pps: int
77
+ glows_sclk_last_pps: int
78
+ glows_ssclk_last_pps: int
79
+ imap_sclk_next_pps: int
80
+ catbed_heater_active: int
81
+ spin_period_valid: int
82
+ spin_phase_at_next_pps_valid: int
83
+ spin_period_source: int
84
+ spin_period: int
85
+ spin_phase_at_next_pps: int
86
+ number_of_completed_spins: int
87
+ filter_temperature: int
88
+ hv_voltage: int
89
+ glows_time_on_pps_valid: int
90
+ time_status_valid: int
91
+ housekeeping_valid: int
92
+ is_pps_autogenerated: int
93
+ hv_test_in_progress: int
94
+ pulse_test_in_progress: int
95
+ memory_error_detected: int
96
+
97
+ def __init__(self, general_data_subset: bytearray):
98
+ """
99
+ Generate the flag and encoded information from 40 bytes of direct event data.
100
+
101
+ The 40 bytes also includes one extra byte of padding at the end.
102
+ """
103
+ byte_attribute_mapping = {
104
+ "imap_sclk_last_pps": 4,
105
+ "glows_sclk_last_pps": 4,
106
+ "glows_ssclk_last_pps": 4,
107
+ "imap_sclk_next_pps": 4,
108
+ "catbed_heater_active": 1,
109
+ "spin_period_valid": 1,
110
+ "spin_phase_at_next_pps_valid": 1,
111
+ "spin_period_source": 1,
112
+ "spin_period": 2,
113
+ "spin_phase_at_next_pps": 2,
114
+ "number_of_completed_spins": 4,
115
+ "filter_temperature": 2,
116
+ "hv_voltage": 2,
117
+ "glows_time_on_pps_valid": 1,
118
+ "time_status_valid": 1,
119
+ "housekeeping_valid": 1,
120
+ "is_pps_autogenerated": 1,
121
+ "hv_test_in_progress": 1,
122
+ "pulse_test_in_progress": 1,
123
+ "memory_error_detected": 1,
124
+ }
125
+
126
+ prev_byte = 0
127
+
128
+ for item in byte_attribute_mapping.items():
129
+ self.__setattr__(
130
+ item[0],
131
+ int.from_bytes(
132
+ general_data_subset[prev_byte : prev_byte + item[1]], "big"
133
+ ),
134
+ )
135
+ prev_byte = prev_byte + item[1]
136
+
137
+
138
+ @dataclass
139
+ class HistogramL1A:
140
+ """
141
+ Data structure for GLOWS Histogram Level 1A data.
142
+
143
+ Attributes
144
+ ----------
145
+ l0: InitVar[HistogramL0]
146
+ HistogramL0 Data class containing the raw data from the histogram packet. This
147
+ is only used to create the class and cannot be accessed from an instance.
148
+ histograms: list[int]
149
+ List of histogram data values
150
+ flight_software_version: int
151
+ Version of the flight software used to generate the data. Part of block header.
152
+ ground_software_version: str
153
+ Version of the ground software used to process the data. Part of block header.
154
+ pkts_file_name: str
155
+ Name of the packet file used to generate the data. Part of block header.
156
+ seq_count_in_pkts_file: int
157
+ Sequence count in the packet file, equal to SRC_SEQ_CTR Part of block header.
158
+ last_spin_id: int
159
+ ID of the last spin in block (computed with start spin and offset)
160
+ imap_start_time: tuple[int, int]
161
+ IMAP start time for the block, in the form (seconds, subseconds)
162
+ imap_time_offset: tuple[int, int]
163
+ IMAP end time offset for the block, in the form (seconds, subseconds). In
164
+ algorithm document as "imap_end_time_offset"
165
+ glows_start_time: tuple[int, int]
166
+ GLOWS start time for the block, in the form (seconds, subseconds)
167
+ glows_time_offset: tuple[int, int]
168
+ GLOWS end time offset for the block, in the form (seconds, subseconds). In
169
+ algorithm document as "glows_end_time_offset"
170
+ number_of_spins_per_block: int
171
+ Number of spins in the block, from L0.SPINS
172
+ number_of_bins_per_histogram: int
173
+ Number of bins in the histogram, from L0.NBINS
174
+ number_of_events: int
175
+ Number of events in the block, from L0.EVENTS
176
+ filter_temperature_average: int
177
+ Average filter temperature in the block, from L0.TEMPAVG. Uint encoded.
178
+ filter_temperature_variance: int
179
+ Variance of filter temperature in the block, from L0.TEMPVAR. Uint encoded.
180
+ hv_voltage_average: int
181
+ Average HV voltage in the block, from L0.HVAVG. Uint encoded.
182
+ hv_voltage_variance: int
183
+ Variance of HV voltage in the block, from L0.HVVAR. Uint encoded.
184
+ spin_period_average: int
185
+ Average spin period in the block, from L0.SPAVG. Uint encoded.
186
+ spin_period_variance: int
187
+ Variance of spin period in the block, from L0.SPVAR. Uint encoded.
188
+ pulse_length_average: int
189
+ Average pulse length in the block, from L0.ELAVG. Uint encoded.
190
+ pulse_length_variance: int
191
+ Variance of pulse length in the block, from L0.ELVAR. Uint encoded.
192
+ flags: dict
193
+ Dictionary containing "flags_set_onboard" from L0, and "is_generated_on_ground",
194
+ which is set to "False" for decommed packets.
195
+ """
196
+
197
+ l0: InitVar[HistogramL0]
198
+ histograms: list[int] = field(init=False)
199
+ # next four are in block header
200
+ flight_software_version: int = field(init=False)
201
+ ground_software_version: str = field(init=False)
202
+ pkts_file_name: str = field(init=False)
203
+ seq_count_in_pkts_file: int = field(init=False)
204
+ last_spin_id: int = field(init=False)
205
+ imap_start_time: TimeTuple = field(init=False)
206
+ imap_time_offset: TimeTuple = field(init=False)
207
+ glows_start_time: TimeTuple = field(init=False)
208
+ glows_time_offset: TimeTuple = field(init=False)
209
+ # Following variables are copied from L0
210
+ number_of_spins_per_block: int = field(init=False)
211
+ number_of_bins_per_histogram: int = field(init=False)
212
+ number_of_events: int = field(init=False)
213
+ filter_temperature_average: int = field(init=False)
214
+ filter_temperature_variance: int = field(init=False)
215
+ hv_voltage_average: int = field(init=False)
216
+ hv_voltage_variance: int = field(init=False)
217
+ spin_period_average: int = field(init=False)
218
+ spin_period_variance: int = field(init=False)
219
+ pulse_length_average: int = field(init=False)
220
+ pulse_length_variance: int = field(init=False)
221
+ flags: dict = field(init=False)
222
+
223
+ def __post_init__(self, l0: HistogramL0) -> None:
224
+ """
225
+ Set the attributes based on the given L0 histogram data.
226
+
227
+ This includes generating a block header and converting the time attributes from
228
+ HistogramL0 into TimeTuple pairs.
229
+
230
+ Parameters
231
+ ----------
232
+ l0 : HistogramL0
233
+ Lo histogram data.
234
+ """
235
+ self.histograms = list(l0.HISTOGRAM_DATA)
236
+
237
+ self.flight_software_version = l0.SWVER
238
+ self.ground_software_version = __version__
239
+ self.pkts_file_name = l0.packet_file_name
240
+ # note: packet number is seq_count (per apid!) field in CCSDS header
241
+ self.seq_count_in_pkts_file = l0.ccsds_header.SRC_SEQ_CTR
242
+
243
+ # use start ID and offset to calculate the last spin ID in the block
244
+ self.last_spin_id = l0.STARTID + l0.ENDID
245
+ # TODO add first spin ID
246
+
247
+ # TODO: This sanity check should probably exist in the final code. However,
248
+ # the emulator code does not properly set these values.
249
+ # if self.l0.ENDID != self.l0.SPINS:
250
+ # raise ValueError(f"Inconsistency between L0 spin-numbering field ENDID "
251
+ # f"[{self.l0.ENDID}] and histogram parameter field SPINS "
252
+ # f"[{self.l0.SPINS}]")
253
+
254
+ # Create time tuples based on second and subsecond pairs
255
+ self.imap_start_time = TimeTuple(l0.SEC, l0.SUBSEC)
256
+ self.imap_time_offset = TimeTuple(l0.OFFSETSEC, l0.OFFSETSUBSEC)
257
+ self.glows_start_time = TimeTuple(l0.GLXSEC, l0.GLXSUBSEC)
258
+ self.glows_time_offset = TimeTuple(l0.GLXOFFSEC, l0.GLXOFFSUBSEC)
259
+
260
+ # In L1a, these are left as unit encoded values.
261
+ self.number_of_spins_per_block = l0.SPINS
262
+ self.number_of_bins_per_histogram = l0.NBINS
263
+ self.number_of_events = l0.EVENTS
264
+ self.filter_temperature_average = l0.TEMPAVG
265
+ self.filter_temperature_variance = l0.TEMPVAR
266
+ self.hv_voltage_average = l0.HVAVG
267
+ self.hv_voltage_variance = l0.HVVAR
268
+ self.spin_period_average = l0.SPAVG
269
+ self.spin_period_variance = l0.SPVAR
270
+ self.pulse_length_average = l0.ELAVG
271
+ self.pulse_length_variance = l0.ELVAR
272
+
273
+ # Flags
274
+ self.flags = {
275
+ "flags_set_onboard": l0.FLAGS,
276
+ "is_generated_on_ground": False,
277
+ }
278
+
279
+
280
+ @dataclass
281
+ class DirectEventL1A:
282
+ """
283
+ Data structure for GLOWS Histogram Level 1A data.
284
+
285
+ This includes steps for merging multiple Direct Event packets into one class,
286
+ so this class may span multiple packets. This is determined by the SEQ and LEN,
287
+ by each packet having an incremental SEQ until LEN number of packets.
288
+
289
+ Block header information is retrieved from l0:
290
+ {
291
+ "flight_software_version" = l0.ccsds_header.VERSION
292
+ "ground_software_version" = __version__
293
+ "pkts_file_name" = l0.packet_file_name
294
+ "seq_count_in_pkts_file" = l0.ccsds_header.SRC_SEQ_CTR
295
+ }
296
+
297
+ Parameters
298
+ ----------
299
+ level0 : DirectEventL0
300
+ Level 0 data.
301
+
302
+ Attributes
303
+ ----------
304
+ l0 : DirectEventL0
305
+ Level 0 data. In the case of multiple L0 direct events, this is the first L0
306
+ data class in the sequence. This is used to verify all events in the sequence
307
+ match.
308
+ de_data : bytearray
309
+ Bytearray of raw DirectEvent data, which is converted into direct_events
310
+ most_recent_seq : int
311
+ The most recent sequence added to the L1A dataclass - for counting gaps
312
+ missing_seq : list[int]
313
+ Any missing sequence counts in the data. Should be an empty array in normal
314
+ operation
315
+ status_data : StatusData
316
+ StatusData generated from the first 40 bytes of direct events data. This
317
+ includes information on flags and ancillary housekeeping info from the
318
+ spacecraft.
319
+ direct_events : list[DirectEvent]
320
+ List of DirectEvent objects, which is created when the final level 0 packet in
321
+ the sequence is added to de_data. Defaults to None.
322
+
323
+ Methods
324
+ -------
325
+ append
326
+ Add another Level0 instance.
327
+ """
328
+
329
+ l0: DirectEventL0
330
+ de_data: bytearray = field(repr=False) # Do not include in prints
331
+ most_recent_seq: int
332
+ missing_seq: list[int]
333
+ status_data: StatusData = field(init=False)
334
+ direct_events: list[DirectEvent] = field(init=False, default=None) # type: ignore[arg-type]
335
+
336
+ def __init__(self, level0: DirectEventL0):
337
+ self.l0 = level0
338
+ self.most_recent_seq = self.l0.SEQ
339
+ self.de_data = bytearray(level0.DE_DATA)
340
+ self.missing_seq = []
341
+
342
+ if level0.LEN == 1:
343
+ self._process_de_data()
344
+
345
+ def append(self, second_l0: DirectEventL0) -> None:
346
+ """
347
+ Merge an additional direct event packet to this DirectEventL1A class.
348
+
349
+ Direct event data can span multiple packets, as marked by the SEQ and LEN
350
+ attributes. This method will add the next piece of data in the sequence
351
+ to this data class. The two packets are compared with
352
+ DirectEventL0.sequence_match_check. If they don't match, the method throws
353
+ a ValueError.
354
+
355
+ If the sequence is broken, the missing sequence numbers are added to
356
+ missing_seq. Once the last value in the sequence is reached, the data is
357
+ processed from raw bytes to useful information.
358
+
359
+ Parameters
360
+ ----------
361
+ second_l0 : DirectEventL0
362
+ Additional L0 packet to add to the DirectEventL1A class.
363
+ """
364
+ # if SEQ is missing or if the sequence is out of order, do not continue.
365
+ if not second_l0.SEQ or second_l0.SEQ < self.most_recent_seq:
366
+ raise ValueError(
367
+ f"Sequence for direct event L1A is out of order or "
368
+ f"incorrect. Attempted to append sequence counter "
369
+ f"{second_l0.SEQ} after {self.most_recent_seq}."
370
+ )
371
+
372
+ # Track any missing sequence counts
373
+ if second_l0.SEQ != self.most_recent_seq + 1:
374
+ self.missing_seq.extend(range(self.most_recent_seq + 1, second_l0.SEQ))
375
+
376
+ # Determine if new L0 packet matches existing L0 packet
377
+ match = self.l0.within_same_sequence(second_l0)
378
+
379
+ # TODO: Should this raise an error? Log? something else?
380
+ if not match:
381
+ raise ValueError(
382
+ f"While attempting to merge L0 packet {second_l0} "
383
+ f"with {self.l0} mismatched values"
384
+ f"were found. "
385
+ )
386
+
387
+ self.de_data.extend(bytearray(second_l0.DE_DATA))
388
+
389
+ self.most_recent_seq = second_l0.SEQ
390
+ # if this is the last packet in the sequence, process the DE data
391
+ # TODO: What if the last packet never arrives?
392
+ if self.l0.LEN == self.most_recent_seq + 1:
393
+ self._process_de_data()
394
+
395
+ def _process_de_data(self) -> None:
396
+ """
397
+ Will process direct event bytes.
398
+
399
+ Once the packets are complete, create the status data table from the first 40
400
+ bytes in de_data, and the direct events from the remaining bytes.
401
+ """
402
+ self.status_data = StatusData(self.de_data[:40])
403
+ self.direct_events = self._generate_direct_events(self.de_data[40:])
404
+
405
+ def _generate_direct_events(self, direct_events: bytearray) -> list[DirectEvent]:
406
+ """
407
+ Generate the list of direct events from the raw bytearray.
408
+
409
+ First, the starting timestamp is created from the first 8 bytes in the direct
410
+ event array. Then, the remaining events are processed based on a marker in the
411
+ first two bits of each section. If the marker is 0, it is uncompressed, and
412
+ the event is processed from the following 7 bytes. If it is 1, it is compressed
413
+ to two bytes, and if it is 2, the direct event is compressed to 3 bytes.
414
+
415
+ Parameters
416
+ ----------
417
+ direct_events : bytearray
418
+ Bytearray containing direct event data.
419
+
420
+ Returns
421
+ -------
422
+ processed_events : list[DirectEvent]
423
+ An array containing DirectEvent objects.
424
+ """
425
+ # read the first direct event, which is always uncompressed
426
+ current_event = self._build_uncompressed_event(direct_events[:8])
427
+ processed_events = [current_event]
428
+
429
+ i = 8
430
+ while i < len(direct_events) - 1:
431
+ first_byte = int(direct_events[i])
432
+ i += 1
433
+ # Remove first two bits, which are used to mark compression
434
+ oldest_diff = first_byte & 0x3F
435
+ marker = first_byte >> 6
436
+
437
+ if (
438
+ marker == 0x0 and i < len(direct_events) - 7
439
+ ): # uncompressed time stamp (8-bytes)
440
+ rest_bytes = direct_events[i : i + 7]
441
+ i += 7
442
+ part = bytearray([oldest_diff])
443
+ part.extend(rest_bytes)
444
+ current_event = self._build_uncompressed_event(part)
445
+
446
+ elif (
447
+ marker == 0x2 and i < len(direct_events) - 1
448
+ ): # 2-byte compression of timedelta
449
+ current_event = self._build_compressed_event(
450
+ direct_events[i : i + 2], oldest_diff, current_event.timestamp
451
+ )
452
+ i += 2
453
+
454
+ elif (
455
+ marker == 0x3 and i < len(direct_events) - 2
456
+ ): # 3-byte compression of timedelta
457
+ current_event = self._build_compressed_event(
458
+ direct_events[i : i + 3], oldest_diff, current_event.timestamp
459
+ )
460
+ i += 3
461
+
462
+ else: # wrong-marker or hitting-the-buffer-end case
463
+ raise IndexError(
464
+ f"Error: Unexpected marker {marker} or out of bounds index {i} for "
465
+ f"direct events list of length {len(direct_events)}. Unable to "
466
+ f"process direct events."
467
+ )
468
+
469
+ processed_events.append(current_event)
470
+
471
+ return processed_events
472
+
473
+ def _build_compressed_event(
474
+ self, raw: bytearray, oldest_diff: int, previous_time: TimeTuple
475
+ ) -> "DirectEvent":
476
+ """
477
+ Build direct event from data with timestamps compressed as timedeltas.
478
+
479
+ This process requires adding onto a previous timestamp to create a new
480
+ timestamp. If raw is three bytes, the three byte method of compression is used,
481
+ if raw is two bytes, then the two byte method is used. Any other length raises
482
+ a ValueError.
483
+
484
+ Parameters
485
+ ----------
486
+ raw : bytearray
487
+ Raw 2 or 3 byte compressed data to process.
488
+ oldest_diff : int
489
+ Last 6 bits of the byte immediately before raw.
490
+ previous_time : TimeTuple
491
+ The previous timestamp to build off of.
492
+
493
+ Returns
494
+ -------
495
+ DirectEvent
496
+ Built by the input data.
497
+ """
498
+ if len(raw) == 2:
499
+ rest = raw[0]
500
+
501
+ diff = oldest_diff << 8 | rest
502
+ length = raw[1]
503
+
504
+ elif len(raw) == 3:
505
+ rest = int.from_bytes(raw[0:2], "big")
506
+ diff = oldest_diff << 16 | rest
507
+ length = int(raw[2])
508
+
509
+ else:
510
+ raise ValueError(
511
+ f"Incorrect length {len(raw)} for {raw}, expecting 2 or 3"
512
+ f"bit compressed direct event data"
513
+ )
514
+
515
+ subseconds = previous_time.subseconds + diff
516
+ seconds = previous_time.seconds
517
+
518
+ return DirectEvent(TimeTuple(seconds, subseconds), length, False)
519
+
520
+ def _build_uncompressed_event(self, raw: bytearray) -> DirectEvent:
521
+ """
522
+ Build direct event from raw binary 8-byte array.
523
+
524
+ This method assumes that the raw binary contains uncompressed timestamps.
525
+
526
+ Parameters
527
+ ----------
528
+ raw : bytearray
529
+ 8 bytes of data to build the event with.
530
+
531
+ Returns
532
+ -------
533
+ DirectEvent
534
+ Object built from raw.
535
+ """
536
+ if len(raw) != 8:
537
+ raise ValueError(
538
+ f"Incorrect length {len(raw)} for {raw}, expecting 8 bytes of "
539
+ f"uncompressed direct event data"
540
+ )
541
+
542
+ values = struct.unpack(">II", raw)
543
+
544
+ seconds = values[0]
545
+
546
+ # subsecond encoding on the least significant 21 bits
547
+ subseconds = values[1] & 0x1FFFFF
548
+
549
+ timestamp = TimeTuple(seconds, subseconds)
550
+ # first byte encodes the impulse length
551
+ impulse_length = (values[1] >> 24) & 0xFF
552
+
553
+ # KPLabs says it is set by FPGA and currently not used by AppSW at all
554
+ multi_event = bool((values[1] >> 23) & 0b1)
555
+ return DirectEvent(timestamp, impulse_length, multi_event)