spectre-core 0.0.25__py3-none-any.whl → 0.0.26__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 (33) hide show
  1. spectre_core/__init__.py +1 -1
  2. spectre_core/capture_configs/_capture_config.py +2 -0
  3. spectre_core/plotting/_panel_stack.py +11 -4
  4. spectre_core/receivers/__init__.py +11 -8
  5. spectre_core/receivers/_factory.py +16 -11
  6. spectre_core/receivers/_receiver.py +246 -0
  7. spectre_core/receivers/_register.py +3 -3
  8. spectre_core/receivers/{_spec_names.py → _specs.py} +42 -7
  9. spectre_core/receivers/plugins/_b200mini.py +219 -34
  10. spectre_core/receivers/plugins/{gr/_usrp.py → _b200mini_gr.py} +38 -61
  11. spectre_core/receivers/plugins/_custom.py +20 -0
  12. spectre_core/receivers/plugins/{gr/_base.py → _gr.py} +1 -1
  13. spectre_core/receivers/plugins/_receiver_names.py +5 -3
  14. spectre_core/receivers/plugins/_rsp1a.py +38 -43
  15. spectre_core/receivers/plugins/_rsp1a_gr.py +112 -0
  16. spectre_core/receivers/plugins/_rspduo.py +47 -57
  17. spectre_core/receivers/plugins/_rspduo_gr.py +165 -0
  18. spectre_core/receivers/plugins/_sdrplay_receiver.py +146 -42
  19. spectre_core/receivers/plugins/_signal_generator.py +225 -0
  20. spectre_core/receivers/plugins/_signal_generator_gr.py +77 -0
  21. spectre_core/spectrograms/_analytical.py +18 -18
  22. {spectre_core-0.0.25.dist-info → spectre_core-0.0.26.dist-info}/METADATA +1 -1
  23. {spectre_core-0.0.25.dist-info → spectre_core-0.0.26.dist-info}/RECORD +26 -27
  24. spectre_core/receivers/_base.py +0 -242
  25. spectre_core/receivers/plugins/_test.py +0 -225
  26. spectre_core/receivers/plugins/_usrp.py +0 -213
  27. spectre_core/receivers/plugins/gr/__init__.py +0 -3
  28. spectre_core/receivers/plugins/gr/_rsp1a.py +0 -127
  29. spectre_core/receivers/plugins/gr/_rspduo.py +0 -202
  30. spectre_core/receivers/plugins/gr/_test.py +0 -117
  31. {spectre_core-0.0.25.dist-info → spectre_core-0.0.26.dist-info}/WHEEL +0 -0
  32. {spectre_core-0.0.25.dist-info → spectre_core-0.0.26.dist-info}/licenses/LICENSE +0 -0
  33. {spectre_core-0.0.25.dist-info → spectre_core-0.0.26.dist-info}/top_level.txt +0 -0
@@ -3,22 +3,217 @@
3
3
  # SPDX-License-Identifier: GPL-3.0-or-later
4
4
 
5
5
  from dataclasses import dataclass
6
+ from functools import partial
7
+ from typing import Callable, Optional
6
8
 
7
- from ._receiver_names import ReceiverName
8
- from ._usrp import (
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,
9
+ from spectre_core.capture_configs import (
10
+ CaptureTemplate,
11
+ CaptureMode,
12
+ Parameters,
13
+ Bound,
14
+ PName,
15
+ OneOf,
16
+ get_base_capture_template,
17
+ get_base_ptemplate,
18
+ validate_fixed_center_frequency,
19
+ validate_swept_center_frequency,
20
+ validate_sample_rate_with_master_clock_rate,
13
21
  )
14
- from .gr._usrp import CaptureMethod
15
- from .._spec_names import SpecName
16
- from .._base import BaseReceiver
22
+
23
+ from ._receiver_names import ReceiverName
24
+ from ._gr import capture
25
+ from ._b200mini_gr import fixed_center_frequency, swept_center_frequency
26
+ from .._receiver import Receiver
27
+ from .._specs import SpecName
17
28
  from .._register import register_receiver
18
29
 
19
30
 
31
+ def _make_pvalidator_fixed_center_frequency(
32
+ receiver: Receiver,
33
+ ) -> Callable[[Parameters], None]:
34
+ def pvalidator(parameters: Parameters) -> None:
35
+ validate_fixed_center_frequency(parameters)
36
+ validate_sample_rate_with_master_clock_rate(parameters)
37
+
38
+ return pvalidator
39
+
40
+
41
+ def _make_pvalidator_swept_center_frequency(
42
+ receiver: Receiver,
43
+ ) -> Callable[[Parameters], None]:
44
+ def pvalidator(parameters: Parameters) -> None:
45
+ validate_swept_center_frequency(
46
+ parameters, receiver.get_spec(SpecName.API_RETUNING_LATENCY)
47
+ )
48
+ validate_sample_rate_with_master_clock_rate(parameters)
49
+
50
+ return pvalidator
51
+
52
+
53
+ def _make_capture_template_fixed_center_frequency(
54
+ receiver: Receiver,
55
+ ) -> CaptureTemplate:
56
+
57
+ capture_template = get_base_capture_template(CaptureMode.FIXED_CENTER_FREQUENCY)
58
+ capture_template.add_ptemplate(get_base_ptemplate(PName.BANDWIDTH))
59
+ capture_template.add_ptemplate(get_base_ptemplate(PName.GAIN))
60
+ capture_template.add_ptemplate(get_base_ptemplate(PName.WIRE_FORMAT))
61
+ capture_template.add_ptemplate(get_base_ptemplate(PName.MASTER_CLOCK_RATE))
62
+
63
+ # TODO: Delegate defaults to receiver subclasses. Currently, these are sensible defaults for the b200mini
64
+ capture_template.set_defaults(
65
+ (PName.BATCH_SIZE, 4.0),
66
+ (PName.CENTER_FREQUENCY, 95800000),
67
+ (PName.SAMPLE_RATE, 2000000),
68
+ (PName.BANDWIDTH, 2000000),
69
+ (PName.WINDOW_HOP, 512),
70
+ (PName.WINDOW_SIZE, 1024),
71
+ (PName.WINDOW_TYPE, "blackman"),
72
+ (PName.GAIN, 35),
73
+ (PName.WIRE_FORMAT, "sc16"),
74
+ (PName.MASTER_CLOCK_RATE, 40e6),
75
+ )
76
+
77
+ capture_template.add_pconstraint(
78
+ PName.CENTER_FREQUENCY,
79
+ [
80
+ Bound(
81
+ lower_bound=receiver.get_spec(SpecName.FREQUENCY_LOWER_BOUND),
82
+ upper_bound=receiver.get_spec(SpecName.FREQUENCY_UPPER_BOUND),
83
+ )
84
+ ],
85
+ )
86
+ capture_template.add_pconstraint(
87
+ PName.SAMPLE_RATE,
88
+ [
89
+ Bound(
90
+ lower_bound=receiver.get_spec(SpecName.SAMPLE_RATE_LOWER_BOUND),
91
+ upper_bound=receiver.get_spec(SpecName.SAMPLE_RATE_UPPER_BOUND),
92
+ )
93
+ ],
94
+ )
95
+ capture_template.add_pconstraint(
96
+ PName.BANDWIDTH,
97
+ [
98
+ Bound(
99
+ lower_bound=receiver.get_spec(SpecName.BANDWIDTH_LOWER_BOUND),
100
+ upper_bound=receiver.get_spec(SpecName.BANDWIDTH_UPPER_BOUND),
101
+ )
102
+ ],
103
+ )
104
+ capture_template.add_pconstraint(
105
+ PName.GAIN,
106
+ [
107
+ Bound(
108
+ lower_bound=0,
109
+ upper_bound=receiver.get_spec(SpecName.GAIN_UPPER_BOUND),
110
+ )
111
+ ],
112
+ )
113
+ capture_template.add_pconstraint(
114
+ PName.WIRE_FORMAT, [OneOf(receiver.get_spec(SpecName.WIRE_FORMATS))]
115
+ )
116
+ capture_template.add_pconstraint(
117
+ PName.MASTER_CLOCK_RATE,
118
+ [
119
+ Bound(
120
+ lower_bound=receiver.get_spec(SpecName.MASTER_CLOCK_RATE_LOWER_BOUND),
121
+ upper_bound=receiver.get_spec(SpecName.MASTER_CLOCK_RATE_UPPER_BOUND),
122
+ )
123
+ ],
124
+ )
125
+ return capture_template
126
+
127
+
128
+ def _make_capture_template_swept_center_frequency(
129
+ receiver: Receiver,
130
+ ) -> CaptureTemplate:
131
+
132
+ capture_template = get_base_capture_template(CaptureMode.SWEPT_CENTER_FREQUENCY)
133
+ capture_template.add_ptemplate(get_base_ptemplate(PName.BANDWIDTH))
134
+ capture_template.add_ptemplate(get_base_ptemplate(PName.GAIN))
135
+ capture_template.add_ptemplate(get_base_ptemplate(PName.WIRE_FORMAT))
136
+ capture_template.add_ptemplate(get_base_ptemplate(PName.MASTER_CLOCK_RATE))
137
+
138
+ # TODO: Delegate defaults to receiver subclasses. Currently, these are sensible defaults for the b200mini
139
+ capture_template.set_defaults(
140
+ (PName.BATCH_SIZE, 4.0),
141
+ (PName.MIN_FREQUENCY, 95000000),
142
+ (PName.MAX_FREQUENCY, 105000000),
143
+ (PName.SAMPLES_PER_STEP, 30000),
144
+ (PName.FREQUENCY_STEP, 2000000),
145
+ (PName.SAMPLE_RATE, 2000000),
146
+ (PName.BANDWIDTH, 2000000),
147
+ (PName.WINDOW_HOP, 512),
148
+ (PName.WINDOW_SIZE, 1024),
149
+ (PName.WINDOW_TYPE, "blackman"),
150
+ (PName.GAIN, 35),
151
+ (PName.WIRE_FORMAT, "sc16"),
152
+ (PName.MASTER_CLOCK_RATE, 40e6),
153
+ )
154
+
155
+ capture_template.add_pconstraint(
156
+ PName.MIN_FREQUENCY,
157
+ [
158
+ Bound(
159
+ lower_bound=receiver.get_spec(SpecName.FREQUENCY_LOWER_BOUND),
160
+ upper_bound=receiver.get_spec(SpecName.FREQUENCY_UPPER_BOUND),
161
+ )
162
+ ],
163
+ )
164
+ capture_template.add_pconstraint(
165
+ PName.MAX_FREQUENCY,
166
+ [
167
+ Bound(
168
+ lower_bound=receiver.get_spec(SpecName.FREQUENCY_LOWER_BOUND),
169
+ upper_bound=receiver.get_spec(SpecName.FREQUENCY_UPPER_BOUND),
170
+ )
171
+ ],
172
+ )
173
+ capture_template.add_pconstraint(
174
+ PName.SAMPLE_RATE,
175
+ [
176
+ Bound(
177
+ lower_bound=receiver.get_spec(SpecName.SAMPLE_RATE_LOWER_BOUND),
178
+ upper_bound=receiver.get_spec(SpecName.SAMPLE_RATE_UPPER_BOUND),
179
+ )
180
+ ],
181
+ )
182
+ capture_template.add_pconstraint(
183
+ PName.BANDWIDTH,
184
+ [
185
+ Bound(
186
+ lower_bound=receiver.get_spec(SpecName.BANDWIDTH_LOWER_BOUND),
187
+ upper_bound=receiver.get_spec(SpecName.BANDWIDTH_UPPER_BOUND),
188
+ )
189
+ ],
190
+ )
191
+ capture_template.add_pconstraint(
192
+ PName.GAIN,
193
+ [
194
+ Bound(
195
+ lower_bound=0,
196
+ upper_bound=receiver.get_spec(SpecName.GAIN_UPPER_BOUND),
197
+ )
198
+ ],
199
+ )
200
+ capture_template.add_pconstraint(
201
+ PName.WIRE_FORMAT, [OneOf(receiver.get_spec(SpecName.WIRE_FORMATS))]
202
+ )
203
+ capture_template.add_pconstraint(
204
+ PName.MASTER_CLOCK_RATE,
205
+ [
206
+ Bound(
207
+ lower_bound=receiver.get_spec(SpecName.MASTER_CLOCK_RATE_LOWER_BOUND),
208
+ upper_bound=receiver.get_spec(SpecName.MASTER_CLOCK_RATE_UPPER_BOUND),
209
+ )
210
+ ],
211
+ )
212
+ return capture_template
213
+
214
+
20
215
  @dataclass(frozen=True)
21
- class Mode:
216
+ class _Mode:
22
217
  """An operating mode for the `B200mini` receiver."""
23
218
 
24
219
  FIXED_CENTER_FREQUENCY = "fixed_center_frequency"
@@ -26,10 +221,12 @@ class Mode:
26
221
 
27
222
 
28
223
  @register_receiver(ReceiverName.B200MINI)
29
- class B200mini(BaseReceiver):
224
+ class B200mini(Receiver):
30
225
  """Receiver implementation for the USRP B200mini (https://www.ettus.com/all-products/usrp-b200mini/)"""
31
226
 
32
- def _add_specs(self) -> None:
227
+ def __init__(self, name: ReceiverName, mode: Optional[str] = None) -> None:
228
+ super().__init__(name, mode)
229
+
33
230
  self.add_spec(SpecName.SAMPLE_RATE_LOWER_BOUND, 200e3)
34
231
  self.add_spec(SpecName.SAMPLE_RATE_UPPER_BOUND, 56e6)
35
232
  self.add_spec(SpecName.FREQUENCY_LOWER_BOUND, 70e6)
@@ -44,28 +241,16 @@ class B200mini(BaseReceiver):
44
241
  SpecName.API_RETUNING_LATENCY, 1e-5
45
242
  ) # TODO: This is a ballpark, pending empirical testing
46
243
 
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),
244
+ self.add_mode(
245
+ _Mode.FIXED_CENTER_FREQUENCY,
246
+ partial(capture, top_block_cls=fixed_center_frequency),
247
+ _make_capture_template_fixed_center_frequency(self),
248
+ _make_pvalidator_fixed_center_frequency(self),
63
249
  )
64
250
 
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)
251
+ self.add_mode(
252
+ _Mode.SWEPT_CENTER_FREQUENCY,
253
+ partial(capture, top_block_cls=swept_center_frequency),
254
+ _make_capture_template_swept_center_frequency(self),
255
+ _make_pvalidator_swept_center_frequency(self),
71
256
  )
@@ -1,25 +1,19 @@
1
- #
2
- # USRP top blocks
3
- #
1
+ # SPDX-FileCopyrightText: © 2024-2025 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
+ # This file is part of SPECTRE
3
+ # SPDX-License-Identifier: GPL-3.0-or-later
4
4
 
5
- from functools import partial
6
- from dataclasses import dataclass
7
5
  import time
8
6
 
9
- from logging import getLogger
10
-
11
- _LOGGER = getLogger(__name__)
7
+ from gnuradio import spectre
8
+ from gnuradio import uhd
12
9
 
13
10
  from spectre_core.capture_configs import Parameters, PName
14
11
  from spectre_core.config import get_batches_dir_path
15
- from ._base import capture, spectre_top_block
12
+ from ._gr import spectre_top_block
16
13
 
17
14
 
18
- class _fixed_center_frequency(spectre_top_block):
15
+ class fixed_center_frequency(spectre_top_block):
19
16
  def flowgraph(self, tag: str, parameters: Parameters) -> None:
20
- # OOT moudle inline imports
21
- from gnuradio import spectre
22
- from gnuradio import uhd
23
17
 
24
18
  # Unpack capture config parameters
25
19
  sample_rate = parameters.get_parameter_value(PName.SAMPLE_RATE)
@@ -32,7 +26,7 @@ class _fixed_center_frequency(spectre_top_block):
32
26
 
33
27
  # Blocks
34
28
  master_clock_rate = f"master_clock_rate={master_clock_rate}"
35
- self.uhd_usrp_source_0 = uhd.usrp_source(
29
+ self.uhd_usrp_sourcespecs.get = uhd.usrp_source(
36
30
  ",".join(("", "", master_clock_rate)),
37
31
  uhd.stream_args(
38
32
  cpu_format="fc32",
@@ -41,30 +35,26 @@ class _fixed_center_frequency(spectre_top_block):
41
35
  channels=[0],
42
36
  ),
43
37
  )
44
- self.uhd_usrp_source_0.set_samp_rate(sample_rate)
45
- self.uhd_usrp_source_0.set_time_now(uhd.time_spec(time.time()), uhd.ALL_MBOARDS)
46
-
47
- self.uhd_usrp_source_0.set_center_freq(center_freq, 0)
48
- self.uhd_usrp_source_0.set_antenna("RX2", 0)
49
- self.uhd_usrp_source_0.set_bandwidth(bandwidth, 0)
50
- self.uhd_usrp_source_0.set_rx_agc(False, 0)
51
- self.uhd_usrp_source_0.set_auto_dc_offset(False, 0)
52
- self.uhd_usrp_source_0.set_auto_iq_balance(False, 0)
53
- self.uhd_usrp_source_0.set_gain(gain, 0)
54
- self.spectre_batched_file_sink_0 = spectre.batched_file_sink(
38
+ self.uhd_usrp_source.set_samp_rate(sample_rate)
39
+ self.uhd_usrp_source.set_time_now(uhd.time_spec(time.time()), uhd.ALL_MBOARDS)
40
+
41
+ self.uhd_usrp_source.set_center_freq(center_freq, 0)
42
+ self.uhd_usrp_source.set_antenna("RX2", 0)
43
+ self.uhd_usrp_source.set_bandwidth(bandwidth, 0)
44
+ self.uhd_usrp_source.set_rx_agc(False, 0)
45
+ self.uhd_usrp_source.set_auto_dc_offset(False, 0)
46
+ self.uhd_usrp_source.set_auto_iq_balance(False, 0)
47
+ self.uhd_usrp_source.set_gain(gain, 0)
48
+ self.spectre_batched_file_sink = spectre.batched_file_sink(
55
49
  get_batches_dir_path(), tag, batch_size, sample_rate, False, "rx_freq", 0
56
50
  )
57
51
 
58
52
  # Connections
59
- self.connect((self.uhd_usrp_source_0, 0), (self.spectre_batched_file_sink_0, 0))
53
+ self.connect((self.uhd_usrp_source, 0), (self.spectre_batched_file_sink, 0))
60
54
 
61
55
 
62
- class _swept_center_frequency(spectre_top_block):
56
+ class swept_center_frequency(spectre_top_block):
63
57
  def flowgraph(self, tag: str, parameters: Parameters) -> None:
64
- # OOT module inline imports
65
- from gnuradio import spectre
66
- from gnuradio import uhd
67
-
68
58
  # Unpack capture config parameters
69
59
  sample_rate = parameters.get_parameter_value(PName.SAMPLE_RATE)
70
60
  bandwidth = parameters.get_parameter_value(PName.BANDWIDTH)
@@ -80,13 +70,8 @@ class _swept_center_frequency(spectre_top_block):
80
70
  gain = parameters.get_parameter_value(PName.GAIN)
81
71
  batch_size = parameters.get_parameter_value(PName.BATCH_SIZE)
82
72
 
83
- # Blocks
84
- _LOGGER.warning(
85
- f"USRP frequency sweep modes will not work as expected until a known bug is fixed in the USRP source block. "
86
- f"Please refer to this GitHub issue for more information: https://github.com/gnuradio/gnuradio/issues/7725"
87
- )
88
73
  master_clock_rate = f"master_clock_rate={master_clock_rate}"
89
- self.uhd_usrp_source_0 = uhd.usrp_source(
74
+ self.uhd_usrp_source = uhd.usrp_source(
90
75
  ",".join(("", "", master_clock_rate)),
91
76
  uhd.stream_args(
92
77
  cpu_format="fc32",
@@ -95,17 +80,17 @@ class _swept_center_frequency(spectre_top_block):
95
80
  channels=[0],
96
81
  ),
97
82
  )
98
- self.uhd_usrp_source_0.set_samp_rate(sample_rate)
99
- self.uhd_usrp_source_0.set_time_now(uhd.time_spec(time.time()), uhd.ALL_MBOARDS)
100
- self.uhd_usrp_source_0.set_center_freq(min_frequency, 0)
101
- self.uhd_usrp_source_0.set_antenna("RX2", 0)
102
- self.uhd_usrp_source_0.set_bandwidth(bandwidth, 0)
103
- self.uhd_usrp_source_0.set_rx_agc(False, 0)
104
- self.uhd_usrp_source_0.set_auto_dc_offset(False, 0)
105
- self.uhd_usrp_source_0.set_auto_iq_balance(False, 0)
106
- self.uhd_usrp_source_0.set_gain(gain, 0)
107
-
108
- self.spectre_sweep_driver_0 = spectre.sweep_driver(
83
+ self.uhd_usrp_source.set_samp_rate(sample_rate)
84
+ self.uhd_usrp_source.set_time_now(uhd.time_spec(time.time()), uhd.ALL_MBOARDS)
85
+ self.uhd_usrp_source.set_center_freq(min_frequency, 0)
86
+ self.uhd_usrp_source.set_antenna("RX2", 0)
87
+ self.uhd_usrp_source.set_bandwidth(bandwidth, 0)
88
+ self.uhd_usrp_source.set_rx_agc(False, 0)
89
+ self.uhd_usrp_source.set_auto_dc_offset(False, 0)
90
+ self.uhd_usrp_source.set_auto_iq_balance(False, 0)
91
+ self.uhd_usrp_source.set_gain(gain, 0)
92
+
93
+ self.spectre_sweep_driver = spectre.sweep_driver(
109
94
  min_frequency,
110
95
  max_frequency,
111
96
  frequency_step,
@@ -114,7 +99,7 @@ class _swept_center_frequency(spectre_top_block):
114
99
  "freq",
115
100
  )
116
101
 
117
- self.spectre_batched_file_sink_0 = spectre.batched_file_sink(
102
+ self.spectre_batched_file_sink = spectre.batched_file_sink(
118
103
  get_batches_dir_path(),
119
104
  tag,
120
105
  batch_size,
@@ -126,16 +111,8 @@ class _swept_center_frequency(spectre_top_block):
126
111
 
127
112
  # Connections
128
113
  self.msg_connect(
129
- (self.spectre_sweep_driver_0, "retune_command"),
130
- (self.uhd_usrp_source_0, "command"),
114
+ (self.spectre_sweep_driver, "retune_command"),
115
+ (self.uhd_usrp_source, "command"),
131
116
  )
132
- self.connect((self.uhd_usrp_source_0, 0), (self.spectre_batched_file_sink_0, 0))
133
- self.connect((self.uhd_usrp_source_0, 0), (self.spectre_sweep_driver_0, 0))
134
-
135
-
136
- @dataclass(frozen=True)
137
- class CaptureMethod:
138
- fixed_center_frequency = partial(capture, top_block_cls=_fixed_center_frequency)
139
- swept_center_frequency = partial(
140
- capture, top_block_cls=_swept_center_frequency, max_noutput_items=1024
141
- )
117
+ self.connect((self.uhd_usrp_source, 0), (self.spectre_batched_file_sink, 0))
118
+ self.connect((self.uhd_usrp_source, 0), (self.spectre_sweep_driver, 0))
@@ -0,0 +1,20 @@
1
+ # SPDX-FileCopyrightText: © 2024-2025 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
2
+ # This file is part of SPECTRE
3
+ # SPDX-License-Identifier: GPL-3.0-or-later
4
+
5
+ from typing import Optional
6
+
7
+ from ._receiver_names import ReceiverName
8
+ from .._register import register_receiver
9
+ from .._receiver import Receiver
10
+
11
+
12
+ @register_receiver(ReceiverName.CUSTOM)
13
+ class CustomReceiver(Receiver):
14
+ """A receiver which starts with no operating modes.
15
+
16
+ Customise by adding modes using the `add_mode` method.
17
+ """
18
+
19
+ def __init__(self, name: ReceiverName, mode: Optional[str] = None) -> None:
20
+ super().__init__(name, mode)
@@ -4,7 +4,7 @@
4
4
 
5
5
  import sys
6
6
  import signal
7
- from typing import Type, TypeVar
7
+ from typing import Type
8
8
 
9
9
  from gnuradio import gr
10
10
 
@@ -6,15 +6,17 @@ from enum import Enum
6
6
 
7
7
 
8
8
  class ReceiverName(Enum):
9
- """A `spectre` supported receiver.
9
+ """The name of a supported receiver.
10
10
 
11
11
  :ivar RSP1A: SDRPlay RSP1A
12
12
  :ivar RSPDUO: SDRPlay RSPduo
13
- :ivar TEST: `spectre` test receiver.
13
+ :ivar SIGNAL_GENERATOR: A synthetic signal generator.
14
14
  :ivar B200MINI: USRP B200mini.
15
+ :ivar CUSTOM: A custom receiver, which starts with no operating modes.
15
16
  """
16
17
 
18
+ SIGNAL_GENERATOR = "signal_generator"
17
19
  RSP1A = "rsp1a"
18
20
  RSPDUO = "rspduo"
19
- TEST = "test"
20
21
  B200MINI = "b200mini"
22
+ CUSTOM = "custom"
@@ -3,22 +3,25 @@
3
3
  # SPDX-License-Identifier: GPL-3.0-or-later
4
4
 
5
5
  from dataclasses import dataclass
6
+ from typing import Optional
7
+ from functools import partial
6
8
 
7
9
  from ._receiver_names import ReceiverName
8
- from .gr._rsp1a import CaptureMethod
9
10
  from ._sdrplay_receiver import (
10
- get_pvalidator_fixed_center_frequency,
11
- get_pvalidator_swept_center_frequency,
12
- get_capture_template_fixed_center_frequency,
13
- get_capture_template_swept_center_frequency,
11
+ SDRplayReceiver,
12
+ make_capture_template_fixed_center_frequency,
13
+ make_capture_template_swept_center_frequency,
14
+ make_pvalidator_fixed_center_frequency,
15
+ make_pvalidator_swept_center_frequency,
14
16
  )
15
- from .._spec_names import SpecName
16
- from .._base import BaseReceiver
17
+ from ._rsp1a_gr import swept_center_frequency, fixed_center_frequency
18
+ from ._receiver_names import ReceiverName
19
+ from ._gr import capture
17
20
  from .._register import register_receiver
18
21
 
19
22
 
20
23
  @dataclass(frozen=True)
21
- class Mode:
24
+ class _Mode:
22
25
  """An operating mode for the `RSP1A` receiver."""
23
26
 
24
27
  FIXED_CENTER_FREQUENCY = "fixed_center_frequency"
@@ -26,44 +29,36 @@ class Mode:
26
29
 
27
30
 
28
31
  @register_receiver(ReceiverName.RSP1A)
29
- class RSP1A(BaseReceiver):
32
+ class RSP1A(SDRplayReceiver):
30
33
  """Receiver implementation for the SDRPlay RSP1A (https://www.sdrplay.com/rsp1a/)"""
31
34
 
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, 10e6)
35
- self.add_spec(SpecName.FREQUENCY_LOWER_BOUND, 1e3)
36
- self.add_spec(SpecName.FREQUENCY_UPPER_BOUND, 2e9)
37
- self.add_spec(SpecName.IF_GAIN_UPPER_BOUND, -20)
38
- self.add_spec(SpecName.RF_GAIN_UPPER_BOUND, 0)
39
- self.add_spec(SpecName.API_RETUNING_LATENCY, 25 * 1e-3)
40
- self.add_spec(
41
- SpecName.BANDWIDTH_OPTIONS,
42
- [200000, 300000, 600000, 1536000, 5000000, 6000000, 7000000, 8000000],
43
- )
35
+ def __init__(self, name: ReceiverName, mode: Optional[str] = None) -> None:
36
+ """Initialise an instance of an `RSP1A`."""
37
+ super().__init__(name, mode)
44
38
 
45
- def _add_capture_methods(self) -> None:
46
- self.add_capture_method(
47
- Mode.FIXED_CENTER_FREQUENCY, CaptureMethod.fixed_center_frequency
39
+ self.add_mode(
40
+ _Mode.FIXED_CENTER_FREQUENCY,
41
+ partial(capture, top_block_cls=fixed_center_frequency),
42
+ make_capture_template_fixed_center_frequency(self),
43
+ make_pvalidator_fixed_center_frequency(self),
48
44
  )
49
- self.add_capture_method(
50
- Mode.SWEPT_CENTER_FREQUENCY, CaptureMethod.swept_center_frequency
45
+ self.add_mode(
46
+ _Mode.SWEPT_CENTER_FREQUENCY,
47
+ partial(
48
+ capture, top_block_cls=swept_center_frequency, max_noutput_items=1024
49
+ ),
50
+ make_capture_template_swept_center_frequency(self),
51
+ make_pvalidator_swept_center_frequency(self),
51
52
  )
52
53
 
53
- def _add_capture_templates(self) -> None:
54
- self.add_capture_template(
55
- Mode.FIXED_CENTER_FREQUENCY,
56
- get_capture_template_fixed_center_frequency(self),
57
- )
58
- self.add_capture_template(
59
- Mode.SWEPT_CENTER_FREQUENCY,
60
- get_capture_template_swept_center_frequency(self),
61
- )
62
-
63
- def _add_pvalidators(self) -> None:
64
- self.add_pvalidator(
65
- Mode.FIXED_CENTER_FREQUENCY, get_pvalidator_fixed_center_frequency(self)
66
- )
67
- self.add_pvalidator(
68
- Mode.SWEPT_CENTER_FREQUENCY, get_pvalidator_swept_center_frequency(self)
69
- )
54
+ def get_rf_gains(self, center_frequency: float) -> list[int]:
55
+ if center_frequency <= 60e6:
56
+ return [0, -6, -12, -18, -37, -42, -61]
57
+ elif center_frequency <= 420e6:
58
+ return [0, -6, -12, -18, -20, -26, -32, -38, -57, -62]
59
+ elif center_frequency <= 1e9:
60
+ return [0, -7, -13, -19, -20, -27, -33, -39, -45, -64]
61
+ elif center_frequency <= 2e9:
62
+ return [0, -6, -12, -20, -26, -32, -38, -43, -62]
63
+ else:
64
+ return []