Skip to content

Commit

Permalink
simplify grscan
Browse files Browse the repository at this point in the history
  • Loading branch information
anarkiwi committed Sep 17, 2024
1 parent a54ba4d commit c6d9db0
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 102 deletions.
2 changes: 1 addition & 1 deletion docker/Dockerfile.base
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libvulkan-dev \
pybind11-dev
WORKDIR /root
RUN git clone https://github.com/iqtlabs/gr-iqtlabs -b 1.0.121
RUN git clone https://github.com/iqtlabs/gr-iqtlabs -b 1.0.122
COPY --from=iqtlabs/gamutrf-vkfft:latest /root /root/gr-iqtlabs
WORKDIR /root/gr-iqtlabs/build
COPY --from=iqtlabs/gamutrf-sigmf:latest /usr/local /usr/local
Expand Down
279 changes: 178 additions & 101 deletions gamutrf/grscan.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,20 +107,13 @@ def __init__(

if description:
description = description.strip('"')
tune_step_hz = int(samp_rate * tuneoverlap)
stare = freq_end == 0

##################################################
# Parameters
##################################################
self.freq_end = freq_end
self.freq_start = freq_start
self.sweep_sec = sweep_sec
self.nfft = nfft
self.wavelearner = wavelearner
self.iqtlabs = iqtlabs
self.samp_rate = samp_rate
self.retune_pre_fft = None
self.tag_now = tag_now

##################################################
Expand All @@ -133,32 +126,19 @@ def __init__(
pbr_version = pbr.version.VersionInfo("gamutrf").version_string()
logging.info(f"gamutrf {pbr_version} with gr-iqtlabs {griqtlabs_path}")

if stare:
freq_end = freq_start + (tune_step_hz - 1)
freq_range = freq_end - freq_start
fft_rate = int(samp_rate / nfft)

if not tune_step_fft:
if tune_dwell_ms:
tune_step_fft = int(fft_rate * (tune_dwell_ms / 1e3))
else:
target_retune_hz = freq_range / self.sweep_sec / tune_step_hz
tune_step_fft = int(fft_rate / target_retune_hz)
logging.info(
f"retuning across {freq_range/1e6}MHz in {self.sweep_sec}s, requires retuning at {target_retune_hz}Hz in {tune_step_hz/1e6}MHz steps ({tune_step_fft} FFTs)"
)
if not tune_step_fft:
logging.info("tune_step_fft cannot be 0 - defaulting to nfft")
tune_step_fft = nfft
tune_dwell_ms = tune_step_fft / fft_rate * 1e3
logging.info(
f"requested retuning across {freq_range/1e6}MHz every {tune_step_fft} FFTs, dwell time {tune_dwell_ms}ms"
tune_step_fft, tune_step_hz, peak_fft_range = self.calc_rates(
stare,
freq_start,
freq_end,
sweep_sec,
samp_rate,
nfft,
tuneoverlap,
tune_dwell_ms,
tune_step_fft,
peak_fft_range,
)
if stare and tune_dwell_ms > 1e3:
logging.warn(">1s dwell time in stare mode, updates will be slow!")
peak_fft_range = min(peak_fft_range, tune_step_fft)

fft_batch_size, self.fft_blocks = self.get_fft_blocks(
fft_batch_size, self.retune_pre_fft, self.fft_blocks = self.get_fft_blocks(
samp_rate,
tune_jitter_hz,
vkfft,
Expand Down Expand Up @@ -215,18 +195,12 @@ def __init__(
slew_rx_time=slew_rx_time,
peak_fft_range=peak_fft_range,
)
try:
freq_start = self.retune_pre_fft.get_freq_start()
freq_end = self.retune_pre_fft.get_freq_end()
initial_freq = self.retune_pre_fft.get_tune_freq()
stare = self.retune_pre_fft.get_stare_mode()
except AttributeError:
freq_start = retune_fft.get_freq_start()
freq_end = retune_fft.get_freq_end()
initial_freq = retune_fft.get_tune_freq()
stare = retune_fft.get_stare_mode()
self.last_db_block = self.fft_blocks[-1]
logging.info(f"will scan from {freq_start} to {freq_end} stare {stare}")
self.freq_start, self.freq_end, initial_freq, stare = self.get_freqs(
self.retune_pre_fft, retune_fft
)
logging.info(
f"will scan from {self.freq_start} to {self.freq_end} stare {stare}"
)
self.sources, cmd_port, self.workaround_start_hook = get_source(
sdr,
samp_rate,
Expand All @@ -251,6 +225,7 @@ def __init__(
"",
)
self.connect((self.retune_pre_fft, 0), (iq_zmq_block, 0))
self.last_db_block = self.fft_blocks[-1]
self.samples_blocks = []
self.write_samples_block = None
if write_samples:
Expand Down Expand Up @@ -290,7 +265,6 @@ def __init__(
logging.info("serving FFT on %s", fft_zmq_block_addr)

self.inference_blocks = []
self.inference_output_block = None
self.image_inference_block = None
self.iq_inference_block = None

Expand Down Expand Up @@ -346,60 +320,31 @@ def __init__(
batch=inference_batch,
)
self.inference_blocks.append(self.iq_inference_block)
if self.write_samples_block:
self.msg_connect(
(self.iq_inference_block, "inference"),
(self.write_samples_block, "inference"),
)

# TODO: provide new block that receives JSON-over-PMT and outputs to MQTT/zmq.
retune_fft_output_block = None
if self.inference_blocks:
inference_zmq_addr = f"tcp://{inference_addr}:{inference_port}"
self.inference_output_block = inferenceoutput(
"inferencemqtt",
inference_zmq_addr,
mqtt_server,
compass,
gps_server,
use_external_gps,
use_external_heading,
external_gps_server,
external_gps_server_port,
inference_output_dir,
)
if self.iq_inference_block:
if iq_inference_squelch_db is not None:
squelch_blocks = self.wrap_batch(
[
analog.pwr_squelch_cc(
iq_inference_squelch_db,
iq_inference_squelch_alpha,
0,
False,
)
],
fft_batch_size,
nfft,
) + [self.iq_inference_block]
self.connect_blocks(self.retune_pre_fft, squelch_blocks)
else:
self.connect((self.retune_pre_fft, 0), (self.iq_inference_block, 0))
self.connect((self.last_db_block, 0), (self.iq_inference_block, 1))
if self.image_inference_block:
if stare:
self.connect(
(self.last_db_block, 0), (self.image_inference_block, 0)
)
else:
retune_fft_output_block = self.image_inference_block
for block in self.inference_blocks:
self.msg_connect(
(block, "inference"), (self.inference_output_block, "inference")
)

if retune_fft_output_block:
self.connect((retune_fft, 0), (retune_fft_output_block, 0))
self.inference_output_block = self.connect_inference(
self.inference_blocks,
self.iq_inference_block,
self.image_inference_block,
inference_addr,
inference_port,
mqtt_server,
compass,
gps_server,
use_external_gps,
use_external_heading,
external_gps_server,
external_gps_server_port,
iq_inference_squelch_db,
iq_inference_squelch_alpha,
fft_batch_size,
nfft,
self.retune_pre_fft,
retune_fft,
stare,
self.last_db_block,
self.write_samples_block,
inference_output_dir,
)

if pretune:
self.msg_connect((self.retune_pre_fft, "tune"), (self.sources[0], cmd_port))
Expand All @@ -408,10 +353,142 @@ def __init__(
self.msg_connect((retune_fft, "tune"), (self.sources[0], cmd_port))
self.msg_connect((retune_fft, "json"), (self.pduzmq_block, "json"))
self.connect_blocks(self.sources[0], self.sources[1:])

self.connect_blocks(self.sources[-1], self.fft_blocks)
self.connect_blocks(self.retune_pre_fft, self.samples_blocks)

def connect_inference(
self,
inference_blocks,
iq_inference_block,
image_inference_block,
inference_addr,
inference_port,
mqtt_server,
compass,
gps_server,
use_external_gps,
use_external_heading,
external_gps_server,
external_gps_server_port,
iq_inference_squelch_db,
iq_inference_squelch_alpha,
fft_batch_size,
nfft,
retune_pre_fft,
retune_fft,
stare,
last_db_block,
write_samples_block,
inference_output_dir,
):
if not inference_blocks:
return None
inference_zmq_addr = f"tcp://{inference_addr}:{inference_port}"
inference_output_block = inferenceoutput(
"inferencemqtt",
inference_zmq_addr,
mqtt_server,
compass,
gps_server,
use_external_gps,
use_external_heading,
external_gps_server,
external_gps_server_port,
inference_output_dir,
)
if iq_inference_block:
if iq_inference_squelch_db is not None:
squelch_blocks = self.wrap_batch(
[
analog.pwr_squelch_cc(
iq_inference_squelch_db,
iq_inference_squelch_alpha,
0,
False,
)
],
fft_batch_size,
nfft,
) + [iq_inference_block]
self.connect_blocks(retune_pre_fft, squelch_blocks)
else:
self.connect((retune_pre_fft, 0), (iq_inference_block, 0))
self.connect((last_db_block, 0), (iq_inference_block, 1))
if write_samples_block:
self.msg_connect(
(iq_inference_block, "inference"),
(write_samples_block, "inference"),
)

if image_inference_block:
if stare:
self.connect((last_db_block, 0), (image_inference_block, 0))
else:
self.connect((retune_fft, 0), (image_inference_block, 0))
for block in inference_blocks:
self.msg_connect(
(block, "inference"), (inference_output_block, "inference")
)
return inference_output_block

def calc_rates(
self,
stare,
freq_start,
freq_end,
sweep_sec,
samp_rate,
nfft,
tuneoverlap,
tune_dwell_ms,
tune_step_fft,
peak_fft_range,
):
tune_step_hz = int(samp_rate * tuneoverlap)
if stare:
freq_range = samp_rate
else:
freq_range = freq_end - freq_start
fft_rate = int(samp_rate / nfft)

if not tune_step_fft:
if tune_dwell_ms:
tune_step_fft = int(fft_rate * (tune_dwell_ms / 1e3))
else:
target_retune_hz = freq_range / sweep_sec / tune_step_hz
tune_step_fft = int(fft_rate / target_retune_hz)
logging.info(
f"retuning across {freq_range/1e6}MHz in {sweep_sec}s, requires retuning at {target_retune_hz}Hz in {tune_step_hz/1e6}MHz steps ({tune_step_fft} FFTs)"
)
if not tune_step_fft:
logging.info("tune_step_fft cannot be 0 - defaulting to nfft")
tune_step_fft = nfft
tune_dwell_ms = tune_step_fft / fft_rate * 1e3
logging.info(
f"requested retuning across {freq_range/1e6}MHz every {tune_step_fft} FFTs, dwell time {tune_dwell_ms}ms"
)
if stare and tune_dwell_ms > 1e3:
logging.warn(">1s dwell time in stare mode, updates will be slow!")
peak_fft_range = min(peak_fft_range, tune_step_fft)
return (
tune_step_hz,
tune_step_fft,
peak_fft_range,
)

def get_freqs(self, retune_pre_fft, retune_fft):
try:
freq_start = retune_pre_fft.get_freq_start()
freq_end = retune_pre_fft.get_freq_end()
initial_freq = retune_pre_fft.get_tune_freq()
stare = retune_pre_fft.get_stare_mode()
except AttributeError:
freq_start = retune_fft.get_freq_start()
freq_end = retune_fft.get_freq_end()
initial_freq = retune_fft.get_tune_freq()
stare = retune_fft.get_stare_mode()
return (freq_start, freq_end, initial_freq, stare)

def connect_blocks(self, source, other_blocks, last_block_port=0):
last_block = source
for block in other_blocks:
Expand Down Expand Up @@ -582,7 +659,7 @@ def get_fft_blocks(
nfft,
fft_processor_affinity,
)
self.retune_pre_fft = self.get_pretune_block(
retune_pre_fft = self.get_pretune_block(
fft_batch_size,
nfft,
samp_rate,
Expand All @@ -597,7 +674,7 @@ def get_fft_blocks(
low_power_hold_down,
slew_rx_time,
)
return (fft_batch_size, [self.retune_pre_fft] + fft_blocks)
return (fft_batch_size, retune_pre_fft, [retune_pre_fft] + fft_blocks)

def start(self):
super().start()
Expand Down

0 comments on commit c6d9db0

Please sign in to comment.