spectre-core 0.0.15__py3-none-any.whl → 0.0.17__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.
@@ -9,7 +9,7 @@ from ._capture_modes import CaptureMode
9
9
  from ._pvalidators import (
10
10
  validate_fixed_center_frequency, validate_non_overlapping_steps, validate_num_samples_per_step,
11
11
  validate_num_steps_per_sweep, validate_nyquist_criterion, validate_step_interval, validate_sweep_interval,
12
- validate_swept_center_frequency, validate_window
12
+ validate_swept_center_frequency, validate_window, validate_sample_rate_with_master_clock_rate
13
13
  )
14
14
  from ._capture_config import CaptureConfig
15
15
  from ._ptemplates import PTemplate, get_base_ptemplate
@@ -29,5 +29,5 @@ __all__ = [
29
29
  "PConstraint", "PConstraint", "Bound", "OneOf", "EnforceSign", "PowerOfTwo", "make_base_capture_template", "PName",
30
30
  "get_base_ptemplate", "BasePConstraint", "validate_fixed_center_frequency", "validate_non_overlapping_steps",
31
31
  "validate_num_samples_per_step", "validate_num_steps_per_sweep", "validate_nyquist_criterion", "validate_step_interval",
32
- "validate_sweep_interval", "validate_swept_center_frequency", "validate_window"
33
- ]
32
+ "validate_sweep_interval", "validate_swept_center_frequency", "validate_window", "validate_sample_rate_with_master_clock_rate"
33
+ ]
@@ -47,4 +47,6 @@ class PName(Enum):
47
47
  OBS_LAT = "obs_lat"
48
48
  OBS_LON = "obs_lon"
49
49
  OBS_ALT = "obs_alt"
50
- NORMALISED_GAIN = "normalised_gain"
50
+ GAIN = "gain"
51
+ MASTER_CLOCK_RATE = "master_clock_rate"
52
+ WIRE_FORMAT = "wire_format"
@@ -300,14 +300,24 @@ _base_ptemplates: dict[PName, PTemplate] = {
300
300
  pconstraints=[
301
301
  EnforceSign.non_positive
302
302
  ]),
303
- PName.NORMALISED_GAIN: PTemplate(PName.NORMALISED_GAIN,
303
+ PName.GAIN: PTemplate(PName.GAIN,
304
304
  float,
305
305
  help = """
306
- The normalised gain value, where 1.0 is mapped to the max gain of the receiver being used.
307
- """,
308
- pconstraints=[
309
- Bound(0.0, 1.0)
310
- ]),
306
+ The gain value for the SDR, in dB
307
+ """
308
+ ),
309
+ PName.MASTER_CLOCK_RATE: PTemplate(PName.MASTER_CLOCK_RATE,
310
+ int,
311
+ help = """
312
+ The primary reference clock for the SDR, specified in Hz.
313
+ """
314
+ ),
315
+ PName.WIRE_FORMAT: PTemplate(PName.WIRE_FORMAT,
316
+ str,
317
+ help = """
318
+ Controls the form of the data over the bus/network.
319
+ """
320
+ ),
311
321
  PName.EVENT_HANDLER_KEY: PTemplate(PName.EVENT_HANDLER_KEY,
312
322
  str,
313
323
  help = """
@@ -184,6 +184,22 @@ def validate_step_interval(
184
184
  f"derived api latency {api_retuning_latency} [s]; you may experience undefined behaviour!")
185
185
 
186
186
 
187
+ def validate_sample_rate_with_master_clock_rate(
188
+ parameters: Parameters,
189
+ ) -> None:
190
+ """Ensure that the master clock rate is an integer multiple of the sample rate.
191
+
192
+ :param parameters: The parameters to be validated.
193
+ :raises ValueError: If the master clock rate is not an integer multiple of the sample rate
194
+ """
195
+ master_clock_rate = cast(int, parameters.get_parameter_value(PName.MASTER_CLOCK_RATE))
196
+ sample_rate = cast(int, parameters.get_parameter_value(PName.SAMPLE_RATE))
197
+
198
+ if master_clock_rate % sample_rate != 0:
199
+ raise ValueError(f"The master clock rate of {master_clock_rate} [Hz] is not an integer "
200
+ f"multiple of the sample rate {sample_rate} [Hz].")
201
+
202
+
187
203
  def validate_fixed_center_frequency(
188
204
  parameters: Parameters
189
205
  ) -> None:
@@ -6,7 +6,8 @@
6
6
  """General `spectre` package configurations."""
7
7
 
8
8
  from ._paths import (
9
- get_spectre_data_dir_path, get_batches_dir_path, get_configs_dir_path, get_logs_dir_path
9
+ get_spectre_data_dir_path, get_batches_dir_path, get_configs_dir_path,
10
+ get_logs_dir_path, trim_spectre_data_dir_path
10
11
  )
11
12
  from ._time_formats import (
12
13
  TimeFormat
@@ -14,5 +15,5 @@ from ._time_formats import (
14
15
 
15
16
  __all__ = [
16
17
  "get_spectre_data_dir_path", "get_batches_dir_path", "get_configs_dir_path", "get_logs_dir_path",
17
- "TimeFormat"
18
+ "TimeFormat", "trim_spectre_data_dir_path"
18
19
  ]
@@ -115,3 +115,35 @@ def get_configs_dir_path(
115
115
  :return: The directory path for configuration files.
116
116
  """
117
117
  return _CONFIGS_DIR_PATH
118
+
119
+
120
+ def trim_spectre_data_dir_path(
121
+ full_path: str
122
+ ) -> str:
123
+ """Remove the `SPECTRE_DATA_DIR_PATH` prefix from a full file path.
124
+
125
+ This function returns the relative path of `full_path` with respect to
126
+ `SPECTRE_DATA_DIR_PATH`. It is useful for trimming absolute paths
127
+ to maintain consistency across different environments where the base
128
+ directory might differ.
129
+
130
+ :param full_path: The full file path to be trimmed.
131
+ :return: The relative path with `SPECTRE_DATA_DIR_PATH` removed.
132
+ """
133
+ return os.path.relpath(full_path, _SPECTRE_DATA_DIR_PATH)
134
+
135
+
136
+ def add_spectre_data_dir_path(
137
+ rel_path: str
138
+ ) -> str:
139
+ """Prepend the `SPECTRE_DATA_DIR_PATH` prefix to a relative file path.
140
+
141
+ This function constructs an absolute path by joining the given relative
142
+ path with `SPECTRE_DATA_DIR_PATH`. It is useful for converting stored
143
+ relative paths back into full paths within the mounted directory.
144
+
145
+ :param rel_path: The relative file path to be appended.
146
+ :return: The full file path prefixed with `SPECTRE_DATA_DIR_PATH`.
147
+ """
148
+ return os.path.join(_SPECTRE_DATA_DIR_PATH, rel_path)
149
+
@@ -226,7 +226,7 @@ class BaseReceiver(ABC):
226
226
  def add_spec(
227
227
  self,
228
228
  name: SpecName,
229
- value: float|int|list[float|int]
229
+ value: Any
230
230
  ) -> None:
231
231
  """
232
232
  Add a hardware specification.
@@ -18,16 +18,24 @@ class SpecName(Enum):
18
18
  Negative values indicate attenuation.
19
19
  :ivar RF_GAIN_UPPER_BOUND: The upper bound for the radio frequency gain, in dB.
20
20
  Negative values indicate attenuation.
21
+ :ivar GAIN_UPPER_BOUND: The upper bound for the gain, in dB.
22
+ :ivar WIRE_FORMATS: Supported data types transferred over the bus/network.
23
+ :ivar MASTER_CLOCK_RATE_LOWER_BOUND: The lower bound for the SDR reference clock rate, in Hz.
24
+ :ivar MASTER_CLOCK_RATE_UPPER_BOUND: The upper bound for the SDR reference clock rate, in Hz.
21
25
  :ivar API_RETUNING_LATENCY: An empirical estimate of the delay between issuing a command
22
26
  for a receiver to retune its center frequency and the actual physical update of the center frequency.
23
27
  """
24
- FREQUENCY_LOWER_BOUND = "frequency_lower_bound"
25
- FREQUENCY_UPPER_BOUND = "frequency_upper_bound"
26
- SAMPLE_RATE_LOWER_BOUND = "sample_rate_lower_bound"
27
- SAMPLE_RATE_UPPER_BOUND = "sample_rate_upper_bound"
28
- BANDWIDTH_LOWER_BOUND = "bandwidth_lower_bound"
29
- BANDWIDTH_UPPER_BOUND = "bandwidth_upper_bound"
30
- BANDWIDTH_OPTIONS = "bandwidth_options"
31
- IF_GAIN_UPPER_BOUND = "if_gain_upper_bound"
32
- RF_GAIN_UPPER_BOUND = "rf_gain_upper_bound"
33
- API_RETUNING_LATENCY = "api_retuning_latency"
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"
39
+ MASTER_CLOCK_RATE_LOWER_BOUND = "master_clock_rate_lower_bound"
40
+ MASTER_CLOCK_RATE_UPPER_BOUND = "master_clock_rate_upper_bound"
41
+ API_RETUNING_LATENCY = "api_retuning_latency"
@@ -6,8 +6,8 @@ from dataclasses import dataclass
6
6
 
7
7
  from ._receiver_names import ReceiverName
8
8
  from ._usrp import (
9
- get_pvalidator_fixed_center_frequency,
10
- get_capture_template_fixed_center_frequency
9
+ get_pvalidator_fixed_center_frequency, get_pvalidator_swept_center_frequency,
10
+ get_capture_template_fixed_center_frequency, get_capture_template_swept_center_frequency
11
11
  )
12
12
  from .gr._usrp import CaptureMethod
13
13
  from .._spec_names import SpecName
@@ -18,6 +18,7 @@ from .._register import register_receiver
18
18
  class Mode:
19
19
  """An operating mode for the `B200mini` receiver."""
20
20
  FIXED_CENTER_FREQUENCY = "fixed_center_frequency"
21
+ SWEPT_CENTER_FREQUENCY = "swept_center_frequency"
21
22
 
22
23
 
23
24
  @register_receiver(ReceiverName.B200MINI)
@@ -26,12 +27,17 @@ class B200mini(BaseReceiver):
26
27
  def _add_specs(
27
28
  self
28
29
  ) -> None:
29
- self.add_spec( SpecName.SAMPLE_RATE_LOWER_BOUND, 200e3 )
30
- self.add_spec( SpecName.SAMPLE_RATE_UPPER_BOUND, 56e6 )
31
- self.add_spec( SpecName.FREQUENCY_LOWER_BOUND , 70e6 )
32
- self.add_spec( SpecName.FREQUENCY_UPPER_BOUND , 6e9 )
33
- self.add_spec( SpecName.BANDWIDTH_LOWER_BOUND , 200e3 )
34
- self.add_spec( SpecName.BANDWIDTH_UPPER_BOUND , 56e6 )
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
35
41
 
36
42
 
37
43
  def _add_capture_methods(
@@ -39,6 +45,8 @@ class B200mini(BaseReceiver):
39
45
  ) -> None:
40
46
  self.add_capture_method(Mode.FIXED_CENTER_FREQUENCY,
41
47
  CaptureMethod.fixed_center_frequency)
48
+ self.add_capture_method(Mode.SWEPT_CENTER_FREQUENCY,
49
+ CaptureMethod.swept_center_frequency)
42
50
 
43
51
 
44
52
  def _add_capture_templates(
@@ -46,6 +54,8 @@ class B200mini(BaseReceiver):
46
54
  ) -> None:
47
55
  self.add_capture_template(Mode.FIXED_CENTER_FREQUENCY,
48
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))
49
59
 
50
60
 
51
61
  def _add_pvalidators(
@@ -53,6 +63,8 @@ class B200mini(BaseReceiver):
53
63
  ) -> None:
54
64
  self.add_pvalidator(Mode.FIXED_CENTER_FREQUENCY,
55
65
  get_pvalidator_fixed_center_frequency(self))
66
+ self.add_pvalidator(Mode.SWEPT_CENTER_FREQUENCY,
67
+ get_pvalidator_swept_center_frequency(self))
56
68
 
57
69
 
58
70
 
@@ -7,6 +7,7 @@ from typing import Callable, overload
7
7
  from spectre_core.capture_configs import (
8
8
  CaptureTemplate, CaptureMode, Parameters, Bound, PName,
9
9
  get_base_capture_template, get_base_ptemplate, OneOf,
10
+ validate_sample_rate_with_master_clock_rate,
10
11
  validate_fixed_center_frequency, validate_swept_center_frequency
11
12
  )
12
13
  from .._base import BaseReceiver
@@ -18,6 +19,17 @@ def get_pvalidator_fixed_center_frequency(
18
19
  ) -> Callable[[Parameters], None]:
19
20
  def pvalidator(parameters: Parameters) -> None:
20
21
  validate_fixed_center_frequency(parameters)
22
+ validate_sample_rate_with_master_clock_rate(parameters)
23
+ return pvalidator
24
+
25
+
26
+ def get_pvalidator_swept_center_frequency(
27
+ usrp_receiver: BaseReceiver
28
+ ) -> Callable[[Parameters], None]:
29
+ def pvalidator(parameters: Parameters) -> None:
30
+ validate_swept_center_frequency(parameters,
31
+ usrp_receiver.get_spec(SpecName.API_RETUNING_LATENCY))
32
+ validate_sample_rate_with_master_clock_rate(parameters)
21
33
  return pvalidator
22
34
 
23
35
 
@@ -27,17 +39,22 @@ def get_capture_template_fixed_center_frequency(
27
39
 
28
40
  capture_template = get_base_capture_template( CaptureMode.FIXED_CENTER_FREQUENCY )
29
41
  capture_template.add_ptemplate( get_base_ptemplate(PName.BANDWIDTH) )
30
- capture_template.add_ptemplate( get_base_ptemplate(PName.NORMALISED_GAIN) )
42
+ capture_template.add_ptemplate( get_base_ptemplate(PName.GAIN) )
43
+ capture_template.add_ptemplate( get_base_ptemplate(PName.WIRE_FORMAT) )
44
+ capture_template.add_ptemplate( get_base_ptemplate(PName.MASTER_CLOCK_RATE) )
31
45
 
46
+ # TODO: Delegate defaults to receiver subclasses. Currently, these are sensible defaults for the b200mini
32
47
  capture_template.set_defaults(
33
- (PName.BATCH_SIZE, 3.0),
48
+ (PName.BATCH_SIZE, 4.0),
34
49
  (PName.CENTER_FREQUENCY, 95800000),
35
- (PName.SAMPLE_RATE, 1000000),
36
- (PName.BANDWIDTH, 1000000),
50
+ (PName.SAMPLE_RATE, 2000000),
51
+ (PName.BANDWIDTH, 2000000),
37
52
  (PName.WINDOW_HOP, 512),
38
53
  (PName.WINDOW_SIZE, 1024),
39
54
  (PName.WINDOW_TYPE, "blackman"),
40
- (PName.NORMALISED_GAIN, 0.3),
55
+ (PName.GAIN, 35),
56
+ (PName.WIRE_FORMAT, "sc16"),
57
+ (PName.MASTER_CLOCK_RATE, 40e6)
41
58
  )
42
59
 
43
60
  capture_template.add_pconstraint(
@@ -67,4 +84,122 @@ def get_capture_template_fixed_center_frequency(
67
84
  )
68
85
  ]
69
86
  )
87
+ capture_template.add_pconstraint(
88
+ PName.GAIN,
89
+ [
90
+ Bound(
91
+ lower_bound=0,
92
+ upper_bound=usrp_receiver.get_spec( SpecName.GAIN_UPPER_BOUND )
93
+ )
94
+ ]
95
+ )
96
+ capture_template.add_pconstraint(
97
+ PName.WIRE_FORMAT,
98
+ [
99
+ OneOf(
100
+ usrp_receiver.get_spec( SpecName.WIRE_FORMATS )
101
+ )
102
+ ]
103
+ )
104
+ capture_template.add_pconstraint(
105
+ PName.MASTER_CLOCK_RATE,
106
+ [
107
+ Bound(
108
+ lower_bound=usrp_receiver.get_spec( SpecName.MASTER_CLOCK_RATE_LOWER_BOUND ),
109
+ upper_bound=usrp_receiver.get_spec( SpecName.MASTER_CLOCK_RATE_UPPER_BOUND )
110
+ )
111
+ ]
112
+ )
113
+ return capture_template
114
+
115
+
116
+ def get_capture_template_swept_center_frequency(
117
+ usrp_receiver: BaseReceiver
118
+ ) -> CaptureTemplate:
119
+
120
+ capture_template = get_base_capture_template( CaptureMode.SWEPT_CENTER_FREQUENCY )
121
+ capture_template.add_ptemplate( get_base_ptemplate(PName.BANDWIDTH) )
122
+ capture_template.add_ptemplate( get_base_ptemplate(PName.GAIN) )
123
+ capture_template.add_ptemplate( get_base_ptemplate(PName.WIRE_FORMAT) )
124
+ capture_template.add_ptemplate( get_base_ptemplate(PName.MASTER_CLOCK_RATE) )
125
+
126
+ # TODO: Delegate defaults to receiver subclasses. Currently, these are sensible defaults for the b200mini
127
+ capture_template.set_defaults(
128
+ (PName.BATCH_SIZE, 4.0),
129
+ (PName.MIN_FREQUENCY, 95000000),
130
+ (PName.MAX_FREQUENCY, 105000000),
131
+ (PName.SAMPLES_PER_STEP, 30000),
132
+ (PName.FREQUENCY_STEP, 2000000),
133
+ (PName.SAMPLE_RATE, 2000000),
134
+ (PName.BANDWIDTH, 2000000),
135
+ (PName.WINDOW_HOP, 512),
136
+ (PName.WINDOW_SIZE, 1024),
137
+ (PName.WINDOW_TYPE, "blackman"),
138
+ (PName.GAIN, 35),
139
+ (PName.WIRE_FORMAT, "sc16"),
140
+ (PName.MASTER_CLOCK_RATE, 40e6)
141
+ )
142
+
143
+ capture_template.add_pconstraint(
144
+ PName.MIN_FREQUENCY,
145
+ [
146
+ Bound(
147
+ lower_bound=usrp_receiver.get_spec(SpecName.FREQUENCY_LOWER_BOUND),
148
+ upper_bound=usrp_receiver.get_spec(SpecName.FREQUENCY_UPPER_BOUND)
149
+ )
150
+ ]
151
+ )
152
+ capture_template.add_pconstraint(
153
+ PName.MAX_FREQUENCY,
154
+ [
155
+ Bound(
156
+ lower_bound=usrp_receiver.get_spec(SpecName.FREQUENCY_LOWER_BOUND),
157
+ upper_bound=usrp_receiver.get_spec(SpecName.FREQUENCY_UPPER_BOUND)
158
+ )
159
+ ]
160
+ )
161
+ capture_template.add_pconstraint(
162
+ PName.SAMPLE_RATE,
163
+ [
164
+ Bound(
165
+ lower_bound=usrp_receiver.get_spec(SpecName.SAMPLE_RATE_LOWER_BOUND),
166
+ upper_bound=usrp_receiver.get_spec(SpecName.SAMPLE_RATE_UPPER_BOUND)
167
+ )
168
+ ]
169
+ )
170
+ capture_template.add_pconstraint(
171
+ PName.BANDWIDTH,
172
+ [
173
+ Bound(
174
+ lower_bound=usrp_receiver.get_spec(SpecName.BANDWIDTH_LOWER_BOUND),
175
+ upper_bound=usrp_receiver.get_spec(SpecName.BANDWIDTH_UPPER_BOUND),
176
+ )
177
+ ]
178
+ )
179
+ capture_template.add_pconstraint(
180
+ PName.GAIN,
181
+ [
182
+ Bound(
183
+ lower_bound=0,
184
+ upper_bound=usrp_receiver.get_spec( SpecName.GAIN_UPPER_BOUND )
185
+ )
186
+ ]
187
+ )
188
+ capture_template.add_pconstraint(
189
+ PName.WIRE_FORMAT,
190
+ [
191
+ OneOf(
192
+ usrp_receiver.get_spec( SpecName.WIRE_FORMATS )
193
+ )
194
+ ]
195
+ )
196
+ capture_template.add_pconstraint(
197
+ PName.MASTER_CLOCK_RATE,
198
+ [
199
+ Bound(
200
+ lower_bound=usrp_receiver.get_spec( SpecName.MASTER_CLOCK_RATE_LOWER_BOUND ),
201
+ upper_bound=usrp_receiver.get_spec( SpecName.MASTER_CLOCK_RATE_UPPER_BOUND )
202
+ )
203
+ ]
204
+ )
70
205
  return capture_template
@@ -6,6 +6,9 @@ from functools import partial
6
6
  from dataclasses import dataclass
7
7
  import time
8
8
 
9
+ from logging import getLogger
10
+ _LOGGER = getLogger(__name__)
11
+
9
12
  from spectre_core.capture_configs import Parameters, PName
10
13
  from spectre_core.config import get_batches_dir_path
11
14
  from ._base import capture, spectre_top_block
@@ -21,20 +24,24 @@ class _fixed_center_frequency(spectre_top_block):
21
24
  from gnuradio import spectre
22
25
  from gnuradio import uhd
23
26
 
24
- # Variables
25
- sample_rate = parameters.get_parameter_value(PName.SAMPLE_RATE)
26
- normalised_gain = parameters.get_parameter_value(PName.NORMALISED_GAIN)
27
- center_freq = parameters.get_parameter_value(PName.CENTER_FREQUENCY)
28
- batch_size = parameters.get_parameter_value(PName.BATCH_SIZE)
29
- bandwidth = parameters.get_parameter_value(PName.BANDWIDTH)
27
+ # Unpack capture config parameters
28
+ sample_rate = parameters.get_parameter_value(PName.SAMPLE_RATE)
29
+ gain = parameters.get_parameter_value(PName.GAIN)
30
+ center_freq = parameters.get_parameter_value(PName.CENTER_FREQUENCY)
31
+ master_clock_rate = parameters.get_parameter_value(PName.MASTER_CLOCK_RATE)
32
+ wire_format = parameters.get_parameter_value(PName.WIRE_FORMAT)
33
+ batch_size = parameters.get_parameter_value(PName.BATCH_SIZE)
34
+ bandwidth = parameters.get_parameter_value(PName.BANDWIDTH)
30
35
 
31
36
  # Blocks
37
+ master_clock_rate = f"master_clock_rate={master_clock_rate}"
32
38
  self.uhd_usrp_source_0 = uhd.usrp_source(
33
- ",".join(("", '')),
39
+ ",".join(("", '', master_clock_rate)),
34
40
  uhd.stream_args(
35
41
  cpu_format="fc32",
42
+ otw_format=wire_format,
36
43
  args='',
37
- channels=list(range(0,1)),
44
+ channels=[0],
38
45
  ),
39
46
  )
40
47
  self.uhd_usrp_source_0.set_samp_rate(sample_rate)
@@ -44,12 +51,14 @@ class _fixed_center_frequency(spectre_top_block):
44
51
  self.uhd_usrp_source_0.set_antenna("RX2", 0)
45
52
  self.uhd_usrp_source_0.set_bandwidth(bandwidth, 0)
46
53
  self.uhd_usrp_source_0.set_rx_agc(False, 0)
47
- self.uhd_usrp_source_0.set_normalized_gain(normalised_gain, 0)
54
+ self.uhd_usrp_source_0.set_auto_dc_offset(False, 0)
55
+ self.uhd_usrp_source_0.set_auto_iq_balance(False, 0)
56
+ self.uhd_usrp_source_0.set_gain(gain, 0)
48
57
  self.spectre_batched_file_sink_0 = spectre.batched_file_sink(get_batches_dir_path(),
49
58
  tag,
50
59
  batch_size,
51
60
  sample_rate, False,
52
- 'freq',
61
+ 'rx_freq',
53
62
  0)
54
63
 
55
64
 
@@ -57,6 +66,74 @@ class _fixed_center_frequency(spectre_top_block):
57
66
  self.connect((self.uhd_usrp_source_0, 0), (self.spectre_batched_file_sink_0, 0))
58
67
 
59
68
 
69
+ class _swept_center_frequency(spectre_top_block):
70
+ def flowgraph(
71
+ self,
72
+ tag: str,
73
+ parameters: Parameters
74
+ ) -> None:
75
+ # OOT module inline imports
76
+ from gnuradio import spectre
77
+ from gnuradio import uhd
78
+
79
+ # Unpack capture config parameters
80
+ sample_rate = parameters.get_parameter_value(PName.SAMPLE_RATE)
81
+ bandwidth = parameters.get_parameter_value(PName.BANDWIDTH)
82
+ min_frequency = parameters.get_parameter_value(PName.MIN_FREQUENCY)
83
+ max_frequency = parameters.get_parameter_value(PName.MAX_FREQUENCY)
84
+ frequency_step = parameters.get_parameter_value(PName.FREQUENCY_STEP)
85
+ samples_per_step = parameters.get_parameter_value(PName.SAMPLES_PER_STEP)
86
+ master_clock_rate = parameters.get_parameter_value(PName.MASTER_CLOCK_RATE)
87
+ master_clock_rate = master_clock_rate = parameters.get_parameter_value(PName.MASTER_CLOCK_RATE)
88
+ wire_format = parameters.get_parameter_value(PName.WIRE_FORMAT)
89
+ gain = parameters.get_parameter_value(PName.GAIN)
90
+ batch_size = parameters.get_parameter_value(PName.BATCH_SIZE)
91
+
92
+ # Blocks
93
+ _LOGGER.warning(f"USRP frequency sweep modes will not work as expected until a known bug is fixed in the USRP source block. "
94
+ f"Please refer to this GitHub issue for more information: https://github.com/gnuradio/gnuradio/issues/7725")
95
+ master_clock_rate = f"master_clock_rate={master_clock_rate}"
96
+ self.uhd_usrp_source_0 = uhd.usrp_source(
97
+ ",".join(("", '', master_clock_rate)),
98
+ uhd.stream_args(
99
+ cpu_format="fc32",
100
+ otw_format=wire_format,
101
+ args='',
102
+ channels=[0],
103
+ ),
104
+ )
105
+ self.uhd_usrp_source_0.set_samp_rate(sample_rate)
106
+ self.uhd_usrp_source_0.set_time_now(uhd.time_spec(time.time()), uhd.ALL_MBOARDS)
107
+ self.uhd_usrp_source_0.set_center_freq(min_frequency, 0)
108
+ self.uhd_usrp_source_0.set_antenna("RX2", 0)
109
+ self.uhd_usrp_source_0.set_bandwidth(bandwidth, 0)
110
+ self.uhd_usrp_source_0.set_rx_agc(False, 0)
111
+ self.uhd_usrp_source_0.set_auto_dc_offset(False, 0)
112
+ self.uhd_usrp_source_0.set_auto_iq_balance(False, 0)
113
+ self.uhd_usrp_source_0.set_gain(gain, 0)
114
+
115
+ self.spectre_sweep_driver_0 = spectre.sweep_driver(min_frequency,
116
+ max_frequency,
117
+ frequency_step,
118
+ sample_rate,
119
+ samples_per_step,
120
+ 'freq')
121
+
122
+ self.spectre_batched_file_sink_0 = spectre.batched_file_sink(get_batches_dir_path(),
123
+ tag,
124
+ batch_size,
125
+ sample_rate,
126
+ True,
127
+ 'rx_freq',
128
+ min_frequency)
129
+
130
+ # Connections
131
+ self.msg_connect((self.spectre_sweep_driver_0, 'freq'), (self.uhd_usrp_source_0, 'command'))
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
+
60
136
  @dataclass(frozen=True)
61
137
  class CaptureMethod:
62
138
  fixed_center_frequency = partial(capture, top_block_cls=_fixed_center_frequency)
139
+ swept_center_frequency = partial(capture, top_block_cls=_swept_center_frequency, max_noutput_items=1024)
@@ -8,7 +8,9 @@ import shutil
8
8
  import gzip
9
9
  from datetime import datetime
10
10
 
11
- from spectre_core.config import get_spectre_data_dir_path, get_batches_dir_path, TimeFormat
11
+ from spectre_core.config import (
12
+ get_spectre_data_dir_path, get_batches_dir_path, TimeFormat, trim_spectre_data_dir_path
13
+ )
12
14
 
13
15
  from enum import Enum
14
16
 
@@ -129,30 +131,37 @@ def _get_batch_path(
129
131
 
130
132
  def _unzip_file_to_batches(
131
133
  gz_path: str
132
- ) -> None:
134
+ ) -> str:
133
135
  """
134
136
  Decompress a `.fit.gz` file and save it as a `.fits` batch file.
135
137
 
136
138
  :param gz_path: Path to the `.fit.gz` file.
139
+ :return: The file path of the newly created batch file, relative to `SPECTRE_DATA_DIR_PATH`.
137
140
  """
138
141
  fits_path = _get_batch_path(gz_path)
139
142
  with gzip.open(gz_path, "rb") as f_in, open(fits_path, "wb") as f_out:
140
143
  shutil.copyfileobj(f_in, f_out)
144
+ return trim_spectre_data_dir_path(f_out.name)
141
145
 
142
146
 
143
147
  def _unzip_to_batches(
144
148
  tmp_dir: str
145
- ) -> None:
149
+ ) -> list[str]:
146
150
  """
147
151
  Decompress all `.gz` files in a temporary directory and save them as `spectre`
148
152
  batch files.
149
153
 
150
154
  :param tmp_dir: Path to the temporary directory containing `.gz` files.
155
+ :return: A list of file names of all newly created batch files, relative to `SPECTRE_DATA_DIR_PATH`.
151
156
  """
157
+ batch_file_names = []
152
158
  for entry in os.scandir(tmp_dir):
153
159
  if entry.is_file() and entry.name.endswith(".gz"):
154
- _unzip_file_to_batches(entry.path)
160
+ batch_file_names.append( _unzip_file_to_batches(entry.path) )
155
161
  os.remove(entry.path)
162
+ shutil.rmtree(tmp_dir)
163
+ return batch_file_names
164
+
156
165
 
157
166
 
158
167
  def _wget_callisto_data(
@@ -186,7 +195,7 @@ def download_callisto_data(
186
195
  year: int,
187
196
  month: int,
188
197
  day: int
189
- ) -> None:
198
+ ) -> list[str]:
190
199
  """
191
200
  Download and decompress e-Callisto FITS files, saving them as `spectre` batch files.
192
201
 
@@ -194,6 +203,7 @@ def download_callisto_data(
194
203
  :param year: Year of the observation.
195
204
  :param month: Month of the observation.
196
205
  :param day: Day of the observation.
206
+ :return: A list of file names of all newly created batch files, relative to `SPECTRE_DATA_DIR_PATH`.
197
207
  """
198
208
  tmp_dir = os.path.join(get_spectre_data_dir_path(), "tmp")
199
209
  # if there are any residual files in the temporary directory, remove them.
@@ -202,5 +212,4 @@ def download_callisto_data(
202
212
  os.makedirs(tmp_dir, exist_ok=True)
203
213
 
204
214
  _wget_callisto_data(instrument_code.value, year, month, day, tmp_dir)
205
- _unzip_to_batches(tmp_dir)
206
- shutil.rmtree(tmp_dir)
215
+ return sorted( _unzip_to_batches(tmp_dir) )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: spectre-core
3
- Version: 0.0.15
3
+ Version: 0.0.17
4
4
  Summary: The core Python package used by the spectre program.
5
5
  Maintainer-email: Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -11,17 +11,17 @@ spectre_core/batches/_register.py,sha256=dSQC8KXj_jG8EiPwmKPdV0HSSalIZLaWt-8E29s
11
11
  spectre_core/batches/plugins/_batch_keys.py,sha256=8v0KE1n0NAQX0i9SwwB4Lgkct7Q_jna-H5S0Gs6p1qg,544
12
12
  spectre_core/batches/plugins/_callisto.py,sha256=ijm-VzGGlLQJjB2eQWw-04R6belCJ_NzSL9Jr7VTu2Q,6259
13
13
  spectre_core/batches/plugins/_iq_stream.py,sha256=DSto5ZzPk7A4VAe_HUAKNd2M9NuWqxcL--_Vneo08Bc,12583
14
- spectre_core/capture_configs/__init__.py,sha256=sUgwilZvQHAexAw_wao49qoBnu0CEBHIicI1kNfvCHg,1645
14
+ spectre_core/capture_configs/__init__.py,sha256=bhwp1Kf2llzd8HpkMPxeM_ZJoIoCFLQoMZJ44AAH6s0,1738
15
15
  spectre_core/capture_configs/_capture_config.py,sha256=ngbIzySgjsgBRJyrfgYZrJtr0wqcKDn8xBH0T1vi-yY,4546
16
16
  spectre_core/capture_configs/_capture_modes.py,sha256=uFBMwHYJCDqqQfYJvAUKzKXTmSBANRZMLlRSKV8WRb8,898
17
17
  spectre_core/capture_configs/_capture_templates.py,sha256=nSAxhOh1DeBzYY16evgOTkDuxRugGG5weJsICUouLPQ,10353
18
18
  spectre_core/capture_configs/_parameters.py,sha256=9KoNuwzDKtnyeju53fkImi1SeUjDn89cNwDL8zxX-YU,5563
19
19
  spectre_core/capture_configs/_pconstraints.py,sha256=bnl1m6M9iyo5KOsPKT_arwrrAZbxRKXVwTHQACzvs2g,5227
20
- spectre_core/capture_configs/_pnames.py,sha256=xqBbaR6Hd6NdzGOZU7DDlKYol02HqW8RAjbnhrXIgAk,1898
21
- spectre_core/capture_configs/_ptemplates.py,sha256=MVx_A2wy8b9zyiAHb2F5LLuYYarkTdv9r-dvMn2C_Fw,25068
22
- spectre_core/capture_configs/_pvalidators.py,sha256=0W-OMDY1lifRPonwgEAwoMYkA0PWbqlK5nE0zsYVcTw,9596
23
- spectre_core/config/__init__.py,sha256=CVddibAIWU4cNerXCxfeUn_cvnWWDBm4pWeUifqM6Ko,502
24
- spectre_core/config/_paths.py,sha256=Qn0KVe27P6Bo65MfHe4LpH_ryPvLgbTxKjc4MTw1BB8,4090
20
+ spectre_core/capture_configs/_pnames.py,sha256=3bJhT4kM5WuiH9SSs4UyBcq_mDybzx-bRiWJcIOqeLA,1975
21
+ spectre_core/capture_configs/_ptemplates.py,sha256=Pepzs7eq31WPdTYmIICJjIVOzf-j5LdA2SD_f2RUZ54,25609
22
+ spectre_core/capture_configs/_pvalidators.py,sha256=fRlFL3rTIpDU2G4iUKp3Lb_jFX5ddHNuUbY5hTzZQQg,10325
23
+ spectre_core/config/__init__.py,sha256=TwQAiDUJLWuwx4IFlStG7Mvb9EFU3u82z5ilPfVH6e0,565
24
+ spectre_core/config/_paths.py,sha256=k9jyPlaFHlM2pAwqPWlpivdc0jCiFFpy4tOny1uxc64,5224
25
25
  spectre_core/config/_time_formats.py,sha256=gS0j5zIvBhnV7KMYvTloloIbVwmCYn8MMKn3zNeQ4Xc,857
26
26
  spectre_core/jobs/__init__.py,sha256=WKTvxvpciedm6tsKjU02iXJhIdNsMDt-BnMVwVme2Bo,412
27
27
  spectre_core/jobs/_jobs.py,sha256=gGpxsLZZ7EdXBYGH-r_pKnRGWSapr78E5SK_VnulaGg,3844
@@ -46,33 +46,33 @@ spectre_core/post_processing/plugins/_event_handler_keys.py,sha256=LPA71kKsaLPyT
46
46
  spectre_core/post_processing/plugins/_fixed_center_frequency.py,sha256=24LB3iDMa2KvgM7jyRnEr7Y45VK46bUT7Nj8bXGiGwc,5231
47
47
  spectre_core/post_processing/plugins/_swept_center_frequency.py,sha256=fzPAZ4zK1DRAHushUB-JS2IgKAuXyP4hdBLZJX6jBmo,20971
48
48
  spectre_core/receivers/__init__.py,sha256=uT3XNn12gSfK_M_GE__sK-TRWra92qkttnUJ-_6uViE,714
49
- spectre_core/receivers/_base.py,sha256=6uilcdMRq0lw4s3IuyWVT_sUJ7fS9va1qUOHuqW9vg4,8993
49
+ spectre_core/receivers/_base.py,sha256=PSC8XWnlVyxkyLa_64Haq4bZTTIxGf42_X8z8_9gYng,8972
50
50
  spectre_core/receivers/_factory.py,sha256=xViruRYb9kFjndY_GmhK5vNQ0VxCE3rbKB3uzqtp_zE,2018
51
51
  spectre_core/receivers/_register.py,sha256=jWS3Q_ZOZcqUFunxJwR5VRZN4_eS3LzcP-5edQdmj4c,1366
52
- spectre_core/receivers/_spec_names.py,sha256=SraBJw2VvO7gZYFEVO8byH_-bp8kpVQDQNhaXrzcLEE,1812
52
+ spectre_core/receivers/_spec_names.py,sha256=V370aeclNqW0hGdbx6C8v61GPnPDkSMol692igv0Aq4,2446
53
53
  spectre_core/receivers/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
- spectre_core/receivers/plugins/_b200mini.py,sha256=gpCnyUpNonFs-0sGSlub_oPTFpIIUqGhm39DB8s8RTY,1884
54
+ spectre_core/receivers/plugins/_b200mini.py,sha256=l0baAg6tRdAfT7N1eAmHoQ9fJlKQO8-AsPZ7YAyc8t4,2890
55
55
  spectre_core/receivers/plugins/_receiver_names.py,sha256=b8cUln47Ya8rr8vnnHQEGa7j9Hf-hJsNbTNtGuZaWlA,498
56
56
  spectre_core/receivers/plugins/_rsp1a.py,sha256=zgPemoRjd93CvI9bRg7PHzgAUHB9xXg5LCvkLHa3jbI,2641
57
57
  spectre_core/receivers/plugins/_rspduo.py,sha256=Sim1TXcG_g1ohWKwvMk7XzrQC8NGydCMGZEf9hhvX-0,3230
58
58
  spectre_core/receivers/plugins/_sdrplay_receiver.py,sha256=bdfjGvKSFW_jfQFIQQcIIf8UfbuMwW04SK6YMNMIINI,5737
59
59
  spectre_core/receivers/plugins/_test.py,sha256=t8oE4zQLYYWJV6SMIZAlNHs9mig263QJmP6XRLyF0RU,8277
60
- spectre_core/receivers/plugins/_usrp.py,sha256=QAhtdhkknL5C7dvY6SECtsG35FuYpXK6zQqgG-ooklE,2416
60
+ spectre_core/receivers/plugins/_usrp.py,sha256=Z0KxOcreic4Bxefeyy6xJ8ips8Q76XBiQcOui56QClU,7603
61
61
  spectre_core/receivers/plugins/gr/__init__.py,sha256=oFSWmGoXQLK5X5xHvWzTdNr9amuaiiGjZirXZVogACU,154
62
62
  spectre_core/receivers/plugins/gr/_base.py,sha256=woFF6498aLIDf4EC7aD-TolY9LtZBqlLy-Vai_gfIvc,2571
63
63
  spectre_core/receivers/plugins/gr/_rsp1a.py,sha256=JLMRCNouSblNizth7EmLrtWvbnpD-5zd7uhc6Pjcopw,6288
64
64
  spectre_core/receivers/plugins/gr/_rspduo.py,sha256=s5g5nOQHiVHCESaHdj2VmgXl_LaiMaqXhTJfUbC7Iew,9811
65
65
  spectre_core/receivers/plugins/gr/_test.py,sha256=YA3JKdJ_CT3J93pqHUjltKrQUoaDXzUloEJEXVHH718,5780
66
- spectre_core/receivers/plugins/gr/_usrp.py,sha256=ZIg-WiiMWYKJbI4KkobeZrgncoRKYnvKlklYBXtmq4Q,2366
66
+ spectre_core/receivers/plugins/gr/_usrp.py,sha256=qhJ701mU5hVI9X7QQN6V4xmrFi2VlDMTz3XfjbCkxRo,6635
67
67
  spectre_core/spectrograms/__init__.py,sha256=AsiOmn9XrAAHUvK-fdhRddAxX4M1Wd6TCtdmxGkl3FA,763
68
68
  spectre_core/spectrograms/_analytical.py,sha256=Axnt9JOJnWXRRuVU5nHPz5QU09KoWqNZkR5NnTX6kMY,11356
69
69
  spectre_core/spectrograms/_array_operations.py,sha256=79vddwWqR5i6OkeD5L_84t8svslpmzW4b8uxbiCQl0I,7553
70
70
  spectre_core/spectrograms/_spectrogram.py,sha256=WhHEt_QpmzspDqYlzdZcJ8CAXxRfs8-JfP0T3NHpjLQ,28205
71
71
  spectre_core/spectrograms/_transform.py,sha256=WZ5jAe3bOpNldxHDSHPf8Q_1ifBdWqXB_mlF6DL1VuE,11734
72
72
  spectre_core/wgetting/__init__.py,sha256=UkS0Z0wuuqpoZ1EL35wJcDpjBiAaZgdZ7064yGESxNE,341
73
- spectre_core/wgetting/_callisto.py,sha256=m9II6ayswrY4h_ST3TodioZ4C865lN_uOF-BozvjZAg,6952
74
- spectre_core-0.0.15.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
75
- spectre_core-0.0.15.dist-info/METADATA,sha256=9PWjpA43grOEKj7uhFP4xVseoSzAmkZrOZkZQYrJTt4,42100
76
- spectre_core-0.0.15.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
77
- spectre_core-0.0.15.dist-info/top_level.txt,sha256=-UsyjpFohXgZpgcZ9QbVeXhsIyF3Am8RxNFNDV_Ta2Y,13
78
- spectre_core-0.0.15.dist-info/RECORD,,
73
+ spectre_core/wgetting/_callisto.py,sha256=B2cb1sqF7SGgHfJ2YDOY-6hbJAqQfwK3NH1NS0Jwfxg,7469
74
+ spectre_core-0.0.17.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
75
+ spectre_core-0.0.17.dist-info/METADATA,sha256=qW29apYQX3YJ39d5Zjc9hlYlSwwQ2E6PdzQ_rv17rH4,42100
76
+ spectre_core-0.0.17.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
77
+ spectre_core-0.0.17.dist-info/top_level.txt,sha256=-UsyjpFohXgZpgcZ9QbVeXhsIyF3Am8RxNFNDV_Ta2Y,13
78
+ spectre_core-0.0.17.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (75.8.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5