spectre-core 0.0.22__py3-none-any.whl → 0.0.24__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 (78) hide show
  1. spectre_core/__init__.py +5 -0
  2. spectre_core/_file_io/__init__.py +4 -4
  3. spectre_core/_file_io/file_handlers.py +60 -106
  4. spectre_core/batches/__init__.py +20 -3
  5. spectre_core/batches/_base.py +85 -134
  6. spectre_core/batches/_batches.py +55 -99
  7. spectre_core/batches/_factory.py +21 -20
  8. spectre_core/batches/_register.py +8 -8
  9. spectre_core/batches/plugins/_batch_keys.py +7 -6
  10. spectre_core/batches/plugins/_callisto.py +65 -97
  11. spectre_core/batches/plugins/_iq_stream.py +105 -169
  12. spectre_core/capture_configs/__init__.py +46 -17
  13. spectre_core/capture_configs/_capture_config.py +25 -52
  14. spectre_core/capture_configs/_capture_modes.py +8 -6
  15. spectre_core/capture_configs/_capture_templates.py +50 -110
  16. spectre_core/capture_configs/_parameters.py +37 -74
  17. spectre_core/capture_configs/_pconstraints.py +40 -40
  18. spectre_core/capture_configs/_pnames.py +36 -34
  19. spectre_core/capture_configs/_ptemplates.py +260 -347
  20. spectre_core/capture_configs/_pvalidators.py +99 -102
  21. spectre_core/config/__init__.py +19 -8
  22. spectre_core/config/_paths.py +25 -47
  23. spectre_core/config/_time_formats.py +6 -5
  24. spectre_core/exceptions.py +38 -0
  25. spectre_core/jobs/__init__.py +3 -6
  26. spectre_core/jobs/_duration.py +12 -0
  27. spectre_core/jobs/_jobs.py +72 -43
  28. spectre_core/jobs/_workers.py +55 -105
  29. spectre_core/logs/__init__.py +7 -2
  30. spectre_core/logs/_configure.py +13 -17
  31. spectre_core/logs/_decorators.py +6 -4
  32. spectre_core/logs/_logs.py +37 -89
  33. spectre_core/logs/_process_types.py +5 -3
  34. spectre_core/plotting/__init__.py +19 -3
  35. spectre_core/plotting/_base.py +112 -177
  36. spectre_core/plotting/_format.py +10 -8
  37. spectre_core/plotting/_panel_names.py +7 -5
  38. spectre_core/plotting/_panel_stack.py +138 -130
  39. spectre_core/plotting/_panels.py +152 -162
  40. spectre_core/post_processing/__init__.py +6 -3
  41. spectre_core/post_processing/_base.py +41 -55
  42. spectre_core/post_processing/_factory.py +14 -11
  43. spectre_core/post_processing/_post_processor.py +16 -12
  44. spectre_core/post_processing/_register.py +10 -7
  45. spectre_core/post_processing/plugins/_event_handler_keys.py +4 -3
  46. spectre_core/post_processing/plugins/_fixed_center_frequency.py +54 -47
  47. spectre_core/post_processing/plugins/_swept_center_frequency.py +199 -174
  48. spectre_core/receivers/__init__.py +9 -2
  49. spectre_core/receivers/_base.py +82 -148
  50. spectre_core/receivers/_factory.py +20 -30
  51. spectre_core/receivers/_register.py +7 -10
  52. spectre_core/receivers/_spec_names.py +17 -15
  53. spectre_core/receivers/plugins/_b200mini.py +47 -60
  54. spectre_core/receivers/plugins/_receiver_names.py +8 -6
  55. spectre_core/receivers/plugins/_rsp1a.py +44 -40
  56. spectre_core/receivers/plugins/_rspduo.py +59 -44
  57. spectre_core/receivers/plugins/_sdrplay_receiver.py +67 -83
  58. spectre_core/receivers/plugins/_test.py +136 -129
  59. spectre_core/receivers/plugins/_usrp.py +93 -85
  60. spectre_core/receivers/plugins/gr/__init__.py +1 -1
  61. spectre_core/receivers/plugins/gr/_base.py +14 -22
  62. spectre_core/receivers/plugins/gr/_rsp1a.py +53 -60
  63. spectre_core/receivers/plugins/gr/_rspduo.py +77 -89
  64. spectre_core/receivers/plugins/gr/_test.py +49 -57
  65. spectre_core/receivers/plugins/gr/_usrp.py +61 -59
  66. spectre_core/spectrograms/__init__.py +21 -13
  67. spectre_core/spectrograms/_analytical.py +108 -99
  68. spectre_core/spectrograms/_array_operations.py +39 -46
  69. spectre_core/spectrograms/_spectrogram.py +293 -324
  70. spectre_core/spectrograms/_transform.py +106 -73
  71. spectre_core/wgetting/__init__.py +1 -3
  72. spectre_core/wgetting/_callisto.py +87 -93
  73. {spectre_core-0.0.22.dist-info → spectre_core-0.0.24.dist-info}/METADATA +9 -23
  74. spectre_core-0.0.24.dist-info/RECORD +79 -0
  75. {spectre_core-0.0.22.dist-info → spectre_core-0.0.24.dist-info}/WHEEL +1 -1
  76. spectre_core-0.0.22.dist-info/RECORD +0 -78
  77. {spectre_core-0.0.22.dist-info → spectre_core-0.0.24.dist-info}/licenses/LICENSE +0 -0
  78. {spectre_core-0.0.22.dist-info → spectre_core-0.0.24.dist-info}/top_level.txt +0 -0
@@ -11,25 +11,22 @@ from ._register import batch_map
11
11
  from .plugins._batch_keys import BatchKey
12
12
  from .plugins._callisto import CallistoBatch
13
13
  from .plugins._iq_stream import IQStreamBatch
14
-
14
+
15
15
 
16
16
  @overload
17
17
  def get_batch_cls(
18
18
  batch_key: Literal[BatchKey.CALLISTO],
19
- ) -> Type[CallistoBatch]:
20
- ...
19
+ ) -> Type[CallistoBatch]: ...
21
20
 
22
21
 
23
22
  @overload
24
23
  def get_batch_cls(
25
24
  batch_key: Literal[BatchKey.IQ_STREAM],
26
- ) -> Type[IQStreamBatch]:
27
- ...
28
-
29
-
25
+ ) -> Type[IQStreamBatch]: ...
26
+
27
+
30
28
  @overload
31
- def get_batch_cls(batch_key: BatchKey) -> Type[BaseBatch]:
32
- ...
29
+ def get_batch_cls(batch_key: BatchKey) -> Type[BaseBatch]: ...
33
30
 
34
31
 
35
32
  def get_batch_cls(
@@ -44,14 +41,14 @@ def get_batch_cls(
44
41
  batch_cls = batch_map.get(batch_key)
45
42
  if batch_cls is None:
46
43
  valid_batch_keys = list(batch_map.keys())
47
- raise BatchNotFoundError(f"No batch found for the batch key: {batch_key}. "
48
- f"Valid batch keys are: {valid_batch_keys}")
44
+ raise BatchNotFoundError(
45
+ f"No batch found for the batch key: {batch_key}. "
46
+ f"Valid batch keys are: {valid_batch_keys}"
47
+ )
49
48
  return batch_cls
50
49
 
51
50
 
52
- def get_batch_cls_from_tag(
53
- tag: str
54
- ) -> Type[BaseBatch]:
51
+ def get_batch_cls_from_tag(tag: str) -> Type[BaseBatch]:
55
52
  # if the tag is reserved (i.e., corresponds to third-party spectrogram data)
56
53
  # directly fetch the right class.
57
54
  if "callisto" in tag:
@@ -61,9 +58,13 @@ def get_batch_cls_from_tag(
61
58
  else:
62
59
  capture_config = CaptureConfig(tag)
63
60
  if PName.BATCH_KEY not in capture_config.parameters.name_list:
64
- raise ValueError(f"Could not infer batch class from the tag 'tag'. "
65
- f"A parameter with name `{PName.BATCH_KEY.value}` "
66
- f"does not exist.")
67
-
68
- batch_key = BatchKey( cast(str, capture_config.get_parameter_value( PName.BATCH_KEY) ) )
69
- return get_batch_cls( batch_key )
61
+ raise ValueError(
62
+ f"Could not infer batch class from the tag 'tag'. "
63
+ f"A parameter with name `{PName.BATCH_KEY.value}` "
64
+ f"does not exist."
65
+ )
66
+
67
+ batch_key = BatchKey(
68
+ cast(str, capture_config.get_parameter_value(PName.BATCH_KEY))
69
+ )
70
+ return get_batch_cls(batch_key)
@@ -10,21 +10,21 @@ from .plugins._batch_keys import BatchKey
10
10
  # Map populated at runtime via the `register_batch` decorator.
11
11
  batch_map: dict[BatchKey, Type[BaseBatch]] = {}
12
12
 
13
- T = TypeVar('T', bound=BaseBatch)
14
- def register_batch(
15
- batch_key: BatchKey
16
- ) -> Callable[[Type[T]], Type[T]]:
13
+ T = TypeVar("T", bound=BaseBatch)
14
+
15
+
16
+ def register_batch(batch_key: BatchKey) -> Callable[[Type[T]], Type[T]]:
17
17
  """Decorator to register a `BaseBatch` subclass under a specified `BatchKey`.
18
18
 
19
19
  :param batch_key: The key to register the `BaseBatch` subclass under.
20
20
  :raises ValueError: If the provided `batch_key` is already registered.
21
21
  :return: A decorator that registers the `BaseBatch` subclass under the given `batch_key`.
22
22
  """
23
- def decorator(
24
- cls: Type[T]
25
- ) -> Type[T]:
23
+
24
+ def decorator(cls: Type[T]) -> Type[T]:
26
25
  if batch_key in batch_map:
27
26
  raise ValueError(f"A batch with key '{batch_key}' is already registered!")
28
27
  batch_map[batch_key] = cls
29
28
  return cls
30
- return decorator
29
+
30
+ return decorator
@@ -4,13 +4,14 @@
4
4
 
5
5
  from enum import Enum
6
6
 
7
- class BatchKey(Enum):
7
+
8
+ class BatchKey(Enum):
8
9
  """Key bound to a `Batch` plugin class.
9
-
10
- :ivar IQ_STREAM: Represents the default batch data generated by `spectre`,
10
+
11
+ :ivar IQ_STREAM: Represents the default batch data generated by `spectre`,
11
12
  containing IQ stream data and other data derived from it.
12
13
  :ivar CALLISTO: Represents FITS files generated by the e-Callisto network.
13
14
  """
14
- IQ_STREAM = "iq_stream"
15
- CALLISTO = "callisto"
16
-
15
+
16
+ IQ_STREAM = "iq_stream"
17
+ CALLISTO = "callisto"
@@ -21,107 +21,89 @@ from .._register import register_batch
21
21
  @dataclass(frozen=True)
22
22
  class _BatchExtension:
23
23
  """Supported extensions for a `CallistoBatch`.
24
-
24
+
25
25
  :ivar FITS: Corresponds to the `.fits` file extension.
26
26
  """
27
+
27
28
  FITS: str = "fits"
28
-
29
-
29
+
30
+
30
31
  class _FitsFile(BatchFile[Spectrogram]):
31
32
  """Stores spectrogram data in the FITS format generated by the e-Callisto network."""
32
- def __init__(
33
- self,
34
- parent_dir_path: str,
35
- base_file_name: str
36
- ) -> None:
33
+
34
+ def __init__(self, parent_dir_path: str, base_file_name: str) -> None:
37
35
  """Initialise a `_FitsFile` instance.
38
36
 
39
37
  :param parent_dir_path: The parent directory for the batch.
40
38
  :param base_file_name: The batch name.
41
39
  """
42
- super().__init__(parent_dir_path,
43
- base_file_name,
44
- _BatchExtension.FITS)
45
-
46
-
47
- def _read(
48
- self
49
- ) -> Spectrogram:
40
+ super().__init__(parent_dir_path, base_file_name, _BatchExtension.FITS)
41
+
42
+ def _read(self) -> Spectrogram:
50
43
  """Parses a FITS file to generate a `Spectrogram` instance.
51
44
 
52
- Reverses the spectra along the frequency axis and converts units to linearised
45
+ Reverses the spectra along the frequency axis and converts units to linearised
53
46
  values if necessary. Infers the spectrum type from the `BUNIT` header.
54
47
 
55
48
  :raises NotImplementedError: If the `BUNIT` header value represents an unsupported spectrum type.
56
49
  :return: A `Spectrogram` instance containing the parsed FITS file data.
57
50
  """
58
- with fits.open(self.file_path, mode='readonly') as hdulist:
59
- primary_hdu = self._get_primary_hdu(hdulist)
60
- dynamic_spectra = self._get_dynamic_spectra(primary_hdu)
61
- spectrogram_start_datetime = self._get_spectrogram_start_datetime(primary_hdu)
62
- bintable_hdu = self._get_bintable_hdu(hdulist)
63
- times = self._get_times(bintable_hdu)
64
- frequencies = self._get_frequencies(bintable_hdu)
65
- bunit = self._get_bunit(primary_hdu)
51
+ with fits.open(self.file_path, mode="readonly") as hdulist:
52
+ primary_hdu = self._get_primary_hdu(hdulist)
53
+ dynamic_spectra = self._get_dynamic_spectra(primary_hdu)
54
+ spectrogram_start_datetime = self._get_spectrogram_start_datetime(
55
+ primary_hdu
56
+ )
57
+ bintable_hdu = self._get_bintable_hdu(hdulist)
58
+ times = self._get_times(bintable_hdu)
59
+ frequencies = self._get_frequencies(bintable_hdu)
60
+ bunit = self._get_bunit(primary_hdu)
66
61
 
67
62
  # bunit is interpreted as a SpectrumUnit
68
63
  spectrum_unit = SpectrumUnit(bunit)
69
64
  if spectrum_unit == SpectrumUnit.DIGITS:
70
- dynamic_spectra_linearised = self._convert_units_to_linearised(dynamic_spectra)
71
-
72
- return Spectrogram(dynamic_spectra_linearised[::-1, :], # reverse the spectra along the frequency axis
73
- times,
74
- frequencies[::-1], # sort the frequencies in ascending order
75
- self.tag,
76
- spectrum_unit,
77
- spectrogram_start_datetime)
65
+ dynamic_spectra_linearised = self._convert_units_to_linearised(
66
+ dynamic_spectra
67
+ )
68
+
69
+ return Spectrogram(
70
+ dynamic_spectra_linearised[
71
+ ::-1, :
72
+ ], # reverse the spectra along the frequency axis
73
+ times,
74
+ frequencies[::-1], # sort the frequencies in ascending order
75
+ self.tag,
76
+ spectrum_unit,
77
+ spectrogram_start_datetime,
78
+ )
78
79
  else:
79
- raise NotImplementedError(f"SPECTRE does not currently support spectrum type with BUNITS '{spectrum_unit}'")
80
+ raise NotImplementedError(
81
+ f"SPECTRE does not currently support spectrum type with BUNITS '{spectrum_unit}'"
82
+ )
80
83
 
84
+ def _get_primary_hdu(self, hdulist: HDUList) -> PrimaryHDU:
85
+ return hdulist["PRIMARY"]
81
86
 
82
- def _get_primary_hdu(
83
- self, hdulist: HDUList
84
- ) -> PrimaryHDU:
85
- return hdulist['PRIMARY']
86
-
87
-
88
- def _get_bintable_hdu(
89
- self,
90
- hdulist: HDUList
91
- ) -> BinTableHDU:
87
+ def _get_bintable_hdu(self, hdulist: HDUList) -> BinTableHDU:
92
88
  return hdulist[1]
93
-
94
-
95
- def _get_dynamic_spectra(
96
- self,
97
- primary_hdu: PrimaryHDU
98
- ) -> npt.NDArray[np.float32]:
99
- return primary_hdu.data.astype(np.float32)
100
89
 
90
+ def _get_dynamic_spectra(self, primary_hdu: PrimaryHDU) -> npt.NDArray[np.float32]:
91
+ return primary_hdu.data.astype(np.float32)
101
92
 
102
- def _get_spectrogram_start_datetime(
103
- self,
104
- primary_hdu: PrimaryHDU
105
- ) -> datetime:
106
- date_obs = primary_hdu.header['DATE-OBS']
107
- time_obs = primary_hdu.header['TIME-OBS']
93
+ def _get_spectrogram_start_datetime(self, primary_hdu: PrimaryHDU) -> datetime:
94
+ date_obs = primary_hdu.header["DATE-OBS"]
95
+ time_obs = primary_hdu.header["TIME-OBS"]
108
96
  return datetime.strptime(f"{date_obs}T{time_obs}", "%Y/%m/%dT%H:%M:%S.%f")
109
97
 
110
-
111
- def _get_bunit(
112
- self,
113
- primary_hdu: PrimaryHDU
114
- ) -> str:
115
- return primary_hdu.header['BUNIT']
116
-
98
+ def _get_bunit(self, primary_hdu: PrimaryHDU) -> str:
99
+ return primary_hdu.header["BUNIT"]
117
100
 
118
101
  def _convert_units_to_linearised(
119
- self,
120
- raw_digits: npt.NDArray[np.float32]
102
+ self, raw_digits: npt.NDArray[np.float32]
121
103
  ) -> npt.NDArray[np.float32]:
122
104
  """Converts spectrogram data from raw digit values to linearised units.
123
105
 
124
- Applies a transformation based on ADC specifications to convert raw values
106
+ Applies a transformation based on ADC specifications to convert raw values
125
107
  to dB and then to linearised units.
126
108
 
127
109
  :param dynamic_spectra: Raw dynamic spectra in digit values.
@@ -130,54 +112,40 @@ class _FitsFile(BatchFile[Spectrogram]):
130
112
  # conversion as per ADC specs [see email from C. Monstein]
131
113
  dB = (raw_digits / 255) * (2500 / 25)
132
114
  return 10 ** (dB / 10)
133
-
134
-
135
- def _get_times(
136
- self,
137
- bintable_hdu: BinTableHDU
138
- ) -> npt.NDArray[np.float32]:
115
+
116
+ def _get_times(self, bintable_hdu: BinTableHDU) -> npt.NDArray[np.float32]:
139
117
  """Extracts the elapsed times for each spectrum in seconds, with the first spectrum set to t=0
140
118
  by convention.
141
119
  """
142
- return bintable_hdu.data['TIME'][0] # already in seconds
120
+ return bintable_hdu.data["TIME"][0] # already in seconds
143
121
 
144
-
145
- def _get_frequencies(
146
- self,
147
- bintable_hdu: BinTableHDU
148
- ) -> npt.NDArray[np.float32]:
122
+ def _get_frequencies(self, bintable_hdu: BinTableHDU) -> npt.NDArray[np.float32]:
149
123
  """Extracts the frequencies for each spectral component."""
150
- frequencies_MHz = bintable_hdu.data['FREQUENCY'][0]
151
- return frequencies_MHz * 1e6 # convert to Hz
152
-
153
-
124
+ frequencies_MHz = bintable_hdu.data["FREQUENCY"][0]
125
+ return frequencies_MHz * 1e6 # convert to Hz
126
+
127
+
154
128
  @register_batch(BatchKey.CALLISTO)
155
129
  class CallistoBatch(BaseBatch):
156
130
  """A batch of data generated by the e-Callisto network.
157
-
131
+
158
132
  Supports the following file extensions:
159
133
  - `.fits` (via the `spectrogram_file` attribute)
160
134
  """
161
- def __init__(
162
- self,
163
- start_time: str,
164
- tag: str
165
- ) -> None:
135
+
136
+ def __init__(self, start_time: str, tag: str) -> None:
166
137
  """Initialise a `CallistoBatch` instance.
167
138
 
168
139
  :param start_time: The start time of the batch.
169
140
  :param tag: The batch name tag.
170
141
  """
171
- super().__init__(start_time, tag)
142
+ super().__init__(start_time, tag)
172
143
  self._fits_file = _FitsFile(self.parent_dir_path, self.name)
173
-
144
+
174
145
  # add files formally to the batch
175
- self.add_file( self.spectrogram_file )
176
-
177
-
146
+ self.add_file(self.spectrogram_file)
147
+
178
148
  @property
179
- def spectrogram_file(
180
- self
181
- ) -> _FitsFile:
149
+ def spectrogram_file(self) -> _FitsFile:
182
150
  """The batch file corresponding to the `.fits` extension."""
183
151
  return self._fits_file