spectre-core 0.0.21__py3-none-any.whl → 0.0.23__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.
- spectre_core/_file_io/__init__.py +5 -5
- spectre_core/_file_io/file_handlers.py +61 -107
- spectre_core/batches/__init__.py +21 -4
- spectre_core/batches/_base.py +86 -135
- spectre_core/batches/_batches.py +56 -100
- spectre_core/batches/_factory.py +22 -21
- spectre_core/batches/_register.py +9 -9
- spectre_core/batches/plugins/_batch_keys.py +8 -7
- spectre_core/batches/plugins/_callisto.py +66 -98
- spectre_core/batches/plugins/_iq_stream.py +106 -170
- spectre_core/capture_configs/__init__.py +47 -18
- spectre_core/capture_configs/_capture_config.py +26 -53
- spectre_core/capture_configs/_capture_modes.py +9 -7
- spectre_core/capture_configs/_capture_templates.py +51 -111
- spectre_core/capture_configs/_parameters.py +38 -75
- spectre_core/capture_configs/_pconstraints.py +41 -41
- spectre_core/capture_configs/_pnames.py +37 -35
- spectre_core/capture_configs/_ptemplates.py +261 -348
- spectre_core/capture_configs/_pvalidators.py +99 -102
- spectre_core/config/__init__.py +14 -9
- spectre_core/config/_paths.py +19 -36
- spectre_core/config/_time_formats.py +7 -6
- spectre_core/exceptions.py +39 -1
- spectre_core/jobs/__init__.py +4 -7
- spectre_core/jobs/_duration.py +12 -0
- spectre_core/jobs/_jobs.py +73 -44
- spectre_core/jobs/_workers.py +56 -106
- spectre_core/logs/__init__.py +8 -3
- spectre_core/logs/_configure.py +14 -18
- spectre_core/logs/_decorators.py +7 -5
- spectre_core/logs/_logs.py +38 -90
- spectre_core/logs/_process_types.py +6 -4
- spectre_core/plotting/__init__.py +14 -4
- spectre_core/plotting/_base.py +65 -139
- spectre_core/plotting/_format.py +11 -9
- spectre_core/plotting/_panel_names.py +8 -6
- spectre_core/plotting/_panel_stack.py +83 -116
- spectre_core/plotting/_panels.py +121 -156
- spectre_core/post_processing/__init__.py +7 -4
- spectre_core/post_processing/_base.py +69 -69
- spectre_core/post_processing/_factory.py +15 -12
- spectre_core/post_processing/_post_processor.py +17 -13
- spectre_core/post_processing/_register.py +11 -8
- spectre_core/post_processing/plugins/_event_handler_keys.py +5 -4
- spectre_core/post_processing/plugins/_fixed_center_frequency.py +55 -48
- spectre_core/post_processing/plugins/_swept_center_frequency.py +200 -175
- spectre_core/receivers/__init__.py +10 -3
- spectre_core/receivers/_base.py +83 -149
- spectre_core/receivers/_factory.py +21 -31
- spectre_core/receivers/_register.py +8 -11
- spectre_core/receivers/_spec_names.py +18 -16
- spectre_core/receivers/plugins/_b200mini.py +48 -61
- spectre_core/receivers/plugins/_receiver_names.py +9 -7
- spectre_core/receivers/plugins/_rsp1a.py +45 -41
- spectre_core/receivers/plugins/_rspduo.py +60 -45
- spectre_core/receivers/plugins/_sdrplay_receiver.py +68 -84
- spectre_core/receivers/plugins/_test.py +137 -130
- spectre_core/receivers/plugins/_usrp.py +94 -86
- spectre_core/receivers/plugins/gr/__init__.py +2 -2
- spectre_core/receivers/plugins/gr/_base.py +15 -23
- spectre_core/receivers/plugins/gr/_rsp1a.py +53 -60
- spectre_core/receivers/plugins/gr/_rspduo.py +78 -90
- spectre_core/receivers/plugins/gr/_test.py +50 -58
- spectre_core/receivers/plugins/gr/_usrp.py +61 -59
- spectre_core/spectrograms/__init__.py +22 -14
- spectre_core/spectrograms/_analytical.py +109 -100
- spectre_core/spectrograms/_array_operations.py +40 -47
- spectre_core/spectrograms/_spectrogram.py +290 -323
- spectre_core/spectrograms/_transform.py +107 -74
- spectre_core/wgetting/__init__.py +2 -4
- spectre_core/wgetting/_callisto.py +88 -94
- {spectre_core-0.0.21.dist-info → spectre_core-0.0.23.dist-info}/METADATA +9 -23
- spectre_core-0.0.23.dist-info/RECORD +79 -0
- {spectre_core-0.0.21.dist-info → spectre_core-0.0.23.dist-info}/WHEEL +1 -1
- spectre_core-0.0.21.dist-info/RECORD +0 -78
- {spectre_core-0.0.21.dist-info → spectre_core-0.0.23.dist-info}/licenses/LICENSE +0 -0
- {spectre_core-0.0.21.dist-info → spectre_core-0.0.23.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
# SPDX-FileCopyrightText: © 2024 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
|
1
|
+
# SPDX-FileCopyrightText: © 2024-2025 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
|
2
2
|
# This file is part of SPECTRE
|
3
3
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
4
4
|
|
@@ -9,11 +9,14 @@ from copy import deepcopy
|
|
9
9
|
from ._pnames import PName
|
10
10
|
from ._pconstraints import BasePConstraint, EnforceSign, PowerOfTwo, Bound
|
11
11
|
from ._parameters import Parameter
|
12
|
-
|
12
|
+
|
13
13
|
# value type
|
14
|
-
VT = TypeVar(
|
14
|
+
VT = TypeVar("VT")
|
15
|
+
|
16
|
+
|
15
17
|
class PTemplate(Generic[VT]):
|
16
18
|
"""A template which constrains the value and type of a capture config parameter."""
|
19
|
+
|
17
20
|
def __init__(
|
18
21
|
self,
|
19
22
|
name: PName,
|
@@ -22,7 +25,7 @@ class PTemplate(Generic[VT]):
|
|
22
25
|
nullable: bool = False,
|
23
26
|
enforce_default: bool = False,
|
24
27
|
help: Optional[str] = None,
|
25
|
-
pconstraints: Optional[list[BasePConstraint]] = None
|
28
|
+
pconstraints: Optional[list[BasePConstraint]] = None,
|
26
29
|
) -> None:
|
27
30
|
"""Initialise an instance of `PTemplate`.
|
28
31
|
|
@@ -39,97 +42,67 @@ class PTemplate(Generic[VT]):
|
|
39
42
|
self._default = default
|
40
43
|
self._nullable = nullable
|
41
44
|
self._enforce_default = enforce_default
|
42
|
-
self._help =
|
45
|
+
self._help = (
|
46
|
+
dedent(help).strip().replace("\n", " ")
|
47
|
+
if help
|
48
|
+
else "No help has been provided."
|
49
|
+
)
|
43
50
|
self._pconstraints: list[BasePConstraint] = pconstraints or []
|
44
51
|
|
45
|
-
|
46
52
|
@property
|
47
|
-
def name(
|
48
|
-
self
|
49
|
-
) -> PName:
|
53
|
+
def name(self) -> PName:
|
50
54
|
"""The name of the parameter."""
|
51
55
|
return self._name
|
52
|
-
|
53
56
|
|
54
57
|
@property
|
55
|
-
def ptype(
|
56
|
-
self
|
57
|
-
) -> Callable[[object], VT]:
|
58
|
+
def ptype(self) -> Callable[[object], VT]:
|
58
59
|
"""The required type of the parameter. The value must be castable as this type."""
|
59
60
|
return self._ptype
|
60
|
-
|
61
61
|
|
62
62
|
@property
|
63
|
-
def default(
|
64
|
-
self
|
65
|
-
) -> Optional[VT]:
|
63
|
+
def default(self) -> Optional[VT]:
|
66
64
|
"""The parameter value if not explictly specified."""
|
67
65
|
return self._default
|
68
|
-
|
69
66
|
|
70
67
|
@default.setter
|
71
|
-
def default(
|
72
|
-
self,
|
73
|
-
value: VT
|
74
|
-
) -> None:
|
68
|
+
def default(self, value: VT) -> None:
|
75
69
|
"""Update the `default` of this parameter template.
|
76
70
|
|
77
71
|
:param value: The new default value to set.
|
78
72
|
"""
|
79
73
|
self._default = self._cast(value)
|
80
74
|
|
81
|
-
|
82
75
|
@property
|
83
|
-
def nullable(
|
84
|
-
self
|
85
|
-
) -> bool:
|
76
|
+
def nullable(self) -> bool:
|
86
77
|
"""Whether the value of the parameter can be `None`."""
|
87
78
|
return self._nullable
|
88
|
-
|
89
79
|
|
90
80
|
@property
|
91
|
-
def enforce_default(
|
92
|
-
self
|
93
|
-
) -> bool:
|
81
|
+
def enforce_default(self) -> bool:
|
94
82
|
"""Indicates whether the value must match the specified `default`."""
|
95
83
|
return self._enforce_default
|
96
|
-
|
97
84
|
|
98
85
|
@enforce_default.setter
|
99
|
-
def enforce_default(
|
100
|
-
self,
|
101
|
-
value: bool
|
102
|
-
) -> None:
|
86
|
+
def enforce_default(self, value: bool) -> None:
|
103
87
|
"""Update whether to `enforce_default` for this parameter template.
|
104
88
|
|
105
89
|
:param value: Whether to enforce the default value.
|
106
90
|
"""
|
107
91
|
self._enforce_default = value
|
108
|
-
|
109
92
|
|
110
93
|
@property
|
111
|
-
def help(
|
112
|
-
self
|
113
|
-
) -> str:
|
94
|
+
def help(self) -> str:
|
114
95
|
"""A helpful description of what the parameter is, and the value it stores."""
|
115
96
|
return self._help
|
116
|
-
|
117
|
-
|
118
|
-
def add_pconstraint(
|
119
|
-
self,
|
120
|
-
pconstraint: BasePConstraint
|
121
|
-
) -> None:
|
97
|
+
|
98
|
+
def add_pconstraint(self, pconstraint: BasePConstraint) -> None:
|
122
99
|
"""Add a parameter constraint to this template.
|
123
100
|
|
124
101
|
:param pconstraint: A `PConstraint` instance compatible with the `ptype`.
|
125
102
|
"""
|
126
103
|
self._pconstraints.append(pconstraint)
|
127
104
|
|
128
|
-
|
129
|
-
def _cast(
|
130
|
-
self,
|
131
|
-
value: Any
|
132
|
-
) -> VT:
|
105
|
+
def _cast(self, value: Any) -> VT:
|
133
106
|
"""Cast the input value to the `ptype` for this parameter template.
|
134
107
|
|
135
108
|
:param value: The value to be type casted.
|
@@ -139,13 +112,11 @@ class PTemplate(Generic[VT]):
|
|
139
112
|
try:
|
140
113
|
return self._ptype(value)
|
141
114
|
except (TypeError, ValueError) as e:
|
142
|
-
raise ValueError(
|
143
|
-
|
115
|
+
raise ValueError(
|
116
|
+
f"Could not cast '{value}' to '{self._ptype.__name__}': {e}"
|
117
|
+
)
|
144
118
|
|
145
|
-
def _constrain(
|
146
|
-
self,
|
147
|
-
value: VT
|
148
|
-
) -> VT:
|
119
|
+
def _constrain(self, value: VT) -> VT:
|
149
120
|
"""Constrain the input value according to constraints of the template.
|
150
121
|
|
151
122
|
:param value: The value to be constrained.
|
@@ -154,25 +125,27 @@ class PTemplate(Generic[VT]):
|
|
154
125
|
:return: The input value unchanged if it passes validation.
|
155
126
|
"""
|
156
127
|
if self._enforce_default and value != self._default:
|
157
|
-
raise ValueError(
|
158
|
-
|
128
|
+
raise ValueError(
|
129
|
+
f"The default value of '{self._default}' "
|
130
|
+
f"is required for the parameter '{self._name}'."
|
131
|
+
)
|
159
132
|
|
160
133
|
# apply existing pconstraints
|
161
134
|
for constraint in self._pconstraints:
|
162
135
|
try:
|
163
136
|
constraint.constrain(value)
|
164
137
|
except ValueError as e:
|
165
|
-
raise ValueError(
|
138
|
+
raise ValueError(
|
139
|
+
f"PConstraint '{constraint.__class__.__name__}' failed for the parameter '{self._name}': {e}"
|
140
|
+
)
|
166
141
|
except Exception as e:
|
167
|
-
raise RuntimeError(
|
168
|
-
|
142
|
+
raise RuntimeError(
|
143
|
+
f"An unexpected error occurred while applying the pconstraint '{constraint.__class__.__name__}' to "
|
144
|
+
f"'{self.name}': {e}"
|
145
|
+
)
|
169
146
|
return value
|
170
147
|
|
171
|
-
|
172
|
-
def apply_template(
|
173
|
-
self,
|
174
|
-
value: Optional[Any]
|
175
|
-
) -> Optional[VT]:
|
148
|
+
def apply_template(self, value: Optional[Any]) -> Optional[VT]:
|
176
149
|
"""Cast a value and validate it according to this parameter template.
|
177
150
|
|
178
151
|
:param value: The input value.
|
@@ -183,19 +156,17 @@ class PTemplate(Generic[VT]):
|
|
183
156
|
if self._default is not None:
|
184
157
|
value = self._default
|
185
158
|
elif not self._nullable:
|
186
|
-
raise ValueError(
|
187
|
-
|
188
|
-
|
159
|
+
raise ValueError(
|
160
|
+
f"The parameter '{self._name}' is not nullable, "
|
161
|
+
f"but no value or default has been provided. "
|
162
|
+
f"Either provide a value, or provide a default."
|
163
|
+
)
|
189
164
|
else:
|
190
165
|
return None
|
191
|
-
|
192
|
-
return self._constrain( self._cast(value) )
|
193
166
|
|
167
|
+
return self._constrain(self._cast(value))
|
194
168
|
|
195
|
-
def make_parameter(
|
196
|
-
self,
|
197
|
-
value: Optional[Any] = None
|
198
|
-
) -> Parameter:
|
169
|
+
def make_parameter(self, value: Optional[Any] = None) -> Parameter:
|
199
170
|
"""Create a `Parameter` compliant with this template.
|
200
171
|
|
201
172
|
:param value: The provided value for the parameter. Defaults to None.
|
@@ -204,10 +175,7 @@ class PTemplate(Generic[VT]):
|
|
204
175
|
value = self.apply_template(value)
|
205
176
|
return Parameter(self._name, value)
|
206
177
|
|
207
|
-
|
208
|
-
def to_dict(
|
209
|
-
self
|
210
|
-
) -> dict[str, str]:
|
178
|
+
def to_dict(self) -> dict[str, str]:
|
211
179
|
"""Convert this parameter template to a serialisable dictionary.
|
212
180
|
|
213
181
|
:return: A dictionary representation of this parameter template with string formatted values.
|
@@ -218,278 +186,221 @@ class PTemplate(Generic[VT]):
|
|
218
186
|
"default": self._default,
|
219
187
|
"enforce_default": self._enforce_default,
|
220
188
|
"help": self._help,
|
221
|
-
"pconstraints": [f"{constraint}" for constraint in self._pconstraints]
|
189
|
+
"pconstraints": [f"{constraint}" for constraint in self._pconstraints],
|
222
190
|
}
|
223
|
-
return {k: f"{v}" for k,v in d.items()}
|
224
|
-
|
191
|
+
return {k: f"{v}" for k, v in d.items()}
|
192
|
+
|
225
193
|
|
226
194
|
# ------------------------------------------------------------------------------------------ #
|
227
|
-
# `_base_ptemplates` holds all shared base parameter templates. They are 'base' templates,
|
228
|
-
# in the sense that they should be configured according to specific use-cases. For example,
|
195
|
+
# `_base_ptemplates` holds all shared base parameter templates. They are 'base' templates,
|
196
|
+
# in the sense that they should be configured according to specific use-cases. For example,
|
229
197
|
# `default` values should be set, and `pconstraints` added according to specific SDR specs.
|
230
|
-
# ------------------------------------------------------------------------------------------ #
|
198
|
+
# ------------------------------------------------------------------------------------------ #
|
231
199
|
|
232
200
|
_base_ptemplates: dict[PName, PTemplate] = {
|
233
|
-
PName.CENTER_FREQUENCY:
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
PName.
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
PName.
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
PName.
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
PName.
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
PName.
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
help="""
|
437
|
-
Corresponds to the FITS keyword OBJECT.
|
438
|
-
"""),
|
439
|
-
PName.OBS_LAT: PTemplate(PName.OBS_LAT,
|
440
|
-
float,
|
441
|
-
nullable=True,
|
442
|
-
help="""
|
443
|
-
Corresponds to the FITS keyword OBS_LAT.
|
444
|
-
"""),
|
445
|
-
PName.OBS_LON: PTemplate(PName.OBS_LON,
|
446
|
-
float,
|
447
|
-
nullable=True,
|
448
|
-
help="""
|
449
|
-
Corresponds to the FITS keyword OBS_LONG.
|
450
|
-
"""),
|
451
|
-
PName.OBS_ALT: PTemplate(PName.OBS_ALT,
|
452
|
-
float,
|
453
|
-
nullable=True,
|
454
|
-
help="""
|
455
|
-
Corresponds to the FITS keyword OBS_ALT.
|
456
|
-
"""),
|
457
|
-
PName.AMPLITUDE: PTemplate(PName.AMPLITUDE,
|
458
|
-
float,
|
459
|
-
help="""
|
460
|
-
The amplitude of the signal.
|
461
|
-
"""),
|
462
|
-
PName.FREQUENCY: PTemplate(PName.FREQUENCY,
|
463
|
-
float,
|
464
|
-
help="""
|
465
|
-
The frequency of the signal, in Hz.
|
466
|
-
"""),
|
467
|
-
PName.MIN_SAMPLES_PER_STEP: PTemplate(PName.MIN_SAMPLES_PER_STEP,
|
468
|
-
int,
|
469
|
-
help="""
|
470
|
-
The number of samples in the shortest step of the staircase.
|
471
|
-
""",
|
472
|
-
pconstraints=[
|
473
|
-
EnforceSign.positive
|
474
|
-
]),
|
475
|
-
PName.MAX_SAMPLES_PER_STEP: PTemplate(PName.MAX_SAMPLES_PER_STEP,
|
476
|
-
int,
|
477
|
-
help="""
|
478
|
-
The number of samples in the longest step of the staircase.
|
479
|
-
""",
|
480
|
-
pconstraints=[
|
481
|
-
EnforceSign.positive
|
482
|
-
]),
|
483
|
-
PName.STEP_INCREMENT: PTemplate(PName.STEP_INCREMENT,
|
484
|
-
int,
|
485
|
-
help="""
|
486
|
-
The length by which each step in the staircase is incremented.
|
487
|
-
""",
|
488
|
-
pconstraints=[
|
489
|
-
EnforceSign.positive,
|
490
|
-
])
|
491
|
-
|
492
|
-
|
201
|
+
PName.CENTER_FREQUENCY: PTemplate(
|
202
|
+
PName.CENTER_FREQUENCY,
|
203
|
+
float,
|
204
|
+
help="The center frequency of the SDR in Hz. This value determines the midpoint of the frequency range being processed.",
|
205
|
+
pconstraints=[EnforceSign.positive],
|
206
|
+
),
|
207
|
+
PName.MIN_FREQUENCY: PTemplate(
|
208
|
+
PName.MIN_FREQUENCY,
|
209
|
+
float,
|
210
|
+
help="The minimum center frequency, in Hz, for the frequency sweep.",
|
211
|
+
pconstraints=[EnforceSign.positive],
|
212
|
+
),
|
213
|
+
PName.MAX_FREQUENCY: PTemplate(
|
214
|
+
PName.MAX_FREQUENCY,
|
215
|
+
float,
|
216
|
+
help="The maximum center frequency, in Hz, for the frequency sweep.",
|
217
|
+
pconstraints=[EnforceSign.positive],
|
218
|
+
),
|
219
|
+
PName.FREQUENCY_STEP: PTemplate(
|
220
|
+
PName.FREQUENCY_STEP,
|
221
|
+
float,
|
222
|
+
help="The amount, in Hz, by which the center frequency is incremented for each step in the frequency sweep.",
|
223
|
+
pconstraints=[EnforceSign.positive],
|
224
|
+
),
|
225
|
+
PName.BANDWIDTH: PTemplate(
|
226
|
+
PName.BANDWIDTH,
|
227
|
+
float,
|
228
|
+
help="The frequency range in Hz the signal will occupy without significant attenutation.",
|
229
|
+
pconstraints=[EnforceSign.positive],
|
230
|
+
),
|
231
|
+
PName.SAMPLE_RATE: PTemplate(
|
232
|
+
PName.SAMPLE_RATE,
|
233
|
+
int,
|
234
|
+
help="The number of samples per second in Hz.",
|
235
|
+
pconstraints=[EnforceSign.positive],
|
236
|
+
),
|
237
|
+
PName.IF_GAIN: PTemplate(
|
238
|
+
PName.IF_GAIN,
|
239
|
+
float,
|
240
|
+
help="The intermediate frequency gain, in dB. Negative value indicates attenuation.",
|
241
|
+
pconstraints=[EnforceSign.negative],
|
242
|
+
),
|
243
|
+
PName.RF_GAIN: PTemplate(
|
244
|
+
PName.RF_GAIN,
|
245
|
+
float,
|
246
|
+
help="The radio frequency gain, in dB. Negative value indicates attenuation.",
|
247
|
+
pconstraints=[EnforceSign.non_positive],
|
248
|
+
),
|
249
|
+
PName.GAIN: PTemplate(
|
250
|
+
PName.GAIN,
|
251
|
+
float,
|
252
|
+
help="The gain value for the SDR, in dB",
|
253
|
+
),
|
254
|
+
PName.MASTER_CLOCK_RATE: PTemplate(
|
255
|
+
PName.MASTER_CLOCK_RATE,
|
256
|
+
int,
|
257
|
+
help="The primary reference clock for the SDR, specified in Hz.",
|
258
|
+
),
|
259
|
+
PName.WIRE_FORMAT: PTemplate(
|
260
|
+
PName.WIRE_FORMAT,
|
261
|
+
str,
|
262
|
+
help="Controls the form of the data over the bus/network.",
|
263
|
+
),
|
264
|
+
PName.EVENT_HANDLER_KEY: PTemplate(
|
265
|
+
PName.EVENT_HANDLER_KEY,
|
266
|
+
str,
|
267
|
+
help="Identifies which post-processing functions to invokeon newly created files.",
|
268
|
+
),
|
269
|
+
PName.BATCH_KEY: PTemplate(
|
270
|
+
PName.BATCH_KEY,
|
271
|
+
str,
|
272
|
+
help="Identifies the type of data is stored in each batch.",
|
273
|
+
),
|
274
|
+
PName.WINDOW_SIZE: PTemplate(
|
275
|
+
PName.WINDOW_SIZE,
|
276
|
+
int,
|
277
|
+
help="The size of the window, in samples, when performing the Short Time FFT.",
|
278
|
+
pconstraints=[
|
279
|
+
EnforceSign.positive,
|
280
|
+
PowerOfTwo(),
|
281
|
+
],
|
282
|
+
),
|
283
|
+
PName.WINDOW_HOP: PTemplate(
|
284
|
+
PName.WINDOW_HOP,
|
285
|
+
int,
|
286
|
+
help="How much the window is shifted, in samples, when performing the Short Time FFT.",
|
287
|
+
pconstraints=[EnforceSign.positive],
|
288
|
+
),
|
289
|
+
PName.WINDOW_TYPE: PTemplate(
|
290
|
+
PName.WINDOW_TYPE,
|
291
|
+
str,
|
292
|
+
help="The type of window applied when performing the Short Time FFT.",
|
293
|
+
),
|
294
|
+
PName.WATCH_EXTENSION: PTemplate(
|
295
|
+
PName.WATCH_EXTENSION,
|
296
|
+
str,
|
297
|
+
help="Post-processing is triggered by newly created files with this extension. Extensions are specified without the '.' character.",
|
298
|
+
),
|
299
|
+
PName.TIME_RESOLUTION: PTemplate(
|
300
|
+
PName.TIME_RESOLUTION,
|
301
|
+
float,
|
302
|
+
nullable=True,
|
303
|
+
help="Batched spectrograms are smoothed by averaging up to the time resolution, specified in seconds.",
|
304
|
+
pconstraints=[EnforceSign.non_negative],
|
305
|
+
),
|
306
|
+
PName.FREQUENCY_RESOLUTION: PTemplate(
|
307
|
+
PName.FREQUENCY_RESOLUTION,
|
308
|
+
float,
|
309
|
+
nullable=True,
|
310
|
+
help="Batched spectrograms are smoothed by averaging up to the frequency resolution, specified in Hz.",
|
311
|
+
pconstraints=[EnforceSign.non_negative],
|
312
|
+
),
|
313
|
+
PName.TIME_RANGE: PTemplate(
|
314
|
+
PName.TIME_RANGE,
|
315
|
+
float,
|
316
|
+
nullable=True,
|
317
|
+
help="Batched spectrograms are stitched together until the time range, in seconds, is surpassed.",
|
318
|
+
pconstraints=[EnforceSign.non_negative],
|
319
|
+
),
|
320
|
+
PName.BATCH_SIZE: PTemplate(
|
321
|
+
PName.BATCH_SIZE,
|
322
|
+
int,
|
323
|
+
help="SDR data is collected in batches of this size, specified in seconds.",
|
324
|
+
pconstraints=[EnforceSign.positive],
|
325
|
+
),
|
326
|
+
PName.SAMPLES_PER_STEP: PTemplate(
|
327
|
+
PName.SAMPLES_PER_STEP,
|
328
|
+
int,
|
329
|
+
help="The number of samples taken at each center frequency in the sweep. This may vary slightly from what is specified due to the nature of GNU Radio runtime.",
|
330
|
+
pconstraints=[EnforceSign.positive],
|
331
|
+
),
|
332
|
+
PName.ORIGIN: PTemplate(
|
333
|
+
PName.ORIGIN,
|
334
|
+
str,
|
335
|
+
nullable=True,
|
336
|
+
help="Corresponds to the FITS keyword ORIGIN.",
|
337
|
+
),
|
338
|
+
PName.TELESCOPE: PTemplate(
|
339
|
+
PName.TELESCOPE,
|
340
|
+
str,
|
341
|
+
nullable=True,
|
342
|
+
help="Corresponds to the FITS keyword TELESCOP.",
|
343
|
+
),
|
344
|
+
PName.INSTRUMENT: PTemplate(
|
345
|
+
PName.INSTRUMENT,
|
346
|
+
str,
|
347
|
+
nullable=True,
|
348
|
+
help="Corresponds to the FITS keyword INSTRUME.",
|
349
|
+
),
|
350
|
+
PName.OBJECT: PTemplate(
|
351
|
+
PName.OBJECT,
|
352
|
+
str,
|
353
|
+
nullable=True,
|
354
|
+
help="Corresponds to the FITS keyword OBJECT.",
|
355
|
+
),
|
356
|
+
PName.OBS_LAT: PTemplate(
|
357
|
+
PName.OBS_LAT,
|
358
|
+
float,
|
359
|
+
nullable=True,
|
360
|
+
help="Corresponds to the FITS keyword OBS_LAT.",
|
361
|
+
),
|
362
|
+
PName.OBS_LON: PTemplate(
|
363
|
+
PName.OBS_LON,
|
364
|
+
float,
|
365
|
+
nullable=True,
|
366
|
+
help="Corresponds to the FITS keyword OBS_LONG.",
|
367
|
+
),
|
368
|
+
PName.OBS_ALT: PTemplate(
|
369
|
+
PName.OBS_ALT,
|
370
|
+
float,
|
371
|
+
nullable=True,
|
372
|
+
help="Corresponds to the FITS keyword OBS_ALT.",
|
373
|
+
),
|
374
|
+
PName.AMPLITUDE: PTemplate(
|
375
|
+
PName.AMPLITUDE,
|
376
|
+
float,
|
377
|
+
help="The amplitude of the signal.",
|
378
|
+
),
|
379
|
+
PName.FREQUENCY: PTemplate(
|
380
|
+
PName.FREQUENCY,
|
381
|
+
float,
|
382
|
+
help="The frequency of the signal, in Hz.",
|
383
|
+
),
|
384
|
+
PName.MIN_SAMPLES_PER_STEP: PTemplate(
|
385
|
+
PName.MIN_SAMPLES_PER_STEP,
|
386
|
+
int,
|
387
|
+
help="The number of samples in the shortest step of the staircase.",
|
388
|
+
pconstraints=[EnforceSign.positive],
|
389
|
+
),
|
390
|
+
PName.MAX_SAMPLES_PER_STEP: PTemplate(
|
391
|
+
PName.MAX_SAMPLES_PER_STEP,
|
392
|
+
int,
|
393
|
+
help="The number of samples in the longest step of the staircase.",
|
394
|
+
pconstraints=[EnforceSign.positive],
|
395
|
+
),
|
396
|
+
PName.STEP_INCREMENT: PTemplate(
|
397
|
+
PName.STEP_INCREMENT,
|
398
|
+
int,
|
399
|
+
help="The length by which each step in the staircase is incremented.",
|
400
|
+
pconstraints=[
|
401
|
+
EnforceSign.positive,
|
402
|
+
],
|
403
|
+
),
|
493
404
|
}
|
494
405
|
|
495
406
|
|
@@ -503,9 +414,11 @@ def get_base_ptemplate(
|
|
503
414
|
:return: A deep copy of the corresponding base parameter template, if it exists.
|
504
415
|
"""
|
505
416
|
if pname not in _base_ptemplates:
|
506
|
-
raise KeyError(
|
507
|
-
|
417
|
+
raise KeyError(
|
418
|
+
f"No ptemplate found for the parameter name '{pname}'. "
|
419
|
+
f"Expected one of {list(_base_ptemplates.keys())}"
|
420
|
+
)
|
508
421
|
# A deep copy is required as each receiver instance may mutate the original instance
|
509
422
|
# according to its particular use case. Copying preserves the original instance,
|
510
423
|
# enabling reuse.
|
511
|
-
return deepcopy(
|
424
|
+
return deepcopy(_base_ptemplates[pname])
|