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>
|
# Maintainer: Michal Krenek (Mikos) <m.krenek@gmail.com>
|
||||||
pkgname=qspectrumanalyzer
|
pkgname=qspectrumanalyzer
|
||||||
pkgver=1.4.0
|
pkgver=1.5.0
|
||||||
pkgrel=1
|
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')
|
arch=('any')
|
||||||
url="https://github.com/xmikos/qspectrumanalyzer"
|
url="https://github.com/xmikos/qspectrumanalyzer"
|
||||||
license=('GPL3')
|
license=('GPL3')
|
||||||
depends=('python-pyqt4' 'python-pyqtgraph' 'rtl-sdr')
|
depends=('python-pyqt4' 'python-pyqtgraph' 'soapy_power')
|
||||||
makedepends=('python-setuptools')
|
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)
|
source=(https://github.com/xmikos/qspectrumanalyzer/archive/v$pkgver.tar.gz)
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
|
39
README.rst
39
README.rst
@ -17,7 +17,8 @@ Requirements
|
|||||||
- Python >= 3.3
|
- Python >= 3.3
|
||||||
- PyQt >= 4.5
|
- PyQt >= 4.5
|
||||||
- PyQtGraph (http://www.pyqtgraph.org)
|
- 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
|
Backends
|
||||||
--------
|
--------
|
||||||
@ -36,7 +37,7 @@ USRP and some other SDR devices).
|
|||||||
|
|
||||||
``rx_power`` (part of ``rx_tools``) is also based on SoapySDR and therefore
|
``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
|
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.
|
and is little buggy.
|
||||||
|
|
||||||
RTL-SDR backends
|
RTL-SDR backends
|
||||||
@ -73,14 +74,14 @@ Usage
|
|||||||
Start QSpectrumAnalyzer by running ``qspectrumanalyzer``.
|
Start QSpectrumAnalyzer by running ``qspectrumanalyzer``.
|
||||||
|
|
||||||
You can choose which backend you want to use in *File* -> *Settings*
|
You can choose which backend you want to use in *File* -> *Settings*
|
||||||
(default is ``soapy_power``). Sample rate and path to backend executable
|
(default is ``soapy_power``). Sample rate, path to backend executable
|
||||||
can be also manually specified there. You can also set waterfall plot
|
and additional backend parameters can be also manually specified there.
|
||||||
history size. Default is 100 lines, be aware that really large sweeps
|
You can also set waterfall plot history size. Default is 100 lines, be aware
|
||||||
(with a lot of bins) would require a lot of system memory,
|
that really large sweeps (with a lot of bins) would require a lot of system
|
||||||
so don't make this number too big.
|
memory, so don't make this number too big.
|
||||||
|
|
||||||
Controls should be intuitive, but if you want consistent results, you should
|
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
|
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>`_.
|
stick, use `kalibrate-rtl <https://github.com/steve-m/kalibrate-rtl>`_.
|
||||||
|
|
||||||
@ -108,17 +109,30 @@ Git master branch:
|
|||||||
cd qspectrumanalyzer-git
|
cd qspectrumanalyzer-git
|
||||||
makepkg -sri
|
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
|
||||||
pacaur -S qspectrumanalyzer-git
|
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
|
sudo pip3 install qspectrumanalyzer
|
||||||
|
|
||||||
Warning! ``pip`` will install packages system-wide by default, but you
|
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:
|
Todo:
|
||||||
-----
|
-----
|
||||||
|
|
||||||
- finish soapy_power backend (new universal default backend)
|
|
||||||
- show scan progress
|
- show scan progress
|
||||||
- allow setting LNB LO frequency
|
- allow setting LNB LO frequency
|
||||||
- save & load FFT history (allow big waterfall plot saved to file)
|
- 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.utils import color_to_str, str_to_color
|
||||||
|
|
||||||
from qspectrumanalyzer.ui_qspectrumanalyzer_settings import Ui_QSpectrumAnalyzerSettings
|
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_smooth import Ui_QSpectrumAnalyzerSmooth
|
||||||
from qspectrumanalyzer.ui_qspectrumanalyzer_persistence import Ui_QSpectrumAnalyzerPersistence
|
from qspectrumanalyzer.ui_qspectrumanalyzer_persistence import Ui_QSpectrumAnalyzerPersistence
|
||||||
from qspectrumanalyzer.ui_qspectrumanalyzer_colors import Ui_QSpectrumAnalyzerColors
|
from qspectrumanalyzer.ui_qspectrumanalyzer_colors import Ui_QSpectrumAnalyzerColors
|
||||||
@ -27,6 +28,7 @@ class QSpectrumAnalyzerSettings(QtGui.QDialog, Ui_QSpectrumAnalyzerSettings):
|
|||||||
# Initialize UI
|
# Initialize UI
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
self.help_dialog = None
|
||||||
|
|
||||||
# Load settings
|
# Load settings
|
||||||
settings = QtCore.QSettings()
|
settings = QtCore.QSettings()
|
||||||
@ -40,15 +42,16 @@ class QSpectrumAnalyzerSettings(QtGui.QDialog, Ui_QSpectrumAnalyzerSettings):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
backend_module = backends.soapy_power
|
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.setMinimum(backend_module.Info.sample_rate_min)
|
||||||
self.sampleRateSpinBox.setMaximum(backend_module.Info.sample_rate_max)
|
self.sampleRateSpinBox.setMaximum(backend_module.Info.sample_rate_max)
|
||||||
self.sampleRateSpinBox.setValue(settings.value("sample_rate", backend_module.Info.sample_rate, int))
|
self.sampleRateSpinBox.setValue(settings.value("sample_rate", backend_module.Info.sample_rate, int))
|
||||||
|
|
||||||
|
self.backendComboBox.blockSignals(True)
|
||||||
self.backendComboBox.clear()
|
self.backendComboBox.clear()
|
||||||
for b in sorted(backends.__all__):
|
for b in sorted(backends.__all__):
|
||||||
self.backendComboBox.addItem(b)
|
self.backendComboBox.addItem(b)
|
||||||
|
|
||||||
self.backendComboBox.blockSignals(True)
|
|
||||||
i = self.backendComboBox.findText(backend)
|
i = self.backendComboBox.findText(backend)
|
||||||
if i == -1:
|
if i == -1:
|
||||||
self.backendComboBox.setCurrentIndex(0)
|
self.backendComboBox.setCurrentIndex(0)
|
||||||
@ -63,6 +66,23 @@ class QSpectrumAnalyzerSettings(QtGui.QDialog, Ui_QSpectrumAnalyzerSettings):
|
|||||||
if filename:
|
if filename:
|
||||||
self.executableEdit.setText(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)
|
@QtCore.pyqtSlot(str)
|
||||||
def on_backendComboBox_currentIndexChanged(self, text):
|
def on_backendComboBox_currentIndexChanged(self, text):
|
||||||
"""Change executable when backend is changed"""
|
"""Change executable when backend is changed"""
|
||||||
@ -74,6 +94,7 @@ class QSpectrumAnalyzerSettings(QtGui.QDialog, Ui_QSpectrumAnalyzerSettings):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
backend_module = backends.soapy_power
|
backend_module = backends.soapy_power
|
||||||
|
|
||||||
|
self.paramsEdit.setText(backend_module.Info.additional_params)
|
||||||
self.sampleRateSpinBox.setMinimum(backend_module.Info.sample_rate_min)
|
self.sampleRateSpinBox.setMinimum(backend_module.Info.sample_rate_min)
|
||||||
self.sampleRateSpinBox.setMaximum(backend_module.Info.sample_rate_max)
|
self.sampleRateSpinBox.setMaximum(backend_module.Info.sample_rate_max)
|
||||||
self.sampleRateSpinBox.setValue(backend_module.Info.sample_rate)
|
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("executable", self.executableEdit.text())
|
||||||
settings.setValue("waterfall_history_size", self.waterfallHistorySizeSpinBox.value())
|
settings.setValue("waterfall_history_size", self.waterfallHistorySizeSpinBox.value())
|
||||||
settings.setValue("device", self.deviceEdit.text())
|
settings.setValue("device", self.deviceEdit.text())
|
||||||
|
settings.setValue("params", self.paramsEdit.text())
|
||||||
settings.setValue("sample_rate", self.sampleRateSpinBox.value())
|
settings.setValue("sample_rate", self.sampleRateSpinBox.value())
|
||||||
settings.setValue("backend", self.backendComboBox.currentText())
|
settings.setValue("backend", self.backendComboBox.currentText())
|
||||||
QtGui.QDialog.accept(self)
|
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):
|
class QSpectrumAnalyzerSmooth(QtGui.QDialog, Ui_QSpectrumAnalyzerSmooth):
|
||||||
"""QSpectrumAnalyzer spectrum smoothing dialog"""
|
"""QSpectrumAnalyzer spectrum smoothing dialog"""
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
@ -185,6 +220,7 @@ class QSpectrumAnalyzerMainWindow(QtGui.QMainWindow, Ui_QSpectrumAnalyzerMainWin
|
|||||||
self.prev_data_timestamp = None
|
self.prev_data_timestamp = None
|
||||||
self.data_storage = None
|
self.data_storage = None
|
||||||
self.power_thread = None
|
self.power_thread = None
|
||||||
|
self.backend = None
|
||||||
self.setup_power_thread()
|
self.setup_power_thread()
|
||||||
|
|
||||||
self.update_buttons()
|
self.update_buttons()
|
||||||
@ -213,27 +249,29 @@ class QSpectrumAnalyzerMainWindow(QtGui.QMainWindow, Ui_QSpectrumAnalyzerMainWin
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
backend_module = backends.soapy_power
|
backend_module = backends.soapy_power
|
||||||
|
|
||||||
self.gainSpinBox.setMinimum(backend_module.Info.gain_min)
|
if not self.backend or backend != self.backend:
|
||||||
self.gainSpinBox.setMaximum(backend_module.Info.gain_max)
|
self.backend = backend
|
||||||
self.gainSpinBox.setValue(backend_module.Info.gain)
|
self.gainSpinBox.setMinimum(backend_module.Info.gain_min)
|
||||||
self.startFreqSpinBox.setMinimum(backend_module.Info.start_freq_min)
|
self.gainSpinBox.setMaximum(backend_module.Info.gain_max)
|
||||||
self.startFreqSpinBox.setMaximum(backend_module.Info.start_freq_max)
|
self.gainSpinBox.setValue(backend_module.Info.gain)
|
||||||
self.startFreqSpinBox.setValue(backend_module.Info.start_freq)
|
self.startFreqSpinBox.setMinimum(backend_module.Info.start_freq_min)
|
||||||
self.stopFreqSpinBox.setMinimum(backend_module.Info.stop_freq_min)
|
self.startFreqSpinBox.setMaximum(backend_module.Info.start_freq_max)
|
||||||
self.stopFreqSpinBox.setMaximum(backend_module.Info.stop_freq_max)
|
self.startFreqSpinBox.setValue(backend_module.Info.start_freq)
|
||||||
self.stopFreqSpinBox.setValue(backend_module.Info.stop_freq)
|
self.stopFreqSpinBox.setMinimum(backend_module.Info.stop_freq_min)
|
||||||
self.binSizeSpinBox.setMinimum(backend_module.Info.bin_size_min)
|
self.stopFreqSpinBox.setMaximum(backend_module.Info.stop_freq_max)
|
||||||
self.binSizeSpinBox.setMaximum(backend_module.Info.bin_size_max)
|
self.stopFreqSpinBox.setValue(backend_module.Info.stop_freq)
|
||||||
self.binSizeSpinBox.setValue(backend_module.Info.bin_size)
|
self.binSizeSpinBox.setMinimum(backend_module.Info.bin_size_min)
|
||||||
self.intervalSpinBox.setMinimum(backend_module.Info.interval_min)
|
self.binSizeSpinBox.setMaximum(backend_module.Info.bin_size_max)
|
||||||
self.intervalSpinBox.setMaximum(backend_module.Info.interval_max)
|
self.binSizeSpinBox.setValue(backend_module.Info.bin_size)
|
||||||
self.intervalSpinBox.setValue(backend_module.Info.interval)
|
self.intervalSpinBox.setMinimum(backend_module.Info.interval_min)
|
||||||
self.ppmSpinBox.setMinimum(backend_module.Info.ppm_min)
|
self.intervalSpinBox.setMaximum(backend_module.Info.interval_max)
|
||||||
self.ppmSpinBox.setMaximum(backend_module.Info.ppm_max)
|
self.intervalSpinBox.setValue(backend_module.Info.interval)
|
||||||
self.ppmSpinBox.setValue(backend_module.Info.ppm)
|
self.ppmSpinBox.setMinimum(backend_module.Info.ppm_min)
|
||||||
self.cropSpinBox.setMinimum(backend_module.Info.crop_min)
|
self.ppmSpinBox.setMaximum(backend_module.Info.ppm_max)
|
||||||
self.cropSpinBox.setMaximum(backend_module.Info.crop_max)
|
self.ppmSpinBox.setValue(backend_module.Info.ppm)
|
||||||
self.cropSpinBox.setValue(backend_module.Info.crop)
|
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 = backend_module.PowerThread(self.data_storage)
|
||||||
self.power_thread.powerThreadStarted.connect(self.update_buttons)
|
self.power_thread.powerThreadStarted.connect(self.update_buttons)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import os, glob
|
import os, glob, subprocess
|
||||||
|
|
||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
|
|
||||||
@ -6,16 +6,16 @@ from PyQt4 import QtCore
|
|||||||
class BaseInfo:
|
class BaseInfo:
|
||||||
"""Default device metadata"""
|
"""Default device metadata"""
|
||||||
sample_rate_min = 0
|
sample_rate_min = 0
|
||||||
sample_rate_max = 61440000
|
sample_rate_max = 3200000
|
||||||
sample_rate = 2560000
|
sample_rate = 2560000
|
||||||
gain_min = -1
|
gain_min = -1
|
||||||
gain_max = 49
|
gain_max = 49
|
||||||
gain = -1
|
gain = 37
|
||||||
start_freq_min = 24
|
start_freq_min = 24
|
||||||
start_freq_max = 1766
|
start_freq_max = 2200
|
||||||
start_freq = 87
|
start_freq = 87
|
||||||
stop_freq_min = 24
|
stop_freq_min = 24
|
||||||
stop_freq_max = 1766
|
stop_freq_max = 2200
|
||||||
stop_freq = 108
|
stop_freq = 108
|
||||||
bin_size_min = 0
|
bin_size_min = 0
|
||||||
bin_size_max = 2800
|
bin_size_max = 2800
|
||||||
@ -29,6 +29,18 @@ class BaseInfo:
|
|||||||
crop_min = 0
|
crop_min = 0
|
||||||
crop_max = 99
|
crop_max = 99
|
||||||
crop = 0
|
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):
|
class BasePowerThread(QtCore.QThread):
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import subprocess, pprint
|
import subprocess, pprint, struct, shlex
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
import struct
|
|
||||||
|
|
||||||
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
|
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
|
||||||
|
|
||||||
@ -102,6 +101,10 @@ class PowerThread(BasePowerThread):
|
|||||||
if self.params["single_shot"]:
|
if self.params["single_shot"]:
|
||||||
cmdline.append("-1")
|
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,
|
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
|
||||||
universal_newlines=False)
|
universal_newlines=False)
|
||||||
|
|
||||||
@ -138,6 +141,10 @@ class PowerThread(BasePowerThread):
|
|||||||
buf = self.process.stdout.read(record_length)
|
buf = self.process.stdout.read(record_length)
|
||||||
if buf:
|
if buf:
|
||||||
self.parse_output(buf)
|
self.parse_output(buf)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
self.process_stop()
|
self.process_stop()
|
||||||
self.alive = False
|
self.alive = False
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import subprocess, pprint
|
import subprocess, pprint, shlex
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
@ -57,6 +57,10 @@ class PowerThread(BasePowerThread):
|
|||||||
if self.params["single_shot"]:
|
if self.params["single_shot"]:
|
||||||
cmdline.append("-1")
|
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,
|
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
|
||||||
universal_newlines=True)
|
universal_newlines=True)
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import subprocess, math, pprint
|
import subprocess, math, pprint, shlex
|
||||||
|
|
||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
|
|
||||||
@ -84,6 +84,10 @@ class PowerThread(BasePowerThread):
|
|||||||
if not self.params["single_shot"]:
|
if not self.params["single_shot"]:
|
||||||
cmdline.append("-c")
|
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,
|
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
|
||||||
universal_newlines=True)
|
universal_newlines=True)
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import subprocess, pprint
|
import subprocess, pprint, shlex
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
@ -8,7 +8,12 @@ from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
|
|||||||
|
|
||||||
class Info(BaseInfo):
|
class Info(BaseInfo):
|
||||||
"""rx_power device metadata"""
|
"""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):
|
class PowerThread(BasePowerThread):
|
||||||
@ -55,6 +60,10 @@ class PowerThread(BasePowerThread):
|
|||||||
if self.params["single_shot"]:
|
if self.params["single_shot"]:
|
||||||
cmdline.append("-1")
|
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,
|
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
|
||||||
universal_newlines=True)
|
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 PyQt4 import QtCore
|
||||||
|
|
||||||
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
|
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
|
||||||
|
from soapypower.writer import SoapyPowerBinFormat
|
||||||
|
|
||||||
|
formatter = SoapyPowerBinFormat()
|
||||||
|
|
||||||
|
|
||||||
class Info(BaseInfo):
|
class Info(BaseInfo):
|
||||||
"""soapy_power device metadata"""
|
"""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):
|
class PowerThread(BasePowerThread):
|
||||||
"""Thread which runs soapy_power process"""
|
"""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,
|
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):
|
ppm=0, crop=0, single_shot=False, device="", sample_rate=2560000):
|
||||||
"""Setup soapy_power params"""
|
"""Setup soapy_power params"""
|
||||||
@ -31,10 +39,7 @@ class PowerThread(BasePowerThread):
|
|||||||
"single_shot": single_shot
|
"single_shot": single_shot
|
||||||
}
|
}
|
||||||
self.databuffer = {"timestamp": [], "x": [], "y": []}
|
self.databuffer = {"timestamp": [], "x": [], "y": []}
|
||||||
self.databuffer_hop = {"timestamp": [], "x": [], "y": []}
|
self.min_freq = 0
|
||||||
self.hop = 0
|
|
||||||
self.run = 0
|
|
||||||
self.prev_line = ""
|
|
||||||
|
|
||||||
print("soapy_power params:")
|
print("soapy_power params:")
|
||||||
pprint.pprint(self.params)
|
pprint.pprint(self.params)
|
||||||
@ -53,6 +58,7 @@ class PowerThread(BasePowerThread):
|
|||||||
"-d", "{}".format(self.params["device"]),
|
"-d", "{}".format(self.params["device"]),
|
||||||
"-r", "{}".format(self.params["sample_rate"]),
|
"-r", "{}".format(self.params["sample_rate"]),
|
||||||
"-p", "{}".format(self.params["ppm"]),
|
"-p", "{}".format(self.params["ppm"]),
|
||||||
|
"-F", "soapy_power_bin",
|
||||||
]
|
]
|
||||||
|
|
||||||
if self.params["gain"] >= 0:
|
if self.params["gain"] >= 0:
|
||||||
@ -62,50 +68,59 @@ class PowerThread(BasePowerThread):
|
|||||||
if not self.params["single_shot"]:
|
if not self.params["single_shot"]:
|
||||||
cmdline.append("-c")
|
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,
|
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
|
||||||
universal_newlines=True)
|
universal_newlines=False)
|
||||||
|
|
||||||
def parse_output(self, line):
|
def parse_output(self, data):
|
||||||
"""Parse one line of output from soapy_power"""
|
"""Parse data from soapy_power"""
|
||||||
line = line.strip()
|
header, y_axis = data
|
||||||
|
|
||||||
# One empty line => new hop
|
timestamp = header.timestamp
|
||||||
if not line and self.prev_line:
|
start_freq = header.start
|
||||||
self.hop += 1
|
stop_freq = header.stop
|
||||||
print(' => HOP:', self.hop)
|
step = header.step
|
||||||
self.databuffer["x"].extend(self.databuffer_hop["x"])
|
samples = header.samples
|
||||||
self.databuffer["y"].extend(self.databuffer_hop["y"])
|
|
||||||
self.databuffer_hop = {"timestamp": [], "x": [], "y": []}
|
|
||||||
|
|
||||||
# Two empty lines => new set
|
x_axis = np.arange(start_freq, stop_freq, step)
|
||||||
elif not line and not self.prev_line:
|
if len(x_axis) != len(y_axis):
|
||||||
self.hop = 0
|
print("ERROR: len(x_axis) != len(y_axis)")
|
||||||
self.run += 1
|
|
||||||
print(' * RUN:', self.run)
|
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.data_storage.update(self.databuffer)
|
||||||
self.databuffer = {"timestamp": [], "x": [], "y": []}
|
|
||||||
|
|
||||||
# Get timestamp for new hop and set
|
def run(self):
|
||||||
elif line.startswith("# Acquisition start:"):
|
"""soapy_power thread main loop"""
|
||||||
timestamp = line.split(":", 1)[1].strip()
|
self.process_start()
|
||||||
if not self.databuffer_hop["timestamp"]:
|
self.alive = True
|
||||||
self.databuffer_hop["timestamp"] = timestamp
|
self.powerThreadStarted.emit()
|
||||||
if not self.databuffer["timestamp"]:
|
|
||||||
self.databuffer["timestamp"] = timestamp
|
|
||||||
|
|
||||||
# Skip other comments
|
while self.alive:
|
||||||
elif line.startswith("#"):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Parse frequency and power
|
|
||||||
elif self.re_two_floats.match(line):
|
|
||||||
try:
|
try:
|
||||||
freq, power = line.split()
|
data = formatter.read(self.process.stdout)
|
||||||
except ValueError:
|
except ValueError as e:
|
||||||
return
|
print(e, file=sys.stderr)
|
||||||
|
break
|
||||||
|
|
||||||
freq, power = float(freq), float(power)
|
if data:
|
||||||
self.databuffer_hop["x"].append(freq)
|
self.parse_output(data)
|
||||||
self.databuffer_hop["y"].append(power)
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
self.prev_line = line
|
self.process_stop()
|
||||||
|
self.alive = False
|
||||||
|
self.powerThreadStopped.emit()
|
||||||
|
@ -81,22 +81,22 @@
|
|||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../__main__.py" line="337"/>
|
<location filename="../__main__.py" line="383"/>
|
||||||
<source>Frequency hops: {} | Sweep time: {:.2f} s | FPS: {:.2f}</source>
|
<source>Frequency hops: {} | Sweep time: {:.2f} s | FPS: {:.2f}</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../__main__.py" line="337"/>
|
<location filename="../__main__.py" line="383"/>
|
||||||
<source>N/A</source>
|
<source>N/A</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../__main__.py" line="504"/>
|
<location filename="../__main__.py" line="550"/>
|
||||||
<source>About - QSpectrumAnalyzer</source>
|
<source>About - QSpectrumAnalyzer</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../__main__.py" line="504"/>
|
<location filename="../__main__.py" line="550"/>
|
||||||
<source>QSpectrumAnalyzer {}</source>
|
<source>QSpectrumAnalyzer {}</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
@ -252,70 +252,88 @@
|
|||||||
<context>
|
<context>
|
||||||
<name>QSpectrumAnalyzerSettings</name>
|
<name>QSpectrumAnalyzerSettings</name>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../__main__.py" line="50"/>
|
<location filename="../__main__.py" line="65"/>
|
||||||
<source>Select executable - QSpectrumAnalyzer</source>
|
<source>Select executable - QSpectrumAnalyzer</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="107"/>
|
<location filename="../ui_qspectrumanalyzer_settings.py" line="122"/>
|
||||||
<source>Settings - QSpectrumAnalyzer</source>
|
<source>Settings - QSpectrumAnalyzer</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="108"/>
|
<location filename="../ui_qspectrumanalyzer_settings.py" line="123"/>
|
||||||
<source>&Backend:</source>
|
<source>&Backend:</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="115"/>
|
<location filename="../ui_qspectrumanalyzer_settings.py" line="130"/>
|
||||||
<source>soapy_power</source>
|
<source>soapy_power</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="110"/>
|
<location filename="../ui_qspectrumanalyzer_settings.py" line="125"/>
|
||||||
<source>rx_power</source>
|
<source>rx_power</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="111"/>
|
<location filename="../ui_qspectrumanalyzer_settings.py" line="126"/>
|
||||||
<source>rtl_power_fftw</source>
|
<source>rtl_power_fftw</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="112"/>
|
<location filename="../ui_qspectrumanalyzer_settings.py" line="127"/>
|
||||||
<source>rtl_power</source>
|
<source>rtl_power</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="113"/>
|
<location filename="../ui_qspectrumanalyzer_settings.py" line="128"/>
|
||||||
<source>hackrf_sweep</source>
|
<source>hackrf_sweep</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="114"/>
|
<location filename="../ui_qspectrumanalyzer_settings.py" line="129"/>
|
||||||
<source>E&xecutable:</source>
|
<source>E&xecutable:</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="116"/>
|
<location filename="../ui_qspectrumanalyzer_settings.py" line="131"/>
|
||||||
<source>...</source>
|
<source>...</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="117"/>
|
<location filename="../ui_qspectrumanalyzer_settings.py" line="133"/>
|
||||||
<source>Device:</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="118"/>
|
|
||||||
<source>Sa&mple rate:</source>
|
<source>Sa&mple rate:</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../ui_qspectrumanalyzer_settings.py" line="119"/>
|
<location filename="../ui_qspectrumanalyzer_settings.py" line="134"/>
|
||||||
<source>&Waterfall history size:</source>
|
<source>&Waterfall history size:</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</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>
|
||||||
<context>
|
<context>
|
||||||
<name>QSpectrumAnalyzerSmooth</name>
|
<name>QSpectrumAnalyzerSmooth</name>
|
||||||
|
@ -42,6 +42,9 @@ class SpectrumPlotWidget:
|
|||||||
self.plot.setLimits(xMin=0)
|
self.plot.setLimits(xMin=0)
|
||||||
self.plot.showButtons()
|
self.plot.showButtons()
|
||||||
|
|
||||||
|
#self.plot.setDownsampling(mode="peak")
|
||||||
|
#self.plot.setClipToView(True)
|
||||||
|
|
||||||
self.create_persistence_curves()
|
self.create_persistence_curves()
|
||||||
self.create_average_curve()
|
self.create_average_curve()
|
||||||
self.create_peak_hold_min_curve()
|
self.create_peak_hold_min_curve()
|
||||||
@ -264,6 +267,7 @@ class WaterfallPlotWidget:
|
|||||||
self.plot.setLimits(xMin=0, yMax=0)
|
self.plot.setLimits(xMin=0, yMax=0)
|
||||||
self.plot.showButtons()
|
self.plot.showButtons()
|
||||||
#self.plot.setAspectLocked(True)
|
#self.plot.setAspectLocked(True)
|
||||||
|
|
||||||
#self.plot.setDownsampling(mode="peak")
|
#self.plot.setDownsampling(mode="peak")
|
||||||
#self.plot.setClipToView(True)
|
#self.plot.setClipToView(True)
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>420</width>
|
<width>600</width>
|
||||||
<height>255</height>
|
<height>310</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@ -86,7 +86,7 @@
|
|||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="label_5">
|
<widget class="QLabel" name="label_5">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Device:</string>
|
<string>&Device:</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="buddy">
|
||||||
<cstring>deviceEdit</cstring>
|
<cstring>deviceEdit</cstring>
|
||||||
@ -96,7 +96,7 @@
|
|||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QLineEdit" name="deviceEdit"/>
|
<widget class="QLineEdit" name="deviceEdit"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="label_4">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Sa&mple rate:</string>
|
<string>Sa&mple rate:</string>
|
||||||
@ -106,7 +106,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QSpinBox" name="sampleRateSpinBox">
|
<widget class="QSpinBox" name="sampleRateSpinBox">
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
@ -122,7 +122,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="5" column="0">
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="label_2">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Waterfall history size:</string>
|
<string>&Waterfall history size:</string>
|
||||||
@ -132,7 +132,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="5" column="1">
|
||||||
<widget class="QSpinBox" name="waterfallHistorySizeSpinBox">
|
<widget class="QSpinBox" name="waterfallHistorySizeSpinBox">
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<number>1</number>
|
<number>1</number>
|
||||||
@ -145,6 +145,30 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -177,6 +201,8 @@
|
|||||||
<tabstop>executableEdit</tabstop>
|
<tabstop>executableEdit</tabstop>
|
||||||
<tabstop>executableButton</tabstop>
|
<tabstop>executableButton</tabstop>
|
||||||
<tabstop>deviceEdit</tabstop>
|
<tabstop>deviceEdit</tabstop>
|
||||||
|
<tabstop>paramsEdit</tabstop>
|
||||||
|
<tabstop>helpButton</tabstop>
|
||||||
<tabstop>sampleRateSpinBox</tabstop>
|
<tabstop>sampleRateSpinBox</tabstop>
|
||||||
<tabstop>waterfallHistorySizeSpinBox</tabstop>
|
<tabstop>waterfallHistorySizeSpinBox</tabstop>
|
||||||
<tabstop>buttonBox</tabstop>
|
<tabstop>buttonBox</tabstop>
|
||||||
@ -190,8 +216,8 @@
|
|||||||
<slot>accept()</slot>
|
<slot>accept()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>242</x>
|
<x>248</x>
|
||||||
<y>248</y>
|
<y>303</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel">
|
||||||
<x>157</x>
|
<x>157</x>
|
||||||
@ -206,8 +232,8 @@
|
|||||||
<slot>reject()</slot>
|
<slot>reject()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel">
|
||||||
<x>310</x>
|
<x>316</x>
|
||||||
<y>248</y>
|
<y>303</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel">
|
||||||
<x>286</x>
|
<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):
|
class Ui_QSpectrumAnalyzerSettings(object):
|
||||||
def setupUi(self, QSpectrumAnalyzerSettings):
|
def setupUi(self, QSpectrumAnalyzerSettings):
|
||||||
QSpectrumAnalyzerSettings.setObjectName(_fromUtf8("QSpectrumAnalyzerSettings"))
|
QSpectrumAnalyzerSettings.setObjectName(_fromUtf8("QSpectrumAnalyzerSettings"))
|
||||||
QSpectrumAnalyzerSettings.resize(420, 255)
|
QSpectrumAnalyzerSettings.resize(600, 310)
|
||||||
self.verticalLayout = QtGui.QVBoxLayout(QSpectrumAnalyzerSettings)
|
self.verticalLayout = QtGui.QVBoxLayout(QSpectrumAnalyzerSettings)
|
||||||
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
|
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
|
||||||
self.formLayout = QtGui.QFormLayout()
|
self.formLayout = QtGui.QFormLayout()
|
||||||
@ -61,23 +61,35 @@ class Ui_QSpectrumAnalyzerSettings(object):
|
|||||||
self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.deviceEdit)
|
self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.deviceEdit)
|
||||||
self.label_4 = QtGui.QLabel(QSpectrumAnalyzerSettings)
|
self.label_4 = QtGui.QLabel(QSpectrumAnalyzerSettings)
|
||||||
self.label_4.setObjectName(_fromUtf8("label_4"))
|
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 = QtGui.QSpinBox(QSpectrumAnalyzerSettings)
|
||||||
self.sampleRateSpinBox.setMinimum(0)
|
self.sampleRateSpinBox.setMinimum(0)
|
||||||
self.sampleRateSpinBox.setMaximum(25000000)
|
self.sampleRateSpinBox.setMaximum(25000000)
|
||||||
self.sampleRateSpinBox.setSingleStep(10000)
|
self.sampleRateSpinBox.setSingleStep(10000)
|
||||||
self.sampleRateSpinBox.setProperty("value", 2560000)
|
self.sampleRateSpinBox.setProperty("value", 2560000)
|
||||||
self.sampleRateSpinBox.setObjectName(_fromUtf8("sampleRateSpinBox"))
|
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 = QtGui.QLabel(QSpectrumAnalyzerSettings)
|
||||||
self.label_2.setObjectName(_fromUtf8("label_2"))
|
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 = QtGui.QSpinBox(QSpectrumAnalyzerSettings)
|
||||||
self.waterfallHistorySizeSpinBox.setMinimum(1)
|
self.waterfallHistorySizeSpinBox.setMinimum(1)
|
||||||
self.waterfallHistorySizeSpinBox.setMaximum(10000000)
|
self.waterfallHistorySizeSpinBox.setMaximum(10000000)
|
||||||
self.waterfallHistorySizeSpinBox.setProperty("value", 100)
|
self.waterfallHistorySizeSpinBox.setProperty("value", 100)
|
||||||
self.waterfallHistorySizeSpinBox.setObjectName(_fromUtf8("waterfallHistorySizeSpinBox"))
|
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)
|
self.verticalLayout.addLayout(self.formLayout)
|
||||||
spacerItem = QtGui.QSpacerItem(20, 21, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
spacerItem = QtGui.QSpacerItem(20, 21, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
||||||
self.verticalLayout.addItem(spacerItem)
|
self.verticalLayout.addItem(spacerItem)
|
||||||
@ -91,6 +103,7 @@ class Ui_QSpectrumAnalyzerSettings(object):
|
|||||||
self.label_5.setBuddy(self.deviceEdit)
|
self.label_5.setBuddy(self.deviceEdit)
|
||||||
self.label_4.setBuddy(self.sampleRateSpinBox)
|
self.label_4.setBuddy(self.sampleRateSpinBox)
|
||||||
self.label_2.setBuddy(self.waterfallHistorySizeSpinBox)
|
self.label_2.setBuddy(self.waterfallHistorySizeSpinBox)
|
||||||
|
self.label_6.setBuddy(self.paramsEdit)
|
||||||
|
|
||||||
self.retranslateUi(QSpectrumAnalyzerSettings)
|
self.retranslateUi(QSpectrumAnalyzerSettings)
|
||||||
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), QSpectrumAnalyzerSettings.accept)
|
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.backendComboBox, self.executableEdit)
|
||||||
QSpectrumAnalyzerSettings.setTabOrder(self.executableEdit, self.executableButton)
|
QSpectrumAnalyzerSettings.setTabOrder(self.executableEdit, self.executableButton)
|
||||||
QSpectrumAnalyzerSettings.setTabOrder(self.executableButton, self.deviceEdit)
|
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.sampleRateSpinBox, self.waterfallHistorySizeSpinBox)
|
||||||
QSpectrumAnalyzerSettings.setTabOrder(self.waterfallHistorySizeSpinBox, self.buttonBox)
|
QSpectrumAnalyzerSettings.setTabOrder(self.waterfallHistorySizeSpinBox, self.buttonBox)
|
||||||
|
|
||||||
@ -114,7 +129,9 @@ class Ui_QSpectrumAnalyzerSettings(object):
|
|||||||
self.label.setText(_translate("QSpectrumAnalyzerSettings", "E&xecutable:", None))
|
self.label.setText(_translate("QSpectrumAnalyzerSettings", "E&xecutable:", None))
|
||||||
self.executableEdit.setText(_translate("QSpectrumAnalyzerSettings", "soapy_power", None))
|
self.executableEdit.setText(_translate("QSpectrumAnalyzerSettings", "soapy_power", None))
|
||||||
self.executableButton.setText(_translate("QSpectrumAnalyzerSettings", "...", 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_4.setText(_translate("QSpectrumAnalyzerSettings", "Sa&mple rate:", None))
|
||||||
self.label_2.setText(_translate("QSpectrumAnalyzerSettings", "&Waterfall history size:", 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(
|
setup(
|
||||||
name="QSpectrumAnalyzer",
|
name="QSpectrumAnalyzer",
|
||||||
version=__version__,
|
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="Michal Krenek (Mikos)",
|
||||||
author_email="m.krenek@gmail.com",
|
author_email="m.krenek@gmail.com",
|
||||||
url="https://github.com/xmikos/qspectrumanalyzer",
|
url="https://github.com/xmikos/qspectrumanalyzer",
|
||||||
@ -29,6 +30,7 @@ setup(
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
install_requires=[
|
install_requires=[
|
||||||
|
"soapy_power",
|
||||||
"pyqtgraph"
|
"pyqtgraph"
|
||||||
],
|
],
|
||||||
classifiers=[
|
classifiers=[
|
||||||
|
Loading…
Reference in New Issue
Block a user