updated for compatibility with new hackrf_sweep -B option
This commit is contained in:
parent
713434d029
commit
4e9ecdb64d
@ -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))
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user