updated for compatibility with new hackrf_sweep -B option

This commit is contained in:
Michael Ossmann 2017-02-09 08:27:53 -07:00
parent 713434d029
commit 4e9ecdb64d
4 changed files with 37 additions and 71 deletions

View File

@ -223,7 +223,7 @@ class QSpectrumAnalyzerMainWindow(QtGui.QMainWindow, Ui_QSpectrumAnalyzerMainWin
def load_settings(self):
"""Restore spectrum analyzer settings and window geometry"""
settings = QtCore.QSettings()
self.startFreqSpinBox.setValue(settings.value("start_freq", 87.0, float))
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.intervalSpinBox.setValue(settings.value("interval", 10.0, float))

View File

@ -272,95 +272,61 @@ class HackRFSweepThread(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 hackrf_sweep params"""
crop = crop * 100
overlap = crop * 2
freq_range = stop_freq * 1e6 - start_freq * 1e6
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
bins = math.ceil(sample_rate / (bin_size * 1e3))
crop_freq = sample_rate * crop * 0.01
self.params = {
"start_freq": start_freq,
"stop_freq": stop_freq,
"freq_range": freq_range,
"device_index": device_index,
"sample_rate": sample_rate,
"bin_size": bin_size,
"bins": bins,
"interval": interval,
"hops": hops,
"time": interval / hops,
"gain": gain * 10,
"ppm": ppm,
"crop": crop,
"overlap": overlap,
"min_overhang": min_overhang,
"overhang": overhang,
"hops": 0,
"device_index": 0,
"sample_rate": 20e6,
"bin_size": 1e6,
"interval": 0,
"gain": 0,
"ppm": 0,
"crop": 0,
"single_shot": single_shot
}
self.fft_size = 64
self.freqs = [self.get_hop_freq(hop) for hop in range(hops)]
self.freqs_crop = [(f[0] + crop_freq, f[1] - crop_freq) for f in self.freqs]
self.fft_size = 20
self.databuffer = {"timestamp": [], "x": [], "y": []}
self.databuffer_hop = {"timestamp": [], "x": [], "y": []}
self.hop = 0
self.prev_line = ""
self.prev_freq = 0
self.skip = True
print("hackrf_sweep params:")
pprint.pprint(self.params)
print()
def get_hop_freq(self, hop):
"""Get start and stop frequency for particular hop"""
start_freq = self.params["start_freq"] * 1e6 + (self.params["sample_rate"] - self.params["overhang"]) * hop
stop_freq = start_freq + self.params["sample_rate"] - (self.params["sample_rate"] / self.params["bins"])
return (start_freq, stop_freq)
def process_start(self):
"""Start hackrf_sweep process"""
if not self.process and self.params:
settings = QtCore.QSettings()
cmdline = [
settings.value("rtl_power_executable", "hackrf_sweep"),
"-f", "{}:{}".format(int(self.params["start_freq"]),
int(self.params["stop_freq"])),
"-f", "{}:{}".format(int(self.params["start_freq"]),
int(self.params["stop_freq"])),
"-B", "-w", "1000000",
]
if self.params["single_shot"]:
cmdline.append("-1")
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
universal_newlines=False)
def filter_nan(self, num):
if np.isnan(num) or np.isinf(num) or np.isneginf(num):
return -80
return num
def parse_output(self, buf):
"""Parse one buf of output from hackrf_sweep"""
data = np.fromstring(buf, dtype='<f4')
centre_freq = data[0] * 1e6
low_edge = data[0] * 1e6
high_edge = low_edge + self.params["sample_rate"] // 4
bin_width = self.params["sample_rate"] / self.fft_size
if centre_freq != self.prev_freq:
if centre_freq < self.prev_freq:
# Skip first run through in case it was incomplete
# otherwise the data_storage array sizes are setup incorrectly and mismatch later
if not self.skip:
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.skip = False
self.databuffer = {"timestamp": [], "x": [], "y": []}
fft_size_eighth = int(self.fft_size / 8)
valid_bins = list(range(fft_size_eighth, fft_size_eighth * 3)) + list(range(fft_size_eighth * 5, fft_size_eighth * 7))
for i in valid_bins:
self.databuffer["x"].append(centre_freq + (i - self.fft_size/2) * 20e6 / self.fft_size)
self.databuffer["y"].append(self.filter_nan(data[1+i]))
self.prev_freq = centre_freq
x_axis = list(np.arange(low_edge, high_edge, bin_width))
self.databuffer["x"].extend(x_axis)
for i in range(self.fft_size//4):
self.databuffer["y"].append(data[1+i])
# The -1 below works around floating point errors
if (high_edge / 1e6) >= (self.params["stop_freq"] - 1):
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):
@ -370,7 +336,7 @@ class HackRFSweepThread(RtlPowerBaseThread):
self.rtlPowerStarted.emit()
while self.alive:
buf = self.process.stdout.read(4*(1+self.fft_size))
buf = self.process.stdout.read(4*(1+self.fft_size//4))
if buf:
self.parse_output(buf)

View File

@ -189,13 +189,13 @@
<number>3</number>
</property>
<property name="minimum">
<double>1.000000000000000</double>
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>6000.000000000000000</double>
</property>
<property name="value">
<double>87.000000000000000</double>
<double>88.000000000000000</double>
</property>
</widget>
</item>
@ -227,7 +227,7 @@
<number>3</number>
</property>
<property name="minimum">
<double>1.000000000000000</double>
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>6000.000000000000000</double>

View File

@ -116,9 +116,9 @@ class Ui_QSpectrumAnalyzerMainWindow(object):
self.startFreqSpinBox.setSizePolicy(sizePolicy)
self.startFreqSpinBox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.startFreqSpinBox.setDecimals(3)
self.startFreqSpinBox.setMinimum(1.0)
self.startFreqSpinBox.setMinimum(0.0)
self.startFreqSpinBox.setMaximum(6000.0)
self.startFreqSpinBox.setProperty("value", 2390.0)
self.startFreqSpinBox.setProperty("value", 88.0)
self.startFreqSpinBox.setObjectName(_fromUtf8("startFreqSpinBox"))
self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.startFreqSpinBox)
self.label_3 = QtGui.QLabel(self.frequencyDockWidgetContents)
@ -132,9 +132,9 @@ class Ui_QSpectrumAnalyzerMainWindow(object):
self.stopFreqSpinBox.setSizePolicy(sizePolicy)
self.stopFreqSpinBox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.stopFreqSpinBox.setDecimals(3)
self.stopFreqSpinBox.setMinimum(1.0)
self.stopFreqSpinBox.setMinimum(0.0)
self.stopFreqSpinBox.setMaximum(6000.0)
self.stopFreqSpinBox.setProperty("value", 2510.0)
self.stopFreqSpinBox.setProperty("value", 108.0)
self.stopFreqSpinBox.setObjectName(_fromUtf8("stopFreqSpinBox"))
self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.stopFreqSpinBox)
self.label = QtGui.QLabel(self.frequencyDockWidgetContents)