New version 1.5.0 (soapy_sdr backend now fully functioning)
This commit is contained in:
parent
dc27e90653
commit
47ea0b99b5
14
PKGBUILD
14
PKGBUILD
@ -1,14 +1,20 @@
|
||||
# Maintainer: Michal Krenek (Mikos) <m.krenek@gmail.com>
|
||||
pkgname=qspectrumanalyzer
|
||||
pkgver=1.4.0
|
||||
pkgver=1.5.0
|
||||
pkgrel=1
|
||||
pkgdesc="Spectrum analyzer for RTL-SDR (GUI for rtl_power based on PyQtGraph)"
|
||||
pkgdesc="Spectrum analyzer for multiple SDR platforms (PyQtGraph based GUI for soapy_power, rx_power, rtl_power, hackrf_sweep and other backends)"
|
||||
arch=('any')
|
||||
url="https://github.com/xmikos/qspectrumanalyzer"
|
||||
license=('GPL3')
|
||||
depends=('python-pyqt4' 'python-pyqtgraph' 'rtl-sdr')
|
||||
depends=('python-pyqt4' 'python-pyqtgraph' 'soapy_power')
|
||||
makedepends=('python-setuptools')
|
||||
optdepends=('rtl_power_fftw-git: alternative rtl_power implementation using FFTW library')
|
||||
optdepends=(
|
||||
'rtl_power_fftw-git: alternative RTL-SDR backend using FFTW library (much faster than rtl_power)'
|
||||
'rtl-sdr-keenerd-git: better version of rtl_power backend'
|
||||
'rtl-sdr: original rtl_power backend (slightly broken, use rtl-sdr-keenerd-git instead)'
|
||||
'rx_tools: rx_power backend (universal SoapySDR based backend, but seems slow and buggy)'
|
||||
'hackrf: hackrf_sweep backend (wideband spectrum monitoring with sweep rate of 8 GHz/s)'
|
||||
)
|
||||
source=(https://github.com/xmikos/qspectrumanalyzer/archive/v$pkgver.tar.gz)
|
||||
|
||||
build() {
|
||||
|
39
README.rst
39
README.rst
@ -17,7 +17,8 @@ Requirements
|
||||
- Python >= 3.3
|
||||
- PyQt >= 4.5
|
||||
- PyQtGraph (http://www.pyqtgraph.org)
|
||||
- soapy_power / rx_tools / rtl-sdr / rtl_power_fftw / hackrf
|
||||
- soapy_power (https://github.com/xmikos/soapy_power)
|
||||
- Optional: rx_tools / rtl-sdr / rtl_power_fftw / hackrf
|
||||
|
||||
Backends
|
||||
--------
|
||||
@ -36,7 +37,7 @@ USRP and some other SDR devices).
|
||||
|
||||
``rx_power`` (part of ``rx_tools``) is also based on SoapySDR and therefore
|
||||
supports nearly all SDR platforms, but it is much slower than soapy_power, doesn't support
|
||||
near real-time continuous measurement (minimum interval is 1 second - same as ``rtl_power``)
|
||||
near real-time continuous measurement (minimum interval is 1 second, same as ``rtl_power``)
|
||||
and is little buggy.
|
||||
|
||||
RTL-SDR backends
|
||||
@ -73,14 +74,14 @@ Usage
|
||||
Start QSpectrumAnalyzer by running ``qspectrumanalyzer``.
|
||||
|
||||
You can choose which backend you want to use in *File* -> *Settings*
|
||||
(default is ``soapy_power``). Sample rate and path to backend executable
|
||||
can be also manually specified there. You can also set waterfall plot
|
||||
history size. Default is 100 lines, be aware that really large sweeps
|
||||
(with a lot of bins) would require a lot of system memory,
|
||||
so don't make this number too big.
|
||||
(default is ``soapy_power``). Sample rate, path to backend executable
|
||||
and additional backend parameters can be also manually specified there.
|
||||
You can also set waterfall plot history size. Default is 100 lines, be aware
|
||||
that really large sweeps (with a lot of bins) would require a lot of system
|
||||
memory, so don't make this number too big.
|
||||
|
||||
Controls should be intuitive, but if you want consistent results, you should
|
||||
turn off automatic gain control (set it to some fixed number) and also set
|
||||
turn off automatic gain control (set gain to some fixed number) and also set
|
||||
crop to 20% or more. For finding out ppm correction factor for your rtl-sdr
|
||||
stick, use `kalibrate-rtl <https://github.com/steve-m/kalibrate-rtl>`_.
|
||||
|
||||
@ -108,17 +109,30 @@ Git master branch:
|
||||
cd qspectrumanalyzer-git
|
||||
makepkg -sri
|
||||
|
||||
Or simply use `pacaur <https://aur.archlinux.org/packages/pacaur>`_ (or any other AUR helper):
|
||||
Or simply use `pacaur <https://aur.archlinux.org/packages/pacaur>`_ (or any other AUR helper)
|
||||
which will also automatically install all QSpectrumAnalyzer dependencies:
|
||||
::
|
||||
|
||||
pacaur -S qspectrumanalyzer
|
||||
pacaur -S qspectrumanalyzer-git
|
||||
|
||||
Debian / Ubuntu:
|
||||
****************
|
||||
Ubuntu:
|
||||
*******
|
||||
::
|
||||
|
||||
sudo apt-get install python3-pip python3-pyqt4 python3-numpy
|
||||
# Add SoapySDR PPA to your system
|
||||
sudo add-apt-repository -y ppa:myriadrf/drivers
|
||||
|
||||
# Update list of packages
|
||||
sudo apt-get update
|
||||
|
||||
# Install basic dependencies
|
||||
sudo apt-get install python3-pip python3-pyqt4 python3-numpy soapysdr python3-soapysdr
|
||||
|
||||
# Install SoapySDR drivers for your hardware (e.g. RTL-SDR, Airspy, HackRF, LimeSDR, etc.)
|
||||
sudo apt-get install soapysdr-module-rtlsdr soapysdr-module-airspy soapysdr-module-hackrf soapysdr-module-lms7
|
||||
|
||||
# Install QSpectrumAnalyzer
|
||||
sudo pip3 install qspectrumanalyzer
|
||||
|
||||
Warning! ``pip`` will install packages system-wide by default, but you
|
||||
@ -142,7 +156,6 @@ If you want to install QSpectrumAnalyzer directly from Git master branch, you ca
|
||||
Todo:
|
||||
-----
|
||||
|
||||
- finish soapy_power backend (new universal default backend)
|
||||
- show scan progress
|
||||
- allow setting LNB LO frequency
|
||||
- save & load FFT history (allow big waterfall plot saved to file)
|
||||
|
@ -11,6 +11,7 @@ from qspectrumanalyzer.plot import SpectrumPlotWidget, WaterfallPlotWidget
|
||||
from qspectrumanalyzer.utils import color_to_str, str_to_color
|
||||
|
||||
from qspectrumanalyzer.ui_qspectrumanalyzer_settings import Ui_QSpectrumAnalyzerSettings
|
||||
from qspectrumanalyzer.ui_qspectrumanalyzer_settings_help import Ui_QSpectrumAnalyzerSettingsHelp
|
||||
from qspectrumanalyzer.ui_qspectrumanalyzer_smooth import Ui_QSpectrumAnalyzerSmooth
|
||||
from qspectrumanalyzer.ui_qspectrumanalyzer_persistence import Ui_QSpectrumAnalyzerPersistence
|
||||
from qspectrumanalyzer.ui_qspectrumanalyzer_colors import Ui_QSpectrumAnalyzerColors
|
||||
@ -27,6 +28,7 @@ class QSpectrumAnalyzerSettings(QtGui.QDialog, Ui_QSpectrumAnalyzerSettings):
|
||||
# Initialize UI
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
self.help_dialog = None
|
||||
|
||||
# Load settings
|
||||
settings = QtCore.QSettings()
|
||||
@ -40,15 +42,16 @@ class QSpectrumAnalyzerSettings(QtGui.QDialog, Ui_QSpectrumAnalyzerSettings):
|
||||
except AttributeError:
|
||||
backend_module = backends.soapy_power
|
||||
|
||||
self.paramsEdit.setText(settings.value("params", backend_module.Info.additional_params))
|
||||
self.sampleRateSpinBox.setMinimum(backend_module.Info.sample_rate_min)
|
||||
self.sampleRateSpinBox.setMaximum(backend_module.Info.sample_rate_max)
|
||||
self.sampleRateSpinBox.setValue(settings.value("sample_rate", backend_module.Info.sample_rate, int))
|
||||
|
||||
self.backendComboBox.blockSignals(True)
|
||||
self.backendComboBox.clear()
|
||||
for b in sorted(backends.__all__):
|
||||
self.backendComboBox.addItem(b)
|
||||
|
||||
self.backendComboBox.blockSignals(True)
|
||||
i = self.backendComboBox.findText(backend)
|
||||
if i == -1:
|
||||
self.backendComboBox.setCurrentIndex(0)
|
||||
@ -63,6 +66,23 @@ class QSpectrumAnalyzerSettings(QtGui.QDialog, Ui_QSpectrumAnalyzerSettings):
|
||||
if filename:
|
||||
self.executableEdit.setText(filename)
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def on_helpButton_clicked(self):
|
||||
"""Open help dialog when button is clicked"""
|
||||
try:
|
||||
backend_module = getattr(backends, self.backendComboBox.currentText())
|
||||
except AttributeError:
|
||||
backend_module = backends.soapy_power
|
||||
|
||||
self.help_dialog = QSpectrumAnalyzerSettingsHelp(
|
||||
backend_module.Info.help(self.executableEdit.text()),
|
||||
parent=self
|
||||
)
|
||||
|
||||
self.help_dialog.show()
|
||||
self.help_dialog.raise_()
|
||||
self.help_dialog.activateWindow()
|
||||
|
||||
@QtCore.pyqtSlot(str)
|
||||
def on_backendComboBox_currentIndexChanged(self, text):
|
||||
"""Change executable when backend is changed"""
|
||||
@ -74,6 +94,7 @@ class QSpectrumAnalyzerSettings(QtGui.QDialog, Ui_QSpectrumAnalyzerSettings):
|
||||
except AttributeError:
|
||||
backend_module = backends.soapy_power
|
||||
|
||||
self.paramsEdit.setText(backend_module.Info.additional_params)
|
||||
self.sampleRateSpinBox.setMinimum(backend_module.Info.sample_rate_min)
|
||||
self.sampleRateSpinBox.setMaximum(backend_module.Info.sample_rate_max)
|
||||
self.sampleRateSpinBox.setValue(backend_module.Info.sample_rate)
|
||||
@ -84,11 +105,25 @@ class QSpectrumAnalyzerSettings(QtGui.QDialog, Ui_QSpectrumAnalyzerSettings):
|
||||
settings.setValue("executable", self.executableEdit.text())
|
||||
settings.setValue("waterfall_history_size", self.waterfallHistorySizeSpinBox.value())
|
||||
settings.setValue("device", self.deviceEdit.text())
|
||||
settings.setValue("params", self.paramsEdit.text())
|
||||
settings.setValue("sample_rate", self.sampleRateSpinBox.value())
|
||||
settings.setValue("backend", self.backendComboBox.currentText())
|
||||
QtGui.QDialog.accept(self)
|
||||
|
||||
|
||||
class QSpectrumAnalyzerSettingsHelp(QtGui.QDialog, Ui_QSpectrumAnalyzerSettingsHelp):
|
||||
"""QSpectrumAnalyzer settings help dialog"""
|
||||
def __init__(self, text, parent=None):
|
||||
# Initialize UI
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
monospace_font = QtGui.QFont('monospace')
|
||||
monospace_font.setStyleHint(QtGui.QFont.Monospace)
|
||||
self.helpTextEdit.setFont(monospace_font)
|
||||
self.helpTextEdit.setPlainText(text)
|
||||
|
||||
|
||||
class QSpectrumAnalyzerSmooth(QtGui.QDialog, Ui_QSpectrumAnalyzerSmooth):
|
||||
"""QSpectrumAnalyzer spectrum smoothing dialog"""
|
||||
def __init__(self, parent=None):
|
||||
@ -185,6 +220,7 @@ class QSpectrumAnalyzerMainWindow(QtGui.QMainWindow, Ui_QSpectrumAnalyzerMainWin
|
||||
self.prev_data_timestamp = None
|
||||
self.data_storage = None
|
||||
self.power_thread = None
|
||||
self.backend = None
|
||||
self.setup_power_thread()
|
||||
|
||||
self.update_buttons()
|
||||
@ -213,27 +249,29 @@ class QSpectrumAnalyzerMainWindow(QtGui.QMainWindow, Ui_QSpectrumAnalyzerMainWin
|
||||
except AttributeError:
|
||||
backend_module = backends.soapy_power
|
||||
|
||||
self.gainSpinBox.setMinimum(backend_module.Info.gain_min)
|
||||
self.gainSpinBox.setMaximum(backend_module.Info.gain_max)
|
||||
self.gainSpinBox.setValue(backend_module.Info.gain)
|
||||
self.startFreqSpinBox.setMinimum(backend_module.Info.start_freq_min)
|
||||
self.startFreqSpinBox.setMaximum(backend_module.Info.start_freq_max)
|
||||
self.startFreqSpinBox.setValue(backend_module.Info.start_freq)
|
||||
self.stopFreqSpinBox.setMinimum(backend_module.Info.stop_freq_min)
|
||||
self.stopFreqSpinBox.setMaximum(backend_module.Info.stop_freq_max)
|
||||
self.stopFreqSpinBox.setValue(backend_module.Info.stop_freq)
|
||||
self.binSizeSpinBox.setMinimum(backend_module.Info.bin_size_min)
|
||||
self.binSizeSpinBox.setMaximum(backend_module.Info.bin_size_max)
|
||||
self.binSizeSpinBox.setValue(backend_module.Info.bin_size)
|
||||
self.intervalSpinBox.setMinimum(backend_module.Info.interval_min)
|
||||
self.intervalSpinBox.setMaximum(backend_module.Info.interval_max)
|
||||
self.intervalSpinBox.setValue(backend_module.Info.interval)
|
||||
self.ppmSpinBox.setMinimum(backend_module.Info.ppm_min)
|
||||
self.ppmSpinBox.setMaximum(backend_module.Info.ppm_max)
|
||||
self.ppmSpinBox.setValue(backend_module.Info.ppm)
|
||||
self.cropSpinBox.setMinimum(backend_module.Info.crop_min)
|
||||
self.cropSpinBox.setMaximum(backend_module.Info.crop_max)
|
||||
self.cropSpinBox.setValue(backend_module.Info.crop)
|
||||
if not self.backend or backend != self.backend:
|
||||
self.backend = backend
|
||||
self.gainSpinBox.setMinimum(backend_module.Info.gain_min)
|
||||
self.gainSpinBox.setMaximum(backend_module.Info.gain_max)
|
||||
self.gainSpinBox.setValue(backend_module.Info.gain)
|
||||
self.startFreqSpinBox.setMinimum(backend_module.Info.start_freq_min)
|
||||
self.startFreqSpinBox.setMaximum(backend_module.Info.start_freq_max)
|
||||
self.startFreqSpinBox.setValue(backend_module.Info.start_freq)
|
||||
self.stopFreqSpinBox.setMinimum(backend_module.Info.stop_freq_min)
|
||||
self.stopFreqSpinBox.setMaximum(backend_module.Info.stop_freq_max)
|
||||
self.stopFreqSpinBox.setValue(backend_module.Info.stop_freq)
|
||||
self.binSizeSpinBox.setMinimum(backend_module.Info.bin_size_min)
|
||||
self.binSizeSpinBox.setMaximum(backend_module.Info.bin_size_max)
|
||||
self.binSizeSpinBox.setValue(backend_module.Info.bin_size)
|
||||
self.intervalSpinBox.setMinimum(backend_module.Info.interval_min)
|
||||
self.intervalSpinBox.setMaximum(backend_module.Info.interval_max)
|
||||
self.intervalSpinBox.setValue(backend_module.Info.interval)
|
||||
self.ppmSpinBox.setMinimum(backend_module.Info.ppm_min)
|
||||
self.ppmSpinBox.setMaximum(backend_module.Info.ppm_max)
|
||||
self.ppmSpinBox.setValue(backend_module.Info.ppm)
|
||||
self.cropSpinBox.setMinimum(backend_module.Info.crop_min)
|
||||
self.cropSpinBox.setMaximum(backend_module.Info.crop_max)
|
||||
self.cropSpinBox.setValue(backend_module.Info.crop)
|
||||
|
||||
self.power_thread = backend_module.PowerThread(self.data_storage)
|
||||
self.power_thread.powerThreadStarted.connect(self.update_buttons)
|
||||
|
@ -1,4 +1,4 @@
|
||||
import os, glob
|
||||
import os, glob, subprocess
|
||||
|
||||
from PyQt4 import QtCore
|
||||
|
||||
@ -6,16 +6,16 @@ from PyQt4 import QtCore
|
||||
class BaseInfo:
|
||||
"""Default device metadata"""
|
||||
sample_rate_min = 0
|
||||
sample_rate_max = 61440000
|
||||
sample_rate_max = 3200000
|
||||
sample_rate = 2560000
|
||||
gain_min = -1
|
||||
gain_max = 49
|
||||
gain = -1
|
||||
gain = 37
|
||||
start_freq_min = 24
|
||||
start_freq_max = 1766
|
||||
start_freq_max = 2200
|
||||
start_freq = 87
|
||||
stop_freq_min = 24
|
||||
stop_freq_max = 1766
|
||||
stop_freq_max = 2200
|
||||
stop_freq = 108
|
||||
bin_size_min = 0
|
||||
bin_size_max = 2800
|
||||
@ -29,6 +29,18 @@ class BaseInfo:
|
||||
crop_min = 0
|
||||
crop_max = 99
|
||||
crop = 0
|
||||
additional_params = ''
|
||||
|
||||
@classmethod
|
||||
def help(cls, executable):
|
||||
try:
|
||||
p = subprocess.run([executable, '-h'], universal_newlines=True,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
env=dict(os.environ, COLUMNS='125'))
|
||||
text = p.stdout
|
||||
except OSError:
|
||||
text = '{} executable not found!'.format(executable)
|
||||
return text
|
||||
|
||||
|
||||
class BasePowerThread(QtCore.QThread):
|
||||
|
@ -1,8 +1,7 @@
|
||||
import subprocess, pprint
|
||||
import subprocess, pprint, struct, shlex
|
||||
|
||||
import numpy as np
|
||||
from PyQt4 import QtCore
|
||||
import struct
|
||||
|
||||
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
|
||||
|
||||
@ -102,6 +101,10 @@ class PowerThread(BasePowerThread):
|
||||
if self.params["single_shot"]:
|
||||
cmdline.append("-1")
|
||||
|
||||
additional_params = settings.value("params", Info.additional_params)
|
||||
if additional_params:
|
||||
cmdline.extend(shlex.split(additional_params))
|
||||
|
||||
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
|
||||
universal_newlines=False)
|
||||
|
||||
@ -138,6 +141,10 @@ class PowerThread(BasePowerThread):
|
||||
buf = self.process.stdout.read(record_length)
|
||||
if buf:
|
||||
self.parse_output(buf)
|
||||
else:
|
||||
break
|
||||
else:
|
||||
break
|
||||
|
||||
self.process_stop()
|
||||
self.alive = False
|
||||
|
@ -1,4 +1,4 @@
|
||||
import subprocess, pprint
|
||||
import subprocess, pprint, shlex
|
||||
|
||||
import numpy as np
|
||||
from PyQt4 import QtCore
|
||||
@ -57,6 +57,10 @@ class PowerThread(BasePowerThread):
|
||||
if self.params["single_shot"]:
|
||||
cmdline.append("-1")
|
||||
|
||||
additional_params = settings.value("params", Info.additional_params)
|
||||
if additional_params:
|
||||
cmdline.extend(shlex.split(additional_params))
|
||||
|
||||
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import subprocess, math, pprint
|
||||
import subprocess, math, pprint, shlex
|
||||
|
||||
from PyQt4 import QtCore
|
||||
|
||||
@ -84,6 +84,10 @@ class PowerThread(BasePowerThread):
|
||||
if not self.params["single_shot"]:
|
||||
cmdline.append("-c")
|
||||
|
||||
additional_params = settings.value("params", Info.additional_params)
|
||||
if additional_params:
|
||||
cmdline.extend(shlex.split(additional_params))
|
||||
|
||||
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
|
||||
universal_newlines=True)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import subprocess, pprint
|
||||
import subprocess, pprint, shlex
|
||||
|
||||
import numpy as np
|
||||
from PyQt4 import QtCore
|
||||
@ -8,7 +8,12 @@ from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
|
||||
|
||||
class Info(BaseInfo):
|
||||
"""rx_power device metadata"""
|
||||
pass
|
||||
sample_rate_min = 0
|
||||
sample_rate_max = 61440000
|
||||
start_freq_min = 0
|
||||
start_freq_max = 6000
|
||||
stop_freq_min = 0
|
||||
stop_freq_max = 6000
|
||||
|
||||
|
||||
class PowerThread(BasePowerThread):
|
||||
@ -55,6 +60,10 @@ class PowerThread(BasePowerThread):
|
||||
if self.params["single_shot"]:
|
||||
cmdline.append("-1")
|
||||
|
||||
additional_params = settings.value("params", Info.additional_params)
|
||||
if additional_params:
|
||||
cmdline.extend(shlex.split(additional_params))
|
||||
|
||||
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
|
||||
|
@ -1,19 +1,27 @@
|
||||
import subprocess, pprint, re
|
||||
import subprocess, pprint, sys, shlex
|
||||
|
||||
import numpy as np
|
||||
from PyQt4 import QtCore
|
||||
|
||||
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
|
||||
from soapypower.writer import SoapyPowerBinFormat
|
||||
|
||||
formatter = SoapyPowerBinFormat()
|
||||
|
||||
|
||||
class Info(BaseInfo):
|
||||
"""soapy_power device metadata"""
|
||||
pass
|
||||
sample_rate_min = 0
|
||||
sample_rate_max = 61440000
|
||||
start_freq_min = 0
|
||||
start_freq_max = 6000
|
||||
stop_freq_min = 0
|
||||
stop_freq_max = 6000
|
||||
additional_params = '--even --fft-window boxcar --remove-dc'
|
||||
|
||||
|
||||
class PowerThread(BasePowerThread):
|
||||
"""Thread which runs soapy_power process"""
|
||||
re_two_floats = re.compile(r'^[-+\d.eE]+\s+[-+\d.eE]+$')
|
||||
|
||||
def setup(self, start_freq, stop_freq, bin_size, interval=10.0, gain=-1,
|
||||
ppm=0, crop=0, single_shot=False, device="", sample_rate=2560000):
|
||||
"""Setup soapy_power params"""
|
||||
@ -31,10 +39,7 @@ class PowerThread(BasePowerThread):
|
||||
"single_shot": single_shot
|
||||
}
|
||||
self.databuffer = {"timestamp": [], "x": [], "y": []}
|
||||
self.databuffer_hop = {"timestamp": [], "x": [], "y": []}
|
||||
self.hop = 0
|
||||
self.run = 0
|
||||
self.prev_line = ""
|
||||
self.min_freq = 0
|
||||
|
||||
print("soapy_power params:")
|
||||
pprint.pprint(self.params)
|
||||
@ -53,6 +58,7 @@ class PowerThread(BasePowerThread):
|
||||
"-d", "{}".format(self.params["device"]),
|
||||
"-r", "{}".format(self.params["sample_rate"]),
|
||||
"-p", "{}".format(self.params["ppm"]),
|
||||
"-F", "soapy_power_bin",
|
||||
]
|
||||
|
||||
if self.params["gain"] >= 0:
|
||||
@ -62,50 +68,59 @@ class PowerThread(BasePowerThread):
|
||||
if not self.params["single_shot"]:
|
||||
cmdline.append("-c")
|
||||
|
||||
additional_params = settings.value("params", Info.additional_params)
|
||||
if additional_params:
|
||||
cmdline.extend(shlex.split(additional_params))
|
||||
|
||||
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
universal_newlines=False)
|
||||
|
||||
def parse_output(self, line):
|
||||
"""Parse one line of output from soapy_power"""
|
||||
line = line.strip()
|
||||
def parse_output(self, data):
|
||||
"""Parse data from soapy_power"""
|
||||
header, y_axis = data
|
||||
|
||||
# One empty line => new hop
|
||||
if not line and self.prev_line:
|
||||
self.hop += 1
|
||||
print(' => HOP:', self.hop)
|
||||
self.databuffer["x"].extend(self.databuffer_hop["x"])
|
||||
self.databuffer["y"].extend(self.databuffer_hop["y"])
|
||||
self.databuffer_hop = {"timestamp": [], "x": [], "y": []}
|
||||
timestamp = header.timestamp
|
||||
start_freq = header.start
|
||||
stop_freq = header.stop
|
||||
step = header.step
|
||||
samples = header.samples
|
||||
|
||||
# Two empty lines => new set
|
||||
elif not line and not self.prev_line:
|
||||
self.hop = 0
|
||||
self.run += 1
|
||||
print(' * RUN:', self.run)
|
||||
x_axis = np.arange(start_freq, stop_freq, step)
|
||||
if len(x_axis) != len(y_axis):
|
||||
print("ERROR: len(x_axis) != len(y_axis)")
|
||||
|
||||
if not self.min_freq:
|
||||
self.min_freq = start_freq
|
||||
|
||||
if start_freq == self.min_freq:
|
||||
self.databuffer = {"timestamp": timestamp,
|
||||
"x": list(x_axis),
|
||||
"y": list(y_axis)}
|
||||
else:
|
||||
self.databuffer["x"].extend(x_axis)
|
||||
self.databuffer["y"].extend(y_axis)
|
||||
|
||||
if stop_freq > (self.params["stop_freq"] * 1e6) - step:
|
||||
self.data_storage.update(self.databuffer)
|
||||
self.databuffer = {"timestamp": [], "x": [], "y": []}
|
||||
|
||||
# Get timestamp for new hop and set
|
||||
elif line.startswith("# Acquisition start:"):
|
||||
timestamp = line.split(":", 1)[1].strip()
|
||||
if not self.databuffer_hop["timestamp"]:
|
||||
self.databuffer_hop["timestamp"] = timestamp
|
||||
if not self.databuffer["timestamp"]:
|
||||
self.databuffer["timestamp"] = timestamp
|
||||
def run(self):
|
||||
"""soapy_power thread main loop"""
|
||||
self.process_start()
|
||||
self.alive = True
|
||||
self.powerThreadStarted.emit()
|
||||
|
||||
# Skip other comments
|
||||
elif line.startswith("#"):
|
||||
pass
|
||||
|
||||
# Parse frequency and power
|
||||
elif self.re_two_floats.match(line):
|
||||
while self.alive:
|
||||
try:
|
||||
freq, power = line.split()
|
||||
except ValueError:
|
||||
return
|
||||
data = formatter.read(self.process.stdout)
|
||||
except ValueError as e:
|
||||
print(e, file=sys.stderr)
|
||||
break
|
||||
|
||||
freq, power = float(freq), float(power)
|
||||
self.databuffer_hop["x"].append(freq)
|
||||
self.databuffer_hop["y"].append(power)
|
||||
if data:
|
||||
self.parse_output(data)
|
||||
else:
|
||||
break
|
||||
|
||||
self.prev_line = line
|
||||
self.process_stop()
|
||||
self.alive = False
|
||||
self.powerThreadStopped.emit()
|
||||
|
@ -81,22 +81,22 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../__main__.py" line="337"/>
|
||||
<location filename="../__main__.py" line="383"/>
|
||||
<source>Frequency hops: {} | Sweep time: {:.2f} s | FPS: {:.2f}</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../__main__.py" line="337"/>
|
||||
<location filename="../__main__.py" line="383"/>
|
||||
<source>N/A</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../__main__.py" line="504"/>
|
||||
<location filename="../__main__.py" line="550"/>
|
||||
<source>About - QSpectrumAnalyzer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../__main__.py" line="504"/>
|
||||
<location filename="../__main__.py" line="550"/>
|
||||
<source>QSpectrumAnalyzer {}</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -252,70 +252,88 @@
|
||||
<context>
|
||||
<name>QSpectrumAnalyzerSettings</name>
|
||||
<message>
|
||||
<location filename="../__main__.py" line="50"/>
|
||||
<location filename="../__main__.py" line="65"/>
|
||||
<source>Select executable - QSpectrumAnalyzer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="107"/>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="122"/>
|
||||
<source>Settings - QSpectrumAnalyzer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="108"/>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="123"/>
|
||||
<source>&Backend:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="115"/>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="130"/>
|
||||
<source>soapy_power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="110"/>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="125"/>
|
||||
<source>rx_power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="111"/>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="126"/>
|
||||
<source>rtl_power_fftw</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="112"/>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="127"/>
|
||||
<source>rtl_power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="113"/>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="128"/>
|
||||
<source>hackrf_sweep</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="114"/>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="129"/>
|
||||
<source>E&xecutable:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="116"/>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="131"/>
|
||||
<source>...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="117"/>
|
||||
<source>Device:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="118"/>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="133"/>
|
||||
<source>Sa&mple rate:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="119"/>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="134"/>
|
||||
<source>&Waterfall history size:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="132"/>
|
||||
<source>&Device:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="135"/>
|
||||
<source>Additional &parameters:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="136"/>
|
||||
<source>?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QSpectrumAnalyzerSettingsHelp</name>
|
||||
<message>
|
||||
<location filename="../ui_qspectrumanalyzer_settings_help.py" line="49"/>
|
||||
<source>Help - QSpectrumAnalyzer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QSpectrumAnalyzerSmooth</name>
|
||||
|
@ -42,6 +42,9 @@ class SpectrumPlotWidget:
|
||||
self.plot.setLimits(xMin=0)
|
||||
self.plot.showButtons()
|
||||
|
||||
#self.plot.setDownsampling(mode="peak")
|
||||
#self.plot.setClipToView(True)
|
||||
|
||||
self.create_persistence_curves()
|
||||
self.create_average_curve()
|
||||
self.create_peak_hold_min_curve()
|
||||
@ -264,6 +267,7 @@ class WaterfallPlotWidget:
|
||||
self.plot.setLimits(xMin=0, yMax=0)
|
||||
self.plot.showButtons()
|
||||
#self.plot.setAspectLocked(True)
|
||||
|
||||
#self.plot.setDownsampling(mode="peak")
|
||||
#self.plot.setClipToView(True)
|
||||
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>420</width>
|
||||
<height>255</height>
|
||||
<width>600</width>
|
||||
<height>310</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -86,7 +86,7 @@
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Device:</string>
|
||||
<string>&Device:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>deviceEdit</cstring>
|
||||
@ -96,7 +96,7 @@
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="deviceEdit"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Sa&mple rate:</string>
|
||||
@ -106,7 +106,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="sampleRateSpinBox">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
@ -122,7 +122,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>&Waterfall history size:</string>
|
||||
@ -132,7 +132,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="5" column="1">
|
||||
<widget class="QSpinBox" name="waterfallHistorySizeSpinBox">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
@ -145,6 +145,30 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Additional &parameters:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>paramsEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="paramsEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="helpButton">
|
||||
<property name="text">
|
||||
<string>?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
@ -177,6 +201,8 @@
|
||||
<tabstop>executableEdit</tabstop>
|
||||
<tabstop>executableButton</tabstop>
|
||||
<tabstop>deviceEdit</tabstop>
|
||||
<tabstop>paramsEdit</tabstop>
|
||||
<tabstop>helpButton</tabstop>
|
||||
<tabstop>sampleRateSpinBox</tabstop>
|
||||
<tabstop>waterfallHistorySizeSpinBox</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
@ -190,8 +216,8 @@
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>242</x>
|
||||
<y>248</y>
|
||||
<x>248</x>
|
||||
<y>303</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
@ -206,8 +232,8 @@
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>310</x>
|
||||
<y>248</y>
|
||||
<x>316</x>
|
||||
<y>303</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
|
78
qspectrumanalyzer/qspectrumanalyzer_settings_help.ui
Normal file
78
qspectrumanalyzer/qspectrumanalyzer_settings_help.ui
Normal file
@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QSpectrumAnalyzerSettingsHelp</class>
|
||||
<widget class="QDialog" name="QSpectrumAnalyzerSettingsHelp">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1200</width>
|
||||
<height>700</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Help - QSpectrumAnalyzer</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="helpTextEdit">
|
||||
<property name="undoRedoEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>helpTextEdit</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>QSpectrumAnalyzerSettingsHelp</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>224</x>
|
||||
<y>672</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>QSpectrumAnalyzerSettingsHelp</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>292</x>
|
||||
<y>678</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -25,7 +25,7 @@ except AttributeError:
|
||||
class Ui_QSpectrumAnalyzerSettings(object):
|
||||
def setupUi(self, QSpectrumAnalyzerSettings):
|
||||
QSpectrumAnalyzerSettings.setObjectName(_fromUtf8("QSpectrumAnalyzerSettings"))
|
||||
QSpectrumAnalyzerSettings.resize(420, 255)
|
||||
QSpectrumAnalyzerSettings.resize(600, 310)
|
||||
self.verticalLayout = QtGui.QVBoxLayout(QSpectrumAnalyzerSettings)
|
||||
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
|
||||
self.formLayout = QtGui.QFormLayout()
|
||||
@ -61,23 +61,35 @@ class Ui_QSpectrumAnalyzerSettings(object):
|
||||
self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.deviceEdit)
|
||||
self.label_4 = QtGui.QLabel(QSpectrumAnalyzerSettings)
|
||||
self.label_4.setObjectName(_fromUtf8("label_4"))
|
||||
self.formLayout.setWidget(3, QtGui.QFormLayout.LabelRole, self.label_4)
|
||||
self.formLayout.setWidget(4, QtGui.QFormLayout.LabelRole, self.label_4)
|
||||
self.sampleRateSpinBox = QtGui.QSpinBox(QSpectrumAnalyzerSettings)
|
||||
self.sampleRateSpinBox.setMinimum(0)
|
||||
self.sampleRateSpinBox.setMaximum(25000000)
|
||||
self.sampleRateSpinBox.setSingleStep(10000)
|
||||
self.sampleRateSpinBox.setProperty("value", 2560000)
|
||||
self.sampleRateSpinBox.setObjectName(_fromUtf8("sampleRateSpinBox"))
|
||||
self.formLayout.setWidget(3, QtGui.QFormLayout.FieldRole, self.sampleRateSpinBox)
|
||||
self.formLayout.setWidget(4, QtGui.QFormLayout.FieldRole, self.sampleRateSpinBox)
|
||||
self.label_2 = QtGui.QLabel(QSpectrumAnalyzerSettings)
|
||||
self.label_2.setObjectName(_fromUtf8("label_2"))
|
||||
self.formLayout.setWidget(4, QtGui.QFormLayout.LabelRole, self.label_2)
|
||||
self.formLayout.setWidget(5, QtGui.QFormLayout.LabelRole, self.label_2)
|
||||
self.waterfallHistorySizeSpinBox = QtGui.QSpinBox(QSpectrumAnalyzerSettings)
|
||||
self.waterfallHistorySizeSpinBox.setMinimum(1)
|
||||
self.waterfallHistorySizeSpinBox.setMaximum(10000000)
|
||||
self.waterfallHistorySizeSpinBox.setProperty("value", 100)
|
||||
self.waterfallHistorySizeSpinBox.setObjectName(_fromUtf8("waterfallHistorySizeSpinBox"))
|
||||
self.formLayout.setWidget(4, QtGui.QFormLayout.FieldRole, self.waterfallHistorySizeSpinBox)
|
||||
self.formLayout.setWidget(5, QtGui.QFormLayout.FieldRole, self.waterfallHistorySizeSpinBox)
|
||||
self.label_6 = QtGui.QLabel(QSpectrumAnalyzerSettings)
|
||||
self.label_6.setObjectName(_fromUtf8("label_6"))
|
||||
self.formLayout.setWidget(3, QtGui.QFormLayout.LabelRole, self.label_6)
|
||||
self.horizontalLayout_3 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName(_fromUtf8("horizontalLayout_3"))
|
||||
self.paramsEdit = QtGui.QLineEdit(QSpectrumAnalyzerSettings)
|
||||
self.paramsEdit.setObjectName(_fromUtf8("paramsEdit"))
|
||||
self.horizontalLayout_3.addWidget(self.paramsEdit)
|
||||
self.helpButton = QtGui.QToolButton(QSpectrumAnalyzerSettings)
|
||||
self.helpButton.setObjectName(_fromUtf8("helpButton"))
|
||||
self.horizontalLayout_3.addWidget(self.helpButton)
|
||||
self.formLayout.setLayout(3, QtGui.QFormLayout.FieldRole, self.horizontalLayout_3)
|
||||
self.verticalLayout.addLayout(self.formLayout)
|
||||
spacerItem = QtGui.QSpacerItem(20, 21, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
||||
self.verticalLayout.addItem(spacerItem)
|
||||
@ -91,6 +103,7 @@ class Ui_QSpectrumAnalyzerSettings(object):
|
||||
self.label_5.setBuddy(self.deviceEdit)
|
||||
self.label_4.setBuddy(self.sampleRateSpinBox)
|
||||
self.label_2.setBuddy(self.waterfallHistorySizeSpinBox)
|
||||
self.label_6.setBuddy(self.paramsEdit)
|
||||
|
||||
self.retranslateUi(QSpectrumAnalyzerSettings)
|
||||
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), QSpectrumAnalyzerSettings.accept)
|
||||
@ -99,7 +112,9 @@ class Ui_QSpectrumAnalyzerSettings(object):
|
||||
QSpectrumAnalyzerSettings.setTabOrder(self.backendComboBox, self.executableEdit)
|
||||
QSpectrumAnalyzerSettings.setTabOrder(self.executableEdit, self.executableButton)
|
||||
QSpectrumAnalyzerSettings.setTabOrder(self.executableButton, self.deviceEdit)
|
||||
QSpectrumAnalyzerSettings.setTabOrder(self.deviceEdit, self.sampleRateSpinBox)
|
||||
QSpectrumAnalyzerSettings.setTabOrder(self.deviceEdit, self.paramsEdit)
|
||||
QSpectrumAnalyzerSettings.setTabOrder(self.paramsEdit, self.helpButton)
|
||||
QSpectrumAnalyzerSettings.setTabOrder(self.helpButton, self.sampleRateSpinBox)
|
||||
QSpectrumAnalyzerSettings.setTabOrder(self.sampleRateSpinBox, self.waterfallHistorySizeSpinBox)
|
||||
QSpectrumAnalyzerSettings.setTabOrder(self.waterfallHistorySizeSpinBox, self.buttonBox)
|
||||
|
||||
@ -114,7 +129,9 @@ class Ui_QSpectrumAnalyzerSettings(object):
|
||||
self.label.setText(_translate("QSpectrumAnalyzerSettings", "E&xecutable:", None))
|
||||
self.executableEdit.setText(_translate("QSpectrumAnalyzerSettings", "soapy_power", None))
|
||||
self.executableButton.setText(_translate("QSpectrumAnalyzerSettings", "...", None))
|
||||
self.label_5.setText(_translate("QSpectrumAnalyzerSettings", "Device:", None))
|
||||
self.label_5.setText(_translate("QSpectrumAnalyzerSettings", "&Device:", None))
|
||||
self.label_4.setText(_translate("QSpectrumAnalyzerSettings", "Sa&mple rate:", None))
|
||||
self.label_2.setText(_translate("QSpectrumAnalyzerSettings", "&Waterfall history size:", None))
|
||||
self.label_6.setText(_translate("QSpectrumAnalyzerSettings", "Additional ¶meters:", None))
|
||||
self.helpButton.setText(_translate("QSpectrumAnalyzerSettings", "?", None))
|
||||
|
||||
|
50
qspectrumanalyzer/ui_qspectrumanalyzer_settings_help.py
Normal file
50
qspectrumanalyzer/ui_qspectrumanalyzer_settings_help.py
Normal file
@ -0,0 +1,50 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer_settings_help.ui'
|
||||
#
|
||||
# Created by: PyQt4 UI code generator 4.12
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||
except AttributeError:
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig)
|
||||
|
||||
class Ui_QSpectrumAnalyzerSettingsHelp(object):
|
||||
def setupUi(self, QSpectrumAnalyzerSettingsHelp):
|
||||
QSpectrumAnalyzerSettingsHelp.setObjectName(_fromUtf8("QSpectrumAnalyzerSettingsHelp"))
|
||||
QSpectrumAnalyzerSettingsHelp.resize(1200, 700)
|
||||
self.verticalLayout = QtGui.QVBoxLayout(QSpectrumAnalyzerSettingsHelp)
|
||||
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
|
||||
self.helpTextEdit = QtGui.QPlainTextEdit(QSpectrumAnalyzerSettingsHelp)
|
||||
self.helpTextEdit.setUndoRedoEnabled(False)
|
||||
self.helpTextEdit.setTextInteractionFlags(QtCore.Qt.TextSelectableByKeyboard|QtCore.Qt.TextSelectableByMouse)
|
||||
self.helpTextEdit.setObjectName(_fromUtf8("helpTextEdit"))
|
||||
self.verticalLayout.addWidget(self.helpTextEdit)
|
||||
self.buttonBox = QtGui.QDialogButtonBox(QSpectrumAnalyzerSettingsHelp)
|
||||
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Close)
|
||||
self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
|
||||
self.verticalLayout.addWidget(self.buttonBox)
|
||||
|
||||
self.retranslateUi(QSpectrumAnalyzerSettingsHelp)
|
||||
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), QSpectrumAnalyzerSettingsHelp.accept)
|
||||
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), QSpectrumAnalyzerSettingsHelp.reject)
|
||||
QtCore.QMetaObject.connectSlotsByName(QSpectrumAnalyzerSettingsHelp)
|
||||
QSpectrumAnalyzerSettingsHelp.setTabOrder(self.helpTextEdit, self.buttonBox)
|
||||
|
||||
def retranslateUi(self, QSpectrumAnalyzerSettingsHelp):
|
||||
QSpectrumAnalyzerSettingsHelp.setWindowTitle(_translate("QSpectrumAnalyzerSettingsHelp", "Help - QSpectrumAnalyzer", None))
|
||||
|
@ -1 +1 @@
|
||||
__version__ = "1.4.0"
|
||||
__version__ = "1.5.0"
|
||||
|
4
setup.py
4
setup.py
@ -6,7 +6,8 @@ from qspectrumanalyzer.version import __version__
|
||||
setup(
|
||||
name="QSpectrumAnalyzer",
|
||||
version=__version__,
|
||||
description="Spectrum analyzer for RTL-SDR (GUI for rtl_power based on PyQtGraph)",
|
||||
description="Spectrum analyzer for multiple SDR platforms (PyQtGraph based GUI for soapy_power, rx_power, rtl_power, hackrf_sweep and other backends)",
|
||||
long_description=open('README.rst').read(),
|
||||
author="Michal Krenek (Mikos)",
|
||||
author_email="m.krenek@gmail.com",
|
||||
url="https://github.com/xmikos/qspectrumanalyzer",
|
||||
@ -29,6 +30,7 @@ setup(
|
||||
],
|
||||
},
|
||||
install_requires=[
|
||||
"soapy_power",
|
||||
"pyqtgraph"
|
||||
],
|
||||
classifiers=[
|
||||
|
Loading…
Reference in New Issue
Block a user