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
@@ -6,19 +6,15 @@ from abc import ABC, abstractmethod
6
6
  from typing import Callable, Optional, Literal, overload, Any
7
7
 
8
8
  from spectre_core.exceptions import ModeNotFoundError
9
- from spectre_core.capture_configs import (
10
- CaptureTemplate, Parameters, CaptureConfig
11
- )
9
+ from spectre_core.capture_configs import CaptureTemplate, Parameters, CaptureConfig
12
10
  from .plugins._receiver_names import ReceiverName
13
11
  from ._spec_names import SpecName
14
12
 
13
+
15
14
  class BaseReceiver(ABC):
16
15
  """Abstract base class for software-defined radio receivers."""
17
- def __init__(
18
- self,
19
- name: ReceiverName,
20
- mode: Optional[str] = None
21
- ) -> None:
16
+
17
+ def __init__(self, name: ReceiverName, mode: Optional[str] = None) -> None:
22
18
  """Initialise an instance of `BaseReceiver`.
23
19
 
24
20
  :param name: The name of the receiver.
@@ -26,165 +22,126 @@ class BaseReceiver(ABC):
26
22
  """
27
23
  self._name = name
28
24
 
29
- self._specs: dict[SpecName, float|int|list[float|int]] = {}
25
+ self._specs: dict[SpecName, float | int | list[float | int]] = {}
30
26
  self._add_specs()
31
-
27
+
32
28
  self._capture_methods: dict[str, Callable[[str, Parameters], None]] = {}
33
29
  self._add_capture_methods()
34
-
30
+
35
31
  self._capture_templates: dict[str, CaptureTemplate] = {}
36
32
  self._add_capture_templates()
37
-
33
+
38
34
  self._pvalidators: dict[str, Callable[[Parameters], None]] = {}
39
35
  self._add_pvalidators()
40
36
 
41
- self._mode = None
42
- if mode is not None:
43
- self.mode = mode
44
-
37
+ self._mode: Optional[str] = mode
45
38
 
46
39
  @abstractmethod
47
- def _add_specs(
48
- self
49
- ) -> None:
40
+ def _add_specs(self) -> None:
50
41
  """Subclasses must use `add_spec` to add hardware specifications."""
51
-
52
42
 
53
43
  @abstractmethod
54
- def _add_capture_methods(
55
- self
56
- ) -> None:
57
- """Subclasses must use `add_capture_method` to specify which method is called to capture
44
+ def _add_capture_methods(self) -> None:
45
+ """Subclasses must use `add_capture_method` to specify which method is called to capture
58
46
  data, for each operating mode."""
59
-
60
47
 
61
48
  @abstractmethod
62
- def _add_capture_templates(
63
- self
64
- ) -> None:
49
+ def _add_capture_templates(self) -> None:
65
50
  """Subclasses must use `add_capture_template` to define a `CaptureTemplate` for each operating mode."""
66
51
 
67
-
68
52
  @abstractmethod
69
- def _add_pvalidators(
70
- self
71
- ) -> None:
72
- """Subclasses must use `add_pvalidator` to add a parameter validation function (pvalidator)
53
+ def _add_pvalidators(self) -> None:
54
+ """Subclasses must use `add_pvalidator` to add a parameter validation function (pvalidator)
73
55
  for each operating mode."""
74
56
 
75
-
76
57
  @property
77
- def name(
78
- self
79
- ) -> ReceiverName:
58
+ def name(self) -> ReceiverName:
80
59
  """The name of the receiver."""
81
60
  return self._name
82
-
83
61
 
84
62
  @property
85
- def capture_methods(
86
- self
87
- ) -> dict[str, Callable[[str, Parameters], None]]:
63
+ def capture_methods(self) -> dict[str, Callable[[str, Parameters], None]]:
88
64
  """For each operating mode, the method which is called to capture data."""
89
65
  return self._capture_methods
90
-
91
-
66
+
92
67
  @property
93
- def capture_templates(
94
- self
95
- ) -> dict[str, CaptureTemplate]:
68
+ def capture_templates(self) -> dict[str, CaptureTemplate]:
96
69
  """For each operating mode, the corresponding `CaptureTemplate`."""
97
- return self._capture_templates
98
-
70
+ return self._capture_templates
99
71
 
100
72
  @property
101
- def pvalidators(
102
- self
103
- ) -> dict[str, Callable[[Parameters], None]]:
73
+ def pvalidators(self) -> dict[str, Callable[[Parameters], None]]:
104
74
  """For each operating mode, the corresponding parameter validation function (pvalidator)."""
105
75
  return self._pvalidators
106
76
 
107
-
108
77
  @property
109
- def specs(
110
- self
111
- ) -> dict[SpecName, float|int|list[float|int]]:
78
+ def specs(self) -> dict[SpecName, float | int | list[float | int]]:
112
79
  """The hardware specifications."""
113
80
  return self._specs
114
81
 
115
-
116
82
  @property
117
- def modes(
118
- self
119
- ) -> list[str]:
83
+ def modes(self) -> list[str]:
120
84
  """The operating modes for the receiver.
121
85
 
122
86
  :raises ValueError: If the modes are inconsistent between `capture_methods`,
123
87
  `pvalidators` and `capture_templates`.
124
88
  """
125
- capture_method_modes = list(self.capture_methods.keys())
126
- pvalidator_modes = list(self.pvalidators.keys())
127
- capture_template_modes = list(self.capture_templates.keys())
128
-
89
+ capture_method_modes = list(self.capture_methods.keys())
90
+ pvalidator_modes = list(self.pvalidators.keys())
91
+ capture_template_modes = list(self.capture_templates.keys())
92
+
129
93
  if not capture_method_modes == pvalidator_modes == capture_template_modes:
130
94
  raise ValueError(f"Mode mismatch for the receiver {self.name}.")
131
95
  return capture_method_modes
132
96
 
133
-
134
97
  @property
135
- def mode(
136
- self
137
- ) -> str:
138
- """The active operating mode for the receiver."""
139
- if self._mode is None:
140
- raise ValueError(f"The operating mode for the receiver `{self.name.value}` is not set.")
98
+ def mode(self) -> Optional[str]:
99
+ """The active operating mode for the receiver, if set."""
141
100
  return self._mode
142
101
 
143
-
144
102
  @mode.setter
145
- def mode(
146
- self,
147
- value: str,
148
- ) -> None:
103
+ def mode(self, value: str) -> None:
149
104
  """Set the active operating mode.
150
105
 
151
106
  :param value: The new operating mode to activate.
152
107
  :raises ModeNotFoundError: If the specified mode is not defined in `modes`.
153
108
  """
154
- if (value not in self.modes):
155
- raise ModeNotFoundError((f"{value} is not a defined mode for the receiver {self.name}. "
156
- f"Expected one of {self.modes}"))
109
+ if value not in self.modes:
110
+ raise ModeNotFoundError(
111
+ f"{value} is not a defined mode for the receiver {self.name}. "
112
+ f"Expected one of {self.modes}"
113
+ )
157
114
  self._mode = value
158
115
 
116
+ def _get_active_mode(self) -> str:
117
+ """Get the current mode, raising an error if none is set.
118
+
119
+ :raises ValueError: If no mode is currently set
120
+ :return: The current mode
121
+ """
122
+ if self._mode is None:
123
+ raise ValueError(
124
+ f"This operation requires an active mode for receiver `{self.name.value}`"
125
+ )
126
+ return self._mode
159
127
 
160
128
  @property
161
- def capture_method(
162
- self
163
- ) -> Callable[[str, Parameters], None]:
129
+ def capture_method(self) -> Callable[[str, Parameters], None]:
164
130
  """Start capturing data under the active operating mode."""
165
- return self.capture_methods[self.mode]
166
-
131
+ return self.capture_methods[self._get_active_mode()]
167
132
 
168
133
  @property
169
- def pvalidator(
170
- self
171
- ) -> Callable[[Parameters], None]:
134
+ def pvalidator(self) -> Callable[[Parameters], None]:
172
135
  """The parameter validation function for the active operating mode."""
173
- return self.pvalidators[self.mode]
174
-
136
+ return self.pvalidators[self._get_active_mode()]
175
137
 
176
138
  @property
177
- def capture_template(
178
- self
179
- ) -> CaptureTemplate:
139
+ def capture_template(self) -> CaptureTemplate:
180
140
  """The `CaptureTemplate` for the active operating mode."""
181
- return self._capture_templates[self.mode]
182
-
141
+ return self._capture_templates[self._get_active_mode()]
183
142
 
184
143
  def add_capture_method(
185
- self,
186
- mode: str,
187
- capture_method: Callable[[str, Parameters], None]
144
+ self, mode: str, capture_method: Callable[[str, Parameters], None]
188
145
  ) -> None:
189
146
  """
190
147
  Add a capture method for a specific operating mode.
@@ -194,11 +151,8 @@ class BaseReceiver(ABC):
194
151
  """
195
152
  self._capture_methods[mode] = capture_method
196
153
 
197
-
198
154
  def add_pvalidator(
199
- self,
200
- mode: str,
201
- pvalidator: Callable[[Parameters], None]
155
+ self, mode: str, pvalidator: Callable[[Parameters], None]
202
156
  ) -> None:
203
157
  """
204
158
  Add a parameter validation function for a specific operating mode.
@@ -208,11 +162,8 @@ class BaseReceiver(ABC):
208
162
  """
209
163
  self._pvalidators[mode] = pvalidator
210
164
 
211
-
212
165
  def add_capture_template(
213
- self,
214
- mode: str,
215
- capture_template: CaptureTemplate
166
+ self, mode: str, capture_template: CaptureTemplate
216
167
  ) -> None:
217
168
  """
218
169
  Add a `CaptureTemplate` for a specific operating mode.
@@ -222,12 +173,7 @@ class BaseReceiver(ABC):
222
173
  """
223
174
  self._capture_templates[mode] = capture_template
224
175
 
225
-
226
- def add_spec(
227
- self,
228
- name: SpecName,
229
- value: Any
230
- ) -> None:
176
+ def add_spec(self, name: SpecName, value: Any) -> None:
231
177
  """
232
178
  Add a hardware specification.
233
179
 
@@ -236,11 +182,7 @@ class BaseReceiver(ABC):
236
182
  """
237
183
  self.specs[name] = value
238
184
 
239
-
240
- def get_spec(
241
- self,
242
- spec_name: SpecName
243
- ) -> Any:
185
+ def get_spec(self, spec_name: SpecName) -> Any:
244
186
  """
245
187
  Retrieve a hardware specification.
246
188
 
@@ -249,60 +191,52 @@ class BaseReceiver(ABC):
249
191
  :return: The specification's value.
250
192
  """
251
193
  if spec_name not in self.specs:
252
- raise KeyError(f"Spec not found with name '{spec_name}' "
253
- f"for the receiver '{self.name}'")
194
+ raise KeyError(
195
+ f"Spec not found with name '{spec_name}' "
196
+ f"for the receiver '{self.name}'"
197
+ )
254
198
  return self.specs[spec_name]
255
199
 
256
-
257
- def start_capture(
258
- self,
259
- tag: str
260
- ) -> None:
200
+ def start_capture(self, tag: str) -> None:
261
201
  """Start capturing data in the active operating mode.
262
202
 
263
203
  :param tag: The tag of the capture config to load.
204
+ :raises ValueError: If no mode is currently set
264
205
  """
265
- self.capture_method( tag, self.load_parameters(tag) )
266
-
206
+ active_mode = self._get_active_mode()
207
+ self.capture_methods[active_mode](tag, self.load_parameters(tag))
267
208
 
268
209
  def save_parameters(
269
- self,
270
- tag: str,
271
- parameters: Parameters,
272
- force: bool = False
210
+ self, tag: str, parameters: Parameters, force: bool = False
273
211
  ) -> None:
274
- """Create a capture config according to the active operating mode and save the
212
+ """Create a capture config according to the active operating mode and save the
275
213
  input parameters.
276
214
 
277
- The input parameters are validated before being written to file.
278
-
279
215
  :param tag: The tag identifying the capture config.
280
216
  :param parameters: The parameters to save in the capture config.
281
- :param force: If True, overwrites the existing file if it already exists. Defaults to False.
217
+ :param force: If True, overwrites existing file if it exists.
218
+ :raises ValueError: If no mode is currently set
282
219
  """
283
- parameters = self.capture_template.apply_template(parameters)
284
- self.pvalidator(parameters)
220
+ active_mode = self._get_active_mode()
221
+ parameters = self.capture_templates[active_mode].apply_template(parameters)
222
+ self.pvalidators[active_mode](parameters)
285
223
 
286
224
  capture_config = CaptureConfig(tag)
287
- capture_config.save_parameters(self.name.value,
288
- self.mode,
289
- parameters,
290
- force)
291
-
292
- def load_parameters(
293
- self,
294
- tag: str
295
- ) -> Parameters:
296
- """Load a capture config, and return the parameters it stores.
225
+ capture_config.save_parameters(self.name.value, active_mode, parameters, force)
297
226
 
298
- The parameters are validated before being returned.
227
+ def load_parameters(self, tag: str) -> Parameters:
228
+ """Load a capture config, and return the parameters it stores.
299
229
 
300
230
  :param tag: The tag identifying the capture config.
231
+ :raises ValueError: If no mode is currently set
301
232
  :return: The validated parameters stored in the capture config.
302
233
  """
234
+ active_mode = self._get_active_mode()
303
235
  capture_config = CaptureConfig(tag)
304
236
 
305
- parameters = self.capture_template.apply_template(capture_config.parameters)
306
- self.pvalidator(parameters)
307
-
237
+ parameters = self.capture_templates[active_mode].apply_template(
238
+ capture_config.parameters
239
+ )
240
+ self.pvalidators[active_mode](parameters)
241
+
308
242
  return parameters
@@ -16,47 +16,36 @@ from .plugins._b200mini import B200mini
16
16
 
17
17
  @overload
18
18
  def get_receiver(
19
- receiver_name: Literal[ReceiverName.RSP1A],
20
- mode: Optional[str] = None
21
- ) -> RSP1A:
22
- ...
23
-
24
-
19
+ receiver_name: Literal[ReceiverName.RSP1A], mode: Optional[str] = None
20
+ ) -> RSP1A: ...
21
+
22
+
25
23
  @overload
26
24
  def get_receiver(
27
- receiver_name: Literal[ReceiverName.RSPDUO],
28
- mode: Optional[str] = None
29
- ) -> RSPduo:
30
- ...
31
-
32
-
25
+ receiver_name: Literal[ReceiverName.RSPDUO], mode: Optional[str] = None
26
+ ) -> RSPduo: ...
27
+
28
+
33
29
  @overload
34
30
  def get_receiver(
35
- receiver_name: Literal[ReceiverName.TEST],
36
- mode: Optional[str] = None
37
- ) -> Test:
38
- ...
31
+ receiver_name: Literal[ReceiverName.TEST], mode: Optional[str] = None
32
+ ) -> Test: ...
39
33
 
40
34
 
41
35
  @overload
42
36
  def get_receiver(
43
- receiver_name: Literal[ReceiverName.B200MINI],
44
- mode: Optional[str] = None
45
- ) -> B200mini:
46
- ...
37
+ receiver_name: Literal[ReceiverName.B200MINI], mode: Optional[str] = None
38
+ ) -> B200mini: ...
47
39
 
48
40
 
49
41
  @overload
50
42
  def get_receiver(
51
- receiver_name: ReceiverName,
52
- mode: Optional[str] = None
53
- ) -> BaseReceiver:
54
- ...
43
+ receiver_name: ReceiverName, mode: Optional[str] = None
44
+ ) -> BaseReceiver: ...
55
45
 
56
46
 
57
47
  def get_receiver(
58
- receiver_name: ReceiverName,
59
- mode: Optional[str] = None
48
+ receiver_name: ReceiverName, mode: Optional[str] = None
60
49
  ) -> BaseReceiver:
61
50
  """Get a registered receiver.
62
51
 
@@ -68,7 +57,8 @@ def get_receiver(
68
57
  receiver_cls = receivers.get(receiver_name)
69
58
  if receiver_cls is None:
70
59
  valid_receivers = list(receivers.keys())
71
- raise ReceiverNotFoundError(f"No class found for the receiver: {receiver_name}. "
72
- f"Please specify one of the following receivers {valid_receivers}")
73
- return receiver_cls(receiver_name,
74
- mode = mode)
60
+ raise ReceiverNotFoundError(
61
+ f"No class found for the receiver: {receiver_name}. "
62
+ f"Please specify one of the following receivers {valid_receivers}"
63
+ )
64
+ return receiver_cls(receiver_name, mode=mode)
@@ -10,7 +10,9 @@ from ._base import BaseReceiver
10
10
  # map populated at runtime via the `register_receiver` decorator.
11
11
  receivers: dict[ReceiverName, Type[BaseReceiver]] = {}
12
12
 
13
- T = TypeVar('T', bound=BaseReceiver)
13
+ T = TypeVar("T", bound=BaseReceiver)
14
+
15
+
14
16
  def register_receiver(
15
17
  receiver_name: ReceiverName,
16
18
  ) -> Callable[[Type[T]], Type[T]]:
@@ -20,24 +22,19 @@ def register_receiver(
20
22
  :raises ValueError: If the provided `receiver_name` is already registered.
21
23
  :return: A decorator that registers the `BaseReceiver` subclass under the given `receiver_name`.
22
24
  """
23
- def decorator(
24
- cls: Type[T]
25
- ) -> Type[T]:
25
+
26
+ def decorator(cls: Type[T]) -> Type[T]:
26
27
  if receiver_name in receivers:
27
28
  raise ValueError(f"The receiver '{receiver_name}' is already registered!")
28
29
  receivers[receiver_name] = cls
29
30
  return cls
31
+
30
32
  return decorator
31
33
 
32
34
 
33
- def get_registered_receivers(
34
- ) -> list[str]:
35
+ def get_registered_receivers() -> list[str]:
35
36
  """List all registered receivers.
36
37
 
37
38
  :return: The string values of all registered `ReceiverName` enum keys.
38
39
  """
39
40
  return [k.value for k in receivers.keys()]
40
-
41
-
42
-
43
-
@@ -4,9 +4,10 @@
4
4
 
5
5
  from enum import Enum
6
6
 
7
+
7
8
  class SpecName(Enum):
8
9
  """A hardware specification name.
9
-
10
+
10
11
  :ivar FREQUENCY_LOWER_BOUND: The lower bound for the center frequency, in Hz.
11
12
  :ivar FREQUENCY_UPPER_BOUND: The upper bound for the center frequency, in Hz.
12
13
  :ivar SAMPLE_RATE_LOWER_BOUND: The lower bound for the sampling rate, in Hz.
@@ -16,26 +17,27 @@ class SpecName(Enum):
16
17
  :ivar BANDWIDTH_OPTIONS: The permitted bandwidths for the receiver, in Hz.
17
18
  :ivar IF_GAIN_UPPER_BOUND: The upper bound for the intermediate frequency gain, in dB.
18
19
  Negative values indicate attenuation.
19
- :ivar RF_GAIN_UPPER_BOUND: The upper bound for the radio frequency gain, in dB.
20
+ :ivar RF_GAIN_UPPER_BOUND: The upper bound for the radio frequency gain, in dB.
20
21
  Negative values indicate attenuation.
21
22
  :ivar GAIN_UPPER_BOUND: The upper bound for the gain, in dB.
22
23
  :ivar WIRE_FORMATS: Supported data types transferred over the bus/network.
23
24
  :ivar MASTER_CLOCK_RATE_LOWER_BOUND: The lower bound for the SDR reference clock rate, in Hz.
24
25
  :ivar MASTER_CLOCK_RATE_UPPER_BOUND: The upper bound for the SDR reference clock rate, in Hz.
25
26
  :ivar API_RETUNING_LATENCY: An empirical estimate of the delay between issuing a command
26
- for a receiver to retune its center frequency and the actual physical update of the center frequency.
27
+ for a receiver to retune its center frequency and the actual physical update of the center frequency.
27
28
  """
28
- FREQUENCY_LOWER_BOUND = "frequency_lower_bound"
29
- FREQUENCY_UPPER_BOUND = "frequency_upper_bound"
30
- SAMPLE_RATE_LOWER_BOUND = "sample_rate_lower_bound"
31
- SAMPLE_RATE_UPPER_BOUND = "sample_rate_upper_bound"
32
- BANDWIDTH_LOWER_BOUND = "bandwidth_lower_bound"
33
- BANDWIDTH_UPPER_BOUND = "bandwidth_upper_bound"
34
- BANDWIDTH_OPTIONS = "bandwidth_options"
35
- IF_GAIN_UPPER_BOUND = "if_gain_upper_bound"
36
- RF_GAIN_UPPER_BOUND = "rf_gain_upper_bound"
37
- GAIN_UPPER_BOUND = "gain_upper_bound"
38
- WIRE_FORMATS = "wire_formats"
29
+
30
+ FREQUENCY_LOWER_BOUND = "frequency_lower_bound"
31
+ FREQUENCY_UPPER_BOUND = "frequency_upper_bound"
32
+ SAMPLE_RATE_LOWER_BOUND = "sample_rate_lower_bound"
33
+ SAMPLE_RATE_UPPER_BOUND = "sample_rate_upper_bound"
34
+ BANDWIDTH_LOWER_BOUND = "bandwidth_lower_bound"
35
+ BANDWIDTH_UPPER_BOUND = "bandwidth_upper_bound"
36
+ BANDWIDTH_OPTIONS = "bandwidth_options"
37
+ IF_GAIN_UPPER_BOUND = "if_gain_upper_bound"
38
+ RF_GAIN_UPPER_BOUND = "rf_gain_upper_bound"
39
+ GAIN_UPPER_BOUND = "gain_upper_bound"
40
+ WIRE_FORMATS = "wire_formats"
39
41
  MASTER_CLOCK_RATE_LOWER_BOUND = "master_clock_rate_lower_bound"
40
42
  MASTER_CLOCK_RATE_UPPER_BOUND = "master_clock_rate_upper_bound"
41
- API_RETUNING_LATENCY = "api_retuning_latency"
43
+ API_RETUNING_LATENCY = "api_retuning_latency"
@@ -6,17 +6,21 @@ from dataclasses import dataclass
6
6
 
7
7
  from ._receiver_names import ReceiverName
8
8
  from ._usrp import (
9
- get_pvalidator_fixed_center_frequency, get_pvalidator_swept_center_frequency,
10
- get_capture_template_fixed_center_frequency, get_capture_template_swept_center_frequency
9
+ get_pvalidator_fixed_center_frequency,
10
+ get_pvalidator_swept_center_frequency,
11
+ get_capture_template_fixed_center_frequency,
12
+ get_capture_template_swept_center_frequency,
11
13
  )
12
14
  from .gr._usrp import CaptureMethod
13
15
  from .._spec_names import SpecName
14
16
  from .._base import BaseReceiver
15
- from .._register import register_receiver
17
+ from .._register import register_receiver
18
+
16
19
 
17
20
  @dataclass(frozen=True)
18
21
  class Mode:
19
22
  """An operating mode for the `B200mini` receiver."""
23
+
20
24
  FIXED_CENTER_FREQUENCY = "fixed_center_frequency"
21
25
  SWEPT_CENTER_FREQUENCY = "swept_center_frequency"
22
26
 
@@ -24,61 +28,44 @@ class Mode:
24
28
  @register_receiver(ReceiverName.B200MINI)
25
29
  class B200mini(BaseReceiver):
26
30
  """Receiver implementation for the USRP B200mini (https://www.ettus.com/all-products/usrp-b200mini/)"""
27
- def _add_specs(
28
- self
29
- ) -> None:
30
- self.add_spec( SpecName.SAMPLE_RATE_LOWER_BOUND , 200e3 )
31
- self.add_spec( SpecName.SAMPLE_RATE_UPPER_BOUND , 56e6 )
32
- self.add_spec( SpecName.FREQUENCY_LOWER_BOUND , 70e6 )
33
- self.add_spec( SpecName.FREQUENCY_UPPER_BOUND , 6e9 )
34
- self.add_spec( SpecName.BANDWIDTH_LOWER_BOUND , 200e3 )
35
- self.add_spec( SpecName.BANDWIDTH_UPPER_BOUND , 56e6 )
36
- self.add_spec( SpecName.GAIN_UPPER_BOUND , 76 )
37
- self.add_spec( SpecName.WIRE_FORMATS , ["sc8", "sc12", "sc16"])
38
- self.add_spec( SpecName.MASTER_CLOCK_RATE_LOWER_BOUND, 5e6)
39
- self.add_spec( SpecName.MASTER_CLOCK_RATE_UPPER_BOUND, 61.44e6)
40
- self.add_spec( SpecName.API_RETUNING_LATENCY , 1e-5 ) # TODO: This is a ballpark, pending empirical testing
41
-
42
-
43
- def _add_capture_methods(
44
- self
45
- ) -> None:
46
- self.add_capture_method(Mode.FIXED_CENTER_FREQUENCY,
47
- CaptureMethod.fixed_center_frequency)
48
- self.add_capture_method(Mode.SWEPT_CENTER_FREQUENCY,
49
- CaptureMethod.swept_center_frequency)
50
-
51
-
52
- def _add_capture_templates(
53
- self
54
- ) -> None:
55
- self.add_capture_template(Mode.FIXED_CENTER_FREQUENCY,
56
- get_capture_template_fixed_center_frequency(self))
57
- self.add_capture_template(Mode.SWEPT_CENTER_FREQUENCY,
58
- get_capture_template_swept_center_frequency(self))
59
-
60
-
61
- def _add_pvalidators(
62
- self
63
- ) -> None:
64
- self.add_pvalidator(Mode.FIXED_CENTER_FREQUENCY,
65
- get_pvalidator_fixed_center_frequency(self))
66
- self.add_pvalidator(Mode.SWEPT_CENTER_FREQUENCY,
67
- get_pvalidator_swept_center_frequency(self))
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
31
 
32
+ def _add_specs(self) -> None:
33
+ self.add_spec(SpecName.SAMPLE_RATE_LOWER_BOUND, 200e3)
34
+ self.add_spec(SpecName.SAMPLE_RATE_UPPER_BOUND, 56e6)
35
+ self.add_spec(SpecName.FREQUENCY_LOWER_BOUND, 70e6)
36
+ self.add_spec(SpecName.FREQUENCY_UPPER_BOUND, 6e9)
37
+ self.add_spec(SpecName.BANDWIDTH_LOWER_BOUND, 200e3)
38
+ self.add_spec(SpecName.BANDWIDTH_UPPER_BOUND, 56e6)
39
+ self.add_spec(SpecName.GAIN_UPPER_BOUND, 76)
40
+ self.add_spec(SpecName.WIRE_FORMATS, ["sc8", "sc12", "sc16"])
41
+ self.add_spec(SpecName.MASTER_CLOCK_RATE_LOWER_BOUND, 5e6)
42
+ self.add_spec(SpecName.MASTER_CLOCK_RATE_UPPER_BOUND, 61.44e6)
43
+ self.add_spec(
44
+ SpecName.API_RETUNING_LATENCY, 1e-5
45
+ ) # TODO: This is a ballpark, pending empirical testing
46
+
47
+ def _add_capture_methods(self) -> None:
48
+ self.add_capture_method(
49
+ Mode.FIXED_CENTER_FREQUENCY, CaptureMethod.fixed_center_frequency
50
+ )
51
+ self.add_capture_method(
52
+ Mode.SWEPT_CENTER_FREQUENCY, CaptureMethod.swept_center_frequency
53
+ )
54
+
55
+ def _add_capture_templates(self) -> None:
56
+ self.add_capture_template(
57
+ Mode.FIXED_CENTER_FREQUENCY,
58
+ get_capture_template_fixed_center_frequency(self),
59
+ )
60
+ self.add_capture_template(
61
+ Mode.SWEPT_CENTER_FREQUENCY,
62
+ get_capture_template_swept_center_frequency(self),
63
+ )
64
+
65
+ def _add_pvalidators(self) -> None:
66
+ self.add_pvalidator(
67
+ Mode.FIXED_CENTER_FREQUENCY, get_pvalidator_fixed_center_frequency(self)
68
+ )
69
+ self.add_pvalidator(
70
+ Mode.SWEPT_CENTER_FREQUENCY, get_pvalidator_swept_center_frequency(self)
71
+ )