Merge pull request #2 from mossmann/master
compute bin width from number of input bins
This commit is contained in:
commit
abc9dd2676
@ -225,7 +225,7 @@ class QSpectrumAnalyzerMainWindow(QtGui.QMainWindow, Ui_QSpectrumAnalyzerMainWin
|
|||||||
settings = QtCore.QSettings()
|
settings = QtCore.QSettings()
|
||||||
self.startFreqSpinBox.setValue(settings.value("start_freq", 88.0, float))
|
self.startFreqSpinBox.setValue(settings.value("start_freq", 88.0, float))
|
||||||
self.stopFreqSpinBox.setValue(settings.value("stop_freq", 108.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.intervalSpinBox.setValue(settings.value("interval", 10.0, float))
|
||||||
self.gainSpinBox.setValue(settings.value("gain", 0, int))
|
self.gainSpinBox.setValue(settings.value("gain", 0, int))
|
||||||
self.ppmSpinBox.setValue(settings.value("ppm", 0, int))
|
self.ppmSpinBox.setValue(settings.value("ppm", 0, int))
|
||||||
|
@ -65,6 +65,8 @@ class RtlPowerThread(RtlPowerBaseThread):
|
|||||||
def setup(self, start_freq, stop_freq, bin_size, interval=10.0, gain=-1,
|
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):
|
ppm=0, crop=0, single_shot=False, device_index=0, sample_rate=2560000):
|
||||||
"""Setup rtl_power params"""
|
"""Setup rtl_power params"""
|
||||||
|
if bin_size > 2800:
|
||||||
|
bin_size = 2800
|
||||||
self.params = {
|
self.params = {
|
||||||
"start_freq": start_freq,
|
"start_freq": start_freq,
|
||||||
"stop_freq": stop_freq,
|
"stop_freq": stop_freq,
|
||||||
@ -153,6 +155,8 @@ class RtlPowerFftwThread(RtlPowerBaseThread):
|
|||||||
min_overhang = sample_rate * overlap * 0.01
|
min_overhang = sample_rate * overlap * 0.01
|
||||||
hops = math.ceil((freq_range - min_overhang) / (sample_rate - min_overhang))
|
hops = math.ceil((freq_range - min_overhang) / (sample_rate - min_overhang))
|
||||||
overhang = (hops * sample_rate - freq_range) / (hops - 1) if hops > 1 else 0
|
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))
|
bins = math.ceil(sample_rate / (bin_size * 1e3))
|
||||||
crop_freq = sample_rate * crop * 0.01
|
crop_freq = sample_rate * crop * 0.01
|
||||||
|
|
||||||
@ -270,18 +274,33 @@ class RtlPowerFftwThread(RtlPowerBaseThread):
|
|||||||
|
|
||||||
class HackRFSweepThread(RtlPowerBaseThread):
|
class HackRFSweepThread(RtlPowerBaseThread):
|
||||||
"""Thread which runs hackrf_sweep process"""
|
"""Thread which runs hackrf_sweep process"""
|
||||||
def setup(self, start_freq, stop_freq, bin_size, interval=10.0, gain=-1,
|
def setup(self, start_freq=0, stop_freq=6000, bin_size=1000,
|
||||||
ppm=0, crop=0, single_shot=False, device_index=0, sample_rate=2560000):
|
interval=0.0, gain=0, ppm=0, crop=0, single_shot=False,
|
||||||
|
device_index=0, sample_rate=20000000):
|
||||||
"""Setup hackrf_sweep params"""
|
"""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
|
||||||
|
|
||||||
|
# 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 = {
|
self.params = {
|
||||||
"start_freq": start_freq,
|
"start_freq": start_freq, # MHz
|
||||||
"stop_freq": stop_freq,
|
"stop_freq": stop_freq, # MHz
|
||||||
"hops": 0,
|
"hops": 0,
|
||||||
"device_index": 0,
|
"device_index": 0,
|
||||||
"sample_rate": 20e6,
|
"sample_rate": 20e6, # sps
|
||||||
"bin_size": int(bin_size*1000),
|
"bin_size": bin_size, # kHz
|
||||||
"interval": 0,
|
"interval": 0, # seconds
|
||||||
"gain": 0,
|
"gain": 0,
|
||||||
"ppm": 0,
|
"ppm": 0,
|
||||||
"crop": 0,
|
"crop": 0,
|
||||||
@ -301,7 +320,8 @@ class HackRFSweepThread(RtlPowerBaseThread):
|
|||||||
settings.value("rtl_power_executable", "hackrf_sweep"),
|
settings.value("rtl_power_executable", "hackrf_sweep"),
|
||||||
"-f", "{}:{}".format(int(self.params["start_freq"]),
|
"-f", "{}:{}".format(int(self.params["start_freq"]),
|
||||||
int(self.params["stop_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"]:
|
if self.params["single_shot"]:
|
||||||
@ -312,18 +332,23 @@ class HackRFSweepThread(RtlPowerBaseThread):
|
|||||||
|
|
||||||
def parse_output(self, buf):
|
def parse_output(self, buf):
|
||||||
"""Parse one buf of output from hackrf_sweep"""
|
"""Parse one buf of output from hackrf_sweep"""
|
||||||
(low_edge, high_edge, bin_width) = struct.unpack('QQI', buf[:20])
|
(low_edge, high_edge) = struct.unpack('QQ', buf[:16])
|
||||||
data = np.fromstring(buf[20:], dtype='<f4')
|
data = np.fromstring(buf[16:], dtype='<f4')
|
||||||
|
step = (high_edge - low_edge) / len(data)
|
||||||
|
|
||||||
x_axis = list(np.arange(low_edge, high_edge, bin_width))
|
if (low_edge//1000000) <= (self.params["start_freq"]):
|
||||||
|
# Reset databuffer at the start of each sweep even if we somehow
|
||||||
|
# did not complete the previous sweep.
|
||||||
|
self.databuffer = {"timestamp": [], "x": [], "y": []}
|
||||||
|
x_axis = list(np.arange(low_edge + step/2, high_edge, step))
|
||||||
self.databuffer["x"].extend(x_axis)
|
self.databuffer["x"].extend(x_axis)
|
||||||
for i in range(len(data)):
|
for i in range(len(data)):
|
||||||
self.databuffer["y"].append(data[i])
|
self.databuffer["y"].append(data[i])
|
||||||
if (high_edge / 1e6) >= (self.params["stop_freq"]):
|
if (high_edge / 1e6) >= (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"]))
|
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.databuffer["x"], self.databuffer["y"] = [list(x) for x in zip(*sorted_data)]
|
||||||
self.data_storage.update(self.databuffer)
|
self.data_storage.update(self.databuffer)
|
||||||
self.databuffer = {"timestamp": [], "x": [], "y": []}
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""hackrf_sweep thread main loop"""
|
"""hackrf_sweep thread main loop"""
|
||||||
|
@ -265,10 +265,10 @@
|
|||||||
<number>3</number>
|
<number>3</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<double>2800.000000000000000</double>
|
<double>5000.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
<property name="value">
|
<property name="value">
|
||||||
<double>10.000000000000000</double>
|
<double>100.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -148,8 +148,8 @@ class Ui_QSpectrumAnalyzerMainWindow(object):
|
|||||||
self.binSizeSpinBox.setSizePolicy(sizePolicy)
|
self.binSizeSpinBox.setSizePolicy(sizePolicy)
|
||||||
self.binSizeSpinBox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
self.binSizeSpinBox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||||
self.binSizeSpinBox.setDecimals(3)
|
self.binSizeSpinBox.setDecimals(3)
|
||||||
self.binSizeSpinBox.setMaximum(2800.0)
|
self.binSizeSpinBox.setMaximum(5000.0)
|
||||||
self.binSizeSpinBox.setProperty("value", 10.0)
|
self.binSizeSpinBox.setProperty("value", 100.0)
|
||||||
self.binSizeSpinBox.setObjectName(_fromUtf8("binSizeSpinBox"))
|
self.binSizeSpinBox.setObjectName(_fromUtf8("binSizeSpinBox"))
|
||||||
self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.binSizeSpinBox)
|
self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.binSizeSpinBox)
|
||||||
spacerItem1 = QtGui.QSpacerItem(20, 0, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
spacerItem1 = QtGui.QSpacerItem(20, 0, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
||||||
|
Loading…
Reference in New Issue
Block a user