Skip to content
This repository was archived by the owner on Jul 1, 2025. It is now read-only.

Commit 1c55117

Browse files
committed
refactor to pipeline blocks.
1 parent dad1889 commit 1c55117

File tree

2 files changed

+142
-112
lines changed

2 files changed

+142
-112
lines changed

gamutrf/grscan.py

Lines changed: 122 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ def __init__(
163163
logging.warn(">1s dwell time in stare mode, updates will be slow!")
164164
peak_fft_range = min(peak_fft_range, tune_step_fft)
165165

166+
fft_dir = ""
167+
if write_fft_points:
168+
fft_dir = sample_dir
169+
166170
self.sources, cmd_port, self.workaround_start_hook = get_source(
167171
sdr,
168172
samp_rate,
@@ -175,7 +179,14 @@ def __init__(
175179
dc_ettus_auto_offset=dc_ettus_auto_offset,
176180
)
177181

178-
fft_batch_size, self.fft_blocks = self.get_fft_blocks(
182+
(
183+
fft_batch_size,
184+
self.retune_pre_fft,
185+
self.retune_fft,
186+
self.db_block,
187+
self.sample_block,
188+
self.pipeline_blocks,
189+
) = self.get_pipeline_blocks(
179190
samp_rate,
180191
tune_jitter_hz,
181192
vkfft,
@@ -194,15 +205,37 @@ def __init__(
194205
dc_block_len,
195206
dc_block_long,
196207
correct_iq,
208+
scaling,
209+
db_clamp_floor,
210+
db_clamp_ceil,
211+
fft_dir,
212+
write_samples,
213+
bucket_range,
214+
description,
215+
rotate_secs,
216+
peak_fft_range,
197217
)
198-
self.fft_blocks = self.fft_blocks + self.get_db_blocks(nfft, samp_rate, scaling)
199-
self.last_db_block = self.fft_blocks[-1]
200-
fft_dir = ""
218+
fft_zmq_block_addr = f"tcp://{fft_zmq_addr}:{fft_zmq_port}"
219+
self.pduzmq_block = pduzmq(fft_zmq_block_addr)
220+
logging.info("serving FFT on %s", fft_zmq_block_addr)
221+
222+
if iq_zmq_port:
223+
iq_zmq_block_addr = f"tcp://{iq_zmq_addr}:{iq_zmq_port}"
224+
logging.info("serving I/Q samples and tags on %s", iq_zmq_block_addr)
225+
iq_zmq_block = zeromq.pub_sink(
226+
gr.sizeof_gr_complex,
227+
fft_batch_size * nfft,
228+
iq_zmq_block_addr,
229+
100,
230+
True,
231+
65536,
232+
"",
233+
)
234+
self.connect((self.sample_block, 0), (iq_zmq_block, 0))
235+
201236
self.samples_blocks = []
202237
self.write_samples_block = None
203238
if write_samples:
204-
if write_fft_points:
205-
fft_dir = sample_dir
206239
Path(sample_dir).mkdir(parents=True, exist_ok=True)
207240
samples_vlen = fft_batch_size * nfft
208241
self.samples_blocks.extend(
@@ -233,49 +266,6 @@ def __init__(
233266
)
234267
self.write_samples_block = self.samples_blocks[-1]
235268

236-
retune_fft = self.iqtlabs.retune_fft(
237-
tag="rx_freq",
238-
nfft=nfft,
239-
samp_rate=int(samp_rate),
240-
tune_jitter_hz=int(tune_jitter_hz),
241-
freq_start=int(freq_start),
242-
freq_end=int(freq_end),
243-
tune_step_hz=tune_step_hz,
244-
tune_step_fft=tune_step_fft,
245-
skip_tune_step_fft=skip_tune_step,
246-
fft_min=db_clamp_floor,
247-
fft_max=db_clamp_ceil,
248-
sdir=fft_dir,
249-
write_step_fft=write_samples,
250-
bucket_range=bucket_range,
251-
tuning_ranges=tuning_ranges,
252-
description=description,
253-
rotate_secs=rotate_secs,
254-
pre_fft=pretune,
255-
tag_now=self.tag_now,
256-
low_power_hold_down=(not pretune and low_power_hold_down),
257-
slew_rx_time=slew_rx_time,
258-
peak_fft_range=peak_fft_range,
259-
)
260-
self.fft_blocks.append(retune_fft)
261-
fft_zmq_block_addr = f"tcp://{fft_zmq_addr}:{fft_zmq_port}"
262-
self.pduzmq_block = pduzmq(fft_zmq_block_addr)
263-
logging.info("serving FFT on %s", fft_zmq_block_addr)
264-
265-
if iq_zmq_port:
266-
iq_zmq_block_addr = f"tcp://{iq_zmq_addr}:{iq_zmq_port}"
267-
logging.info("serving I/Q samples and tags on %s", iq_zmq_block_addr)
268-
iq_zmq_block = zeromq.pub_sink(
269-
gr.sizeof_gr_complex,
270-
fft_batch_size * nfft,
271-
iq_zmq_block_addr,
272-
100,
273-
True,
274-
65536,
275-
"",
276-
)
277-
self.connect((self.retune_pre_fft, 0), (iq_zmq_block, 0))
278-
279269
self.inference_blocks = []
280270
self.inference_output_block = None
281271
self.image_inference_block = None
@@ -284,20 +274,17 @@ def __init__(
284274
if inference_output_dir:
285275
Path(inference_output_dir).mkdir(parents=True, exist_ok=True)
286276

287-
if inference_text_color:
288-
wc = webcolors.name_to_rgb(inference_text_color, "css3")
289-
inference_text_color = ",".join(
290-
[str(c) for c in [wc.blue, wc.green, wc.red]]
291-
)
292-
293277
if (inference_model_server and inference_model_name) or inference_output_dir:
294-
x = 640
295-
y = 640
278+
if inference_text_color:
279+
wc = webcolors.name_to_rgb(inference_text_color, "css3")
280+
inference_text_color = ",".join(
281+
[str(c) for c in [wc.blue, wc.green, wc.red]]
282+
)
296283
self.image_inference_block = self.iqtlabs.image_inference(
297284
tag="rx_freq",
298285
vlen=nfft,
299-
x=x,
300-
y=y,
286+
x=640,
287+
y=640,
301288
image_dir=inference_output_dir,
302289
convert_alpha=255,
303290
norm_alpha=0,
@@ -343,7 +330,6 @@ def __init__(
343330
)
344331

345332
# TODO: provide new block that receives JSON-over-PMT and outputs to MQTT/zmq.
346-
retune_fft_output_block = None
347333
if self.inference_blocks:
348334
inference_zmq_addr = f"tcp://{inference_addr}:{inference_port}"
349335
self.inference_output_block = inferenceoutput(
@@ -359,48 +345,46 @@ def __init__(
359345
inference_output_dir,
360346
)
361347
if self.iq_inference_block:
348+
iq_inference_blocks = [self.iq_inference_block]
362349
if iq_inference_squelch_db is not None:
363-
squelch_blocks = self.wrap_batch(
364-
[
365-
analog.pwr_squelch_cc(
366-
iq_inference_squelch_db,
367-
iq_inference_squelch_alpha,
368-
0,
369-
False,
370-
)
371-
],
372-
fft_batch_size,
373-
nfft,
374-
) + [self.iq_inference_block]
375-
self.connect_blocks(self.retune_pre_fft, squelch_blocks)
376-
else:
377-
self.connect((self.retune_pre_fft, 0), (self.iq_inference_block, 0))
378-
self.connect((self.last_db_block, 0), (self.iq_inference_block, 1))
350+
self.iq_inference_block = (
351+
self.wrap_batch(
352+
[
353+
analog.pwr_squelch_cc(
354+
iq_inference_squelch_db,
355+
iq_inference_squelch_alpha,
356+
0,
357+
False,
358+
)
359+
],
360+
fft_batch_size,
361+
nfft,
362+
)
363+
+ iq_inference_blocks
364+
)
365+
self.connect_blocks(self.sample_block, iq_inference_blocks)
366+
self.connect((self.db_block, 0), (self.iq_inference_block, 1))
379367
if self.image_inference_block:
380368
if stare:
381-
self.connect(
382-
(self.last_db_block, 0), (self.image_inference_block, 0)
383-
)
369+
self.connect((self.db_block, 0), (self.image_inference_block, 0))
384370
else:
385-
retune_fft_output_block = self.image_inference_block
371+
# need to pass samples through retune_fft if using image inference
372+
self.connect((self.retune_fft, 0), (self.image_inference_block, 0))
386373
for block in self.inference_blocks:
387374
self.msg_connect(
388375
(block, "inference"), (self.inference_output_block, "inference")
389376
)
390377

391-
if retune_fft_output_block:
392-
self.connect((retune_fft, 0), (retune_fft_output_block, 0))
393-
394378
if pretune:
395379
self.msg_connect((self.retune_pre_fft, "tune"), (self.sources[0], cmd_port))
396-
self.msg_connect((self.retune_pre_fft, "tune"), (retune_fft, "cmd"))
380+
self.msg_connect((self.retune_pre_fft, "tune"), (self.retune_fft, "cmd"))
397381
else:
398-
self.msg_connect((retune_fft, "tune"), (self.sources[0], cmd_port))
399-
self.msg_connect((retune_fft, "json"), (self.pduzmq_block, "json"))
400-
self.connect_blocks(self.sources[0], self.sources[1:])
382+
self.msg_connect((self.retune_fft, "tune"), (self.sources[0], cmd_port))
383+
self.msg_connect((self.retune_fft, "json"), (self.pduzmq_block, "json"))
401384

402-
self.connect_blocks(self.sources[-1], self.fft_blocks)
403-
self.connect_blocks(self.retune_pre_fft, self.samples_blocks)
385+
self.connect_blocks(self.sources[0], self.sources[1:])
386+
self.connect_blocks(self.sources[-1], self.pipeline_blocks)
387+
self.connect_blocks(self.sample_block, self.samples_blocks)
404388

405389
def connect_blocks(self, source, other_blocks, last_block_port=0):
406390
last_block = source
@@ -535,7 +519,7 @@ def get_dc_blocks(
535519
)
536520
return []
537521

538-
def get_fft_blocks(
522+
def get_pipeline_blocks(
539523
self,
540524
samp_rate,
541525
tune_jitter_hz,
@@ -555,14 +539,23 @@ def get_fft_blocks(
555539
dc_block_len,
556540
dc_block_long,
557541
correct_iq,
542+
scaling,
543+
db_clamp_floor,
544+
db_clamp_ceil,
545+
fft_dir,
546+
write_samples,
547+
bucket_range,
548+
description,
549+
rotate_secs,
550+
peak_fft_range,
558551
):
559552
fft_batch_size, fft_blocks = self.get_offload_fft_blocks(
560553
vkfft,
561554
fft_batch_size,
562555
nfft,
563556
fft_processor_affinity,
564557
)
565-
self.retune_pre_fft = self.get_pretune_block(
558+
retune_pre_fft = self.get_pretune_block(
566559
fft_batch_size,
567560
nfft,
568561
samp_rate,
@@ -577,13 +570,46 @@ def get_fft_blocks(
577570
low_power_hold_down,
578571
slew_rx_time,
579572
)
573+
retune_fft = self.iqtlabs.retune_fft(
574+
tag="rx_freq",
575+
nfft=nfft,
576+
samp_rate=int(samp_rate),
577+
tune_jitter_hz=int(tune_jitter_hz),
578+
freq_start=int(freq_start),
579+
freq_end=int(freq_end),
580+
tune_step_hz=tune_step_hz,
581+
tune_step_fft=tune_step_fft,
582+
skip_tune_step_fft=skip_tune_step,
583+
fft_min=db_clamp_floor,
584+
fft_max=db_clamp_ceil,
585+
sdir=fft_dir,
586+
write_step_fft=write_samples,
587+
bucket_range=bucket_range,
588+
tuning_ranges=tuning_ranges,
589+
description=description,
590+
rotate_secs=rotate_secs,
591+
pre_fft=pretune,
592+
tag_now=self.tag_now,
593+
low_power_hold_down=(not pretune and low_power_hold_down),
594+
slew_rx_time=slew_rx_time,
595+
peak_fft_range=peak_fft_range,
596+
)
597+
sample_blocks = [retune_pre_fft] + self.get_dc_blocks(
598+
correct_iq, dc_block_len, dc_block_long, fft_batch_size, nfft
599+
)
600+
pipeline_blocks = (
601+
sample_blocks
602+
+ fft_blocks
603+
+ self.get_db_blocks(nfft, samp_rate, scaling)
604+
+ [retune_fft]
605+
)
580606
return (
581607
fft_batch_size,
582-
[self.retune_pre_fft]
583-
+ self.get_dc_blocks(
584-
correct_iq, dc_block_len, dc_block_long, fft_batch_size, nfft
585-
)
586-
+ fft_blocks,
608+
retune_pre_fft,
609+
retune_fft,
610+
pipeline_blocks[-1],
611+
sample_blocks[-1],
612+
pipeline_blocks,
587613
)
588614

589615
def start(self):

tests/test_grscan.py

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -143,22 +143,26 @@ def run_grscan_smoke(self, pretune, wavelearner, write_samples, test_file):
143143
]
144144
)
145145
sdr = "file:" + sdr_file
146-
tb = grscan(
147-
freq_start=freq_start,
148-
freq_end=freq_end,
149-
sdr=sdr,
150-
samp_rate=samp_rate,
151-
tune_step_fft=512,
152-
write_samples=write_samples,
153-
sample_dir=tempdir,
154-
iqtlabs=iqtlabs,
155-
wavelearner=wavelearner,
156-
rotate_secs=900,
157-
db_clamp_floor=-1e6,
158-
pretune=pretune,
159-
fft_batch_size=4,
160-
inference_output_dir=str(tempdir),
161-
)
146+
try:
147+
tb = grscan(
148+
freq_start=freq_start,
149+
freq_end=freq_end,
150+
sdr=sdr,
151+
samp_rate=samp_rate,
152+
tune_step_fft=512,
153+
write_samples=write_samples,
154+
sample_dir=tempdir,
155+
iqtlabs=iqtlabs,
156+
wavelearner=wavelearner,
157+
rotate_secs=900,
158+
db_clamp_floor=-1e6,
159+
pretune=pretune,
160+
fft_batch_size=4,
161+
inference_output_dir=str(tempdir),
162+
)
163+
except Exception as e:
164+
print(e)
165+
raise
162166
tb.start()
163167
time.sleep(3)
164168
tb.stop()

0 commit comments

Comments
 (0)