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.
- spectre_core/__init__.py +1 -1
- spectre_core/capture_configs/_capture_config.py +2 -0
- spectre_core/plotting/_panel_stack.py +11 -4
- spectre_core/receivers/__init__.py +11 -8
- spectre_core/receivers/_factory.py +16 -11
- spectre_core/receivers/_receiver.py +246 -0
- spectre_core/receivers/_register.py +3 -3
- spectre_core/receivers/{_spec_names.py → _specs.py} +42 -7
- spectre_core/receivers/plugins/_b200mini.py +219 -34
- spectre_core/receivers/plugins/{gr/_usrp.py → _b200mini_gr.py} +38 -61
- spectre_core/receivers/plugins/_custom.py +20 -0
- spectre_core/receivers/plugins/{gr/_base.py → _gr.py} +1 -1
- spectre_core/receivers/plugins/_receiver_names.py +5 -3
- spectre_core/receivers/plugins/_rsp1a.py +38 -43
- spectre_core/receivers/plugins/_rsp1a_gr.py +112 -0
- spectre_core/receivers/plugins/_rspduo.py +47 -57
- spectre_core/receivers/plugins/_rspduo_gr.py +165 -0
- spectre_core/receivers/plugins/_sdrplay_receiver.py +146 -42
- spectre_core/receivers/plugins/_signal_generator.py +225 -0
- spectre_core/receivers/plugins/_signal_generator_gr.py +77 -0
- spectre_core/spectrograms/_analytical.py +18 -18
- {spectre_core-0.0.25.dist-info → spectre_core-0.0.26.dist-info}/METADATA +1 -1
- {spectre_core-0.0.25.dist-info → spectre_core-0.0.26.dist-info}/RECORD +26 -27
- spectre_core/receivers/_base.py +0 -242
- spectre_core/receivers/plugins/_test.py +0 -225
- spectre_core/receivers/plugins/_usrp.py +0 -213
- spectre_core/receivers/plugins/gr/__init__.py +0 -3
- spectre_core/receivers/plugins/gr/_rsp1a.py +0 -127
- spectre_core/receivers/plugins/gr/_rspduo.py +0 -202
- spectre_core/receivers/plugins/gr/_test.py +0 -117
- {spectre_core-0.0.25.dist-info → spectre_core-0.0.26.dist-info}/WHEEL +0 -0
- {spectre_core-0.0.25.dist-info → spectre_core-0.0.26.dist-info}/licenses/LICENSE +0 -0
- {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 .
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
15
|
-
from
|
16
|
-
from
|
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
|
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(
|
224
|
+
class B200mini(Receiver):
|
30
225
|
"""Receiver implementation for the USRP B200mini (https://www.ettus.com/all-products/usrp-b200mini/)"""
|
31
226
|
|
32
|
-
def
|
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
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
-
#
|
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
|
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 .
|
12
|
+
from ._gr import spectre_top_block
|
16
13
|
|
17
14
|
|
18
|
-
class
|
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.
|
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.
|
45
|
-
self.
|
46
|
-
|
47
|
-
self.
|
48
|
-
self.
|
49
|
-
self.
|
50
|
-
self.
|
51
|
-
self.
|
52
|
-
self.
|
53
|
-
self.
|
54
|
-
self.
|
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.
|
53
|
+
self.connect((self.uhd_usrp_source, 0), (self.spectre_batched_file_sink, 0))
|
60
54
|
|
61
55
|
|
62
|
-
class
|
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.
|
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.
|
99
|
-
self.
|
100
|
-
self.
|
101
|
-
self.
|
102
|
-
self.
|
103
|
-
self.
|
104
|
-
self.
|
105
|
-
self.
|
106
|
-
self.
|
107
|
-
|
108
|
-
self.
|
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.
|
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.
|
130
|
-
(self.
|
114
|
+
(self.spectre_sweep_driver, "retune_command"),
|
115
|
+
(self.uhd_usrp_source, "command"),
|
131
116
|
)
|
132
|
-
self.connect((self.
|
133
|
-
self.connect((self.
|
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)
|
@@ -6,15 +6,17 @@ from enum import Enum
|
|
6
6
|
|
7
7
|
|
8
8
|
class ReceiverName(Enum):
|
9
|
-
"""
|
9
|
+
"""The name of a supported receiver.
|
10
10
|
|
11
11
|
:ivar RSP1A: SDRPlay RSP1A
|
12
12
|
:ivar RSPDUO: SDRPlay RSPduo
|
13
|
-
:ivar
|
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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
16
|
-
from
|
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
|
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(
|
32
|
+
class RSP1A(SDRplayReceiver):
|
30
33
|
"""Receiver implementation for the SDRPlay RSP1A (https://www.sdrplay.com/rsp1a/)"""
|
31
34
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
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
|
-
|
46
|
-
|
47
|
-
|
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.
|
50
|
-
|
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
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
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 []
|