From eef73719f0257bfea16a15482d3c2f00bbdbf795 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Fri, 10 Feb 2017 16:29:47 -0700 Subject: [PATCH 1/5] compute bin width from number of input bins --- qspectrumanalyzer/backend.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qspectrumanalyzer/backend.py b/qspectrumanalyzer/backend.py index 43c07da..16ec82c 100644 --- a/qspectrumanalyzer/backend.py +++ b/qspectrumanalyzer/backend.py @@ -314,8 +314,9 @@ class HackRFSweepThread(RtlPowerBaseThread): """Parse one buf of output from hackrf_sweep""" (low_edge, high_edge, bin_width) = struct.unpack('QQI', buf[:20]) data = np.fromstring(buf[20:], dtype=' Date: Fri, 10 Feb 2017 16:38:01 -0700 Subject: [PATCH 2/5] removed bin width from hackrf_sweep output format --- qspectrumanalyzer/backend.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qspectrumanalyzer/backend.py b/qspectrumanalyzer/backend.py index 16ec82c..120abd5 100644 --- a/qspectrumanalyzer/backend.py +++ b/qspectrumanalyzer/backend.py @@ -312,8 +312,8 @@ class HackRFSweepThread(RtlPowerBaseThread): def parse_output(self, buf): """Parse one buf of output from hackrf_sweep""" - (low_edge, high_edge, bin_width) = struct.unpack('QQI', buf[:20]) - data = np.fromstring(buf[20:], dtype=' Date: Fri, 10 Feb 2017 16:57:12 -0700 Subject: [PATCH 3/5] limit bin size configuration to acceptable bounds --- qspectrumanalyzer/backend.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/qspectrumanalyzer/backend.py b/qspectrumanalyzer/backend.py index 120abd5..259db3b 100644 --- a/qspectrumanalyzer/backend.py +++ b/qspectrumanalyzer/backend.py @@ -270,18 +270,25 @@ class RtlPowerFftwThread(RtlPowerBaseThread): class HackRFSweepThread(RtlPowerBaseThread): """Thread which runs hackrf_sweep process""" - def setup(self, start_freq, stop_freq, bin_size, interval=10.0, gain=-1, - ppm=0, crop=0, single_shot=False, device_index=0, sample_rate=2560000): + def setup(self, start_freq=0, stop_freq=6000, bin_size=1000, + interval=0.0, gain=0, ppm=0, crop=0, single_shot=False, + device_index=0, sample_rate=20000000): """Setup hackrf_sweep params""" + # theoretically we can support bins smaller than 40 kHz, but it is + # unlikely to result in acceptable performance + if bin_size < 40: + bin_size = 40 + if bin_size > 5000: + bin_size = 5000 self.params = { - "start_freq": start_freq, - "stop_freq": stop_freq, + "start_freq": start_freq, # MHz + "stop_freq": stop_freq, # MHz "hops": 0, "device_index": 0, - "sample_rate": 20e6, - "bin_size": int(bin_size*1000), - "interval": 0, + "sample_rate": 20e6, # Msps + "bin_size": bin_size, # kHz + "interval": 0, # seconds "gain": 0, "ppm": 0, "crop": 0, @@ -301,7 +308,8 @@ class HackRFSweepThread(RtlPowerBaseThread): settings.value("rtl_power_executable", "hackrf_sweep"), "-f", "{}:{}".format(int(self.params["start_freq"]), int(self.params["stop_freq"])), - "-B", "-w", "{}".format(self.params["bin_size"]), + "-B", + "-w", "{}".format(int(self.params["bin_size"]*1000)), ] if self.params["single_shot"]: From 76c3ad2b55ee090494bbf9f54189ee07e6520432 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Fri, 10 Feb 2017 17:04:54 -0700 Subject: [PATCH 4/5] increased default and maximum bin size settings --- qspectrumanalyzer/__main__.py | 2 +- qspectrumanalyzer/backend.py | 4 ++++ qspectrumanalyzer/qspectrumanalyzer.ui | 4 ++-- qspectrumanalyzer/ui_qspectrumanalyzer.py | 4 ++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/qspectrumanalyzer/__main__.py b/qspectrumanalyzer/__main__.py index e96cc24..0a2d33a 100755 --- a/qspectrumanalyzer/__main__.py +++ b/qspectrumanalyzer/__main__.py @@ -225,7 +225,7 @@ class QSpectrumAnalyzerMainWindow(QtGui.QMainWindow, Ui_QSpectrumAnalyzerMainWin settings = QtCore.QSettings() self.startFreqSpinBox.setValue(settings.value("start_freq", 88.0, float)) self.stopFreqSpinBox.setValue(settings.value("stop_freq", 108.0, float)) - self.binSizeSpinBox.setValue(settings.value("bin_size", 10.0, float)) + self.binSizeSpinBox.setValue(settings.value("bin_size", 100.0, float)) self.intervalSpinBox.setValue(settings.value("interval", 10.0, float)) self.gainSpinBox.setValue(settings.value("gain", 0, int)) self.ppmSpinBox.setValue(settings.value("ppm", 0, int)) diff --git a/qspectrumanalyzer/backend.py b/qspectrumanalyzer/backend.py index 259db3b..62f76a1 100644 --- a/qspectrumanalyzer/backend.py +++ b/qspectrumanalyzer/backend.py @@ -65,6 +65,8 @@ class RtlPowerThread(RtlPowerBaseThread): def setup(self, start_freq, stop_freq, bin_size, interval=10.0, gain=-1, ppm=0, crop=0, single_shot=False, device_index=0, sample_rate=2560000): """Setup rtl_power params""" + if bin_size > 2800: + bin_size = 2800 self.params = { "start_freq": start_freq, "stop_freq": stop_freq, @@ -153,6 +155,8 @@ class RtlPowerFftwThread(RtlPowerBaseThread): min_overhang = sample_rate * overlap * 0.01 hops = math.ceil((freq_range - min_overhang) / (sample_rate - min_overhang)) overhang = (hops * sample_rate - freq_range) / (hops - 1) if hops > 1 else 0 + if bin_size > 2800: + bin_size = 2800 bins = math.ceil(sample_rate / (bin_size * 1e3)) crop_freq = sample_rate * crop * 0.01 diff --git a/qspectrumanalyzer/qspectrumanalyzer.ui b/qspectrumanalyzer/qspectrumanalyzer.ui index 238c9ab..2562645 100644 --- a/qspectrumanalyzer/qspectrumanalyzer.ui +++ b/qspectrumanalyzer/qspectrumanalyzer.ui @@ -265,10 +265,10 @@ 3 - 2800.000000000000000 + 5000.000000000000000 - 10.000000000000000 + 100.000000000000000 diff --git a/qspectrumanalyzer/ui_qspectrumanalyzer.py b/qspectrumanalyzer/ui_qspectrumanalyzer.py index db72b62..115af1d 100644 --- a/qspectrumanalyzer/ui_qspectrumanalyzer.py +++ b/qspectrumanalyzer/ui_qspectrumanalyzer.py @@ -148,8 +148,8 @@ class Ui_QSpectrumAnalyzerMainWindow(object): self.binSizeSpinBox.setSizePolicy(sizePolicy) self.binSizeSpinBox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.binSizeSpinBox.setDecimals(3) - self.binSizeSpinBox.setMaximum(2800.0) - self.binSizeSpinBox.setProperty("value", 10.0) + self.binSizeSpinBox.setMaximum(5000.0) + self.binSizeSpinBox.setProperty("value", 100.0) self.binSizeSpinBox.setObjectName(_fromUtf8("binSizeSpinBox")) self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.binSizeSpinBox) spacerItem1 = QtGui.QSpacerItem(20, 0, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) From c060f82c251b39cb7ddb534199a447b008ca5299 Mon Sep 17 00:00:00 2001 From: Michael Ossmann Date: Fri, 10 Feb 2017 22:18:46 -0700 Subject: [PATCH 5/5] fixed bug that can happen when frequency ranges are interleaved around the stop frequency --- qspectrumanalyzer/backend.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/qspectrumanalyzer/backend.py b/qspectrumanalyzer/backend.py index 62f76a1..1fa6556 100644 --- a/qspectrumanalyzer/backend.py +++ b/qspectrumanalyzer/backend.py @@ -285,12 +285,20 @@ class HackRFSweepThread(RtlPowerBaseThread): if bin_size > 5000: bin_size = 5000 + # We only support whole numbers of steps with bandwidth equal to the + # sample rate. + step_bandwidth = sample_rate / 1000000 + total_bandwidth = stop_freq - start_freq + step_count = 1 + (total_bandwidth - 1) // step_bandwidth + total_bandwidth = step_count * step_bandwidth + stop_freq = start_freq + total_bandwidth + self.params = { "start_freq": start_freq, # MHz "stop_freq": stop_freq, # MHz "hops": 0, "device_index": 0, - "sample_rate": 20e6, # Msps + "sample_rate": 20e6, # sps "bin_size": bin_size, # kHz "interval": 0, # seconds "gain": 0, @@ -328,15 +336,19 @@ class HackRFSweepThread(RtlPowerBaseThread): data = np.fromstring(buf[16:], dtype='= (self.params["stop_freq"]): + # We've reached the end of a pass, so sort and display it. sorted_data = sorted(zip(self.databuffer["x"], self.databuffer["y"])) self.databuffer["x"], self.databuffer["y"] = [list(x) for x in zip(*sorted_data)] self.data_storage.update(self.databuffer) - self.databuffer = {"timestamp": [], "x": [], "y": []} def run(self): """hackrf_sweep thread main loop"""