Compare commits

..

No commits in common. "master" and "hackrf_sweep" have entirely different histories.

42 changed files with 1679 additions and 3404 deletions

View File

@ -2,3 +2,4 @@ include LICENSE
include README.rst
include qspectrumanalyzer.desktop
include qspectrumanalyzer.png
include qspectrumanalyzer.svg

View File

@ -1,20 +1,14 @@
# Maintainer: Michal Krenek (Mikos) <m.krenek@gmail.com>
pkgname=qspectrumanalyzer
pkgver=2.2.0
pkgver=1.4.0
pkgrel=1
pkgdesc="Spectrum analyzer for multiple SDR platforms (PyQtGraph based GUI for soapy_power, hackrf_sweep, rtl_power, rx_power and other backends)"
pkgdesc="Spectrum analyzer for RTL-SDR (GUI for rtl_power based on PyQtGraph)"
arch=('any')
url="https://github.com/xmikos/qspectrumanalyzer"
license=('GPL3')
depends=('python-qt.py' 'python-pyqt5' 'python-pyqtgraph' 'soapy_power>=1.6.0')
depends=('python-pyqt4' 'python-pyqtgraph' 'rtl-sdr')
makedepends=('python-setuptools')
optdepends=(
'hackrf: hackrf_sweep backend (wideband spectrum monitoring with sweep rate of 8 GHz/s)'
'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)'
)
optdepends=('rtl_power_fftw-git: alternative rtl_power implementation using FFTW library')
source=(https://github.com/xmikos/qspectrumanalyzer/archive/v$pkgver.tar.gz)
build() {

View File

@ -1,8 +1,7 @@
QSpectrumAnalyzer
=================
Spectrum analyzer for multiple SDR platforms (PyQtGraph based GUI for soapy_power,
hackrf_sweep, rtl_power, rx_power and other backends)
Spectrum analyzer for RTL-SDR (GUI for rtl_power based on PyQtGraph)
Screenshots
-----------
@ -15,73 +14,37 @@ Requirements
------------
- Python >= 3.3
- PyQt4 / PyQt5 / PySide / PySide2
- Qt.py (https://github.com/mottosso/Qt.py)
- PyQt >= 4.5
- PyQtGraph (http://www.pyqtgraph.org)
- soapy_power (https://github.com/xmikos/soapy_power)
- Optional: hackrf / rtl-sdr / rtl_power_fftw / rx_tools
- rtl-sdr (https://github.com/keenerd/rtl-sdr)
- Optional: rtl_power_fftw (https://github.com/AD-Vega/rtl-power-fftw)
Backends
--------
Default backend
***************
- **soapy_power** (https://github.com/xmikos/soapy_power)
``soapy_power`` is the default and recommended universal SDR backend in QSpectrumAnalyzer.
It is based on `SoapySDR <https://github.com/pothosware/SoapySDR>`_ and supports
nearly all SDR platforms (RTL-SDR, HackRF, Airspy, SDRplay, LimeSDR, bladeRF,
USRP and some other SDR devices). It is highly configurable (see additional parameters
help in *Settings* menu) and supports short acquisition time for
near real-time continuous measurement.
Other backends
**************
- **hackrf_sweep** (https://github.com/mossmann/hackrf)
``hackrf_sweep`` backend enables wideband spectrum monitoring by rapidly retuning the radio
without requiring individual tuning requests from the host computer. This allows unprecedented
sweep rate of 8 GHz per second. Only HackRF is supported.
- **rtl_power_fftw** (https://github.com/AD-Vega/rtl-power-fftw)
``rtl_power_fftw`` is alternative backend for RTL-SDR devices and has various
benefits over ``rtl_power``. E.g. better FFT performance (thanks to
use of ``fftw`` library) and possibility to use short acquisition time
for near real-time continuous measurement (minimum interval in original
``rtl_power`` is 1 second).
- **rtl_power** (https://github.com/keenerd/rtl-sdr)
``rtl_power`` is original backend for RTL-SDR devices. There are better alternatives now, but
if you want to use it, you should use `Keenerds fork of rtl-sdr <https://github.com/keenerd/rtl-sdr>`_
(latest Git revision), because ``rtl_power`` in original rtl-sdr package (from osmocom.org)
You should use `Keenerds fork of rtl-sdr <https://github.com/keenerd/rtl-sdr>`_
(latest Git revision), because ``rtl_power`` in original rtl-sdr (from osmocom.org)
is broken (especially when used with cropping).
- **rx_power** (https://github.com/rxseger/rx_tools) *[unsupported]*
``rx_power`` (part of ``rx_tools``) is also based on SoapySDR (like default ``soapy_power`` backend)
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``)
and is buggy. Backend is currently unsupported, if you want to fix it, patches are welcome.
Another alternative is
`rtl_power_fftw <https://github.com/AD-Vega/rtl-power-fftw>`_ which has various
benefits over ``rtl_power``. E.g. better FFT performance (thanks to
use of ``fftw`` library) and possibility to use much shorter acquisition time
for more real-time continuous measurement (minimum interval in original
``rtl_power`` is 1 second, but in ``rtl_power_fftw`` you are only limited
by number of frequency hops).
Usage
-----
Start QSpectrumAnalyzer by running ``qspectrumanalyzer``.
You can choose which backend you want to use in *File* -> *Settings*
(or *Application menu* -> *Preferences* on Mac OS X), default is
``soapy_power``. Device, sample rate, bandwidth, LNB LO, 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.
You can choose if you want to use ``rtl_power`` or ``rtl_power_fftw`` backend in
*File* -> *Settings* (default is ``rtl_power``). Path to ``rtl_power``
(or ``rtl_power_fftw``) executable can be also manually specified there. You can also
set waterfall plot history size in there. 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 gain to some fixed number) and also set
turn off automatic gain control (set it 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>`_.
@ -92,93 +55,39 @@ table can be changed in mini-histogram widget (on *Levels* tab).
Installation
------------
Arch Linux:
***********
Stable version:
**Arch Linux:**
::
git clone https://aur.archlinux.org/qspectrumanalyzer.git
cd qspectrumanalyzer
makepkg -sri
Git master branch:
::
git clone https://aur.archlinux.org/qspectrumanalyzer-git.git
cd qspectrumanalyzer-git
makepkg -sri
Or simply use `pacaur <https://aur.archlinux.org/packages/pacaur>`_ (or any other AUR helper)
which will also automatically install all QSpectrumAnalyzer dependencies:
Or simply use `pacaur <https://aur.archlinux.org/packages/pacaur>`_ (or any other AUR helper):
::
pacaur -S qspectrumanalyzer
pacaur -S qspectrumanalyzer-git
Ubuntu:
*******
**Debian / Ubuntu:**
::
# Add SoapySDR PPA to your system
sudo add-apt-repository -y ppa:myriadrf/drivers
sudo apt-get install python3-pip python3-pyqt4 python3-numpy
sudo pip3 install qspectrumanalyzer
# Update list of packages
sudo apt-get update
Warning! ``pip`` will install packages system-wide by default, but you
should always use your distribution package manager for this.
# Install basic dependencies
sudo apt-get install python3-pip python3-pyqt5 python3-numpy python3-scipy soapysdr python3-soapysdr
You can install it locally only for your current user by running this (without ``sudo``):
::
# 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 locally for your current user
pip3 install --user qspectrumanalyzer
``qspectrumanalyzer`` and ``soapy_power`` executables will be then placed in
``~/.local/bin`` directory, you can add it to your PATH in ``~/.bashrc``.
If you want to install QSpectrumAnalyzer directly from Git master branch, you can use this procedure:
::
git clone https://github.com/xmikos/qspectrumanalyzer.git
cd qspectrumanalyzer
pip3 install --user .
Windows:
********
*Only 64-bit Windows are supported (there are no public 32-bit builds of SoapySDR
libraries and drivers).*
1. install `SoapySDR <https://github.com/pothosware/SoapySDR/wiki>`_ libraries and drivers
(bundled as part of Pothos SDR installer: `download <http://downloads.myriadrf.org/builds/PothosSDR/?C=M;O=D>`_).
This bundle also includes other great SDR apps like `CubicSDR <http://cubicsdr.com>`_, `GQRX <http://gqrx.dk>`_,
`GNU Radio Companion <https://gnuradio.org>`_, `Pothos GUI <https://github.com/pothosware/pothos/wiki>`_,
`Lime Suite <https://github.com/myriadrf/LimeSuite>`_ and `Zadig <http://zadig.akeo.ie>`_.
Utilities like ``hackrf_sweep`` and ``rtl_power`` are also included.
2. download QSpectrumAnalyzer installer or portable zip archive from GitHub
`releases <https://github.com/xmikos/qspectrumanalyzer/releases>`_ page
3. after you connect your SDR device, you have to run `Zadig <http://zadig.akeo.ie>`_ to install USB drivers
You can also install QSpectrumAnalyzer manually from `PyPI <https://pypi.python.org>`_:
1. install Python 3.6.x (64-bit) from `python.org <https://www.python.org>`_ and add Python to PATH
2. install `SoapySDR <https://github.com/pothosware/SoapySDR/wiki>`_ libraries and drivers
(bundled as part of Pothos SDR installer: `download <http://downloads.myriadrf.org/builds/PothosSDR/?C=M;O=D>`_)
3. Open ``cmd.exe`` and run::
pip install PyQt5
pip install QSpectrumAnalyzer
You should then be able to run it with ``qspectrumanalyzer`` (or ``python -m qspectrumanalyzer``
if it doesn't work for you).
Executables will be then placed in ``~/.local/bin`` directory, you can add it to your
PATH in ``~/.bashrc``.
Todo:
-----
- save FFT history (allow big waterfall plot saved to file)
- automatic peak detection / highlighting
- display average noise level
- frequency markers / bookmarks with notes (even importing and exporting .csv file with
- frequency markers / bookmarks with notes (even importing / exporting .csv file with
predefined channels, etc.)

View File

@ -1,7 +1,7 @@
[Desktop Entry]
Name=QSpectrumAnalyzer
GenericName=Spectrum analyzer
Comment=Spectrum analyzer for multiple SDR platforms (PyQtGraph based GUI for soapy_power, hackrf_sweep, rtl_power, rx_power and other backends)
Comment=Spectrum analyzer for RTL-SDR (GUI for rtl_power based on PyQtGraph)
Exec=qspectrumanalyzer
Icon=qspectrumanalyzer
StartupNotify=true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

479
qspectrumanalyzer/__main__.py Normal file → Executable file
View File

@ -1,46 +1,166 @@
#!/usr/bin/env python
import sys, os, signal, time, argparse
import sys, signal, time
from Qt import QtCore, QtGui, QtWidgets
from PyQt4 import QtCore, QtGui
from qspectrumanalyzer import backends
from qspectrumanalyzer.version import __version__
from qspectrumanalyzer.backend import RtlPowerThread, RtlPowerFftwThread, SoapyPowerThread, RxPowerThread, HackRFSweepThread
from qspectrumanalyzer.data import DataStorage
from qspectrumanalyzer.plot import SpectrumPlotWidget, WaterfallPlotWidget
from qspectrumanalyzer.utils import str_to_color, human_time
from qspectrumanalyzer.settings import QSpectrumAnalyzerSettings
from qspectrumanalyzer.smoothing import QSpectrumAnalyzerSmoothing
from qspectrumanalyzer.persistence import QSpectrumAnalyzerPersistence
from qspectrumanalyzer.colors import QSpectrumAnalyzerColors
from qspectrumanalyzer.baseline import QSpectrumAnalyzerBaseline
from qspectrumanalyzer.utils import color_to_str, str_to_color
from qspectrumanalyzer.ui_qspectrumanalyzer_settings import Ui_QSpectrumAnalyzerSettings
from qspectrumanalyzer.ui_qspectrumanalyzer_smooth import Ui_QSpectrumAnalyzerSmooth
from qspectrumanalyzer.ui_qspectrumanalyzer_persistence import Ui_QSpectrumAnalyzerPersistence
from qspectrumanalyzer.ui_qspectrumanalyzer_colors import Ui_QSpectrumAnalyzerColors
from qspectrumanalyzer.ui_qspectrumanalyzer import Ui_QSpectrumAnalyzerMainWindow
debug = False
# Allow CTRL+C and/or SIGTERM to kill us (PyQt blocks it otherwise)
signal.signal(signal.SIGINT, signal.SIG_DFL)
signal.signal(signal.SIGTERM, signal.SIG_DFL)
class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMainWindow):
"""QSpectrumAnalyzer main window"""
class QSpectrumAnalyzerSettings(QtGui.QDialog, Ui_QSpectrumAnalyzerSettings):
"""QSpectrumAnalyzer settings dialog"""
def __init__(self, parent=None):
# Initialize UI
super().__init__(parent)
self.setupUi(self)
# Set window icon
icon_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "qspectrumanalyzer.svg")
self.setWindowIcon(QtGui.QIcon(icon_path))
# Load settings
settings = QtCore.QSettings()
self.executableEdit.setText(settings.value("executable", "soapy_power"))
self.waterfallHistorySizeSpinBox.setValue(settings.value("waterfall_history_size", 100, int))
self.deviceEdit.setText(settings.value("device", ""))
self.sampleRateSpinBox.setValue(settings.value("sample_rate", 2560000, int))
# Create progress bar
self.progressbar = QtWidgets.QProgressBar()
self.progressbar.setMaximumWidth(250)
self.progressbar.setVisible(False)
self.statusbar.addPermanentWidget(self.progressbar)
backend = settings.value("backend", "soapy_power")
self.backendComboBox.blockSignals(True)
i = self.backendComboBox.findText(backend)
if i == -1:
self.backendComboBox.setCurrentIndex(0)
else:
self.backendComboBox.setCurrentIndex(i)
self.backendComboBox.blockSignals(False)
@QtCore.pyqtSlot()
def on_executableButton_clicked(self):
"""Open file dialog when button is clicked"""
filename = QtGui.QFileDialog.getOpenFileName(self, self.tr("Select executable - QSpectrumAnalyzer"))
if filename:
self.executableEdit.setText(filename)
@QtCore.pyqtSlot(str)
def on_backendComboBox_currentIndexChanged(self, text):
"""Change executable when backend is changed"""
self.executableEdit.setText(text)
self.deviceEdit.setText("")
if text == "hackrf_sweep":
self.sampleRateSpinBox.setMinimum(20000000)
self.sampleRateSpinBox.setMaximum(20000000)
self.sampleRateSpinBox.setValue(20000000)
else:
self.sampleRateSpinBox.setMinimum(0)
self.sampleRateSpinBox.setMaximum(25000000)
self.sampleRateSpinBox.setValue(2560000)
def accept(self):
"""Save settings when dialog is accepted"""
settings = QtCore.QSettings()
settings.setValue("executable", self.executableEdit.text())
settings.setValue("waterfall_history_size", self.waterfallHistorySizeSpinBox.value())
settings.setValue("device", self.deviceEdit.text())
settings.setValue("sample_rate", self.sampleRateSpinBox.value())
settings.setValue("backend", self.backendComboBox.currentText())
QtGui.QDialog.accept(self)
class QSpectrumAnalyzerSmooth(QtGui.QDialog, Ui_QSpectrumAnalyzerSmooth):
"""QSpectrumAnalyzer spectrum smoothing dialog"""
def __init__(self, parent=None):
# Initialize UI
super().__init__(parent)
self.setupUi(self)
# Load settings
settings = QtCore.QSettings()
self.windowLengthSpinBox.setValue(settings.value("smooth_length", 11, int))
window_function = settings.value("smooth_window", "hanning")
i = self.windowFunctionComboBox.findText(window_function)
if i == -1:
self.windowFunctionComboBox.setCurrentIndex(0)
else:
self.windowFunctionComboBox.setCurrentIndex(i)
def accept(self):
"""Save settings when dialog is accepted"""
settings = QtCore.QSettings()
settings.setValue("smooth_length", self.windowLengthSpinBox.value())
settings.setValue("smooth_window", self.windowFunctionComboBox.currentText())
QtGui.QDialog.accept(self)
class QSpectrumAnalyzerPersistence(QtGui.QDialog, Ui_QSpectrumAnalyzerPersistence):
"""QSpectrumAnalyzer spectrum persistence dialog"""
def __init__(self, parent=None):
# Initialize UI
super().__init__(parent)
self.setupUi(self)
# Load settings
settings = QtCore.QSettings()
self.persistenceLengthSpinBox.setValue(settings.value("persistence_length", 5, int))
decay_function = settings.value("persistence_decay", "exponential")
i = self.decayFunctionComboBox.findText(decay_function)
if i == -1:
self.decayFunctionComboBox.setCurrentIndex(0)
else:
self.decayFunctionComboBox.setCurrentIndex(i)
def accept(self):
"""Save settings when dialog is accepted"""
settings = QtCore.QSettings()
settings.setValue("persistence_length", self.persistenceLengthSpinBox.value())
settings.setValue("persistence_decay", self.decayFunctionComboBox.currentText())
QtGui.QDialog.accept(self)
class QSpectrumAnalyzerColors(QtGui.QDialog, Ui_QSpectrumAnalyzerColors):
"""QSpectrumAnalyzer colors dialog"""
def __init__(self, parent=None):
# Initialize UI
super().__init__(parent)
self.setupUi(self)
# Load settings
settings = QtCore.QSettings()
self.mainColorButton.setColor(str_to_color(settings.value("main_color", "255, 255, 0, 255")))
self.peakHoldMaxColorButton.setColor(str_to_color(settings.value("peak_hold_max_color", "255, 0, 0, 255")))
self.peakHoldMinColorButton.setColor(str_to_color(settings.value("peak_hold_min_color", "0, 0, 255, 255")))
self.averageColorButton.setColor(str_to_color(settings.value("average_color", "0, 255, 255, 255")))
self.persistenceColorButton.setColor(str_to_color(settings.value("persistence_color", "0, 255, 0, 255")))
def accept(self):
"""Save settings when dialog is accepted"""
settings = QtCore.QSettings()
settings.setValue("main_color", color_to_str(self.mainColorButton.color()))
settings.setValue("peak_hold_max_color", color_to_str(self.peakHoldMaxColorButton.color()))
settings.setValue("peak_hold_min_color", color_to_str(self.peakHoldMinColorButton.color()))
settings.setValue("average_color", color_to_str(self.averageColorButton.color()))
settings.setValue("persistence_color", color_to_str(self.persistenceColorButton.color()))
QtGui.QDialog.accept(self)
class QSpectrumAnalyzerMainWindow(QtGui.QMainWindow, Ui_QSpectrumAnalyzerMainWindow):
"""QSpectrumAnalyzer main window"""
def __init__(self, parent=None):
# Initialize UI
super().__init__(parent)
self.setupUi(self)
# Create plot widgets and update UI
self.spectrumPlotWidget = SpectrumPlotWidget(self.mainPlotLayout)
@ -50,14 +170,9 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai
self.spectrumPlotWidget.plot.setXLink(self.waterfallPlotWidget.plot)
# Setup power thread and connect signals
self.update_status_timer = QtCore.QTimer()
self.update_status_timer.timeout.connect(self.update_status)
self.prev_sweep_time = None
self.prev_data_timestamp = None
self.start_timestamp = None
self.data_storage = None
self.power_thread = None
self.backend = None
self.setup_power_thread()
self.update_buttons()
@ -76,66 +191,45 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai
self.data_storage.data_recalculated.connect(self.spectrumPlotWidget.recalculate_plot)
self.data_storage.data_recalculated.connect(self.spectrumPlotWidget.recalculate_persistence)
self.data_storage.history_updated.connect(self.waterfallPlotWidget.update_plot)
self.data_storage.history_recalculated.connect(self.waterfallPlotWidget.recalculate_plot)
self.data_storage.average_updated.connect(self.spectrumPlotWidget.update_average)
self.data_storage.baseline_updated.connect(self.spectrumPlotWidget.update_baseline)
self.data_storage.peak_hold_max_updated.connect(self.spectrumPlotWidget.update_peak_hold_max)
self.data_storage.peak_hold_min_updated.connect(self.spectrumPlotWidget.update_peak_hold_min)
# Setup default values and limits in case that backend is changed
backend = settings.value("backend", "soapy_power")
try:
backend_module = getattr(backends, backend)
except AttributeError:
backend_module = backends.soapy_power
if backend == "soapy_power":
self.power_thread = SoapyPowerThread(self.data_storage)
elif backend == "rx_power":
self.power_thread = RxPowerThread(self.data_storage)
elif backend == "rtl_power_fftw":
self.power_thread = RtlPowerFftwThread(self.data_storage)
elif backend == "hackrf_sweep":
self.gainSpinBox.setMinimum(0)
self.gainSpinBox.setMaximum(102)
self.gainSpinBox.setValue(40)
self.startFreqSpinBox.setMinimum(0)
self.startFreqSpinBox.setMaximum(7230)
self.startFreqSpinBox.setValue(0)
self.stopFreqSpinBox.setMinimum(0)
self.stopFreqSpinBox.setMaximum(7250)
self.stopFreqSpinBox.setValue(6000)
self.binSizeSpinBox.setMinimum(40)
self.binSizeSpinBox.setMaximum(5000)
self.binSizeSpinBox.setValue(1000)
self.intervalSpinBox.setMinimum(0)
self.intervalSpinBox.setMaximum(0)
self.intervalSpinBox.setValue(0)
self.ppmSpinBox.setMinimum(0)
self.ppmSpinBox.setMaximum(0)
self.ppmSpinBox.setValue(0)
self.cropSpinBox.setMinimum(0)
self.cropSpinBox.setMaximum(0)
self.cropSpinBox.setValue(0)
self.power_thread = HackRFSweepThread(self.data_storage)
else:
self.power_thread = RtlPowerThread(self.data_storage)
if self.backend is None 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)
# Setup default values and limits in case that LNB LO is changed
lnb_lo = settings.value("lnb_lo", 0, float) / 1e6
start_freq_min = backend_module.Info.start_freq_min + lnb_lo
start_freq_max = backend_module.Info.start_freq_max + lnb_lo
start_freq = self.startFreqSpinBox.value()
stop_freq_min = backend_module.Info.stop_freq_min + lnb_lo
stop_freq_max = backend_module.Info.stop_freq_max + lnb_lo
stop_freq = self.stopFreqSpinBox.value()
self.startFreqSpinBox.setMinimum(start_freq_min if start_freq_min > 0 else 0)
self.startFreqSpinBox.setMaximum(start_freq_max)
if start_freq < start_freq_min or start_freq > start_freq_max:
self.startFreqSpinBox.setValue(start_freq_min)
self.stopFreqSpinBox.setMinimum(stop_freq_min if stop_freq_min > 0 else 0)
self.stopFreqSpinBox.setMaximum(stop_freq_max)
if stop_freq < stop_freq_min or stop_freq > stop_freq_max:
self.stopFreqSpinBox.setValue(stop_freq_max)
self.power_thread = backend_module.PowerThread(self.data_storage)
self.power_thread.powerThreadStarted.connect(self.on_power_thread_started)
self.power_thread.powerThreadStopped.connect(self.on_power_thread_stopped)
self.power_thread.powerThreadStarted.connect(self.update_buttons)
self.power_thread.powerThreadStopped.connect(self.update_buttons)
def set_dock_size(self, dock, width, height):
"""Ugly hack for resizing QDockWidget (because it doesn't respect minimumSize / sizePolicy set in Designer)
@ -169,7 +263,7 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai
self.stopFreqSpinBox.setValue(settings.value("stop_freq", 108.0, float))
self.binSizeSpinBox.setValue(settings.value("bin_size", 10.0, float))
self.intervalSpinBox.setValue(settings.value("interval", 10.0, float))
self.gainSpinBox.setValue(settings.value("gain", 0, float))
self.gainSpinBox.setValue(settings.value("gain", 0, int))
self.ppmSpinBox.setValue(settings.value("ppm", 0, int))
self.cropSpinBox.setValue(settings.value("crop", 0, int))
self.mainCurveCheckBox.setChecked(settings.value("main_curve", 1, int))
@ -178,8 +272,6 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai
self.averageCheckBox.setChecked(settings.value("average", 0, int))
self.smoothCheckBox.setChecked(settings.value("smooth", 0, int))
self.persistenceCheckBox.setChecked(settings.value("persistence", 0, int))
self.baselineCheckBox.setChecked(settings.value("baseline", 0, int))
self.subtractBaselineCheckBox.setChecked(settings.value("subtract_baseline", 0, int))
# Restore window state
if settings.value("window_state"):
@ -219,8 +311,6 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai
settings.setValue("average", int(self.averageCheckBox.isChecked()))
settings.setValue("smooth", int(self.smoothCheckBox.isChecked()))
settings.setValue("persistence", int(self.persistenceCheckBox.isChecked()))
settings.setValue("baseline", int(self.baselineCheckBox.isChecked()))
settings.setValue("subtract_baseline", int(self.subtractBaselineCheckBox.isChecked()))
# Save window state and geometry
settings.setValue("window_geometry", self.saveGeometry())
@ -239,72 +329,32 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai
def update_data(self, data_storage):
"""Update GUI when new data is received"""
# Show number of hops and how much time did the sweep really take
timestamp = time.time()
self.prev_sweep_time = timestamp - self.prev_data_timestamp
sweep_time = timestamp - self.prev_data_timestamp
self.prev_data_timestamp = timestamp
self.update_status()
def update_status(self):
"""Update status bar"""
timestamp = time.time()
status = []
if self.power_thread.params["hops"]:
status.append(self.tr("Frequency hops: {}").format(self.power_thread.params["hops"]))
status.append(self.tr("Total time: {} | Sweep time: {:.2f} s ({:.2f} FPS)").format(
human_time(timestamp - self.start_timestamp),
self.prev_sweep_time,
(1 / self.prev_sweep_time) if self.prev_sweep_time else 0
))
self.show_status(" | ".join(status), timeout=0)
self.update_progress(timestamp - self.prev_data_timestamp)
def update_progress(self, value):
"""Update progress bar"""
value *= 1000
value_max = self.intervalSpinBox.value() * 1000
if value_max < 1000:
return
if value > value_max + 1000:
self.progressbar.setRange(0, 0)
value = value_max
elif value > value_max:
value = value_max
else:
self.progressbar.setRange(0, value_max)
self.progressbar.setValue(value)
def on_power_thread_started(self):
"""Update buttons state when power thread is started"""
self.update_buttons()
self.progressbar.setVisible(True)
def on_power_thread_stopped(self):
"""Update buttons state and status bar when power thread is stopped"""
self.update_buttons()
self.update_status_timer.stop()
self.update_status()
self.progressbar.setVisible(False)
self.show_status(
self.tr("Frequency hops: {} | Sweep time: {:.2f} s | FPS: {:.2f}").format(
self.power_thread.params["hops"] or self.tr("N/A"),
sweep_time,
1 / sweep_time
),
timeout=0
)
def start(self, single_shot=False):
"""Start power thread"""
settings = QtCore.QSettings()
self.prev_sweep_time = 0
self.prev_data_timestamp = time.time()
self.start_timestamp = self.prev_data_timestamp
if self.intervalSpinBox.value() >= 1:
self.progressbar.setRange(0, self.intervalSpinBox.value() * 1000)
else:
self.progressbar.setRange(0, 0)
self.update_progress(0)
self.update_status_timer.start(100)
self.data_storage.reset()
self.data_storage.set_smooth(
bool(self.smoothCheckBox.isChecked()),
settings.value("smooth_length", 11, int),
settings.value("smooth_window", "hanning"),
recalculate=False
)
self.waterfallPlotWidget.history_size = settings.value("waterfall_history_size", 100, int)
self.waterfallPlotWidget.clear_plot()
@ -317,8 +367,6 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai
self.spectrumPlotWidget.peak_hold_min_color = str_to_color(settings.value("peak_hold_min_color", "0, 0, 255, 255"))
self.spectrumPlotWidget.average = bool(self.averageCheckBox.isChecked())
self.spectrumPlotWidget.average_color = str_to_color(settings.value("average_color", "0, 255, 255, 255"))
self.spectrumPlotWidget.baseline = bool(self.baselineCheckBox.isChecked())
self.spectrumPlotWidget.baseline_color = str_to_color(settings.value("baseline_color", "255, 0, 255, 255"))
self.spectrumPlotWidget.persistence = bool(self.persistenceCheckBox.isChecked())
self.spectrumPlotWidget.persistence_length = settings.value("persistence_length", 5, int)
self.spectrumPlotWidget.persistence_decay = settings.value("persistence_decay", "exponential")
@ -327,35 +375,19 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai
self.spectrumPlotWidget.clear_peak_hold_max()
self.spectrumPlotWidget.clear_peak_hold_min()
self.spectrumPlotWidget.clear_average()
self.spectrumPlotWidget.clear_baseline()
self.spectrumPlotWidget.clear_persistence()
self.data_storage.reset()
self.data_storage.set_smooth(
bool(self.smoothCheckBox.isChecked()),
settings.value("smooth_length", 11, int),
settings.value("smooth_window", "hanning")
)
self.data_storage.set_subtract_baseline(
bool(self.subtractBaselineCheckBox.isChecked()),
settings.value("baseline_file", None)
)
if not self.power_thread.alive:
self.power_thread.setup(
float(self.startFreqSpinBox.value()),
float(self.stopFreqSpinBox.value()),
float(self.binSizeSpinBox.value()),
interval=float(self.intervalSpinBox.value()),
gain=float(self.gainSpinBox.value()),
ppm=int(self.ppmSpinBox.value()),
crop=int(self.cropSpinBox.value()) / 100.0,
single_shot=single_shot,
device=settings.value("device", ""),
sample_rate=settings.value("sample_rate", 2560000, float),
bandwidth=settings.value("bandwidth", 0, float),
lnb_lo=settings.value("lnb_lo", 0, float)
)
self.power_thread.setup(float(self.startFreqSpinBox.value()),
float(self.stopFreqSpinBox.value()),
float(self.binSizeSpinBox.value()),
interval=float(self.intervalSpinBox.value()),
gain=int(self.gainSpinBox.value()),
ppm=int(self.ppmSpinBox.value()),
crop=int(self.cropSpinBox.value()) / 100.0,
single_shot=single_shot,
device=settings.value("device", ""),
sample_rate=settings.value("sample_rate", 2560000, int))
self.power_thread.start()
def stop(self):
@ -363,47 +395,47 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai
if self.power_thread.alive:
self.power_thread.stop()
@QtCore.Slot()
@QtCore.pyqtSlot()
def on_startButton_clicked(self):
self.start()
@QtCore.Slot()
@QtCore.pyqtSlot()
def on_singleShotButton_clicked(self):
self.start(single_shot=True)
@QtCore.Slot()
@QtCore.pyqtSlot()
def on_stopButton_clicked(self):
self.stop()
@QtCore.Slot(bool)
@QtCore.pyqtSlot(bool)
def on_mainCurveCheckBox_toggled(self, checked):
self.spectrumPlotWidget.main_curve = checked
if self.spectrumPlotWidget.curve.xData is None:
self.spectrumPlotWidget.update_plot(self.data_storage)
self.spectrumPlotWidget.curve.setVisible(checked)
@QtCore.Slot(bool)
@QtCore.pyqtSlot(bool)
def on_peakHoldMaxCheckBox_toggled(self, checked):
self.spectrumPlotWidget.peak_hold_max = checked
if self.spectrumPlotWidget.curve_peak_hold_max.xData is None:
self.spectrumPlotWidget.update_peak_hold_max(self.data_storage)
self.spectrumPlotWidget.curve_peak_hold_max.setVisible(checked)
@QtCore.Slot(bool)
@QtCore.pyqtSlot(bool)
def on_peakHoldMinCheckBox_toggled(self, checked):
self.spectrumPlotWidget.peak_hold_min = checked
if self.spectrumPlotWidget.curve_peak_hold_min.xData is None:
self.spectrumPlotWidget.update_peak_hold_min(self.data_storage)
self.spectrumPlotWidget.curve_peak_hold_min.setVisible(checked)
@QtCore.Slot(bool)
@QtCore.pyqtSlot(bool)
def on_averageCheckBox_toggled(self, checked):
self.spectrumPlotWidget.average = checked
if self.spectrumPlotWidget.curve_average.xData is None:
self.spectrumPlotWidget.update_average(self.data_storage)
self.spectrumPlotWidget.curve_average.setVisible(checked)
@QtCore.Slot(bool)
@QtCore.pyqtSlot(bool)
def on_persistenceCheckBox_toggled(self, checked):
self.spectrumPlotWidget.persistence = checked
if self.spectrumPlotWidget.persistence_curves[0].xData is None:
@ -411,52 +443,29 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai
for curve in self.spectrumPlotWidget.persistence_curves:
curve.setVisible(checked)
@QtCore.Slot(bool)
@QtCore.pyqtSlot(bool)
def on_smoothCheckBox_toggled(self, checked):
settings = QtCore.QSettings()
self.data_storage.set_smooth(
checked,
settings.value("smooth_length", 11, int),
settings.value("smooth_window", "hanning")
settings.value("smooth_window", "hanning"),
recalculate=True
)
@QtCore.Slot(bool)
def on_baselineCheckBox_toggled(self, checked):
self.spectrumPlotWidget.baseline = checked
if self.spectrumPlotWidget.curve_baseline.xData is None:
self.spectrumPlotWidget.update_baseline(self.data_storage)
self.spectrumPlotWidget.curve_baseline.setVisible(checked)
@QtCore.Slot(bool)
def on_subtractBaselineCheckBox_toggled(self, checked):
settings = QtCore.QSettings()
self.data_storage.set_subtract_baseline(
checked,
settings.value("baseline_file", None)
)
@QtCore.Slot()
def on_baselineButton_clicked(self):
dialog = QSpectrumAnalyzerBaseline(self)
if dialog.exec_():
settings = QtCore.QSettings()
self.data_storage.set_subtract_baseline(
bool(self.subtractBaselineCheckBox.isChecked()),
settings.value("baseline_file", None)
)
@QtCore.Slot()
@QtCore.pyqtSlot()
def on_smoothButton_clicked(self):
dialog = QSpectrumAnalyzerSmoothing(self)
dialog = QSpectrumAnalyzerSmooth(self)
if dialog.exec_():
settings = QtCore.QSettings()
self.data_storage.set_smooth(
bool(self.smoothCheckBox.isChecked()),
settings.value("smooth_length", 11, int),
settings.value("smooth_window", "hanning")
settings.value("smooth_window", "hanning"),
recalculate=True
)
@QtCore.Slot()
@QtCore.pyqtSlot()
def on_persistenceButton_clicked(self):
prev_persistence_length = self.spectrumPlotWidget.persistence_length
dialog = QSpectrumAnalyzerPersistence(self)
@ -472,7 +481,7 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai
else:
self.spectrumPlotWidget.recalculate_persistence(self.data_storage)
@QtCore.Slot()
@QtCore.pyqtSlot()
def on_colorsButton_clicked(self):
dialog = QSpectrumAnalyzerColors(self)
if dialog.exec_():
@ -482,21 +491,20 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai
self.spectrumPlotWidget.peak_hold_min_color = str_to_color(settings.value("peak_hold_min_color", "0, 0, 255, 255"))
self.spectrumPlotWidget.average_color = str_to_color(settings.value("average_color", "0, 255, 255, 255"))
self.spectrumPlotWidget.persistence_color = str_to_color(settings.value("persistence_color", "0, 255, 0, 255"))
self.spectrumPlotWidget.baseline_color = str_to_color(settings.value("baseline_color", "255, 0, 255, 255"))
self.spectrumPlotWidget.set_colors()
@QtCore.Slot()
@QtCore.pyqtSlot()
def on_action_Settings_triggered(self):
dialog = QSpectrumAnalyzerSettings(self)
if dialog.exec_():
self.setup_power_thread()
@QtCore.Slot()
@QtCore.pyqtSlot()
def on_action_About_triggered(self):
QtWidgets.QMessageBox.information(self, self.tr("About - QSpectrumAnalyzer"),
self.tr("QSpectrumAnalyzer {}").format(__version__))
QtGui.QMessageBox.information(self, self.tr("About - QSpectrumAnalyzer"),
self.tr("QSpectrumAnalyzer {}").format(__version__))
@QtCore.Slot()
@QtCore.pyqtSlot()
def on_action_Quit_triggered(self):
self.close()
@ -507,37 +515,12 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai
def main():
global debug
# Parse command line arguments
parser = argparse.ArgumentParser(
prog="qspectrumanalyzer",
description="Spectrum analyzer for multiple SDR platforms",
)
parser.add_argument("--debug", action="store_true",
help="detailed debugging messages")
parser.add_argument("--version", action="version",
version="%(prog)s {}".format(__version__))
args, unparsed_args = parser.parse_known_args()
debug = args.debug
try:
# Hide console window on Windows
if sys.platform == 'win32' and not debug:
from qspectrumanalyzer import windows
windows.set_attached_console_visible(False)
# Start PyQt application
app = QtWidgets.QApplication(sys.argv[:1] + unparsed_args)
app.setOrganizationName("QSpectrumAnalyzer")
app.setOrganizationDomain("qspectrumanalyzer.eutopia.cz")
app.setApplicationName("QSpectrumAnalyzer")
window = QSpectrumAnalyzerMainWindow()
sys.exit(app.exec_())
finally:
# Unhide console window on Windows (we don't want to leave zombies behind)
if sys.platform == 'win32' and not debug:
windows.set_attached_console_visible(True)
app = QtGui.QApplication(sys.argv)
app.setOrganizationName("QSpectrumAnalyzer")
app.setOrganizationDomain("qspectrumanalyzer.eutopia.cz")
app.setApplicationName("QSpectrumAnalyzer")
window = QSpectrumAnalyzerMainWindow()
sys.exit(app.exec_())
if __name__ == "__main__":

View File

@ -0,0 +1,566 @@
import subprocess, math, pprint, re
import numpy as np
from PyQt4 import QtCore
import struct
class BasePowerThread(QtCore.QThread):
"""Thread which runs Power Spectral Density acquisition and calculation process"""
powerThreadStarted = QtCore.pyqtSignal()
powerThreadStopped = QtCore.pyqtSignal()
def __init__(self, data_storage, parent=None):
super().__init__(parent)
self.data_storage = data_storage
self.alive = False
self.process = None
def stop(self):
"""Stop power process thread"""
self.process_stop()
self.alive = False
self.wait()
def setup(self, start_freq, stop_freq, bin_size, interval=10.0, gain=-1,
ppm=0, crop=0, single_shot=False, device=0, sample_rate=2560000):
"""Setup power process params"""
raise NotImplementedError
def process_start(self):
"""Start power process"""
raise NotImplementedError
def process_stop(self):
"""Terminate power process"""
if self.process:
try:
self.process.terminate()
except ProcessLookupError:
pass
self.process.wait()
self.process = None
def parse_output(self, line):
"""Parse one line of output from power process"""
raise NotImplementedError
def run(self):
"""Power process thread main loop"""
self.process_start()
self.alive = True
self.powerThreadStarted.emit()
for line in self.process.stdout:
if not self.alive:
break
self.parse_output(line)
self.process_stop()
self.alive = False
self.powerThreadStopped.emit()
class RxPowerThread(BasePowerThread):
"""Thread which runs rx_power process"""
def setup(self, start_freq, stop_freq, bin_size, interval=10.0, gain=-1,
ppm=0, crop=0, single_shot=False, device=0, sample_rate=2560000):
"""Setup rx_power params"""
self.params = {
"start_freq": start_freq,
"stop_freq": stop_freq,
"bin_size": bin_size,
"interval": interval,
"device": device,
"hops": 0,
"gain": gain,
"ppm": ppm,
"crop": crop,
"single_shot": single_shot
}
self.databuffer = {}
self.last_timestamp = ""
print("rx_power params:")
pprint.pprint(self.params)
print()
def process_start(self):
"""Start rx_power process"""
if not self.process and self.params:
settings = QtCore.QSettings()
cmdline = [
settings.value("executable", "rx_power"),
"-f", "{}M:{}M:{}k".format(self.params["start_freq"],
self.params["stop_freq"],
self.params["bin_size"]),
"-i", "{}".format(self.params["interval"]),
"-d", "{}".format(self.params["device"]),
"-p", "{}".format(self.params["ppm"]),
"-c", "{}".format(self.params["crop"])
]
if self.params["gain"] >= 0:
cmdline.extend(["-g", "{}".format(self.params["gain"])])
if self.params["single_shot"]:
cmdline.append("-1")
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
universal_newlines=True)
def parse_output(self, line):
"""Parse one line of output from rx_power"""
line = [col.strip() for col in line.split(",")]
timestamp = " ".join(line[:2])
start_freq = int(line[2])
stop_freq = int(line[3])
step = float(line[4])
samples = float(line[5])
x_axis = list(np.arange(start_freq, stop_freq, step))
y_axis = [float(y) for y in line[6:]]
if len(x_axis) != len(y_axis):
print("ERROR: len(x_axis) != len(y_axis), use newer version of rx_power!")
if len(x_axis) > len(y_axis):
print("Trimming x_axis...")
x_axis = x_axis[:len(y_axis)]
else:
print("Trimming y_axis...")
y_axis = y_axis[:len(x_axis)]
if timestamp != self.last_timestamp:
self.last_timestamp = timestamp
self.databuffer = {"timestamp": timestamp,
"x": x_axis,
"y": y_axis}
else:
self.databuffer["x"].extend(x_axis)
self.databuffer["y"].extend(y_axis)
# This have to be stupid like this to be compatible with old broken version of rx_power. Right way is:
# if stop_freq == self.params["stop_freq"] * 1e6:
if stop_freq > (self.params["stop_freq"] * 1e6) - step:
self.data_storage.update(self.databuffer)
class RtlPowerThread(BasePowerThread):
"""Thread which runs rtl_power process"""
def setup(self, start_freq, stop_freq, bin_size, interval=10.0, gain=-1,
ppm=0, crop=0, single_shot=False, device=0, sample_rate=2560000):
"""Setup rtl_power params"""
if bin_size > 2800:
bin_size = 2800
self.params = {
"start_freq": start_freq,
"stop_freq": stop_freq,
"bin_size": bin_size,
"interval": interval,
"device": device,
"hops": 0,
"gain": gain,
"ppm": ppm,
"crop": crop,
"single_shot": single_shot
}
self.databuffer = {}
self.last_timestamp = ""
print("rtl_power params:")
pprint.pprint(self.params)
print()
def process_start(self):
"""Start rtl_power process"""
if not self.process and self.params:
settings = QtCore.QSettings()
cmdline = [
settings.value("executable", "rtl_power"),
"-f", "{}M:{}M:{}k".format(self.params["start_freq"],
self.params["stop_freq"],
self.params["bin_size"]),
"-i", "{}".format(self.params["interval"]),
"-d", "{}".format(self.params["device"]),
"-p", "{}".format(self.params["ppm"]),
"-c", "{}".format(self.params["crop"])
]
if self.params["gain"] >= 0:
cmdline.extend(["-g", "{}".format(self.params["gain"])])
if self.params["single_shot"]:
cmdline.append("-1")
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
universal_newlines=True)
def parse_output(self, line):
"""Parse one line of output from rtl_power"""
line = [col.strip() for col in line.split(",")]
timestamp = " ".join(line[:2])
start_freq = int(line[2])
stop_freq = int(line[3])
step = float(line[4])
samples = float(line[5])
x_axis = list(np.arange(start_freq, stop_freq, step))
y_axis = [float(y) for y in line[6:]]
if len(x_axis) != len(y_axis):
print("ERROR: len(x_axis) != len(y_axis), use newer version of rtl_power!")
if len(x_axis) > len(y_axis):
print("Trimming x_axis...")
x_axis = x_axis[:len(y_axis)]
else:
print("Trimming y_axis...")
y_axis = y_axis[:len(x_axis)]
if timestamp != self.last_timestamp:
self.last_timestamp = timestamp
self.databuffer = {"timestamp": timestamp,
"x": x_axis,
"y": y_axis}
else:
self.databuffer["x"].extend(x_axis)
self.databuffer["y"].extend(y_axis)
# This have to be stupid like this to be compatible with old broken version of rtl_power. Right way is:
# if stop_freq == self.params["stop_freq"] * 1e6:
if stop_freq > (self.params["stop_freq"] * 1e6) - step:
self.data_storage.update(self.databuffer)
class RtlPowerFftwThread(BasePowerThread):
"""Thread which runs rtl_power_fftw process"""
def setup(self, start_freq, stop_freq, bin_size, interval=10.0, gain=-1,
ppm=0, crop=0, single_shot=False, device=0, sample_rate=2560000):
"""Setup rtl_power_fftw params"""
crop = crop * 100
overlap = crop * 2
freq_range = stop_freq * 1e6 - start_freq * 1e6
min_overhang = sample_rate * overlap * 0.01
hops = math.ceil((freq_range - min_overhang) / (sample_rate - min_overhang))
overhang = (hops * sample_rate - freq_range) / (hops - 1) if hops > 1 else 0
if bin_size > 2800:
bin_size = 2800
bins = math.ceil(sample_rate / (bin_size * 1e3))
crop_freq = sample_rate * crop * 0.01
self.params = {
"start_freq": start_freq,
"stop_freq": stop_freq,
"freq_range": freq_range,
"device": device,
"sample_rate": sample_rate,
"bin_size": bin_size,
"bins": bins,
"interval": interval,
"hops": hops,
"time": interval / hops,
"gain": gain * 10,
"ppm": ppm,
"crop": crop,
"overlap": overlap,
"min_overhang": min_overhang,
"overhang": overhang,
"single_shot": single_shot
}
self.freqs = [self.get_hop_freq(hop) for hop in range(hops)]
self.freqs_crop = [(f[0] + crop_freq, f[1] - crop_freq) for f in self.freqs]
self.databuffer = {"timestamp": [], "x": [], "y": []}
self.databuffer_hop = {"timestamp": [], "x": [], "y": []}
self.hop = 0
self.prev_line = ""
print("rtl_power_fftw params:")
pprint.pprint(self.params)
print()
def get_hop_freq(self, hop):
"""Get start and stop frequency for particular hop"""
start_freq = self.params["start_freq"] * 1e6 + (self.params["sample_rate"] - self.params["overhang"]) * hop
stop_freq = start_freq + self.params["sample_rate"] - (self.params["sample_rate"] / self.params["bins"])
return (start_freq, stop_freq)
def process_start(self):
"""Start rtl_power_fftw process"""
if not self.process and self.params:
settings = QtCore.QSettings()
cmdline = [
settings.value("executable", "rtl_power_fftw"),
"-f", "{}M:{}M".format(self.params["start_freq"],
self.params["stop_freq"]),
"-b", "{}".format(self.params["bins"]),
"-t", "{}".format(self.params["time"]),
"-d", "{}".format(self.params["device"]),
"-r", "{}".format(self.params["sample_rate"]),
"-p", "{}".format(self.params["ppm"]),
]
if self.params["gain"] >= 0:
cmdline.extend(["-g", "{}".format(self.params["gain"])])
if self.params["overlap"] > 0:
cmdline.extend(["-o", "{}".format(self.params["overlap"])])
if not self.params["single_shot"]:
cmdline.append("-c")
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
universal_newlines=True)
def parse_output(self, line):
"""Parse one line of output from rtl_power_fftw"""
line = line.strip()
# One empty line => new hop
if not line and self.prev_line:
self.hop += 1
self.databuffer["x"].extend(self.databuffer_hop["x"])
self.databuffer["y"].extend(self.databuffer_hop["y"])
self.databuffer_hop = {"timestamp": [], "x": [], "y": []}
# Two empty lines => new set
elif not line and not self.prev_line:
self.hop = 0
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
# Skip other comments
elif line.startswith("#"):
pass
# Parse frequency and power
elif line[0].isdigit():
freq, power = line.split()
freq, power = float(freq), float(power)
start_freq, stop_freq = self.freqs_crop[self.hop]
# Apply cropping
if freq >= start_freq and freq <= stop_freq:
# Skip overlapping frequencies
if not self.databuffer["x"] or freq > self.databuffer["x"][-1]:
#print(" {:.3f} MHz".format(freq / 1e6))
self.databuffer_hop["x"].append(freq)
self.databuffer_hop["y"].append(power)
else:
#print(" Overlapping {:.3f} MHz".format(freq / 1e6))
pass
else:
#print(" Cropping {:.3f} MHz".format(freq / 1e6))
pass
self.prev_line = line
class SoapyPowerThread(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"""
self.params = {
"start_freq": start_freq,
"stop_freq": stop_freq,
"device": device,
"sample_rate": sample_rate,
"bin_size": bin_size,
"interval": interval,
"hops": 0,
"gain": gain * 10,
"ppm": ppm,
"crop": crop * 100,
"single_shot": single_shot
}
self.databuffer = {"timestamp": [], "x": [], "y": []}
self.databuffer_hop = {"timestamp": [], "x": [], "y": []}
self.hop = 0
self.run = 0
self.prev_line = ""
print("soapy_power params:")
pprint.pprint(self.params)
print()
def process_start(self):
"""Start soapy_power process"""
if not self.process and self.params:
settings = QtCore.QSettings()
cmdline = [
settings.value("executable", "soapy_power"),
"-f", "{}M:{}M".format(self.params["start_freq"],
self.params["stop_freq"]),
"-B", "{}k".format(self.params["bin_size"]),
"-T", "{}".format(self.params["interval"]),
"-d", "{}".format(self.params["device"]),
"-r", "{}".format(self.params["sample_rate"]),
"-p", "{}".format(self.params["ppm"]),
]
if self.params["gain"] >= 0:
cmdline.extend(["-g", "{}".format(self.params["gain"])])
if self.params["crop"] > 0:
cmdline.extend(["-k", "{}".format(self.params["crop"])])
if not self.params["single_shot"]:
cmdline.append("-c")
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
universal_newlines=True)
def parse_output(self, line):
"""Parse one line of output from soapy_power"""
line = line.strip()
# 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": []}
# Two empty lines => new set
elif not line and not self.prev_line:
self.hop = 0
self.run += 1
print(' * RUN:', self.run)
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
# Skip other comments
elif line.startswith("#"):
pass
# Parse frequency and power
elif self.re_two_floats.match(line):
try:
freq, power = line.split()
except ValueError:
return
freq, power = float(freq), float(power)
self.databuffer_hop["x"].append(freq)
self.databuffer_hop["y"].append(power)
self.prev_line = line
class HackRFSweepThread(BasePowerThread):
"""Thread which runs hackrf_sweep process"""
def setup(self, start_freq=0, stop_freq=6000, bin_size=1000,
interval=0.0, gain=40, ppm=0, crop=0, single_shot=False,
device_index=0, sample_rate=20000000):
"""Setup hackrf_sweep params"""
# theoretically we can support bins smaller than 40 kHz, but it is
# unlikely to result in acceptable performance
if bin_size < 40:
bin_size = 40
if bin_size > 5000:
bin_size = 5000
# We only support whole numbers of steps with bandwidth equal to the
# sample rate.
step_bandwidth = sample_rate / 1000000
total_bandwidth = stop_freq - start_freq
step_count = 1 + (total_bandwidth - 1) // step_bandwidth
total_bandwidth = step_count * step_bandwidth
stop_freq = start_freq + total_bandwidth
# distribute gain between two analog gain stages
if gain < 0:
gain = 0
if gain > 102:
gain = 102
lna_gain = 8 * (gain // 18)
vga_gain = 2 * ((gain - lna_gain) // 2)
self.params = {
"start_freq": start_freq, # MHz
"stop_freq": stop_freq, # MHz
"hops": 0,
"device_index": 0,
"sample_rate": 20e6, # sps
"bin_size": bin_size, # kHz
"interval": 0, # seconds
"gain": gain,
"lna_gain": lna_gain,
"vga_gain": vga_gain,
"ppm": 0,
"crop": 0,
"single_shot": single_shot
}
self.databuffer = {"timestamp": [], "x": [], "y": []}
print("hackrf_sweep params:")
pprint.pprint(self.params)
print()
def process_start(self):
"""Start hackrf_sweep process"""
if not self.process and self.params:
settings = QtCore.QSettings()
cmdline = [
settings.value("executable", "hackrf_sweep"),
"-f", "{}:{}".format(int(self.params["start_freq"]),
int(self.params["stop_freq"])),
"-B",
"-w", "{}".format(int(self.params["bin_size"]*1000)),
"-l", "{}".format(int(self.params["lna_gain"])),
"-g", "{}".format(int(self.params["vga_gain"])),
]
if self.params["single_shot"]:
cmdline.append("-1")
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
universal_newlines=False)
def parse_output(self, buf):
"""Parse one buf of output from hackrf_sweep"""
(low_edge, high_edge) = struct.unpack('QQ', buf[:16])
data = np.fromstring(buf[16:], dtype='<f4')
step = (high_edge - low_edge) / len(data)
if (low_edge//1000000) <= (self.params["start_freq"]):
# Reset databuffer at the start of each sweep even if we somehow
# did not complete the previous sweep.
self.databuffer = {"timestamp": [], "x": [], "y": []}
x_axis = list(np.arange(low_edge + step/2, high_edge, step))
self.databuffer["x"].extend(x_axis)
for i in range(len(data)):
self.databuffer["y"].append(data[i])
if (high_edge / 1e6) >= (self.params["stop_freq"]):
# We've reached the end of a pass, so sort and display it.
sorted_data = sorted(zip(self.databuffer["x"], self.databuffer["y"]))
self.databuffer["x"], self.databuffer["y"] = [list(x) for x in zip(*sorted_data)]
self.data_storage.update(self.databuffer)
def run(self):
"""hackrf_sweep thread main loop"""
self.process_start()
self.alive = True
self.powerThreadStarted.emit()
while self.alive:
buf = self.process.stdout.read(4)
if buf:
(record_length,) = struct.unpack('I', buf)
buf = self.process.stdout.read(record_length)
if buf:
self.parse_output(buf)
self.process_stop()
self.alive = False
self.powerThreadStopped.emit()

View File

@ -1,117 +0,0 @@
import os, threading, shlex
from Qt import QtCore
from qspectrumanalyzer import subprocess
class BaseInfo:
"""Default device metadata"""
sample_rate_min = 0
sample_rate_max = 3200000
sample_rate = 2560000
bandwidth_min = 0
bandwidth_max = 0
bandwidth = 0
gain_min = -1
gain_max = 49.6
gain = 37
start_freq_min = 0
start_freq_max = 2200
start_freq = 87
stop_freq_min = 0
stop_freq_max = 2200
stop_freq = 108
bin_size_min = 0
bin_size_max = 2800
bin_size = 10
interval_min = 0
interval_max = 3600
interval = 1
ppm_min = -999
ppm_max = 999
ppm = 0
crop_min = 0
crop_max = 99
crop = 0
additional_params = ''
help_device = None
@classmethod
def help_params(cls, executable):
cmdline = shlex.split(executable)
try:
text = subprocess.check_output(cmdline + ['-h'], universal_newlines=True,
stderr=subprocess.STDOUT, env=dict(os.environ, COLUMNS='125'),
console=False)
except subprocess.CalledProcessError as e:
text = e.output
except OSError:
text = '{} executable not found!'.format(executable)
return text
class BasePowerThread(QtCore.QThread):
"""Thread which runs Power Spectral Density acquisition and calculation process"""
powerThreadStarted = QtCore.Signal()
powerThreadStopped = QtCore.Signal()
def __init__(self, data_storage, parent=None):
super().__init__(parent)
self.data_storage = data_storage
self.alive = False
self.process = None
self._shutdown_lock = threading.Lock()
def stop(self):
"""Stop power process thread"""
self.process_stop()
self.alive = False
self.wait()
def setup(self, start_freq, stop_freq, bin_size, interval=10.0, gain=-1, ppm=0, crop=0,
single_shot=False, device=0, sample_rate=2560000, bandwidth=0, lnb_lo=0):
"""Setup power process params"""
raise NotImplementedError
def process_start(self):
"""Start power process"""
raise NotImplementedError
def process_stop(self):
"""Terminate power process"""
with self._shutdown_lock:
if self.process:
if self.process.poll() is None:
try:
self.process.terminate()
except ProcessLookupError:
pass
self.process.wait()
self.process = None
def parse_output(self, line):
"""Parse one line of output from power process"""
raise NotImplementedError
def run(self):
"""Power process thread main loop"""
self.process_start()
self.alive = True
self.powerThreadStarted.emit()
for line in self.process.stdout:
if not self.alive:
break
self.parse_output(line)
self.process_stop()
self.alive = False
self.powerThreadStopped.emit()
# Build list of all backends
__all__ = ['soapy_power', 'hackrf_sweep', 'rtl_power', 'rtl_power_fftw', 'rx_power']
# Import all backends
from qspectrumanalyzer.backends import soapy_power, hackrf_sweep, rtl_power, rtl_power_fftw, rx_power

View File

@ -1,171 +0,0 @@
import struct, shlex, sys, time
import numpy as np
from Qt import QtCore
from qspectrumanalyzer import subprocess
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
class Info(BaseInfo):
"""hackrf_sweep device metadata"""
sample_rate_min = 20000000
sample_rate_max = 20000000
sample_rate = 20000000
gain_min = -1
gain_max = 102
gain = 40
start_freq_min = 0
start_freq_max = 7230
start_freq = 0
stop_freq_min = 0
stop_freq_max = 7250
stop_freq = 6000
bin_size_min = 3
bin_size_max = 5000
bin_size = 1000
interval = 0
ppm_min = 0
ppm_max = 0
ppm = 0
crop_min = 0
crop_max = 0
crop = 0
class PowerThread(BasePowerThread):
"""Thread which runs hackrf_sweep process"""
def setup(self, start_freq=0, stop_freq=6000, bin_size=1000,
interval=0.0, gain=40, ppm=0, crop=0, single_shot=False,
device=0, sample_rate=20000000, bandwidth=0, lnb_lo=0):
"""Setup hackrf_sweep params"""
# Small bin sizes (<40 kHz) are only suitable with an arbitrarily
# reduced sweep interval. Bin sizes smaller than 3 kHz showed to be
# infeasible also in these cases.
if bin_size < 3:
bin_size = 3
if bin_size > 5000:
bin_size = 5000
# We only support whole numbers of steps with bandwidth equal to the
# sample rate.
step_bandwidth = sample_rate / 1000000
total_bandwidth = stop_freq - start_freq
step_count = 1 + (total_bandwidth - 1) // step_bandwidth
total_bandwidth = step_count * step_bandwidth
stop_freq = start_freq + total_bandwidth
# distribute gain between two analog gain stages
if gain > 102:
gain = 102
lna_gain = 8 * (gain // 18) if gain >= 0 else 0
vga_gain = 2 * ((gain - lna_gain) // 2) if gain >= 0 else 0
self.params = {
"start_freq": start_freq, # MHz
"stop_freq": stop_freq, # MHz
"hops": 0,
"device": 0,
"sample_rate": 20e6, # sps
"bin_size": bin_size, # kHz
"interval": interval, # seconds
"gain": gain,
"lna_gain": lna_gain,
"vga_gain": vga_gain,
"ppm": 0,
"crop": 0,
"single_shot": single_shot
}
self.lnb_lo = lnb_lo
self.databuffer = {"timestamp": [], "x": [], "y": []}
self.lastsweep = 0
self.interval = interval
def process_start(self):
"""Start hackrf_sweep process"""
if not self.process and self.params:
settings = QtCore.QSettings()
cmdline = shlex.split(settings.value("executable", "hackrf_sweep"))
cmdline.extend([
"-f", "{}:{}".format(int(self.params["start_freq"] - self.lnb_lo / 1e6),
int(self.params["stop_freq"] - self.lnb_lo / 1e6)),
"-B",
"-w", "{}".format(int(self.params["bin_size"] * 1000)),
])
if self.params["gain"] >= 0:
cmdline.extend([
"-l", "{}".format(int(self.params["lna_gain"])),
"-g", "{}".format(int(self.params["vga_gain"])),
])
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))
print('Starting backend:')
print(' '.join(cmdline))
print()
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
universal_newlines=False, console=False)
def parse_output(self, buf):
"""Parse one buf of output from hackrf_sweep"""
(low_edge, high_edge) = struct.unpack('QQ', buf[:16])
data = np.fromstring(buf[16:], dtype='<f4')
step = (high_edge - low_edge) / len(data)
if (low_edge // 1000000) <= (self.params["start_freq"] - self.lnb_lo / 1e6):
# Reset databuffer at the start of each sweep even if we somehow
# did not complete the previous sweep.
self.databuffer = {"timestamp": [], "x": [], "y": []}
x_axis = list(np.arange(low_edge + self.lnb_lo + step / 2, high_edge + self.lnb_lo, step))
self.databuffer["x"].extend(x_axis)
for i in range(len(data)):
self.databuffer["y"].append(data[i])
if (high_edge / 1e6) >= (self.params["stop_freq"] - self.lnb_lo / 1e6):
# We've reached the end of a pass. If it went too fast for our sweep interval, ignore it
t_finish = time.time()
if (t_finish < self.lastsweep + self.interval):
return
self.lastsweep = t_finish
# otherwise sort and display the data.
sorted_data = sorted(zip(self.databuffer["x"], self.databuffer["y"]))
self.databuffer["x"], self.databuffer["y"] = [list(x) for x in zip(*sorted_data)]
self.data_storage.update(self.databuffer)
def run(self):
"""hackrf_sweep thread main loop"""
self.process_start()
self.alive = True
self.powerThreadStarted.emit()
while self.alive:
try:
buf = self.process.stdout.read(4)
except AttributeError as e:
print(e, file=sys.stderr)
continue
if buf:
(record_length,) = struct.unpack('I', buf)
try:
buf = self.process.stdout.read(record_length)
except AttributeError as e:
print(e, file=sys.stderr)
continue
if buf:
self.parse_output(buf)
else:
break
else:
break
self.process_stop()
self.alive = False
self.powerThreadStopped.emit()

View File

@ -1,104 +0,0 @@
import shlex
import numpy as np
from Qt import QtCore
from qspectrumanalyzer import subprocess
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
class Info(BaseInfo):
"""rtl_power device metadata"""
pass
class PowerThread(BasePowerThread):
"""Thread which runs rtl_power process"""
def setup(self, start_freq, stop_freq, bin_size, interval=10.0, gain=-1, ppm=0, crop=0,
single_shot=False, device=0, sample_rate=2560000, bandwidth=0, lnb_lo=0):
"""Setup rtl_power params"""
if bin_size > 2800:
bin_size = 2800
self.params = {
"start_freq": start_freq,
"stop_freq": stop_freq,
"bin_size": bin_size,
"interval": interval,
"device": device,
"sample_rate": sample_rate,
"hops": 0,
"gain": gain,
"ppm": ppm,
"crop": crop,
"single_shot": single_shot
}
self.lnb_lo = lnb_lo
self.databuffer = {}
self.last_timestamp = ""
def process_start(self):
"""Start rtl_power process"""
if not self.process and self.params:
settings = QtCore.QSettings()
cmdline = shlex.split(settings.value("executable", "rtl_power"))
cmdline.extend([
"-f", "{}M:{}M:{}k".format(self.params["start_freq"] - self.lnb_lo / 1e6,
self.params["stop_freq"] - self.lnb_lo / 1e6,
self.params["bin_size"]),
"-i", "{}".format(self.params["interval"]),
"-d", "{}".format(self.params["device"]),
"-p", "{}".format(self.params["ppm"]),
"-c", "{}".format(self.params["crop"])
])
if self.params["sample_rate"] > 0:
cmdline.extend(["-r", "{}M".format(self.params["sample_rate"] / 1e6)])
if self.params["gain"] >= 0:
cmdline.extend(["-g", "{}".format(self.params["gain"])])
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))
print('Starting backend:')
print(' '.join(cmdline))
print()
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
universal_newlines=True, console=False)
def parse_output(self, line):
"""Parse one line of output from rtl_power"""
line = [col.strip() for col in line.split(",")]
timestamp = " ".join(line[:2])
start_freq = int(line[2])
stop_freq = int(line[3])
step = float(line[4])
samples = float(line[5])
x_axis = list(np.linspace(start_freq + self.lnb_lo, stop_freq + self.lnb_lo,
round((stop_freq - start_freq) / step)))
y_axis = [float(y) for y in line[6:]]
if len(x_axis) != len(y_axis):
print("ERROR: len(x_axis) != len(y_axis), use newer version of rtl_power!")
if len(x_axis) > len(y_axis):
print("Trimming x_axis...")
x_axis = x_axis[:len(y_axis)]
else:
print("Trimming y_axis...")
y_axis = y_axis[:len(x_axis)]
if timestamp != self.last_timestamp:
self.last_timestamp = timestamp
self.databuffer = {"timestamp": timestamp,
"x": x_axis,
"y": y_axis}
else:
self.databuffer["x"].extend(x_axis)
self.databuffer["y"].extend(y_axis)
# This have to be stupid like this to be compatible with old broken version of rtl_power. Right way is:
# if stop_freq == (self.params["stop_freq"] - self.lnb_lo / 1e6) * 1e6:
if stop_freq > ((self.params["stop_freq"] - self.lnb_lo / 1e6) * 1e6) - step:
self.data_storage.update(self.databuffer)

View File

@ -1,145 +0,0 @@
import math, shlex
from Qt import QtCore
from qspectrumanalyzer import subprocess
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
class Info(BaseInfo):
"""rtl_power_fftw device metadata"""
pass
class PowerThread(BasePowerThread):
"""Thread which runs rtl_power_fftw process"""
def setup(self, start_freq, stop_freq, bin_size, interval=10.0, gain=-1, ppm=0, crop=0,
single_shot=False, device=0, sample_rate=2560000, bandwidth=0, lnb_lo=0):
"""Setup rtl_power_fftw params"""
crop = crop * 100
overlap = crop * 2
freq_range = stop_freq * 1e6 - start_freq * 1e6
min_overhang = sample_rate * overlap * 0.01
hops = math.ceil((freq_range - min_overhang) / (sample_rate - min_overhang))
overhang = (hops * sample_rate - freq_range) / (hops - 1) if hops > 1 else 0
if bin_size > 2800:
bin_size = 2800
bins = math.ceil(sample_rate / (bin_size * 1e3))
crop_freq = sample_rate * crop * 0.01
self.params = {
"start_freq": start_freq,
"stop_freq": stop_freq,
"freq_range": freq_range,
"device": device,
"sample_rate": int(sample_rate),
"bin_size": bin_size,
"bins": bins,
"interval": interval,
"hops": hops,
"time": interval / hops,
"gain": int(gain * 10),
"ppm": ppm,
"crop": crop,
"overlap": overlap,
"min_overhang": min_overhang,
"overhang": overhang,
"single_shot": single_shot
}
self.lnb_lo = lnb_lo
self.freqs = [self.get_hop_freq(hop) for hop in range(hops)]
self.freqs_crop = [(f[0] + crop_freq, f[1] - crop_freq) for f in self.freqs]
self.databuffer = {"timestamp": [], "x": [], "y": []}
self.databuffer_hop = {"timestamp": [], "x": [], "y": []}
self.hop = 0
self.prev_line = ""
def get_hop_freq(self, hop):
"""Get start and stop frequency for particular hop"""
start_freq = self.params["start_freq"] * 1e6 + (self.params["sample_rate"] - self.params["overhang"]) * hop
stop_freq = start_freq + self.params["sample_rate"] - (self.params["sample_rate"] / self.params["bins"])
return (start_freq, stop_freq)
def process_start(self):
"""Start rtl_power_fftw process"""
if not self.process and self.params:
settings = QtCore.QSettings()
cmdline = shlex.split(settings.value("executable", "rtl_power_fftw"))
cmdline.extend([
"-f", "{}M:{}M".format(self.params["start_freq"] - self.lnb_lo / 1e6,
self.params["stop_freq"] - self.lnb_lo / 1e6),
"-b", "{}".format(self.params["bins"]),
"-t", "{}".format(self.params["time"]),
"-d", "{}".format(self.params["device"]),
"-r", "{}".format(self.params["sample_rate"]),
"-p", "{}".format(self.params["ppm"]),
"-q",
])
if self.params["gain"] >= 0:
cmdline.extend(["-g", "{}".format(self.params["gain"])])
if self.params["overlap"] > 0:
cmdline.extend(["-o", "{}".format(self.params["overlap"])])
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))
print('Starting backend:')
print(' '.join(cmdline))
print()
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
universal_newlines=True, console=False)
def parse_output(self, line):
"""Parse one line of output from rtl_power_fftw"""
line = line.strip()
# One empty line => new hop
if not line and self.prev_line:
self.hop += 1
self.databuffer["x"].extend(self.databuffer_hop["x"])
self.databuffer["y"].extend(self.databuffer_hop["y"])
self.databuffer_hop = {"timestamp": [], "x": [], "y": []}
# Two empty lines => new set
elif not line and not self.prev_line:
self.hop = 0
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
# Skip other comments
elif line.startswith("#"):
pass
# Parse frequency and power
elif line[0].isdigit():
freq, power = line.split()
freq, power = float(freq) + self.lnb_lo, float(power)
start_freq, stop_freq = self.freqs_crop[self.hop]
# Apply cropping
if freq >= start_freq and freq <= stop_freq:
# Skip overlapping frequencies
if not self.databuffer["x"] or freq > self.databuffer["x"][-1]:
#print(" {:.3f} MHz".format(freq / 1e6))
self.databuffer_hop["x"].append(freq)
self.databuffer_hop["y"].append(power)
else:
#print(" Overlapping {:.3f} MHz".format(freq / 1e6))
pass
else:
#print(" Cropping {:.3f} MHz".format(freq / 1e6))
pass
self.prev_line = line

View File

@ -1,109 +0,0 @@
import shlex
import numpy as np
from Qt import QtCore
from qspectrumanalyzer import subprocess
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
class Info(BaseInfo):
"""rx_power device metadata"""
sample_rate_min = 0
sample_rate_max = 0
sample_rate = 0
start_freq_min = 0
start_freq_max = 7250
stop_freq_min = 0
stop_freq_max = 7250
gain_min = -1
gain_max = 999
bin_size_min = 0
bin_size_max = 2800
class PowerThread(BasePowerThread):
"""Thread which runs rx_power process"""
def setup(self, start_freq, stop_freq, bin_size, interval=10.0, gain=-1, ppm=0, crop=0,
single_shot=False, device=0, sample_rate=2560000, bandwidth=0, lnb_lo=0):
"""Setup rx_power params"""
self.params = {
"start_freq": start_freq,
"stop_freq": stop_freq,
"bin_size": bin_size,
"interval": interval,
"device": device,
"hops": 0,
"gain": gain,
"ppm": ppm,
"crop": crop,
"single_shot": single_shot
}
self.lnb_lo = lnb_lo
self.databuffer = {}
self.last_timestamp = ""
def process_start(self):
"""Start rx_power process"""
if not self.process and self.params:
settings = QtCore.QSettings()
cmdline = shlex.split(settings.value("executable", "rx_power"))
cmdline.extend([
"-f", "{}M:{}M:{}k".format(self.params["start_freq"] - self.lnb_lo / 1e6,
self.params["stop_freq"] - self.lnb_lo / 1e6,
self.params["bin_size"]),
"-i", "{}".format(self.params["interval"]),
"-d", "{}".format(self.params["device"]),
"-p", "{}".format(self.params["ppm"]),
"-c", "{}".format(self.params["crop"])
])
if self.params["gain"] >= 0:
cmdline.extend(["-g", "{}".format(self.params["gain"])])
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))
print('Starting backend:')
print(' '.join(cmdline))
print()
self.process = subprocess.Popen(cmdline, stdout=subprocess.PIPE,
universal_newlines=True, console=False)
def parse_output(self, line):
"""Parse one line of output from rx_power"""
line = [col.strip() for col in line.split(",")]
timestamp = " ".join(line[:2])
start_freq = int(line[2])
stop_freq = int(line[3])
step = float(line[4])
samples = float(line[5])
x_axis = list(np.linspace(start_freq + self.lnb_lo, stop_freq + self.lnb_lo,
round((stop_freq - start_freq) / step)))
y_axis = [float(y) for y in line[6:]]
if len(x_axis) != len(y_axis):
print("ERROR: len(x_axis) != len(y_axis)!")
if len(x_axis) > len(y_axis):
print("Trimming x_axis...")
x_axis = x_axis[:len(y_axis)]
else:
print("Trimming y_axis...")
y_axis = y_axis[:len(x_axis)]
if timestamp != self.last_timestamp:
self.last_timestamp = timestamp
self.databuffer = {"timestamp": timestamp,
"x": x_axis,
"y": y_axis}
else:
self.databuffer["x"].extend(x_axis)
self.databuffer["y"].extend(y_axis)
# This have to be stupid like this to be compatible with old broken version of rtl_power. Right way is:
# if stop_freq == (self.params["stop_freq"] - self.lnb_lo / 1e6) * 1e6:
if stop_freq > ((self.params["stop_freq"] - self.lnb_lo / 1e6) * 1e6) - step:
self.data_storage.update(self.databuffer)

View File

@ -1,254 +0,0 @@
import os, sys, shlex, signal
import numpy as np
from Qt import QtCore
from qspectrumanalyzer import subprocess
from qspectrumanalyzer.backends import BaseInfo, BasePowerThread
try:
from soapypower.writer import SoapyPowerBinFormat
formatter = SoapyPowerBinFormat()
except ImportError:
print('soapy_power module not found!')
formatter = None
class Info(BaseInfo):
"""soapy_power device metadata"""
sample_rate_min = 0
sample_rate_max = 61440000
bandwidth_min = 0
bandwidth_max = 61440000
start_freq_min = 0
start_freq_max = 7250
stop_freq_min = 0
stop_freq_max = 7250
gain_min = -1
gain_max = 999
bin_size_min = 0
bin_size_max = 10000
additional_params = '--even --fft-window boxcar --remove-dc'
@classmethod
def help_device(cls, executable, device):
cmdline = shlex.split(executable)
try:
text = subprocess.check_output(cmdline + ['--detect'], universal_newlines=True,
stderr=subprocess.DEVNULL, env=dict(os.environ, COLUMNS='125'),
console=False)
text += '\n'
text += subprocess.check_output(cmdline + ['--device', device, '--info'], universal_newlines=True,
stderr=subprocess.DEVNULL, env=dict(os.environ, COLUMNS='125'),
console=False)
except subprocess.CalledProcessError as e:
text = e.output
except OSError:
text = '{} executable not found!'.format(executable)
return text
class PowerThread(BasePowerThread):
"""Thread which runs soapy_power process"""
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, bandwidth=0, lnb_lo=0):
"""Setup soapy_power params"""
self.params = {
"start_freq": start_freq,
"stop_freq": stop_freq,
"device": device,
"sample_rate": sample_rate,
"bandwidth": bandwidth,
"bin_size": bin_size,
"interval": interval,
"hops": 0,
"gain": gain,
"ppm": ppm,
"crop": crop * 100,
"single_shot": single_shot
}
self.lnb_lo = lnb_lo
self.databuffer = {"timestamp": [], "x": [], "y": []}
self.min_freq = None
self.pipe_read = None
self.pipe_read_fd = None
self.pipe_write_fd = None
self.pipe_write_handle = None
def process_start(self):
"""Start soapy_power process"""
if not self.process and self.params:
# Create pipe used for communication with soapy_power process
self.pipe_read_fd, self.pipe_write_fd = os.pipe()
self.pipe_read = open(self.pipe_read_fd, 'rb')
os.set_inheritable(self.pipe_write_fd, True)
if sys.platform == 'win32':
self.pipe_write_handle = subprocess.make_inheritable_handle(self.pipe_write_fd)
# Prepare soapy_power cmdline parameters
settings = QtCore.QSettings()
cmdline = shlex.split(settings.value("executable", "soapy_power"))
cmdline.extend([
"-f", "{}M:{}M".format(self.params["start_freq"],
self.params["stop_freq"]),
"-B", "{}k".format(self.params["bin_size"]),
"-T", "{}".format(self.params["interval"]),
"-d", "{}".format(self.params["device"]),
"-r", "{}".format(self.params["sample_rate"]),
"-p", "{}".format(self.params["ppm"]),
"-F", "soapy_power_bin",
"--output-fd", "{}".format(
int(self.pipe_write_handle) if sys.platform == 'win32' else self.pipe_write_fd
),
])
if self.lnb_lo != 0:
cmdline.extend(["--lnb-lo", "{}".format(self.lnb_lo)])
if self.params["bandwidth"] > 0:
cmdline.extend(["-w", "{}".format(self.params["bandwidth"])])
if self.params["gain"] >= 0:
cmdline.extend(["-g", "{}".format(self.params["gain"])])
if self.params["crop"] > 0:
cmdline.extend(["-k", "{}".format(self.params["crop"])])
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))
# Start soapy_power process and close write part of pipe
if sys.platform == 'win32':
creationflags = subprocess.CREATE_NEW_PROCESS_GROUP
else:
creationflags = 0
print('Starting backend:')
print(' '.join(cmdline))
print()
self.process = subprocess.Popen(cmdline, close_fds=False, universal_newlines=False,
creationflags=creationflags, console=False)
os.close(self.pipe_write_fd)
if sys.platform == 'win32':
self.pipe_write_handle.Close()
def process_stop(self):
"""Stop soapy_power process"""
with self._shutdown_lock:
if self.process:
if self.process.poll() is None:
try:
if sys.platform == 'win32':
self.process.send_signal(signal.CTRL_BREAK_EVENT)
else:
self.process.terminate()
except ProcessLookupError:
pass
self.process.wait()
self.process = None
# Close pipe used for communication with soapy_power process
self.pipe_read.close()
self.pipe_read = None
self.pipe_read_fd = None
self.pipe_write_fd = None
self.pipe_write_handle = None
def parse_output(self, data):
"""Parse data from soapy_power"""
header, y_axis = data
time_start = header.time_start
time_stop = header.time_stop
start_freq = header.start
stop_freq = header.stop
step = header.step
samples = header.samples
x_axis = np.linspace(start_freq, stop_freq, round((stop_freq - start_freq) / step))
if len(x_axis) != len(y_axis):
print("ERROR: len(x_axis) != len(y_axis)")
return
if self.min_freq is None:
self.min_freq = start_freq
if start_freq == self.min_freq:
self.databuffer = {"timestamp": time_stop,
"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)
def run(self):
"""soapy_power thread main loop"""
if not formatter:
return
self.process_start()
self.alive = True
self.powerThreadStarted.emit()
while self.alive:
try:
data = formatter.read(self.pipe_read)
except ValueError as e:
print(e, file=sys.stderr)
continue
if data:
self.parse_output(data)
else:
break
self.process_stop()
self.alive = False
self.powerThreadStopped.emit()
def read_from_file(f):
"""Generator for reading data from soapy_power binary files"""
if not formatter:
return
min_freq = None
databuffer = None
while True:
try:
data = formatter.read(f)
except ValueError as e:
print(e, file=sys.stderr)
continue
if not data:
if min_freq is not None:
yield databuffer
return
header, y_axis = data
x_axis = np.linspace(header.start, header.stop, round((header.stop - header.start) / header.step))
if len(x_axis) != len(y_axis):
print("ERROR: len(x_axis) != len(y_axis)")
continue
if min_freq is None:
min_freq = header.start
elif header.start == min_freq:
yield databuffer
if header.start == min_freq:
databuffer = {"timestamp": header.time_stop,
"x": list(x_axis),
"y": list(y_axis)}
else:
databuffer["x"].extend(x_axis)
databuffer["y"].extend(y_axis)

View File

@ -1,28 +0,0 @@
from Qt import QtCore, QtWidgets
from qspectrumanalyzer.ui_qspectrumanalyzer_baseline import Ui_QSpectrumAnalyzerBaseline
class QSpectrumAnalyzerBaseline(QtWidgets.QDialog, Ui_QSpectrumAnalyzerBaseline):
"""QSpectrumAnalyzer baseline dialog"""
def __init__(self, parent=None):
# Initialize UI
super().__init__(parent)
self.setupUi(self)
# Load settings
settings = QtCore.QSettings()
self.baselineFileEdit.setText(settings.value("baseline_file", ""))
@QtCore.Slot()
def on_baselineFileButton_clicked(self):
"""Open file dialog when button is clicked"""
filename = QtWidgets.QFileDialog.getOpenFileName(self, self.tr("Select baseline file - QSpectrumAnalyzer"))[0]
if filename:
self.baselineFileEdit.setText(filename)
def accept(self):
"""Save settings when dialog is accepted"""
settings = QtCore.QSettings()
settings.setValue("baseline_file", self.baselineFileEdit.text())
QtWidgets.QDialog.accept(self)

View File

@ -1,33 +0,0 @@
from Qt import QtCore, QtWidgets
from qspectrumanalyzer.utils import color_to_str, str_to_color
from qspectrumanalyzer.ui_qspectrumanalyzer_colors import Ui_QSpectrumAnalyzerColors
class QSpectrumAnalyzerColors(QtWidgets.QDialog, Ui_QSpectrumAnalyzerColors):
"""QSpectrumAnalyzer colors dialog"""
def __init__(self, parent=None):
# Initialize UI
super().__init__(parent)
self.setupUi(self)
# Load settings
settings = QtCore.QSettings()
self.mainColorButton.setColor(str_to_color(settings.value("main_color", "255, 255, 0, 255")))
self.peakHoldMaxColorButton.setColor(str_to_color(settings.value("peak_hold_max_color", "255, 0, 0, 255")))
self.peakHoldMinColorButton.setColor(str_to_color(settings.value("peak_hold_min_color", "0, 0, 255, 255")))
self.averageColorButton.setColor(str_to_color(settings.value("average_color", "0, 255, 255, 255")))
self.persistenceColorButton.setColor(str_to_color(settings.value("persistence_color", "0, 255, 0, 255")))
self.baselineColorButton.setColor(str_to_color(settings.value("baseline_color", "255, 0, 255, 255")))
def accept(self):
"""Save settings when dialog is accepted"""
settings = QtCore.QSettings()
settings.setValue("main_color", color_to_str(self.mainColorButton.color()))
settings.setValue("peak_hold_max_color", color_to_str(self.peakHoldMaxColorButton.color()))
settings.setValue("peak_hold_min_color", color_to_str(self.peakHoldMinColorButton.color()))
settings.setValue("average_color", color_to_str(self.averageColorButton.color()))
settings.setValue("persistence_color", color_to_str(self.persistenceColorButton.color()))
settings.setValue("baseline_color", color_to_str(self.baselineColorButton.color()))
QtWidgets.QDialog.accept(self)

View File

@ -1,10 +1,9 @@
import time, sys, os
import time, sys
from Qt import QtCore
from PyQt4 import QtCore
import numpy as np
from qspectrumanalyzer.utils import smooth
from qspectrumanalyzer.backends import soapy_power
class HistoryBuffer:
@ -37,7 +36,7 @@ class HistoryBuffer:
class TaskSignals(QtCore.QObject):
"""Task signals emitter"""
result = QtCore.Signal(object)
result = QtCore.pyqtSignal(object)
class Task(QtCore.QRunnable):
@ -58,14 +57,12 @@ class Task(QtCore.QRunnable):
class DataStorage(QtCore.QObject):
"""Data storage for spectrum measurements"""
history_updated = QtCore.Signal(object)
data_updated = QtCore.Signal(object)
history_recalculated = QtCore.Signal(object)
data_recalculated = QtCore.Signal(object)
average_updated = QtCore.Signal(object)
baseline_updated = QtCore.Signal(object)
peak_hold_max_updated = QtCore.Signal(object)
peak_hold_min_updated = QtCore.Signal(object)
history_updated = QtCore.pyqtSignal(object)
data_updated = QtCore.pyqtSignal(object)
data_recalculated = QtCore.pyqtSignal(object)
average_updated = QtCore.pyqtSignal(object)
peak_hold_max_updated = QtCore.pyqtSignal(object)
peak_hold_min_updated = QtCore.pyqtSignal(object)
def __init__(self, max_history_size=100, parent=None):
super().__init__(parent)
@ -73,10 +70,6 @@ class DataStorage(QtCore.QObject):
self.smooth = False
self.smooth_length = 11
self.smooth_window = "hanning"
self.subtract_baseline = False
self.prev_baseline = None
self.baseline = None
self.baseline_x = None
# Use only one worker thread because it is not faster
# with more threads (and memory consumption is much higher)
@ -112,20 +105,11 @@ class DataStorage(QtCore.QObject):
def update(self, data):
"""Update data storage"""
if self.y is not None and len(data["y"]) != len(self.y):
print("{:d} bins coming from backend, expected {:d}".format(len(data["y"]), len(self.y)))
return
self.average_counter += 1
if self.x is None:
self.x = data["x"]
# Subtract baseline from data
data["y"] = np.asarray(data["y"])
if self.subtract_baseline and self.baseline is not None and len(data["y"]) == len(self.baseline):
data["y"] -= self.baseline
self.start_task(self.update_history, data.copy())
self.start_task(self.update_data, data)
@ -177,63 +161,16 @@ class DataStorage(QtCore.QObject):
"""Apply smoothing function to data"""
return smooth(y, window_len=self.smooth_length, window=self.smooth_window)
def set_smooth(self, toggle, length=11, window="hanning"):
def set_smooth(self, toggle, length=11, window="hanning", recalculate=False):
"""Toggle smoothing and set smoothing params"""
if toggle != self.smooth or length != self.smooth_length or window != self.smooth_window:
self.smooth = toggle
self.smooth_length = length
self.smooth_window = window
self.start_task(self.recalculate_data)
def set_subtract_baseline(self, toggle, baseline_file=None):
"""Toggle baseline subtraction and set baseline"""
baseline = None
baseline_x = None
# Load baseline from file (compute average if there are multiple PSD data in file)
if baseline_file and os.path.isfile(baseline_file):
average_counter = 0
with open(baseline_file, 'rb') as f:
for data in soapy_power.read_from_file(f):
average_counter += 1
if baseline is None:
baseline = data['y'].copy()
baseline_x = data['x'].copy()
else:
baseline = np.average((baseline, data['y']), axis=0, weights=(average_counter - 1, 1))
# Don't subtract baseline if number of bins in baseline differs from number of bins in data
if self.y is not None and baseline is not None and len(self.y) != len(baseline):
print("Can't subtract baseline (expected {:d} bins, but baseline has {:d} bins)".format(
len(self.y), len(baseline)
))
#baseline = None
if self.subtract_baseline:
self.prev_baseline = self.baseline
#if not np.array_equal(baseline, self.baseline):
self.baseline = baseline
self.baseline_x = baseline_x
self.baseline_updated.emit(self)
self.subtract_baseline = toggle
self.start_task(self.recalculate_history)
self.start_task(self.recalculate_data)
def recalculate_history(self):
"""Recalculate spectrum measurements history"""
if self.history is None:
return
history = self.history.get_buffer()
if self.prev_baseline is not None and len(history[-1]) == len(self.prev_baseline):
history += self.prev_baseline
self.prev_baseline = None
if self.subtract_baseline and self.baseline is not None and len(history[-1]) == len(self.baseline):
history -= self.baseline
self.history_recalculated.emit(self)
if recalculate:
self.start_task(self.recalculate_data)
else:
self.reset_data()
def recalculate_data(self):
"""Recalculate current data from history"""

View File

@ -1,288 +1,250 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS><TS version="2.0">
<context>
<name>QSpectrumAnalyzerBaseline</name>
<message>
<location filename="../baseline.py" line="20"/>
<source>Select baseline file - QSpectrumAnalyzer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_baseline.py" line="50"/>
<source>Baseline - QSpectrumAnalyzer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_baseline.py" line="51"/>
<source>Baseline &amp;file:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_baseline.py" line="52"/>
<source>...</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QSpectrumAnalyzerColors</name>
<message>
<location filename="../ui_qspectrumanalyzer_colors.py" line="112"/>
<location filename="../ui_qspectrumanalyzer_colors.py" line="113"/>
<source>Colors - QSpectrumAnalyzer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_colors.py" line="124"/>
<source>...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_colors.py" line="113"/>
<source>&amp;Main curve color:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_colors.py" line="115"/>
<source>Max. peak &amp;hold color:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_colors.py" line="117"/>
<source>M&amp;in. peak hold color:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_colors.py" line="119"/>
<source>Average &amp;color:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_colors.py" line="121"/>
<source>Persistence co&amp;lor:</source>
<location filename="../ui_qspectrumanalyzer_colors.py" line="114"/>
<source>Main curve color:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_colors.py" line="123"/>
<source>&amp;Baseline color:</source>
<source>...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_colors.py" line="120"/>
<source>Average color:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_colors.py" line="122"/>
<source>Persistence color:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_colors.py" line="116"/>
<source>Max. peak hold color:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_colors.py" line="118"/>
<source>Min. peak hold color:</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QSpectrumAnalyzerMainWindow</name>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="317"/>
<location filename="../ui_qspectrumanalyzer.py" line="311"/>
<source>QSpectrumAnalyzer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../__main__.py" line="496"/>
<source>About - QSpectrumAnalyzer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../__main__.py" line="496"/>
<source>QSpectrumAnalyzer {}</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="318"/>
<source>&amp;File</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="319"/>
<source>&amp;Help</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="350"/>
<source>&amp;Settings...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="351"/>
<source>&amp;Quit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="352"/>
<source>Ctrl+Q</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="353"/>
<source>&amp;About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../__main__.py" line="253"/>
<source>Frequency hops: {}</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../__main__.py" line="255"/>
<source>Total time: {} | Sweep time: {:.2f} s ({:.2f} FPS)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="321"/>
<source>&amp;Start</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="322"/>
<source>S&amp;top</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="323"/>
<source>Si&amp;ngle shot</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="325"/>
<source>Start:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="328"/>
<source> MHz</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="327"/>
<source>Stop:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="329"/>
<source>&amp;Bin size:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="330"/>
<source> kHz</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="332"/>
<source>&amp;Interval [s]:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="333"/>
<source>&amp;Gain [dB]:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="334"/>
<source>Corr. [ppm]:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="335"/>
<source>Crop [%]:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="336"/>
<source>Main curve</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="337"/>
<source>Colors...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="338"/>
<source>Max. hold</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="339"/>
<source>Min. hold</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="340"/>
<source>Average</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="341"/>
<source>Smoothing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="347"/>
<source>...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="343"/>
<source>Persistence</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="345"/>
<source>auto</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="348"/>
<source>Subtract baseline</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="346"/>
<source>Baseline</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="320"/>
<source>Controls</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="324"/>
<source>Frequency</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="331"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="349"/>
<location filename="../ui_qspectrumanalyzer.py" line="322"/>
<source> MHz</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="324"/>
<source> kHz</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="328"/>
<source>auto</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="318"/>
<source>Frequency</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="314"/>
<source>Controls</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="340"/>
<source>Levels</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../__main__.py" line="337"/>
<source>Frequency hops: {} | Sweep time: {:.2f} s | FPS: {:.2f}</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../__main__.py" line="337"/>
<source>N/A</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../__main__.py" line="504"/>
<source>About - QSpectrumAnalyzer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../__main__.py" line="504"/>
<source>QSpectrumAnalyzer {}</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="312"/>
<source>&amp;File</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="313"/>
<source>&amp;Help</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="315"/>
<source>&amp;Start</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="316"/>
<source>S&amp;top</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="317"/>
<source>Si&amp;ngle shot</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="319"/>
<source>Start:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="321"/>
<source>Stop:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="323"/>
<source>Bin size:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="326"/>
<source>Interval [s]:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="327"/>
<source>Gain [dB]:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="329"/>
<source>Corr. [ppm]:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="330"/>
<source>Crop [%]:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="331"/>
<source>Main curve</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="332"/>
<source>Colors...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="333"/>
<source>Max. hold</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="334"/>
<source>Min. hold</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="335"/>
<source>Average</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="336"/>
<source>Smoothing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="339"/>
<source>...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="338"/>
<source>Persistence</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="341"/>
<source>&amp;Settings...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="342"/>
<source>&amp;Quit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="343"/>
<source>Ctrl+Q</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer.py" line="344"/>
<source>&amp;About</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QSpectrumAnalyzerPersistence</name>
<message>
<location filename="../ui_qspectrumanalyzer_persistence.py" line="55"/>
<location filename="../ui_qspectrumanalyzer_persistence.py" line="68"/>
<source>Persistence - QSpectrumAnalyzer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_persistence.py" line="56"/>
<location filename="../ui_qspectrumanalyzer_persistence.py" line="69"/>
<source>Decay function:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_persistence.py" line="57"/>
<location filename="../ui_qspectrumanalyzer_persistence.py" line="70"/>
<source>linear</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_persistence.py" line="58"/>
<location filename="../ui_qspectrumanalyzer_persistence.py" line="71"/>
<source>exponential</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_persistence.py" line="59"/>
<location filename="../ui_qspectrumanalyzer_persistence.py" line="72"/>
<source>Persistence length:</source>
<translation type="unfinished"></translation>
</message>
@ -290,148 +252,110 @@
<context>
<name>QSpectrumAnalyzerSettings</name>
<message>
<location filename="../settings.py" line="57"/>
<location filename="../__main__.py" line="50"/>
<source>Select executable - QSpectrumAnalyzer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="148"/>
<location filename="../ui_qspectrumanalyzer_settings.py" line="107"/>
<source>Settings - QSpectrumAnalyzer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="149"/>
<location filename="../ui_qspectrumanalyzer_settings.py" line="108"/>
<source>&amp;Backend:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="156"/>
<location filename="../ui_qspectrumanalyzer_settings.py" line="115"/>
<source>soapy_power</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="151"/>
<location filename="../ui_qspectrumanalyzer_settings.py" line="110"/>
<source>rx_power</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="152"/>
<location filename="../ui_qspectrumanalyzer_settings.py" line="111"/>
<source>rtl_power_fftw</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="153"/>
<location filename="../ui_qspectrumanalyzer_settings.py" line="112"/>
<source>rtl_power</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="154"/>
<location filename="../ui_qspectrumanalyzer_settings.py" line="113"/>
<source>hackrf_sweep</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="155"/>
<location filename="../ui_qspectrumanalyzer_settings.py" line="114"/>
<source>E&amp;xecutable:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="157"/>
<location filename="../ui_qspectrumanalyzer_settings.py" line="116"/>
<source>...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="159"/>
<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"/>
<source>Sa&amp;mple rate:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="160"/>
<location filename="../ui_qspectrumanalyzer_settings.py" line="119"/>
<source>&amp;Waterfall history size:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="158"/>
<source>&amp;Device:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="161"/>
<source>Bandwidt&amp;h:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="163"/>
<source>&amp;LNB LO:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="166"/>
<source> ? </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="169"/>
<source>Negative frequency for upconverters, positive frequency for downconverters.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="164"/>
<source>Add&amp;itional parameters:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_settings.py" line="170"/>
<source> MHz</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QSpectrumAnalyzerSettingsHelp</name>
<name>QSpectrumAnalyzerSmooth</name>
<message>
<location filename="../ui_qspectrumanalyzer_settings_help.py" line="36"/>
<source>Help - QSpectrumAnalyzer</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QSpectrumAnalyzerSmoothing</name>
<message>
<location filename="../ui_qspectrumanalyzer_smoothing.py" line="60"/>
<location filename="../ui_qspectrumanalyzer_smooth.py" line="73"/>
<source>Smoothing - QSpectrumAnalyzer</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_smoothing.py" line="61"/>
<location filename="../ui_qspectrumanalyzer_smooth.py" line="74"/>
<source>&amp;Window function:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_smoothing.py" line="62"/>
<location filename="../ui_qspectrumanalyzer_smooth.py" line="75"/>
<source>rectangular</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_smoothing.py" line="63"/>
<location filename="../ui_qspectrumanalyzer_smooth.py" line="76"/>
<source>hanning</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_smoothing.py" line="64"/>
<location filename="../ui_qspectrumanalyzer_smooth.py" line="77"/>
<source>hamming</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_smoothing.py" line="65"/>
<location filename="../ui_qspectrumanalyzer_smooth.py" line="78"/>
<source>bartlett</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_smoothing.py" line="66"/>
<location filename="../ui_qspectrumanalyzer_smooth.py" line="79"/>
<source>blackman</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui_qspectrumanalyzer_smoothing.py" line="67"/>
<location filename="../ui_qspectrumanalyzer_smooth.py" line="80"/>
<source>Window len&amp;gth:</source>
<translation type="unfinished"></translation>
</message>

View File

@ -1,29 +0,0 @@
from Qt import QtCore, QtWidgets
from qspectrumanalyzer.ui_qspectrumanalyzer_persistence import Ui_QSpectrumAnalyzerPersistence
class QSpectrumAnalyzerPersistence(QtWidgets.QDialog, Ui_QSpectrumAnalyzerPersistence):
"""QSpectrumAnalyzer spectrum persistence dialog"""
def __init__(self, parent=None):
# Initialize UI
super().__init__(parent)
self.setupUi(self)
# Load settings
settings = QtCore.QSettings()
self.persistenceLengthSpinBox.setValue(settings.value("persistence_length", 5, int))
decay_function = settings.value("persistence_decay", "exponential")
i = self.decayFunctionComboBox.findText(decay_function)
if i == -1:
self.decayFunctionComboBox.setCurrentIndex(0)
else:
self.decayFunctionComboBox.setCurrentIndex(i)
def accept(self):
"""Save settings when dialog is accepted"""
settings = QtCore.QSettings()
settings.setValue("persistence_length", self.persistenceLengthSpinBox.value())
settings.setValue("persistence_decay", self.decayFunctionComboBox.currentText())
QtWidgets.QDialog.accept(self)

View File

@ -1,6 +1,6 @@
import collections, math
from Qt import QtCore
from PyQt4 import QtCore
import pyqtgraph as pg
# Basic PyQtGraph settings
@ -29,8 +29,6 @@ class SpectrumPlotWidget:
self.peak_hold_min_color = pg.mkColor("b")
self.average = False
self.average_color = pg.mkColor("c")
self.baseline = False
self.baseline_color = pg.mkColor("m")
self.create_plot()
@ -44,10 +42,6 @@ class SpectrumPlotWidget:
self.plot.setLimits(xMin=0)
self.plot.showButtons()
#self.plot.setDownsampling(mode="peak")
#self.plot.setClipToView(True)
self.create_baseline_curve()
self.create_persistence_curves()
self.create_average_curve()
self.create_peak_hold_min_curve()
@ -84,11 +78,6 @@ class SpectrumPlotWidget:
self.curve_average = self.plot.plot(pen=self.average_color)
self.curve_average.setZValue(700)
def create_baseline_curve(self):
"""Create baseline curve"""
self.curve_baseline = self.plot.plot(pen=self.baseline_color)
self.curve_baseline.setZValue(500)
def create_persistence_curves(self):
"""Create spectrum persistence curves"""
z_index_base = 600
@ -107,7 +96,6 @@ class SpectrumPlotWidget:
self.curve_peak_hold_max.setPen(self.peak_hold_max_color)
self.curve_peak_hold_min.setPen(self.peak_hold_min_color)
self.curve_average.setPen(self.average_color)
self.curve_baseline.setPen(self.baseline_color)
decay = self.get_decay()
for i, curve in enumerate(self.persistence_curves):
@ -170,17 +158,6 @@ class SpectrumPlotWidget:
if force:
self.curve_average.setVisible(self.average)
def update_baseline(self, data_storage, force=False):
"""Update baseline curve"""
if data_storage.baseline_x is None or data_storage.baseline is None:
self.curve_baseline.clear()
return
if self.baseline or force:
self.curve_baseline.setData(data_storage.baseline_x, data_storage.baseline)
if force:
self.curve_baseline.setVisible(self.baseline)
def update_persistence(self, data_storage, force=False):
"""Update persistence curves"""
if data_storage.x is None:
@ -204,7 +181,6 @@ class SpectrumPlotWidget:
QtCore.QTimer.singleShot(0, lambda: self.update_plot(data_storage, force=True))
QtCore.QTimer.singleShot(0, lambda: self.update_average(data_storage, force=True))
QtCore.QTimer.singleShot(0, lambda: self.update_baseline(data_storage, force=True))
QtCore.QTimer.singleShot(0, lambda: self.update_peak_hold_max(data_storage, force=True))
QtCore.QTimer.singleShot(0, lambda: self.update_peak_hold_min(data_storage, force=True))
@ -252,10 +228,6 @@ class SpectrumPlotWidget:
"""Clear average curve"""
self.curve_average.clear()
def clear_baseline(self):
"""Clear baseline curve"""
self.curve_baseline.clear()
def clear_persistence(self):
"""Clear spectrum persistence curves"""
self.persistence_data = None
@ -292,7 +264,6 @@ 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)
@ -333,16 +304,3 @@ class WaterfallPlotWidget:
def clear_plot(self):
"""Clear waterfall plot"""
self.counter = 0
def recalculate_plot(self, data_storage):
"""Recalculate waterfall plot"""
if data_storage.x is None:
return
self.waterfallImg.setImage(data_storage.history.buffer[-self.counter:].T,
autoLevels=False, autoRange=False)
self.waterfallImg.setPos(
data_storage.x[0],
-self.counter if self.counter < self.history_size else -self.history_size
)
self.histogram.setImageItem(self.waterfallImg)

View File

@ -1,133 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
id="svg4290"
version="1.1"
inkscape:version="0.91 r13725"
viewBox="0 0 32 32"
inkscape:export-filename="qspectrumanalyzer.png"
inkscape:export-xdpi="135"
inkscape:export-ydpi="135"
sodipodi:docname="qspectrumanalyzer.svg">
<defs
id="defs4292" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6568543"
inkscape:cx="0.51171273"
inkscape:cy="17.429759"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:snap-intersection-paths="true"
inkscape:snap-bbox="false"
inkscape:snap-nodes="true"
inkscape:object-nodes="true"
inkscape:snap-global="false"
inkscape:window-width="1366"
inkscape:window-height="709"
inkscape:window-x="-4"
inkscape:window-y="0"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid4298" />
</sodipodi:namedview>
<metadata
id="metadata4295">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<rect
style="fill:#000000;stroke:#666666;stroke-opacity:1"
id="rect4300"
width="30"
height="30"
x="1"
y="1"
rx="3"
ry="3" />
<path
style="fill:none;fill-rule:evenodd;stroke:#666666;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 16,1 0,30"
id="path4302"
inkscape:connector-curvature="0" />
<path
style="fill:none;fill-rule:evenodd;stroke:#666666;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 31,16 1,16"
id="path4302-5"
inkscape:connector-curvature="0" />
<use
x="0"
y="0"
xlink:href="#path4302"
id="use4369"
transform="translate(-7.5,0)"
width="100%"
height="100%" />
<use
x="0"
y="0"
xlink:href="#path4302"
id="use4371"
transform="translate(7.5,0)"
width="100%"
height="100%" />
<path
inkscape:connector-curvature="0"
id="path4373"
d="M 31,8.5 1,8.5"
style="fill:none;fill-rule:evenodd;stroke:#666666;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<use
x="0"
y="0"
xlink:href="#path4302-5"
id="use4375"
transform="translate(0,7.5)"
width="100%"
height="100%" />
<path
style="fill:none;fill-rule:evenodd;stroke:#00ff00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 1.0625,25.25 c 0,0 2.5545099,5.432144 4.3470654,0.903939 0.6415968,-1.620748 1.1843693,-10.505075 2.3294368,-10.451145 1.124605,0.05297 1.2928473,9.79388 3.0231028,11.399454 0.836834,0.735662 2.019611,-2.789575 2.96484,-2.691821 1.178304,0.121857 2.125956,3.657855 3.181223,2.383073 2.07617,-2.508052 1.527752,-21.6078848 2.588897,-21.5746877 1.200441,0.037555 1.333727,19.4989257 3.765313,21.7522057 1.533625,1.421166 1.791478,-2.106359 3.115303,-2.461012 0.660576,-0.176968 2.034012,3.420657 2.702589,3.52241 0.772278,0.117536 1.624099,-1.153766 2.01348,-0.813666"
id="path4394"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csscssssssc" />
<rect
style="fill:none;stroke:#666666;stroke-opacity:1"
id="rect4300-8"
width="30"
height="30"
x="1"
y="1"
rx="3"
ry="3" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>1200</width>
<height>892</height>
<height>810</height>
</rect>
</property>
<property name="windowTitle">
@ -52,7 +52,7 @@
<x>0</x>
<y>0</y>
<width>1200</width>
<height>32</height>
<height>30</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
@ -82,8 +82,8 @@
</property>
<property name="minimumSize">
<size>
<width>190</width>
<height>130</height>
<width>10</width>
<height>10</height>
</size>
</property>
<property name="features">
@ -143,8 +143,8 @@
</property>
<property name="minimumSize">
<size>
<width>208</width>
<height>166</height>
<width>10</width>
<height>10</height>
</size>
</property>
<property name="features">
@ -182,9 +182,6 @@
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="showGroupSeparator" stdset="0">
<bool>true</bool>
</property>
<property name="suffix">
<string> MHz</string>
</property>
@ -192,10 +189,10 @@
<number>3</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
<double>24.000000000000000</double>
</property>
<property name="maximum">
<double>2200.000000000000000</double>
<double>1766.000000000000000</double>
</property>
<property name="value">
<double>87.000000000000000</double>
@ -223,9 +220,6 @@
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="showGroupSeparator" stdset="0">
<bool>true</bool>
</property>
<property name="suffix">
<string> MHz</string>
</property>
@ -233,10 +227,10 @@
<number>3</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
<double>24.000000000000000</double>
</property>
<property name="maximum">
<double>2200.000000000000000</double>
<double>1766.000000000000000</double>
</property>
<property name="value">
<double>108.000000000000000</double>
@ -246,7 +240,7 @@
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Bin size:</string>
<string>Bin size:</string>
</property>
<property name="buddy">
<cstring>binSizeSpinBox</cstring>
@ -264,20 +258,14 @@
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="showGroupSeparator" stdset="0">
<bool>true</bool>
</property>
<property name="suffix">
<string> kHz</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>10000.000000000000000</double>
<double>2800.000000000000000</double>
</property>
<property name="value">
<double>10.000000000000000</double>
@ -321,7 +309,7 @@
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>&amp;Interval [s]:</string>
<string>Interval [s]:</string>
</property>
<property name="buddy">
<cstring>intervalSpinBox</cstring>
@ -331,7 +319,7 @@
<item row="0" column="1">
<widget class="QLabel" name="label_6">
<property name="text">
<string>&amp;Gain [dB]:</string>
<string>Gain [dB]:</string>
</property>
<property name="buddy">
<cstring>gainSpinBox</cstring>
@ -351,6 +339,25 @@
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QSpinBox" name="gainSpinBox">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="specialValueText">
<string>auto</string>
</property>
<property name="minimum">
<number>-1</number>
</property>
<property name="maximum">
<number>49</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
@ -456,7 +463,7 @@
</property>
</widget>
</item>
<item row="11" column="0">
<item row="9" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -476,55 +483,6 @@
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QDoubleSpinBox" name="gainSpinBox">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="specialValueText">
<string>auto</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>-1.000000000000000</double>
</property>
<property name="maximum">
<double>999.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>-1.000000000000000</double>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="baselineCheckBox">
<property name="text">
<string>Baseline</string>
</property>
</widget>
</item>
<item row="9" column="2">
<widget class="QToolButton" name="baselineButton">
<property name="text">
<string>...</string>
</property>
<property name="autoRaise">
<bool>false</bool>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QCheckBox" name="subtractBaselineCheckBox">
<property name="text">
<string>Subtract baseline</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
@ -605,9 +563,6 @@
<tabstop>smoothButton</tabstop>
<tabstop>persistenceCheckBox</tabstop>
<tabstop>persistenceButton</tabstop>
<tabstop>baselineCheckBox</tabstop>
<tabstop>baselineButton</tabstop>
<tabstop>subtractBaselineCheckBox</tabstop>
<tabstop>histogramPlotLayout</tabstop>
<tabstop>mainPlotLayout</tabstop>
<tabstop>waterfallPlotLayout</tabstop>

View File

@ -1,115 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QSpectrumAnalyzerBaseline</class>
<widget class="QDialog" name="QSpectrumAnalyzerBaseline">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>100</height>
</rect>
</property>
<property name="windowTitle">
<string>Baseline - QSpectrumAnalyzer</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Baseline &amp;file:</string>
</property>
<property name="buddy">
<cstring>baselineFileEdit</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="baselineFileEdit"/>
</item>
<item>
<widget class="QToolButton" name="baselineFileButton">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>baselineFileEdit</tabstop>
<tabstop>baselineFileButton</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QSpectrumAnalyzerBaseline</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>224</x>
<y>72</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>99</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QSpectrumAnalyzerBaseline</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>292</x>
<y>78</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>99</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>253</width>
<height>266</height>
<width>232</width>
<height>260</height>
</rect>
</property>
<property name="windowTitle">
@ -19,7 +19,7 @@
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&amp;Main curve color:</string>
<string>Main curve color:</string>
</property>
<property name="buddy">
<cstring>mainColorButton</cstring>
@ -42,7 +42,7 @@
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Max. peak &amp;hold color:</string>
<string>Max. peak hold color:</string>
</property>
<property name="buddy">
<cstring>peakHoldMaxColorButton</cstring>
@ -65,7 +65,7 @@
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>M&amp;in. peak hold color:</string>
<string>Min. peak hold color:</string>
</property>
<property name="buddy">
<cstring>peakHoldMinColorButton</cstring>
@ -88,7 +88,7 @@
<item row="3" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Average &amp;color:</string>
<string>Average color:</string>
</property>
<property name="buddy">
<cstring>averageColorButton</cstring>
@ -111,7 +111,7 @@
<item row="4" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Persistence co&amp;lor:</string>
<string>Persistence color:</string>
</property>
<property name="buddy">
<cstring>persistenceColorButton</cstring>
@ -131,29 +131,6 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Baseline color:</string>
</property>
<property name="buddy">
<cstring>baselineColorButton</cstring>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="ColorButton" name="baselineColorButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
@ -194,7 +171,7 @@
<tabstop>peakHoldMinColorButton</tabstop>
<tabstop>averageColorButton</tabstop>
<tabstop>persistenceColorButton</tabstop>
<tabstop>baselineColorButton</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
@ -205,12 +182,12 @@
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>246</x>
<y>259</y>
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>265</y>
<y>274</y>
</hint>
</hints>
</connection>
@ -221,12 +198,12 @@
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>246</x>
<y>259</y>
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>252</x>
<y>265</y>
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>388</height>
<width>420</width>
<height>255</height>
</rect>
</property>
<property name="windowTitle">
@ -76,12 +76,6 @@
</item>
<item>
<widget class="QToolButton" name="executableButton">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
@ -89,17 +83,20 @@
</item>
</layout>
</item>
<item row="3" column="0">
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>&amp;Device:</string>
<string>Device:</string>
</property>
<property name="buddy">
<cstring>deviceEdit</cstring>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="2" column="1">
<widget class="QLineEdit" name="deviceEdit"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Sa&amp;mple rate:</string>
@ -109,7 +106,23 @@
</property>
</widget>
</item>
<item row="7" column="0">
<item row="3" column="1">
<widget class="QSpinBox" name="sampleRateSpinBox">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>25000000</number>
</property>
<property name="singleStep">
<number>10000</number>
</property>
<property name="value">
<number>2560000</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&amp;Waterfall history size:</string>
@ -119,7 +132,7 @@
</property>
</widget>
</item>
<item row="7" column="1">
<item row="4" column="1">
<widget class="QSpinBox" name="waterfallHistorySizeSpinBox">
<property name="minimum">
<number>1</number>
@ -132,157 +145,6 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Bandwidt&amp;h:</string>
</property>
<property name="buddy">
<cstring>bandwidthSpinBox</cstring>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_8">
<property name="toolTip">
<string>Negative frequency for upconverters, positive frequency for downconverters.</string>
</property>
<property name="text">
<string>&amp;LNB LO:</string>
</property>
<property name="buddy">
<cstring>lnbSpinBox</cstring>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Add&amp;itional parameters:</string>
</property>
<property name="buddy">
<cstring>paramsEdit</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="paramsEdit"/>
</item>
<item>
<widget class="QToolButton" name="paramsHelpButton">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string> ? </string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="deviceEdit"/>
</item>
<item>
<widget class="QToolButton" name="deviceHelpButton">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string> ? </string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="1">
<widget class="QDoubleSpinBox" name="sampleRateSpinBox">
<property name="showGroupSeparator" stdset="0">
<bool>true</bool>
</property>
<property name="suffix">
<string> MHz</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>999999.989999999990687</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>61.439999999999998</double>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QDoubleSpinBox" name="bandwidthSpinBox">
<property name="showGroupSeparator" stdset="0">
<bool>true</bool>
</property>
<property name="suffix">
<string> MHz</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>999999.989999999990687</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QDoubleSpinBox" name="lnbSpinBox">
<property name="toolTip">
<string>Negative frequency for upconverters, positive frequency for downconverters.</string>
</property>
<property name="showGroupSeparator" stdset="0">
<bool>true</bool>
</property>
<property name="suffix">
<string> MHz</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>-999999.998999999952503</double>
</property>
<property name="maximum">
<double>999999.998999999952503</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
@ -314,14 +176,10 @@
<tabstop>backendComboBox</tabstop>
<tabstop>executableEdit</tabstop>
<tabstop>executableButton</tabstop>
<tabstop>paramsEdit</tabstop>
<tabstop>paramsHelpButton</tabstop>
<tabstop>deviceEdit</tabstop>
<tabstop>deviceHelpButton</tabstop>
<tabstop>sampleRateSpinBox</tabstop>
<tabstop>bandwidthSpinBox</tabstop>
<tabstop>lnbSpinBox</tabstop>
<tabstop>waterfallHistorySizeSpinBox</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
@ -332,8 +190,8 @@
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>254</x>
<y>377</y>
<x>242</x>
<y>248</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
@ -348,8 +206,8 @@
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>322</x>
<y>377</y>
<x>310</x>
<y>248</y>
</hint>
<hint type="destinationlabel">
<x>286</x>

View File

@ -1,78 +0,0 @@
<?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>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QSpectrumAnalyzerSmoothing</class>
<widget class="QDialog" name="QSpectrumAnalyzerSmoothing">
<class>QSpectrumAnalyzerSmooth</class>
<widget class="QDialog" name="QSpectrumAnalyzerSmooth">
<property name="geometry">
<rect>
<x>0</x>
@ -118,7 +118,7 @@
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QSpectrumAnalyzerSmoothing</receiver>
<receiver>QSpectrumAnalyzerSmooth</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
@ -134,7 +134,7 @@
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QSpectrumAnalyzerSmoothing</receiver>
<receiver>QSpectrumAnalyzerSmooth</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">

View File

@ -1,139 +0,0 @@
from Qt import QtCore, QtGui, QtWidgets
from qspectrumanalyzer import backends
from qspectrumanalyzer.ui_qspectrumanalyzer_settings import Ui_QSpectrumAnalyzerSettings
from qspectrumanalyzer.ui_qspectrumanalyzer_settings_help import Ui_QSpectrumAnalyzerSettingsHelp
class QSpectrumAnalyzerSettings(QtWidgets.QDialog, Ui_QSpectrumAnalyzerSettings):
"""QSpectrumAnalyzer settings dialog"""
def __init__(self, parent=None):
# Initialize UI
super().__init__(parent)
self.setupUi(self)
self.params_help_dialog = None
self.device_help_dialog = None
# Load settings
settings = QtCore.QSettings()
self.executableEdit.setText(settings.value("executable", "soapy_power"))
self.deviceEdit.setText(settings.value("device", ""))
self.lnbSpinBox.setValue(settings.value("lnb_lo", 0, float) / 1e6)
self.waterfallHistorySizeSpinBox.setValue(settings.value("waterfall_history_size", 100, int))
backend = settings.value("backend", "soapy_power")
try:
backend_module = getattr(backends, backend)
except AttributeError:
backend_module = backends.soapy_power
self.paramsEdit.setText(settings.value("params", backend_module.Info.additional_params))
self.deviceHelpButton.setEnabled(bool(backend_module.Info.help_device))
self.sampleRateSpinBox.setMinimum(backend_module.Info.sample_rate_min / 1e6)
self.sampleRateSpinBox.setMaximum(backend_module.Info.sample_rate_max / 1e6)
self.sampleRateSpinBox.setValue(settings.value("sample_rate", backend_module.Info.sample_rate, float) / 1e6)
self.bandwidthSpinBox.setMinimum(backend_module.Info.bandwidth_min / 1e6)
self.bandwidthSpinBox.setMaximum(backend_module.Info.bandwidth_max / 1e6)
self.bandwidthSpinBox.setValue(settings.value("bandwidth", backend_module.Info.bandwidth, float) / 1e6)
self.backendComboBox.blockSignals(True)
self.backendComboBox.clear()
for b in sorted(backends.__all__):
self.backendComboBox.addItem(b)
i = self.backendComboBox.findText(backend)
if i == -1:
self.backendComboBox.setCurrentIndex(0)
else:
self.backendComboBox.setCurrentIndex(i)
self.backendComboBox.blockSignals(False)
@QtCore.Slot()
def on_executableButton_clicked(self):
"""Open file dialog when button is clicked"""
filename = QtWidgets.QFileDialog.getOpenFileName(self, self.tr("Select executable - QSpectrumAnalyzer"))[0]
if filename:
self.executableEdit.setText(filename)
@QtCore.Slot()
def on_paramsHelpButton_clicked(self):
"""Open additional parameters help dialog when button is clicked"""
try:
backend_module = getattr(backends, self.backendComboBox.currentText())
except AttributeError:
backend_module = backends.soapy_power
self.params_help_dialog = QSpectrumAnalyzerSettingsHelp(
backend_module.Info.help_params(self.executableEdit.text()),
parent=self
)
self.params_help_dialog.show()
self.params_help_dialog.raise_()
self.params_help_dialog.activateWindow()
@QtCore.Slot()
def on_deviceHelpButton_clicked(self):
"""Open device help dialog when button is clicked"""
try:
backend_module = getattr(backends, self.backendComboBox.currentText())
except AttributeError:
backend_module = backends.soapy_power
self.device_help_dialog = QSpectrumAnalyzerSettingsHelp(
backend_module.Info.help_device(self.executableEdit.text(), self.deviceEdit.text()),
parent=self
)
self.device_help_dialog.show()
self.device_help_dialog.raise_()
self.device_help_dialog.activateWindow()
@QtCore.Slot(str)
def on_backendComboBox_currentIndexChanged(self, text):
"""Change executable when backend is changed"""
self.executableEdit.setText(text)
self.deviceEdit.setText("")
try:
backend_module = getattr(backends, text)
except AttributeError:
backend_module = backends.soapy_power
self.paramsEdit.setText(backend_module.Info.additional_params)
self.deviceHelpButton.setEnabled(bool(backend_module.Info.help_device))
self.sampleRateSpinBox.setMinimum(backend_module.Info.sample_rate_min / 1e6)
self.sampleRateSpinBox.setMaximum(backend_module.Info.sample_rate_max / 1e6)
self.sampleRateSpinBox.setValue(backend_module.Info.sample_rate / 1e6)
self.bandwidthSpinBox.setMinimum(backend_module.Info.bandwidth_min / 1e6)
self.bandwidthSpinBox.setMaximum(backend_module.Info.bandwidth_max / 1e6)
self.bandwidthSpinBox.setValue(backend_module.Info.bandwidth / 1e6)
def accept(self):
"""Save settings when dialog is accepted"""
settings = QtCore.QSettings()
settings.setValue("backend", self.backendComboBox.currentText())
settings.setValue("executable", self.executableEdit.text())
settings.setValue("params", self.paramsEdit.text())
settings.setValue("device", self.deviceEdit.text())
settings.setValue("sample_rate", self.sampleRateSpinBox.value() * 1e6)
settings.setValue("bandwidth", self.bandwidthSpinBox.value() * 1e6)
settings.setValue("lnb_lo", self.lnbSpinBox.value() * 1e6)
settings.setValue("waterfall_history_size", self.waterfallHistorySizeSpinBox.value())
QtWidgets.QDialog.accept(self)
class QSpectrumAnalyzerSettingsHelp(QtWidgets.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)

View File

@ -1,29 +0,0 @@
from Qt import QtCore, QtWidgets
from qspectrumanalyzer.ui_qspectrumanalyzer_smoothing import Ui_QSpectrumAnalyzerSmoothing
class QSpectrumAnalyzerSmoothing(QtWidgets.QDialog, Ui_QSpectrumAnalyzerSmoothing):
"""QSpectrumAnalyzer spectrum smoothing dialog"""
def __init__(self, parent=None):
# Initialize UI
super().__init__(parent)
self.setupUi(self)
# Load settings
settings = QtCore.QSettings()
self.windowLengthSpinBox.setValue(settings.value("smooth_length", 11, int))
window_function = settings.value("smooth_window", "hanning")
i = self.windowFunctionComboBox.findText(window_function)
if i == -1:
self.windowFunctionComboBox.setCurrentIndex(0)
else:
self.windowFunctionComboBox.setCurrentIndex(i)
def accept(self):
"""Save settings when dialog is accepted"""
settings = QtCore.QSettings()
settings.setValue("smooth_length", self.windowLengthSpinBox.value())
settings.setValue("smooth_window", self.windowFunctionComboBox.currentText())
QtWidgets.QDialog.accept(self)

View File

@ -1,81 +0,0 @@
import sys, subprocess
# Basic attributes and exceptions
PIPE = subprocess.PIPE
STDOUT = subprocess.STDOUT
DEVNULL = subprocess.DEVNULL
SubprocessError = subprocess.SubprocessError
TimeoutExpired = subprocess.TimeoutExpired
CalledProcessError = subprocess.CalledProcessError
# Windows-only attributes and functions
if sys.platform == 'win32':
import msvcrt
import _winapi
# creationflags
CREATE_NEW_CONSOLE = subprocess.CREATE_NEW_CONSOLE
CREATE_NEW_PROCESS_GROUP = subprocess.CREATE_NEW_PROCESS_GROUP
# startupinfo
STARTUPINFO = subprocess.STARTUPINFO
STARTF_USESTDHANDLES = subprocess.STARTF_USESTDHANDLES
STARTF_USESHOWWINDOW = subprocess.STARTF_USESHOWWINDOW
SW_HIDE = subprocess.SW_HIDE
# file handles
Handle = subprocess.Handle
STD_INPUT_HANDLE = subprocess.STD_INPUT_HANDLE
STD_OUTPUT_HANDLE = subprocess.STD_OUTPUT_HANDLE
STD_ERROR_HANDLE = subprocess.STD_ERROR_HANDLE
def make_inheritable_handle(fd):
"""Create inheritable duplicate of handle from file descriptor"""
h = _winapi.DuplicateHandle(
_winapi.GetCurrentProcess(),
msvcrt.get_osfhandle(fd),
_winapi.GetCurrentProcess(), 0, 1,
_winapi.DUPLICATE_SAME_ACCESS
)
return subprocess.Handle(h)
def hide_console_window(startupinfo=None):
"""Returns altered startupinfo to hide console window on Windows"""
if sys.platform != 'win32':
return None
if not startupinfo:
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
return startupinfo
class Popen(subprocess.Popen):
"""subprocess.Popen with ability to hide console window on Windows"""
def __init__(self, *pargs, console=True, **kwargs):
if not console:
kwargs['startupinfo'] = hide_console_window(kwargs.get('startupinfo'))
super().__init__(*pargs, **kwargs)
def call(*pargs, console=True, **kwargs):
"""subprocess.call with ability to hide console window on Windows"""
if not console:
kwargs['startupinfo'] = hide_console_window(kwargs.get('startupinfo'))
return subprocess.call(*pargs, **kwargs)
def check_call(*pargs, console=True, **kwargs):
"""subprocess.check_call with ability to hide console window on Windows"""
if not console:
kwargs['startupinfo'] = hide_console_window(kwargs.get('startupinfo'))
return subprocess.check_call(*pargs, **kwargs)
def check_output(*pargs, console=True, **kwargs):
"""subprocess.check_output with ability to hide console window on Windows"""
if not console:
kwargs['startupinfo'] = hide_console_window(kwargs.get('startupinfo'))
return subprocess.check_output(*pargs, **kwargs)

View File

@ -2,275 +2,273 @@
# Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer.ui'
#
# Created by: PyQt5 UI code generator 5.8
# Created by: PyQt4 UI code generator 4.12
#
# WARNING! All changes made in this file will be lost!
from Qt import QtCore, QtGui, QtWidgets
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_QSpectrumAnalyzerMainWindow(object):
def setupUi(self, QSpectrumAnalyzerMainWindow):
QSpectrumAnalyzerMainWindow.setObjectName("QSpectrumAnalyzerMainWindow")
QSpectrumAnalyzerMainWindow.resize(1200, 892)
self.centralwidget = QtWidgets.QWidget(QSpectrumAnalyzerMainWindow)
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
self.horizontalLayout.setObjectName("horizontalLayout")
self.plotSplitter = QtWidgets.QSplitter(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
QSpectrumAnalyzerMainWindow.setObjectName(_fromUtf8("QSpectrumAnalyzerMainWindow"))
QSpectrumAnalyzerMainWindow.resize(1200, 810)
self.centralwidget = QtGui.QWidget(QSpectrumAnalyzerMainWindow)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget)
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.plotSplitter = QtGui.QSplitter(self.centralwidget)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.plotSplitter.sizePolicy().hasHeightForWidth())
self.plotSplitter.setSizePolicy(sizePolicy)
self.plotSplitter.setOrientation(QtCore.Qt.Vertical)
self.plotSplitter.setObjectName("plotSplitter")
self.plotSplitter.setObjectName(_fromUtf8("plotSplitter"))
self.mainPlotLayout = GraphicsLayoutWidget(self.plotSplitter)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.mainPlotLayout.sizePolicy().hasHeightForWidth())
self.mainPlotLayout.setSizePolicy(sizePolicy)
self.mainPlotLayout.setObjectName("mainPlotLayout")
self.mainPlotLayout.setObjectName(_fromUtf8("mainPlotLayout"))
self.waterfallPlotLayout = GraphicsLayoutWidget(self.plotSplitter)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.waterfallPlotLayout.sizePolicy().hasHeightForWidth())
self.waterfallPlotLayout.setSizePolicy(sizePolicy)
self.waterfallPlotLayout.setObjectName("waterfallPlotLayout")
self.waterfallPlotLayout.setObjectName(_fromUtf8("waterfallPlotLayout"))
self.horizontalLayout.addWidget(self.plotSplitter)
QSpectrumAnalyzerMainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(QSpectrumAnalyzerMainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1200, 32))
self.menubar.setObjectName("menubar")
self.menu_File = QtWidgets.QMenu(self.menubar)
self.menu_File.setObjectName("menu_File")
self.menu_Help = QtWidgets.QMenu(self.menubar)
self.menu_Help.setObjectName("menu_Help")
self.menubar = QtGui.QMenuBar(QSpectrumAnalyzerMainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1200, 30))
self.menubar.setObjectName(_fromUtf8("menubar"))
self.menu_File = QtGui.QMenu(self.menubar)
self.menu_File.setObjectName(_fromUtf8("menu_File"))
self.menu_Help = QtGui.QMenu(self.menubar)
self.menu_Help.setObjectName(_fromUtf8("menu_Help"))
QSpectrumAnalyzerMainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(QSpectrumAnalyzerMainWindow)
self.statusbar.setObjectName("statusbar")
self.statusbar = QtGui.QStatusBar(QSpectrumAnalyzerMainWindow)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
QSpectrumAnalyzerMainWindow.setStatusBar(self.statusbar)
self.controlsDockWidget = QtWidgets.QDockWidget(QSpectrumAnalyzerMainWindow)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
self.controlsDockWidget = QtGui.QDockWidget(QSpectrumAnalyzerMainWindow)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.controlsDockWidget.sizePolicy().hasHeightForWidth())
self.controlsDockWidget.setSizePolicy(sizePolicy)
self.controlsDockWidget.setMinimumSize(QtCore.QSize(190, 130))
self.controlsDockWidget.setFeatures(QtWidgets.QDockWidget.DockWidgetFloatable|QtWidgets.QDockWidget.DockWidgetMovable)
self.controlsDockWidget.setObjectName("controlsDockWidget")
self.controlsDockWidgetContents = QtWidgets.QWidget()
self.controlsDockWidgetContents.setObjectName("controlsDockWidgetContents")
self.gridLayout_2 = QtWidgets.QGridLayout(self.controlsDockWidgetContents)
self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
self.gridLayout_2.setObjectName("gridLayout_2")
self.startButton = QtWidgets.QPushButton(self.controlsDockWidgetContents)
self.startButton.setObjectName("startButton")
self.controlsDockWidget.setMinimumSize(QtCore.QSize(10, 10))
self.controlsDockWidget.setFeatures(QtGui.QDockWidget.DockWidgetFloatable|QtGui.QDockWidget.DockWidgetMovable)
self.controlsDockWidget.setObjectName(_fromUtf8("controlsDockWidget"))
self.controlsDockWidgetContents = QtGui.QWidget()
self.controlsDockWidgetContents.setObjectName(_fromUtf8("controlsDockWidgetContents"))
self.gridLayout_2 = QtGui.QGridLayout(self.controlsDockWidgetContents)
self.gridLayout_2.setMargin(0)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.startButton = QtGui.QPushButton(self.controlsDockWidgetContents)
self.startButton.setObjectName(_fromUtf8("startButton"))
self.gridLayout_2.addWidget(self.startButton, 0, 0, 1, 1)
self.stopButton = QtWidgets.QPushButton(self.controlsDockWidgetContents)
self.stopButton.setObjectName("stopButton")
self.stopButton = QtGui.QPushButton(self.controlsDockWidgetContents)
self.stopButton.setObjectName(_fromUtf8("stopButton"))
self.gridLayout_2.addWidget(self.stopButton, 0, 1, 1, 1)
self.singleShotButton = QtWidgets.QPushButton(self.controlsDockWidgetContents)
self.singleShotButton.setObjectName("singleShotButton")
self.singleShotButton = QtGui.QPushButton(self.controlsDockWidgetContents)
self.singleShotButton.setObjectName(_fromUtf8("singleShotButton"))
self.gridLayout_2.addWidget(self.singleShotButton, 1, 0, 1, 2)
spacerItem = QtWidgets.QSpacerItem(20, 561, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
spacerItem = QtGui.QSpacerItem(20, 561, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout_2.addItem(spacerItem, 2, 0, 1, 1)
self.controlsDockWidget.setWidget(self.controlsDockWidgetContents)
QSpectrumAnalyzerMainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.controlsDockWidget)
self.frequencyDockWidget = QtWidgets.QDockWidget(QSpectrumAnalyzerMainWindow)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
self.frequencyDockWidget = QtGui.QDockWidget(QSpectrumAnalyzerMainWindow)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.frequencyDockWidget.sizePolicy().hasHeightForWidth())
self.frequencyDockWidget.setSizePolicy(sizePolicy)
self.frequencyDockWidget.setMinimumSize(QtCore.QSize(208, 166))
self.frequencyDockWidget.setFeatures(QtWidgets.QDockWidget.DockWidgetFloatable|QtWidgets.QDockWidget.DockWidgetMovable)
self.frequencyDockWidget.setObjectName("frequencyDockWidget")
self.frequencyDockWidgetContents = QtWidgets.QWidget()
self.frequencyDockWidgetContents.setObjectName("frequencyDockWidgetContents")
self.formLayout = QtWidgets.QFormLayout(self.frequencyDockWidgetContents)
self.formLayout.setFieldGrowthPolicy(QtWidgets.QFormLayout.ExpandingFieldsGrow)
self.formLayout.setContentsMargins(0, 0, 0, 0)
self.formLayout.setObjectName("formLayout")
self.label_2 = QtWidgets.QLabel(self.frequencyDockWidgetContents)
self.label_2.setObjectName("label_2")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_2)
self.startFreqSpinBox = QtWidgets.QDoubleSpinBox(self.frequencyDockWidgetContents)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
self.frequencyDockWidget.setMinimumSize(QtCore.QSize(10, 10))
self.frequencyDockWidget.setFeatures(QtGui.QDockWidget.DockWidgetFloatable|QtGui.QDockWidget.DockWidgetMovable)
self.frequencyDockWidget.setObjectName(_fromUtf8("frequencyDockWidget"))
self.frequencyDockWidgetContents = QtGui.QWidget()
self.frequencyDockWidgetContents.setObjectName(_fromUtf8("frequencyDockWidgetContents"))
self.formLayout = QtGui.QFormLayout(self.frequencyDockWidgetContents)
self.formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.ExpandingFieldsGrow)
self.formLayout.setMargin(0)
self.formLayout.setObjectName(_fromUtf8("formLayout"))
self.label_2 = QtGui.QLabel(self.frequencyDockWidgetContents)
self.label_2.setObjectName(_fromUtf8("label_2"))
self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.label_2)
self.startFreqSpinBox = QtGui.QDoubleSpinBox(self.frequencyDockWidgetContents)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.startFreqSpinBox.sizePolicy().hasHeightForWidth())
self.startFreqSpinBox.setSizePolicy(sizePolicy)
self.startFreqSpinBox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.startFreqSpinBox.setProperty("showGroupSeparator", True)
self.startFreqSpinBox.setDecimals(3)
self.startFreqSpinBox.setMinimum(0.0)
self.startFreqSpinBox.setMaximum(2200.0)
self.startFreqSpinBox.setMinimum(24.0)
self.startFreqSpinBox.setMaximum(1766.0)
self.startFreqSpinBox.setProperty("value", 87.0)
self.startFreqSpinBox.setObjectName("startFreqSpinBox")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.startFreqSpinBox)
self.label_3 = QtWidgets.QLabel(self.frequencyDockWidgetContents)
self.label_3.setObjectName("label_3")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_3)
self.stopFreqSpinBox = QtWidgets.QDoubleSpinBox(self.frequencyDockWidgetContents)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
self.startFreqSpinBox.setObjectName(_fromUtf8("startFreqSpinBox"))
self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.startFreqSpinBox)
self.label_3 = QtGui.QLabel(self.frequencyDockWidgetContents)
self.label_3.setObjectName(_fromUtf8("label_3"))
self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.label_3)
self.stopFreqSpinBox = QtGui.QDoubleSpinBox(self.frequencyDockWidgetContents)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.stopFreqSpinBox.sizePolicy().hasHeightForWidth())
self.stopFreqSpinBox.setSizePolicy(sizePolicy)
self.stopFreqSpinBox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.stopFreqSpinBox.setProperty("showGroupSeparator", True)
self.stopFreqSpinBox.setDecimals(3)
self.stopFreqSpinBox.setMinimum(0.0)
self.stopFreqSpinBox.setMaximum(2200.0)
self.stopFreqSpinBox.setMinimum(24.0)
self.stopFreqSpinBox.setMaximum(1766.0)
self.stopFreqSpinBox.setProperty("value", 108.0)
self.stopFreqSpinBox.setObjectName("stopFreqSpinBox")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.stopFreqSpinBox)
self.label = QtWidgets.QLabel(self.frequencyDockWidgetContents)
self.label.setObjectName("label")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label)
self.binSizeSpinBox = QtWidgets.QDoubleSpinBox(self.frequencyDockWidgetContents)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
self.stopFreqSpinBox.setObjectName(_fromUtf8("stopFreqSpinBox"))
self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.stopFreqSpinBox)
self.label = QtGui.QLabel(self.frequencyDockWidgetContents)
self.label.setObjectName(_fromUtf8("label"))
self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.label)
self.binSizeSpinBox = QtGui.QDoubleSpinBox(self.frequencyDockWidgetContents)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.binSizeSpinBox.sizePolicy().hasHeightForWidth())
self.binSizeSpinBox.setSizePolicy(sizePolicy)
self.binSizeSpinBox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.binSizeSpinBox.setProperty("showGroupSeparator", True)
self.binSizeSpinBox.setDecimals(3)
self.binSizeSpinBox.setMinimum(0.0)
self.binSizeSpinBox.setMaximum(10000.0)
self.binSizeSpinBox.setMaximum(2800.0)
self.binSizeSpinBox.setProperty("value", 10.0)
self.binSizeSpinBox.setObjectName("binSizeSpinBox")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.binSizeSpinBox)
spacerItem1 = QtWidgets.QSpacerItem(20, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.formLayout.setItem(3, QtWidgets.QFormLayout.SpanningRole, spacerItem1)
self.binSizeSpinBox.setObjectName(_fromUtf8("binSizeSpinBox"))
self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.binSizeSpinBox)
spacerItem1 = QtGui.QSpacerItem(20, 0, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.formLayout.setItem(3, QtGui.QFormLayout.SpanningRole, spacerItem1)
self.frequencyDockWidget.setWidget(self.frequencyDockWidgetContents)
QSpectrumAnalyzerMainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.frequencyDockWidget)
self.settingsDockWidget = QtWidgets.QDockWidget(QSpectrumAnalyzerMainWindow)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
self.settingsDockWidget = QtGui.QDockWidget(QSpectrumAnalyzerMainWindow)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.settingsDockWidget.sizePolicy().hasHeightForWidth())
self.settingsDockWidget.setSizePolicy(sizePolicy)
self.settingsDockWidget.setFeatures(QtWidgets.QDockWidget.DockWidgetFloatable|QtWidgets.QDockWidget.DockWidgetMovable)
self.settingsDockWidget.setObjectName("settingsDockWidget")
self.settingsDockWidgetContents = QtWidgets.QWidget()
self.settingsDockWidgetContents.setObjectName("settingsDockWidgetContents")
self.gridLayout = QtWidgets.QGridLayout(self.settingsDockWidgetContents)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
self.label_4 = QtWidgets.QLabel(self.settingsDockWidgetContents)
self.label_4.setObjectName("label_4")
self.settingsDockWidget.setFeatures(QtGui.QDockWidget.DockWidgetFloatable|QtGui.QDockWidget.DockWidgetMovable)
self.settingsDockWidget.setObjectName(_fromUtf8("settingsDockWidget"))
self.settingsDockWidgetContents = QtGui.QWidget()
self.settingsDockWidgetContents.setObjectName(_fromUtf8("settingsDockWidgetContents"))
self.gridLayout = QtGui.QGridLayout(self.settingsDockWidgetContents)
self.gridLayout.setMargin(0)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.label_4 = QtGui.QLabel(self.settingsDockWidgetContents)
self.label_4.setObjectName(_fromUtf8("label_4"))
self.gridLayout.addWidget(self.label_4, 0, 0, 1, 1)
self.label_6 = QtWidgets.QLabel(self.settingsDockWidgetContents)
self.label_6.setObjectName("label_6")
self.label_6 = QtGui.QLabel(self.settingsDockWidgetContents)
self.label_6.setObjectName(_fromUtf8("label_6"))
self.gridLayout.addWidget(self.label_6, 0, 1, 1, 1)
self.intervalSpinBox = QtWidgets.QDoubleSpinBox(self.settingsDockWidgetContents)
self.intervalSpinBox = QtGui.QDoubleSpinBox(self.settingsDockWidgetContents)
self.intervalSpinBox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.intervalSpinBox.setMaximum(999.0)
self.intervalSpinBox.setProperty("value", 1.0)
self.intervalSpinBox.setObjectName("intervalSpinBox")
self.intervalSpinBox.setObjectName(_fromUtf8("intervalSpinBox"))
self.gridLayout.addWidget(self.intervalSpinBox, 1, 0, 1, 1)
self.label_5 = QtWidgets.QLabel(self.settingsDockWidgetContents)
self.label_5.setObjectName("label_5")
self.gainSpinBox = QtGui.QSpinBox(self.settingsDockWidgetContents)
self.gainSpinBox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.gainSpinBox.setMinimum(-1)
self.gainSpinBox.setMaximum(49)
self.gainSpinBox.setProperty("value", -1)
self.gainSpinBox.setObjectName(_fromUtf8("gainSpinBox"))
self.gridLayout.addWidget(self.gainSpinBox, 1, 1, 1, 2)
self.label_5 = QtGui.QLabel(self.settingsDockWidgetContents)
self.label_5.setObjectName(_fromUtf8("label_5"))
self.gridLayout.addWidget(self.label_5, 2, 0, 1, 1)
self.label_7 = QtWidgets.QLabel(self.settingsDockWidgetContents)
self.label_7.setObjectName("label_7")
self.label_7 = QtGui.QLabel(self.settingsDockWidgetContents)
self.label_7.setObjectName(_fromUtf8("label_7"))
self.gridLayout.addWidget(self.label_7, 2, 1, 1, 1)
self.ppmSpinBox = QtWidgets.QSpinBox(self.settingsDockWidgetContents)
self.ppmSpinBox = QtGui.QSpinBox(self.settingsDockWidgetContents)
self.ppmSpinBox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.ppmSpinBox.setMinimum(-999)
self.ppmSpinBox.setMaximum(999)
self.ppmSpinBox.setObjectName("ppmSpinBox")
self.ppmSpinBox.setObjectName(_fromUtf8("ppmSpinBox"))
self.gridLayout.addWidget(self.ppmSpinBox, 3, 0, 1, 1)
self.mainCurveCheckBox = QtWidgets.QCheckBox(self.settingsDockWidgetContents)
self.mainCurveCheckBox = QtGui.QCheckBox(self.settingsDockWidgetContents)
self.mainCurveCheckBox.setChecked(True)
self.mainCurveCheckBox.setObjectName("mainCurveCheckBox")
self.mainCurveCheckBox.setObjectName(_fromUtf8("mainCurveCheckBox"))
self.gridLayout.addWidget(self.mainCurveCheckBox, 4, 0, 1, 1)
self.colorsButton = QtWidgets.QPushButton(self.settingsDockWidgetContents)
self.colorsButton.setObjectName("colorsButton")
self.colorsButton = QtGui.QPushButton(self.settingsDockWidgetContents)
self.colorsButton.setObjectName(_fromUtf8("colorsButton"))
self.gridLayout.addWidget(self.colorsButton, 4, 1, 1, 2)
self.peakHoldMaxCheckBox = QtWidgets.QCheckBox(self.settingsDockWidgetContents)
self.peakHoldMaxCheckBox.setObjectName("peakHoldMaxCheckBox")
self.peakHoldMaxCheckBox = QtGui.QCheckBox(self.settingsDockWidgetContents)
self.peakHoldMaxCheckBox.setObjectName(_fromUtf8("peakHoldMaxCheckBox"))
self.gridLayout.addWidget(self.peakHoldMaxCheckBox, 5, 0, 1, 1)
self.peakHoldMinCheckBox = QtWidgets.QCheckBox(self.settingsDockWidgetContents)
self.peakHoldMinCheckBox.setObjectName("peakHoldMinCheckBox")
self.peakHoldMinCheckBox = QtGui.QCheckBox(self.settingsDockWidgetContents)
self.peakHoldMinCheckBox.setObjectName(_fromUtf8("peakHoldMinCheckBox"))
self.gridLayout.addWidget(self.peakHoldMinCheckBox, 5, 1, 1, 2)
self.averageCheckBox = QtWidgets.QCheckBox(self.settingsDockWidgetContents)
self.averageCheckBox.setObjectName("averageCheckBox")
self.averageCheckBox = QtGui.QCheckBox(self.settingsDockWidgetContents)
self.averageCheckBox.setObjectName(_fromUtf8("averageCheckBox"))
self.gridLayout.addWidget(self.averageCheckBox, 6, 0, 1, 1)
self.smoothCheckBox = QtWidgets.QCheckBox(self.settingsDockWidgetContents)
self.smoothCheckBox.setObjectName("smoothCheckBox")
self.smoothCheckBox = QtGui.QCheckBox(self.settingsDockWidgetContents)
self.smoothCheckBox.setObjectName(_fromUtf8("smoothCheckBox"))
self.gridLayout.addWidget(self.smoothCheckBox, 7, 0, 1, 1)
self.smoothButton = QtWidgets.QToolButton(self.settingsDockWidgetContents)
self.smoothButton = QtGui.QToolButton(self.settingsDockWidgetContents)
self.smoothButton.setAutoRaise(False)
self.smoothButton.setObjectName("smoothButton")
self.smoothButton.setObjectName(_fromUtf8("smoothButton"))
self.gridLayout.addWidget(self.smoothButton, 7, 2, 1, 1)
self.persistenceCheckBox = QtWidgets.QCheckBox(self.settingsDockWidgetContents)
self.persistenceCheckBox.setObjectName("persistenceCheckBox")
self.persistenceCheckBox = QtGui.QCheckBox(self.settingsDockWidgetContents)
self.persistenceCheckBox.setObjectName(_fromUtf8("persistenceCheckBox"))
self.gridLayout.addWidget(self.persistenceCheckBox, 8, 0, 1, 1)
self.persistenceButton = QtWidgets.QToolButton(self.settingsDockWidgetContents)
self.persistenceButton = QtGui.QToolButton(self.settingsDockWidgetContents)
self.persistenceButton.setAutoRaise(False)
self.persistenceButton.setObjectName("persistenceButton")
self.persistenceButton.setObjectName(_fromUtf8("persistenceButton"))
self.gridLayout.addWidget(self.persistenceButton, 8, 2, 1, 1)
spacerItem2 = QtWidgets.QSpacerItem(20, 1, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout.addItem(spacerItem2, 11, 0, 1, 1)
self.cropSpinBox = QtWidgets.QSpinBox(self.settingsDockWidgetContents)
spacerItem2 = QtGui.QSpacerItem(20, 1, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout.addItem(spacerItem2, 9, 0, 1, 1)
self.cropSpinBox = QtGui.QSpinBox(self.settingsDockWidgetContents)
self.cropSpinBox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.cropSpinBox.setObjectName("cropSpinBox")
self.cropSpinBox.setObjectName(_fromUtf8("cropSpinBox"))
self.gridLayout.addWidget(self.cropSpinBox, 3, 1, 1, 2)
self.gainSpinBox = QtWidgets.QDoubleSpinBox(self.settingsDockWidgetContents)
self.gainSpinBox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.gainSpinBox.setDecimals(1)
self.gainSpinBox.setMinimum(-1.0)
self.gainSpinBox.setMaximum(999.0)
self.gainSpinBox.setSingleStep(1.0)
self.gainSpinBox.setProperty("value", -1.0)
self.gainSpinBox.setObjectName("gainSpinBox")
self.gridLayout.addWidget(self.gainSpinBox, 1, 1, 1, 2)
self.baselineCheckBox = QtWidgets.QCheckBox(self.settingsDockWidgetContents)
self.baselineCheckBox.setObjectName("baselineCheckBox")
self.gridLayout.addWidget(self.baselineCheckBox, 9, 0, 1, 1)
self.baselineButton = QtWidgets.QToolButton(self.settingsDockWidgetContents)
self.baselineButton.setAutoRaise(False)
self.baselineButton.setObjectName("baselineButton")
self.gridLayout.addWidget(self.baselineButton, 9, 2, 1, 1)
self.subtractBaselineCheckBox = QtWidgets.QCheckBox(self.settingsDockWidgetContents)
self.subtractBaselineCheckBox.setObjectName("subtractBaselineCheckBox")
self.gridLayout.addWidget(self.subtractBaselineCheckBox, 10, 0, 1, 1)
self.settingsDockWidget.setWidget(self.settingsDockWidgetContents)
QSpectrumAnalyzerMainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.settingsDockWidget)
self.levelsDockWidget = QtWidgets.QDockWidget(QSpectrumAnalyzerMainWindow)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
self.levelsDockWidget = QtGui.QDockWidget(QSpectrumAnalyzerMainWindow)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.levelsDockWidget.sizePolicy().hasHeightForWidth())
self.levelsDockWidget.setSizePolicy(sizePolicy)
self.levelsDockWidget.setFeatures(QtWidgets.QDockWidget.DockWidgetFloatable|QtWidgets.QDockWidget.DockWidgetMovable)
self.levelsDockWidget.setObjectName("levelsDockWidget")
self.levelsDockWidgetContents = QtWidgets.QWidget()
self.levelsDockWidgetContents.setObjectName("levelsDockWidgetContents")
self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.levelsDockWidgetContents)
self.verticalLayout_6.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_6.setObjectName("verticalLayout_6")
self.levelsDockWidget.setFeatures(QtGui.QDockWidget.DockWidgetFloatable|QtGui.QDockWidget.DockWidgetMovable)
self.levelsDockWidget.setObjectName(_fromUtf8("levelsDockWidget"))
self.levelsDockWidgetContents = QtGui.QWidget()
self.levelsDockWidgetContents.setObjectName(_fromUtf8("levelsDockWidgetContents"))
self.verticalLayout_6 = QtGui.QVBoxLayout(self.levelsDockWidgetContents)
self.verticalLayout_6.setMargin(0)
self.verticalLayout_6.setObjectName(_fromUtf8("verticalLayout_6"))
self.histogramPlotLayout = GraphicsLayoutWidget(self.levelsDockWidgetContents)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Expanding)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.histogramPlotLayout.sizePolicy().hasHeightForWidth())
self.histogramPlotLayout.setSizePolicy(sizePolicy)
self.histogramPlotLayout.setObjectName("histogramPlotLayout")
self.histogramPlotLayout.setObjectName(_fromUtf8("histogramPlotLayout"))
self.verticalLayout_6.addWidget(self.histogramPlotLayout)
self.levelsDockWidget.setWidget(self.levelsDockWidgetContents)
QSpectrumAnalyzerMainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(2), self.levelsDockWidget)
self.action_Settings = QtWidgets.QAction(QSpectrumAnalyzerMainWindow)
self.action_Settings.setObjectName("action_Settings")
self.action_Quit = QtWidgets.QAction(QSpectrumAnalyzerMainWindow)
self.action_Quit.setObjectName("action_Quit")
self.action_About = QtWidgets.QAction(QSpectrumAnalyzerMainWindow)
self.action_About.setObjectName("action_About")
self.action_Settings = QtGui.QAction(QSpectrumAnalyzerMainWindow)
self.action_Settings.setObjectName(_fromUtf8("action_Settings"))
self.action_Quit = QtGui.QAction(QSpectrumAnalyzerMainWindow)
self.action_Quit.setObjectName(_fromUtf8("action_Quit"))
self.action_About = QtGui.QAction(QSpectrumAnalyzerMainWindow)
self.action_About.setObjectName(_fromUtf8("action_About"))
self.menu_File.addAction(self.action_Settings)
self.menu_File.addSeparator()
self.menu_File.addAction(self.action_Quit)
@ -305,51 +303,44 @@ class Ui_QSpectrumAnalyzerMainWindow(object):
QSpectrumAnalyzerMainWindow.setTabOrder(self.smoothCheckBox, self.smoothButton)
QSpectrumAnalyzerMainWindow.setTabOrder(self.smoothButton, self.persistenceCheckBox)
QSpectrumAnalyzerMainWindow.setTabOrder(self.persistenceCheckBox, self.persistenceButton)
QSpectrumAnalyzerMainWindow.setTabOrder(self.persistenceButton, self.baselineCheckBox)
QSpectrumAnalyzerMainWindow.setTabOrder(self.baselineCheckBox, self.baselineButton)
QSpectrumAnalyzerMainWindow.setTabOrder(self.baselineButton, self.subtractBaselineCheckBox)
QSpectrumAnalyzerMainWindow.setTabOrder(self.subtractBaselineCheckBox, self.histogramPlotLayout)
QSpectrumAnalyzerMainWindow.setTabOrder(self.persistenceButton, self.histogramPlotLayout)
QSpectrumAnalyzerMainWindow.setTabOrder(self.histogramPlotLayout, self.mainPlotLayout)
QSpectrumAnalyzerMainWindow.setTabOrder(self.mainPlotLayout, self.waterfallPlotLayout)
def retranslateUi(self, QSpectrumAnalyzerMainWindow):
_translate = QtCore.QCoreApplication.translate
QSpectrumAnalyzerMainWindow.setWindowTitle(_translate("QSpectrumAnalyzerMainWindow", "QSpectrumAnalyzer"))
self.menu_File.setTitle(_translate("QSpectrumAnalyzerMainWindow", "&File"))
self.menu_Help.setTitle(_translate("QSpectrumAnalyzerMainWindow", "&Help"))
self.controlsDockWidget.setWindowTitle(_translate("QSpectrumAnalyzerMainWindow", "Controls"))
self.startButton.setText(_translate("QSpectrumAnalyzerMainWindow", "&Start"))
self.stopButton.setText(_translate("QSpectrumAnalyzerMainWindow", "S&top"))
self.singleShotButton.setText(_translate("QSpectrumAnalyzerMainWindow", "Si&ngle shot"))
self.frequencyDockWidget.setWindowTitle(_translate("QSpectrumAnalyzerMainWindow", "Frequency"))
self.label_2.setText(_translate("QSpectrumAnalyzerMainWindow", "Start:"))
self.startFreqSpinBox.setSuffix(_translate("QSpectrumAnalyzerMainWindow", " MHz"))
self.label_3.setText(_translate("QSpectrumAnalyzerMainWindow", "Stop:"))
self.stopFreqSpinBox.setSuffix(_translate("QSpectrumAnalyzerMainWindow", " MHz"))
self.label.setText(_translate("QSpectrumAnalyzerMainWindow", "&Bin size:"))
self.binSizeSpinBox.setSuffix(_translate("QSpectrumAnalyzerMainWindow", " kHz"))
self.settingsDockWidget.setWindowTitle(_translate("QSpectrumAnalyzerMainWindow", "Settings"))
self.label_4.setText(_translate("QSpectrumAnalyzerMainWindow", "&Interval [s]:"))
self.label_6.setText(_translate("QSpectrumAnalyzerMainWindow", "&Gain [dB]:"))
self.label_5.setText(_translate("QSpectrumAnalyzerMainWindow", "Corr. [ppm]:"))
self.label_7.setText(_translate("QSpectrumAnalyzerMainWindow", "Crop [%]:"))
self.mainCurveCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Main curve"))
self.colorsButton.setText(_translate("QSpectrumAnalyzerMainWindow", "Colors..."))
self.peakHoldMaxCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Max. hold"))
self.peakHoldMinCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Min. hold"))
self.averageCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Average"))
self.smoothCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Smoothing"))
self.smoothButton.setText(_translate("QSpectrumAnalyzerMainWindow", "..."))
self.persistenceCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Persistence"))
self.persistenceButton.setText(_translate("QSpectrumAnalyzerMainWindow", "..."))
self.gainSpinBox.setSpecialValueText(_translate("QSpectrumAnalyzerMainWindow", "auto"))
self.baselineCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Baseline"))
self.baselineButton.setText(_translate("QSpectrumAnalyzerMainWindow", "..."))
self.subtractBaselineCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Subtract baseline"))
self.levelsDockWidget.setWindowTitle(_translate("QSpectrumAnalyzerMainWindow", "Levels"))
self.action_Settings.setText(_translate("QSpectrumAnalyzerMainWindow", "&Settings..."))
self.action_Quit.setText(_translate("QSpectrumAnalyzerMainWindow", "&Quit"))
self.action_Quit.setShortcut(_translate("QSpectrumAnalyzerMainWindow", "Ctrl+Q"))
self.action_About.setText(_translate("QSpectrumAnalyzerMainWindow", "&About"))
QSpectrumAnalyzerMainWindow.setWindowTitle(_translate("QSpectrumAnalyzerMainWindow", "QSpectrumAnalyzer", None))
self.menu_File.setTitle(_translate("QSpectrumAnalyzerMainWindow", "&File", None))
self.menu_Help.setTitle(_translate("QSpectrumAnalyzerMainWindow", "&Help", None))
self.controlsDockWidget.setWindowTitle(_translate("QSpectrumAnalyzerMainWindow", "Controls", None))
self.startButton.setText(_translate("QSpectrumAnalyzerMainWindow", "&Start", None))
self.stopButton.setText(_translate("QSpectrumAnalyzerMainWindow", "S&top", None))
self.singleShotButton.setText(_translate("QSpectrumAnalyzerMainWindow", "Si&ngle shot", None))
self.frequencyDockWidget.setWindowTitle(_translate("QSpectrumAnalyzerMainWindow", "Frequency", None))
self.label_2.setText(_translate("QSpectrumAnalyzerMainWindow", "Start:", None))
self.startFreqSpinBox.setSuffix(_translate("QSpectrumAnalyzerMainWindow", " MHz", None))
self.label_3.setText(_translate("QSpectrumAnalyzerMainWindow", "Stop:", None))
self.stopFreqSpinBox.setSuffix(_translate("QSpectrumAnalyzerMainWindow", " MHz", None))
self.label.setText(_translate("QSpectrumAnalyzerMainWindow", "Bin size:", None))
self.binSizeSpinBox.setSuffix(_translate("QSpectrumAnalyzerMainWindow", " kHz", None))
self.settingsDockWidget.setWindowTitle(_translate("QSpectrumAnalyzerMainWindow", "Settings", None))
self.label_4.setText(_translate("QSpectrumAnalyzerMainWindow", "Interval [s]:", None))
self.label_6.setText(_translate("QSpectrumAnalyzerMainWindow", "Gain [dB]:", None))
self.gainSpinBox.setSpecialValueText(_translate("QSpectrumAnalyzerMainWindow", "auto", None))
self.label_5.setText(_translate("QSpectrumAnalyzerMainWindow", "Corr. [ppm]:", None))
self.label_7.setText(_translate("QSpectrumAnalyzerMainWindow", "Crop [%]:", None))
self.mainCurveCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Main curve", None))
self.colorsButton.setText(_translate("QSpectrumAnalyzerMainWindow", "Colors...", None))
self.peakHoldMaxCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Max. hold", None))
self.peakHoldMinCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Min. hold", None))
self.averageCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Average", None))
self.smoothCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Smoothing", None))
self.smoothButton.setText(_translate("QSpectrumAnalyzerMainWindow", "...", None))
self.persistenceCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Persistence", None))
self.persistenceButton.setText(_translate("QSpectrumAnalyzerMainWindow", "...", None))
self.levelsDockWidget.setWindowTitle(_translate("QSpectrumAnalyzerMainWindow", "Levels", None))
self.action_Settings.setText(_translate("QSpectrumAnalyzerMainWindow", "&Settings...", None))
self.action_Quit.setText(_translate("QSpectrumAnalyzerMainWindow", "&Quit", None))
self.action_Quit.setShortcut(_translate("QSpectrumAnalyzerMainWindow", "Ctrl+Q", None))
self.action_About.setText(_translate("QSpectrumAnalyzerMainWindow", "&About", None))
from pyqtgraph import GraphicsLayoutWidget

View File

@ -1,53 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer_baseline.ui'
#
# Created by: PyQt5 UI code generator 5.8
#
# WARNING! All changes made in this file will be lost!
from Qt import QtCore, QtGui, QtWidgets
class Ui_QSpectrumAnalyzerBaseline(object):
def setupUi(self, QSpectrumAnalyzerBaseline):
QSpectrumAnalyzerBaseline.setObjectName("QSpectrumAnalyzerBaseline")
QSpectrumAnalyzerBaseline.resize(500, 100)
self.verticalLayout = QtWidgets.QVBoxLayout(QSpectrumAnalyzerBaseline)
self.verticalLayout.setObjectName("verticalLayout")
self.formLayout = QtWidgets.QFormLayout()
self.formLayout.setObjectName("formLayout")
self.label = QtWidgets.QLabel(QSpectrumAnalyzerBaseline)
self.label.setObjectName("label")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.baselineFileEdit = QtWidgets.QLineEdit(QSpectrumAnalyzerBaseline)
self.baselineFileEdit.setObjectName("baselineFileEdit")
self.horizontalLayout.addWidget(self.baselineFileEdit)
self.baselineFileButton = QtWidgets.QToolButton(QSpectrumAnalyzerBaseline)
self.baselineFileButton.setMinimumSize(QtCore.QSize(50, 0))
self.baselineFileButton.setObjectName("baselineFileButton")
self.horizontalLayout.addWidget(self.baselineFileButton)
self.formLayout.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout)
self.verticalLayout.addLayout(self.formLayout)
spacerItem = QtWidgets.QSpacerItem(20, 1, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.buttonBox = QtWidgets.QDialogButtonBox(QSpectrumAnalyzerBaseline)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.verticalLayout.addWidget(self.buttonBox)
self.label.setBuddy(self.baselineFileEdit)
self.retranslateUi(QSpectrumAnalyzerBaseline)
self.buttonBox.accepted.connect(QSpectrumAnalyzerBaseline.accept)
self.buttonBox.rejected.connect(QSpectrumAnalyzerBaseline.reject)
QtCore.QMetaObject.connectSlotsByName(QSpectrumAnalyzerBaseline)
QSpectrumAnalyzerBaseline.setTabOrder(self.baselineFileEdit, self.baselineFileButton)
def retranslateUi(self, QSpectrumAnalyzerBaseline):
_translate = QtCore.QCoreApplication.translate
QSpectrumAnalyzerBaseline.setWindowTitle(_translate("QSpectrumAnalyzerBaseline", "Baseline - QSpectrumAnalyzer"))
self.label.setText(_translate("QSpectrumAnalyzerBaseline", "Baseline &file:"))
self.baselineFileButton.setText(_translate("QSpectrumAnalyzerBaseline", "..."))

View File

@ -2,125 +2,124 @@
# Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer_colors.ui'
#
# Created by: PyQt5 UI code generator 5.8
# Created by: PyQt4 UI code generator 4.12
#
# WARNING! All changes made in this file will be lost!
from Qt import QtCore, QtGui, QtWidgets
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_QSpectrumAnalyzerColors(object):
def setupUi(self, QSpectrumAnalyzerColors):
QSpectrumAnalyzerColors.setObjectName("QSpectrumAnalyzerColors")
QSpectrumAnalyzerColors.resize(253, 266)
self.verticalLayout = QtWidgets.QVBoxLayout(QSpectrumAnalyzerColors)
self.verticalLayout.setObjectName("verticalLayout")
self.formLayout = QtWidgets.QFormLayout()
self.formLayout.setObjectName("formLayout")
self.label_2 = QtWidgets.QLabel(QSpectrumAnalyzerColors)
self.label_2.setObjectName("label_2")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_2)
QSpectrumAnalyzerColors.setObjectName(_fromUtf8("QSpectrumAnalyzerColors"))
QSpectrumAnalyzerColors.resize(232, 260)
self.verticalLayout = QtGui.QVBoxLayout(QSpectrumAnalyzerColors)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.formLayout = QtGui.QFormLayout()
self.formLayout.setObjectName(_fromUtf8("formLayout"))
self.label_2 = QtGui.QLabel(QSpectrumAnalyzerColors)
self.label_2.setObjectName(_fromUtf8("label_2"))
self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.label_2)
self.mainColorButton = ColorButton(QSpectrumAnalyzerColors)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.mainColorButton.sizePolicy().hasHeightForWidth())
self.mainColorButton.setSizePolicy(sizePolicy)
self.mainColorButton.setObjectName("mainColorButton")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.mainColorButton)
self.label_4 = QtWidgets.QLabel(QSpectrumAnalyzerColors)
self.label_4.setObjectName("label_4")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_4)
self.mainColorButton.setObjectName(_fromUtf8("mainColorButton"))
self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.mainColorButton)
self.label_4 = QtGui.QLabel(QSpectrumAnalyzerColors)
self.label_4.setObjectName(_fromUtf8("label_4"))
self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.label_4)
self.peakHoldMaxColorButton = ColorButton(QSpectrumAnalyzerColors)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.peakHoldMaxColorButton.sizePolicy().hasHeightForWidth())
self.peakHoldMaxColorButton.setSizePolicy(sizePolicy)
self.peakHoldMaxColorButton.setObjectName("peakHoldMaxColorButton")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.peakHoldMaxColorButton)
self.label_6 = QtWidgets.QLabel(QSpectrumAnalyzerColors)
self.label_6.setObjectName("label_6")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_6)
self.peakHoldMaxColorButton.setObjectName(_fromUtf8("peakHoldMaxColorButton"))
self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.peakHoldMaxColorButton)
self.label_6 = QtGui.QLabel(QSpectrumAnalyzerColors)
self.label_6.setObjectName(_fromUtf8("label_6"))
self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.label_6)
self.peakHoldMinColorButton = ColorButton(QSpectrumAnalyzerColors)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.peakHoldMinColorButton.sizePolicy().hasHeightForWidth())
self.peakHoldMinColorButton.setSizePolicy(sizePolicy)
self.peakHoldMinColorButton.setObjectName("peakHoldMinColorButton")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.peakHoldMinColorButton)
self.label_5 = QtWidgets.QLabel(QSpectrumAnalyzerColors)
self.label_5.setObjectName("label_5")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_5)
self.peakHoldMinColorButton.setObjectName(_fromUtf8("peakHoldMinColorButton"))
self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.peakHoldMinColorButton)
self.label_5 = QtGui.QLabel(QSpectrumAnalyzerColors)
self.label_5.setObjectName(_fromUtf8("label_5"))
self.formLayout.setWidget(3, QtGui.QFormLayout.LabelRole, self.label_5)
self.averageColorButton = ColorButton(QSpectrumAnalyzerColors)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.averageColorButton.sizePolicy().hasHeightForWidth())
self.averageColorButton.setSizePolicy(sizePolicy)
self.averageColorButton.setObjectName("averageColorButton")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.averageColorButton)
self.label_3 = QtWidgets.QLabel(QSpectrumAnalyzerColors)
self.label_3.setObjectName("label_3")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_3)
self.averageColorButton.setObjectName(_fromUtf8("averageColorButton"))
self.formLayout.setWidget(3, QtGui.QFormLayout.FieldRole, self.averageColorButton)
self.label_3 = QtGui.QLabel(QSpectrumAnalyzerColors)
self.label_3.setObjectName(_fromUtf8("label_3"))
self.formLayout.setWidget(4, QtGui.QFormLayout.LabelRole, self.label_3)
self.persistenceColorButton = ColorButton(QSpectrumAnalyzerColors)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.persistenceColorButton.sizePolicy().hasHeightForWidth())
self.persistenceColorButton.setSizePolicy(sizePolicy)
self.persistenceColorButton.setObjectName("persistenceColorButton")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.persistenceColorButton)
self.label = QtWidgets.QLabel(QSpectrumAnalyzerColors)
self.label.setObjectName("label")
self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label)
self.baselineColorButton = ColorButton(QSpectrumAnalyzerColors)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.baselineColorButton.sizePolicy().hasHeightForWidth())
self.baselineColorButton.setSizePolicy(sizePolicy)
self.baselineColorButton.setObjectName("baselineColorButton")
self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.baselineColorButton)
self.persistenceColorButton.setObjectName(_fromUtf8("persistenceColorButton"))
self.formLayout.setWidget(4, QtGui.QFormLayout.FieldRole, self.persistenceColorButton)
self.verticalLayout.addLayout(self.formLayout)
spacerItem = QtWidgets.QSpacerItem(20, 2, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
spacerItem = QtGui.QSpacerItem(20, 2, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.buttonBox = QtWidgets.QDialogButtonBox(QSpectrumAnalyzerColors)
self.buttonBox = QtGui.QDialogButtonBox(QSpectrumAnalyzerColors)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
self.verticalLayout.addWidget(self.buttonBox)
self.label_2.setBuddy(self.mainColorButton)
self.label_4.setBuddy(self.peakHoldMaxColorButton)
self.label_6.setBuddy(self.peakHoldMinColorButton)
self.label_5.setBuddy(self.averageColorButton)
self.label_3.setBuddy(self.persistenceColorButton)
self.label.setBuddy(self.baselineColorButton)
self.retranslateUi(QSpectrumAnalyzerColors)
self.buttonBox.accepted.connect(QSpectrumAnalyzerColors.accept)
self.buttonBox.rejected.connect(QSpectrumAnalyzerColors.reject)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), QSpectrumAnalyzerColors.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), QSpectrumAnalyzerColors.reject)
QtCore.QMetaObject.connectSlotsByName(QSpectrumAnalyzerColors)
QSpectrumAnalyzerColors.setTabOrder(self.mainColorButton, self.peakHoldMaxColorButton)
QSpectrumAnalyzerColors.setTabOrder(self.peakHoldMaxColorButton, self.peakHoldMinColorButton)
QSpectrumAnalyzerColors.setTabOrder(self.peakHoldMinColorButton, self.averageColorButton)
QSpectrumAnalyzerColors.setTabOrder(self.averageColorButton, self.persistenceColorButton)
QSpectrumAnalyzerColors.setTabOrder(self.persistenceColorButton, self.baselineColorButton)
QSpectrumAnalyzerColors.setTabOrder(self.persistenceColorButton, self.buttonBox)
def retranslateUi(self, QSpectrumAnalyzerColors):
_translate = QtCore.QCoreApplication.translate
QSpectrumAnalyzerColors.setWindowTitle(_translate("QSpectrumAnalyzerColors", "Colors - QSpectrumAnalyzer"))
self.label_2.setText(_translate("QSpectrumAnalyzerColors", "&Main curve color:"))
self.mainColorButton.setText(_translate("QSpectrumAnalyzerColors", "..."))
self.label_4.setText(_translate("QSpectrumAnalyzerColors", "Max. peak &hold color:"))
self.peakHoldMaxColorButton.setText(_translate("QSpectrumAnalyzerColors", "..."))
self.label_6.setText(_translate("QSpectrumAnalyzerColors", "M&in. peak hold color:"))
self.peakHoldMinColorButton.setText(_translate("QSpectrumAnalyzerColors", "..."))
self.label_5.setText(_translate("QSpectrumAnalyzerColors", "Average &color:"))
self.averageColorButton.setText(_translate("QSpectrumAnalyzerColors", "..."))
self.label_3.setText(_translate("QSpectrumAnalyzerColors", "Persistence co&lor:"))
self.persistenceColorButton.setText(_translate("QSpectrumAnalyzerColors", "..."))
self.label.setText(_translate("QSpectrumAnalyzerColors", "&Baseline color:"))
self.baselineColorButton.setText(_translate("QSpectrumAnalyzerColors", "..."))
QSpectrumAnalyzerColors.setWindowTitle(_translate("QSpectrumAnalyzerColors", "Colors - QSpectrumAnalyzer", None))
self.label_2.setText(_translate("QSpectrumAnalyzerColors", "Main curve color:", None))
self.mainColorButton.setText(_translate("QSpectrumAnalyzerColors", "...", None))
self.label_4.setText(_translate("QSpectrumAnalyzerColors", "Max. peak hold color:", None))
self.peakHoldMaxColorButton.setText(_translate("QSpectrumAnalyzerColors", "...", None))
self.label_6.setText(_translate("QSpectrumAnalyzerColors", "Min. peak hold color:", None))
self.peakHoldMinColorButton.setText(_translate("QSpectrumAnalyzerColors", "...", None))
self.label_5.setText(_translate("QSpectrumAnalyzerColors", "Average color:", None))
self.averageColorButton.setText(_translate("QSpectrumAnalyzerColors", "...", None))
self.label_3.setText(_translate("QSpectrumAnalyzerColors", "Persistence color:", None))
self.persistenceColorButton.setText(_translate("QSpectrumAnalyzerColors", "...", None))
from pyqtgraph import ColorButton

View File

@ -2,59 +2,72 @@
# Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer_persistence.ui'
#
# Created by: PyQt5 UI code generator 5.8
# Created by: PyQt4 UI code generator 4.12
#
# WARNING! All changes made in this file will be lost!
from Qt import QtCore, QtGui, QtWidgets
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_QSpectrumAnalyzerPersistence(object):
def setupUi(self, QSpectrumAnalyzerPersistence):
QSpectrumAnalyzerPersistence.setObjectName("QSpectrumAnalyzerPersistence")
QSpectrumAnalyzerPersistence.setObjectName(_fromUtf8("QSpectrumAnalyzerPersistence"))
QSpectrumAnalyzerPersistence.resize(250, 130)
self.verticalLayout = QtWidgets.QVBoxLayout(QSpectrumAnalyzerPersistence)
self.verticalLayout.setObjectName("verticalLayout")
self.formLayout = QtWidgets.QFormLayout()
self.formLayout.setObjectName("formLayout")
self.label_2 = QtWidgets.QLabel(QSpectrumAnalyzerPersistence)
self.label_2.setObjectName("label_2")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_2)
self.decayFunctionComboBox = QtWidgets.QComboBox(QSpectrumAnalyzerPersistence)
self.decayFunctionComboBox.setObjectName("decayFunctionComboBox")
self.decayFunctionComboBox.addItem("")
self.decayFunctionComboBox.addItem("")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.decayFunctionComboBox)
self.label = QtWidgets.QLabel(QSpectrumAnalyzerPersistence)
self.label.setObjectName("label")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label)
self.persistenceLengthSpinBox = QtWidgets.QSpinBox(QSpectrumAnalyzerPersistence)
self.verticalLayout = QtGui.QVBoxLayout(QSpectrumAnalyzerPersistence)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.formLayout = QtGui.QFormLayout()
self.formLayout.setObjectName(_fromUtf8("formLayout"))
self.label_2 = QtGui.QLabel(QSpectrumAnalyzerPersistence)
self.label_2.setObjectName(_fromUtf8("label_2"))
self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.label_2)
self.decayFunctionComboBox = QtGui.QComboBox(QSpectrumAnalyzerPersistence)
self.decayFunctionComboBox.setObjectName(_fromUtf8("decayFunctionComboBox"))
self.decayFunctionComboBox.addItem(_fromUtf8(""))
self.decayFunctionComboBox.addItem(_fromUtf8(""))
self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.decayFunctionComboBox)
self.label = QtGui.QLabel(QSpectrumAnalyzerPersistence)
self.label.setObjectName(_fromUtf8("label"))
self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.label)
self.persistenceLengthSpinBox = QtGui.QSpinBox(QSpectrumAnalyzerPersistence)
self.persistenceLengthSpinBox.setProperty("value", 5)
self.persistenceLengthSpinBox.setObjectName("persistenceLengthSpinBox")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.persistenceLengthSpinBox)
self.persistenceLengthSpinBox.setObjectName(_fromUtf8("persistenceLengthSpinBox"))
self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.persistenceLengthSpinBox)
self.verticalLayout.addLayout(self.formLayout)
spacerItem = QtWidgets.QSpacerItem(20, 5, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
spacerItem = QtGui.QSpacerItem(20, 5, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.buttonBox = QtWidgets.QDialogButtonBox(QSpectrumAnalyzerPersistence)
self.buttonBox = QtGui.QDialogButtonBox(QSpectrumAnalyzerPersistence)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
self.verticalLayout.addWidget(self.buttonBox)
self.label_2.setBuddy(self.decayFunctionComboBox)
self.label.setBuddy(self.persistenceLengthSpinBox)
self.retranslateUi(QSpectrumAnalyzerPersistence)
self.decayFunctionComboBox.setCurrentIndex(1)
self.buttonBox.accepted.connect(QSpectrumAnalyzerPersistence.accept)
self.buttonBox.rejected.connect(QSpectrumAnalyzerPersistence.reject)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), QSpectrumAnalyzerPersistence.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), QSpectrumAnalyzerPersistence.reject)
QtCore.QMetaObject.connectSlotsByName(QSpectrumAnalyzerPersistence)
QSpectrumAnalyzerPersistence.setTabOrder(self.decayFunctionComboBox, self.persistenceLengthSpinBox)
QSpectrumAnalyzerPersistence.setTabOrder(self.persistenceLengthSpinBox, self.buttonBox)
def retranslateUi(self, QSpectrumAnalyzerPersistence):
_translate = QtCore.QCoreApplication.translate
QSpectrumAnalyzerPersistence.setWindowTitle(_translate("QSpectrumAnalyzerPersistence", "Persistence - QSpectrumAnalyzer"))
self.label_2.setText(_translate("QSpectrumAnalyzerPersistence", "Decay function:"))
self.decayFunctionComboBox.setItemText(0, _translate("QSpectrumAnalyzerPersistence", "linear"))
self.decayFunctionComboBox.setItemText(1, _translate("QSpectrumAnalyzerPersistence", "exponential"))
self.label.setText(_translate("QSpectrumAnalyzerPersistence", "Persistence length:"))
QSpectrumAnalyzerPersistence.setWindowTitle(_translate("QSpectrumAnalyzerPersistence", "Persistence - QSpectrumAnalyzer", None))
self.label_2.setText(_translate("QSpectrumAnalyzerPersistence", "Decay function:", None))
self.decayFunctionComboBox.setItemText(0, _translate("QSpectrumAnalyzerPersistence", "linear", None))
self.decayFunctionComboBox.setItemText(1, _translate("QSpectrumAnalyzerPersistence", "exponential", None))
self.label.setText(_translate("QSpectrumAnalyzerPersistence", "Persistence length:", None))

View File

@ -2,170 +2,119 @@
# Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer_settings.ui'
#
# Created by: PyQt5 UI code generator 5.8
# Created by: PyQt4 UI code generator 4.12
#
# WARNING! All changes made in this file will be lost!
from Qt import QtCore, QtGui, QtWidgets
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_QSpectrumAnalyzerSettings(object):
def setupUi(self, QSpectrumAnalyzerSettings):
QSpectrumAnalyzerSettings.setObjectName("QSpectrumAnalyzerSettings")
QSpectrumAnalyzerSettings.resize(600, 388)
self.verticalLayout = QtWidgets.QVBoxLayout(QSpectrumAnalyzerSettings)
self.verticalLayout.setObjectName("verticalLayout")
self.formLayout = QtWidgets.QFormLayout()
self.formLayout.setObjectName("formLayout")
self.label_3 = QtWidgets.QLabel(QSpectrumAnalyzerSettings)
self.label_3.setObjectName("label_3")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_3)
self.backendComboBox = QtWidgets.QComboBox(QSpectrumAnalyzerSettings)
self.backendComboBox.setObjectName("backendComboBox")
self.backendComboBox.addItem("")
self.backendComboBox.addItem("")
self.backendComboBox.addItem("")
self.backendComboBox.addItem("")
self.backendComboBox.addItem("")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.backendComboBox)
self.label = QtWidgets.QLabel(QSpectrumAnalyzerSettings)
self.label.setObjectName("label")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label)
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.executableEdit = QtWidgets.QLineEdit(QSpectrumAnalyzerSettings)
self.executableEdit.setObjectName("executableEdit")
QSpectrumAnalyzerSettings.setObjectName(_fromUtf8("QSpectrumAnalyzerSettings"))
QSpectrumAnalyzerSettings.resize(420, 255)
self.verticalLayout = QtGui.QVBoxLayout(QSpectrumAnalyzerSettings)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.formLayout = QtGui.QFormLayout()
self.formLayout.setObjectName(_fromUtf8("formLayout"))
self.label_3 = QtGui.QLabel(QSpectrumAnalyzerSettings)
self.label_3.setObjectName(_fromUtf8("label_3"))
self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.label_3)
self.backendComboBox = QtGui.QComboBox(QSpectrumAnalyzerSettings)
self.backendComboBox.setObjectName(_fromUtf8("backendComboBox"))
self.backendComboBox.addItem(_fromUtf8(""))
self.backendComboBox.addItem(_fromUtf8(""))
self.backendComboBox.addItem(_fromUtf8(""))
self.backendComboBox.addItem(_fromUtf8(""))
self.backendComboBox.addItem(_fromUtf8(""))
self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.backendComboBox)
self.label = QtGui.QLabel(QSpectrumAnalyzerSettings)
self.label.setObjectName(_fromUtf8("label"))
self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.label)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.executableEdit = QtGui.QLineEdit(QSpectrumAnalyzerSettings)
self.executableEdit.setObjectName(_fromUtf8("executableEdit"))
self.horizontalLayout.addWidget(self.executableEdit)
self.executableButton = QtWidgets.QToolButton(QSpectrumAnalyzerSettings)
self.executableButton.setMinimumSize(QtCore.QSize(50, 0))
self.executableButton.setObjectName("executableButton")
self.executableButton = QtGui.QToolButton(QSpectrumAnalyzerSettings)
self.executableButton.setObjectName(_fromUtf8("executableButton"))
self.horizontalLayout.addWidget(self.executableButton)
self.formLayout.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout)
self.label_5 = QtWidgets.QLabel(QSpectrumAnalyzerSettings)
self.label_5.setObjectName("label_5")
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_5)
self.label_4 = QtWidgets.QLabel(QSpectrumAnalyzerSettings)
self.label_4.setObjectName("label_4")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_4)
self.label_2 = QtWidgets.QLabel(QSpectrumAnalyzerSettings)
self.label_2.setObjectName("label_2")
self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_2)
self.waterfallHistorySizeSpinBox = QtWidgets.QSpinBox(QSpectrumAnalyzerSettings)
self.formLayout.setLayout(1, QtGui.QFormLayout.FieldRole, self.horizontalLayout)
self.label_5 = QtGui.QLabel(QSpectrumAnalyzerSettings)
self.label_5.setObjectName(_fromUtf8("label_5"))
self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.label_5)
self.deviceEdit = QtGui.QLineEdit(QSpectrumAnalyzerSettings)
self.deviceEdit.setObjectName(_fromUtf8("deviceEdit"))
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.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.label_2 = QtGui.QLabel(QSpectrumAnalyzerSettings)
self.label_2.setObjectName(_fromUtf8("label_2"))
self.formLayout.setWidget(4, 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("waterfallHistorySizeSpinBox")
self.formLayout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.waterfallHistorySizeSpinBox)
self.label_7 = QtWidgets.QLabel(QSpectrumAnalyzerSettings)
self.label_7.setObjectName("label_7")
self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_7)
self.label_8 = QtWidgets.QLabel(QSpectrumAnalyzerSettings)
self.label_8.setObjectName("label_8")
self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_8)
self.label_6 = QtWidgets.QLabel(QSpectrumAnalyzerSettings)
self.label_6.setObjectName("label_6")
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_6)
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.paramsEdit = QtWidgets.QLineEdit(QSpectrumAnalyzerSettings)
self.paramsEdit.setObjectName("paramsEdit")
self.horizontalLayout_2.addWidget(self.paramsEdit)
self.paramsHelpButton = QtWidgets.QToolButton(QSpectrumAnalyzerSettings)
self.paramsHelpButton.setMinimumSize(QtCore.QSize(50, 0))
self.paramsHelpButton.setObjectName("paramsHelpButton")
self.horizontalLayout_2.addWidget(self.paramsHelpButton)
self.formLayout.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout_2)
self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.deviceEdit = QtWidgets.QLineEdit(QSpectrumAnalyzerSettings)
self.deviceEdit.setObjectName("deviceEdit")
self.horizontalLayout_3.addWidget(self.deviceEdit)
self.deviceHelpButton = QtWidgets.QToolButton(QSpectrumAnalyzerSettings)
self.deviceHelpButton.setMinimumSize(QtCore.QSize(50, 0))
self.deviceHelpButton.setObjectName("deviceHelpButton")
self.horizontalLayout_3.addWidget(self.deviceHelpButton)
self.formLayout.setLayout(3, QtWidgets.QFormLayout.FieldRole, self.horizontalLayout_3)
self.sampleRateSpinBox = QtWidgets.QDoubleSpinBox(QSpectrumAnalyzerSettings)
self.sampleRateSpinBox.setProperty("showGroupSeparator", True)
self.sampleRateSpinBox.setDecimals(3)
self.sampleRateSpinBox.setMinimum(0.0)
self.sampleRateSpinBox.setMaximum(999999.99)
self.sampleRateSpinBox.setSingleStep(0.01)
self.sampleRateSpinBox.setProperty("value", 61.44)
self.sampleRateSpinBox.setObjectName("sampleRateSpinBox")
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.sampleRateSpinBox)
self.bandwidthSpinBox = QtWidgets.QDoubleSpinBox(QSpectrumAnalyzerSettings)
self.bandwidthSpinBox.setProperty("showGroupSeparator", True)
self.bandwidthSpinBox.setDecimals(3)
self.bandwidthSpinBox.setMinimum(0.0)
self.bandwidthSpinBox.setMaximum(999999.99)
self.bandwidthSpinBox.setSingleStep(0.01)
self.bandwidthSpinBox.setProperty("value", 0.0)
self.bandwidthSpinBox.setObjectName("bandwidthSpinBox")
self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.bandwidthSpinBox)
self.lnbSpinBox = QtWidgets.QDoubleSpinBox(QSpectrumAnalyzerSettings)
self.lnbSpinBox.setProperty("showGroupSeparator", True)
self.lnbSpinBox.setDecimals(3)
self.lnbSpinBox.setMinimum(-999999.999)
self.lnbSpinBox.setMaximum(999999.999)
self.lnbSpinBox.setSingleStep(0.01)
self.lnbSpinBox.setProperty("value", 0.0)
self.lnbSpinBox.setObjectName("lnbSpinBox")
self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.lnbSpinBox)
self.waterfallHistorySizeSpinBox.setObjectName(_fromUtf8("waterfallHistorySizeSpinBox"))
self.formLayout.setWidget(4, QtGui.QFormLayout.FieldRole, self.waterfallHistorySizeSpinBox)
self.verticalLayout.addLayout(self.formLayout)
spacerItem = QtWidgets.QSpacerItem(20, 21, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
spacerItem = QtGui.QSpacerItem(20, 21, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.buttonBox = QtWidgets.QDialogButtonBox(QSpectrumAnalyzerSettings)
self.buttonBox = QtGui.QDialogButtonBox(QSpectrumAnalyzerSettings)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
self.verticalLayout.addWidget(self.buttonBox)
self.label_3.setBuddy(self.backendComboBox)
self.label.setBuddy(self.executableEdit)
self.label_5.setBuddy(self.deviceEdit)
self.label_4.setBuddy(self.sampleRateSpinBox)
self.label_2.setBuddy(self.waterfallHistorySizeSpinBox)
self.label_7.setBuddy(self.bandwidthSpinBox)
self.label_8.setBuddy(self.lnbSpinBox)
self.label_6.setBuddy(self.paramsEdit)
self.retranslateUi(QSpectrumAnalyzerSettings)
self.buttonBox.accepted.connect(QSpectrumAnalyzerSettings.accept)
self.buttonBox.rejected.connect(QSpectrumAnalyzerSettings.reject)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), QSpectrumAnalyzerSettings.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), QSpectrumAnalyzerSettings.reject)
QtCore.QMetaObject.connectSlotsByName(QSpectrumAnalyzerSettings)
QSpectrumAnalyzerSettings.setTabOrder(self.backendComboBox, self.executableEdit)
QSpectrumAnalyzerSettings.setTabOrder(self.executableEdit, self.executableButton)
QSpectrumAnalyzerSettings.setTabOrder(self.executableButton, self.paramsEdit)
QSpectrumAnalyzerSettings.setTabOrder(self.paramsEdit, self.paramsHelpButton)
QSpectrumAnalyzerSettings.setTabOrder(self.paramsHelpButton, self.deviceEdit)
QSpectrumAnalyzerSettings.setTabOrder(self.deviceEdit, self.deviceHelpButton)
QSpectrumAnalyzerSettings.setTabOrder(self.deviceHelpButton, self.sampleRateSpinBox)
QSpectrumAnalyzerSettings.setTabOrder(self.sampleRateSpinBox, self.bandwidthSpinBox)
QSpectrumAnalyzerSettings.setTabOrder(self.bandwidthSpinBox, self.lnbSpinBox)
QSpectrumAnalyzerSettings.setTabOrder(self.lnbSpinBox, self.waterfallHistorySizeSpinBox)
QSpectrumAnalyzerSettings.setTabOrder(self.executableButton, self.deviceEdit)
QSpectrumAnalyzerSettings.setTabOrder(self.deviceEdit, self.sampleRateSpinBox)
QSpectrumAnalyzerSettings.setTabOrder(self.sampleRateSpinBox, self.waterfallHistorySizeSpinBox)
QSpectrumAnalyzerSettings.setTabOrder(self.waterfallHistorySizeSpinBox, self.buttonBox)
def retranslateUi(self, QSpectrumAnalyzerSettings):
_translate = QtCore.QCoreApplication.translate
QSpectrumAnalyzerSettings.setWindowTitle(_translate("QSpectrumAnalyzerSettings", "Settings - QSpectrumAnalyzer"))
self.label_3.setText(_translate("QSpectrumAnalyzerSettings", "&Backend:"))
self.backendComboBox.setItemText(0, _translate("QSpectrumAnalyzerSettings", "soapy_power"))
self.backendComboBox.setItemText(1, _translate("QSpectrumAnalyzerSettings", "rx_power"))
self.backendComboBox.setItemText(2, _translate("QSpectrumAnalyzerSettings", "rtl_power_fftw"))
self.backendComboBox.setItemText(3, _translate("QSpectrumAnalyzerSettings", "rtl_power"))
self.backendComboBox.setItemText(4, _translate("QSpectrumAnalyzerSettings", "hackrf_sweep"))
self.label.setText(_translate("QSpectrumAnalyzerSettings", "E&xecutable:"))
self.executableEdit.setText(_translate("QSpectrumAnalyzerSettings", "soapy_power"))
self.executableButton.setText(_translate("QSpectrumAnalyzerSettings", "..."))
self.label_5.setText(_translate("QSpectrumAnalyzerSettings", "&Device:"))
self.label_4.setText(_translate("QSpectrumAnalyzerSettings", "Sa&mple rate:"))
self.label_2.setText(_translate("QSpectrumAnalyzerSettings", "&Waterfall history size:"))
self.label_7.setText(_translate("QSpectrumAnalyzerSettings", "Bandwidt&h:"))
self.label_8.setToolTip(_translate("QSpectrumAnalyzerSettings", "Negative frequency for upconverters, positive frequency for downconverters."))
self.label_8.setText(_translate("QSpectrumAnalyzerSettings", "&LNB LO:"))
self.label_6.setText(_translate("QSpectrumAnalyzerSettings", "Add&itional parameters:"))
self.paramsHelpButton.setText(_translate("QSpectrumAnalyzerSettings", " ? "))
self.deviceHelpButton.setText(_translate("QSpectrumAnalyzerSettings", " ? "))
self.sampleRateSpinBox.setSuffix(_translate("QSpectrumAnalyzerSettings", " MHz"))
self.bandwidthSpinBox.setSuffix(_translate("QSpectrumAnalyzerSettings", " MHz"))
self.lnbSpinBox.setToolTip(_translate("QSpectrumAnalyzerSettings", "Negative frequency for upconverters, positive frequency for downconverters."))
self.lnbSpinBox.setSuffix(_translate("QSpectrumAnalyzerSettings", " MHz"))
QSpectrumAnalyzerSettings.setWindowTitle(_translate("QSpectrumAnalyzerSettings", "Settings - QSpectrumAnalyzer", None))
self.label_3.setText(_translate("QSpectrumAnalyzerSettings", "&Backend:", None))
self.backendComboBox.setItemText(0, _translate("QSpectrumAnalyzerSettings", "soapy_power", None))
self.backendComboBox.setItemText(1, _translate("QSpectrumAnalyzerSettings", "rx_power", None))
self.backendComboBox.setItemText(2, _translate("QSpectrumAnalyzerSettings", "rtl_power_fftw", None))
self.backendComboBox.setItemText(3, _translate("QSpectrumAnalyzerSettings", "rtl_power", None))
self.backendComboBox.setItemText(4, _translate("QSpectrumAnalyzerSettings", "hackrf_sweep", None))
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_4.setText(_translate("QSpectrumAnalyzerSettings", "Sa&mple rate:", None))
self.label_2.setText(_translate("QSpectrumAnalyzerSettings", "&Waterfall history size:", None))

View File

@ -1,37 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer_settings_help.ui'
#
# Created by: PyQt5 UI code generator 5.8
#
# WARNING! All changes made in this file will be lost!
from Qt import QtCore, QtGui, QtWidgets
class Ui_QSpectrumAnalyzerSettingsHelp(object):
def setupUi(self, QSpectrumAnalyzerSettingsHelp):
QSpectrumAnalyzerSettingsHelp.setObjectName("QSpectrumAnalyzerSettingsHelp")
QSpectrumAnalyzerSettingsHelp.resize(1200, 700)
self.verticalLayout = QtWidgets.QVBoxLayout(QSpectrumAnalyzerSettingsHelp)
self.verticalLayout.setObjectName("verticalLayout")
self.helpTextEdit = QtWidgets.QPlainTextEdit(QSpectrumAnalyzerSettingsHelp)
self.helpTextEdit.setUndoRedoEnabled(False)
self.helpTextEdit.setTextInteractionFlags(QtCore.Qt.TextSelectableByKeyboard|QtCore.Qt.TextSelectableByMouse)
self.helpTextEdit.setObjectName("helpTextEdit")
self.verticalLayout.addWidget(self.helpTextEdit)
self.buttonBox = QtWidgets.QDialogButtonBox(QSpectrumAnalyzerSettingsHelp)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close)
self.buttonBox.setObjectName("buttonBox")
self.verticalLayout.addWidget(self.buttonBox)
self.retranslateUi(QSpectrumAnalyzerSettingsHelp)
self.buttonBox.accepted.connect(QSpectrumAnalyzerSettingsHelp.accept)
self.buttonBox.rejected.connect(QSpectrumAnalyzerSettingsHelp.reject)
QtCore.QMetaObject.connectSlotsByName(QSpectrumAnalyzerSettingsHelp)
QSpectrumAnalyzerSettingsHelp.setTabOrder(self.helpTextEdit, self.buttonBox)
def retranslateUi(self, QSpectrumAnalyzerSettingsHelp):
_translate = QtCore.QCoreApplication.translate
QSpectrumAnalyzerSettingsHelp.setWindowTitle(_translate("QSpectrumAnalyzerSettingsHelp", "Help - QSpectrumAnalyzer"))

View File

@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer_smooth.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_QSpectrumAnalyzerSmooth(object):
def setupUi(self, QSpectrumAnalyzerSmooth):
QSpectrumAnalyzerSmooth.setObjectName(_fromUtf8("QSpectrumAnalyzerSmooth"))
QSpectrumAnalyzerSmooth.resize(250, 130)
self.verticalLayout = QtGui.QVBoxLayout(QSpectrumAnalyzerSmooth)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.formLayout = QtGui.QFormLayout()
self.formLayout.setObjectName(_fromUtf8("formLayout"))
self.label = QtGui.QLabel(QSpectrumAnalyzerSmooth)
self.label.setObjectName(_fromUtf8("label"))
self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.label)
self.windowFunctionComboBox = QtGui.QComboBox(QSpectrumAnalyzerSmooth)
self.windowFunctionComboBox.setObjectName(_fromUtf8("windowFunctionComboBox"))
self.windowFunctionComboBox.addItem(_fromUtf8(""))
self.windowFunctionComboBox.addItem(_fromUtf8(""))
self.windowFunctionComboBox.addItem(_fromUtf8(""))
self.windowFunctionComboBox.addItem(_fromUtf8(""))
self.windowFunctionComboBox.addItem(_fromUtf8(""))
self.formLayout.setWidget(0, QtGui.QFormLayout.FieldRole, self.windowFunctionComboBox)
self.label_2 = QtGui.QLabel(QSpectrumAnalyzerSmooth)
self.label_2.setObjectName(_fromUtf8("label_2"))
self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.label_2)
self.windowLengthSpinBox = QtGui.QSpinBox(QSpectrumAnalyzerSmooth)
self.windowLengthSpinBox.setMinimum(3)
self.windowLengthSpinBox.setMaximum(1001)
self.windowLengthSpinBox.setProperty("value", 11)
self.windowLengthSpinBox.setObjectName(_fromUtf8("windowLengthSpinBox"))
self.formLayout.setWidget(1, QtGui.QFormLayout.FieldRole, self.windowLengthSpinBox)
self.verticalLayout.addLayout(self.formLayout)
spacerItem = QtGui.QSpacerItem(20, 1, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.buttonBox = QtGui.QDialogButtonBox(QSpectrumAnalyzerSmooth)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
self.verticalLayout.addWidget(self.buttonBox)
self.label.setBuddy(self.windowFunctionComboBox)
self.label_2.setBuddy(self.windowLengthSpinBox)
self.retranslateUi(QSpectrumAnalyzerSmooth)
self.windowFunctionComboBox.setCurrentIndex(1)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), QSpectrumAnalyzerSmooth.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), QSpectrumAnalyzerSmooth.reject)
QtCore.QMetaObject.connectSlotsByName(QSpectrumAnalyzerSmooth)
QSpectrumAnalyzerSmooth.setTabOrder(self.windowFunctionComboBox, self.windowLengthSpinBox)
QSpectrumAnalyzerSmooth.setTabOrder(self.windowLengthSpinBox, self.buttonBox)
def retranslateUi(self, QSpectrumAnalyzerSmooth):
QSpectrumAnalyzerSmooth.setWindowTitle(_translate("QSpectrumAnalyzerSmooth", "Smoothing - QSpectrumAnalyzer", None))
self.label.setText(_translate("QSpectrumAnalyzerSmooth", "&Window function:", None))
self.windowFunctionComboBox.setItemText(0, _translate("QSpectrumAnalyzerSmooth", "rectangular", None))
self.windowFunctionComboBox.setItemText(1, _translate("QSpectrumAnalyzerSmooth", "hanning", None))
self.windowFunctionComboBox.setItemText(2, _translate("QSpectrumAnalyzerSmooth", "hamming", None))
self.windowFunctionComboBox.setItemText(3, _translate("QSpectrumAnalyzerSmooth", "bartlett", None))
self.windowFunctionComboBox.setItemText(4, _translate("QSpectrumAnalyzerSmooth", "blackman", None))
self.label_2.setText(_translate("QSpectrumAnalyzerSmooth", "Window len&gth:", None))

View File

@ -1,68 +0,0 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer_smoothing.ui'
#
# Created by: PyQt5 UI code generator 5.8
#
# WARNING! All changes made in this file will be lost!
from Qt import QtCore, QtGui, QtWidgets
class Ui_QSpectrumAnalyzerSmoothing(object):
def setupUi(self, QSpectrumAnalyzerSmoothing):
QSpectrumAnalyzerSmoothing.setObjectName("QSpectrumAnalyzerSmoothing")
QSpectrumAnalyzerSmoothing.resize(250, 130)
self.verticalLayout = QtWidgets.QVBoxLayout(QSpectrumAnalyzerSmoothing)
self.verticalLayout.setObjectName("verticalLayout")
self.formLayout = QtWidgets.QFormLayout()
self.formLayout.setObjectName("formLayout")
self.label = QtWidgets.QLabel(QSpectrumAnalyzerSmoothing)
self.label.setObjectName("label")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label)
self.windowFunctionComboBox = QtWidgets.QComboBox(QSpectrumAnalyzerSmoothing)
self.windowFunctionComboBox.setObjectName("windowFunctionComboBox")
self.windowFunctionComboBox.addItem("")
self.windowFunctionComboBox.addItem("")
self.windowFunctionComboBox.addItem("")
self.windowFunctionComboBox.addItem("")
self.windowFunctionComboBox.addItem("")
self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.windowFunctionComboBox)
self.label_2 = QtWidgets.QLabel(QSpectrumAnalyzerSmoothing)
self.label_2.setObjectName("label_2")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_2)
self.windowLengthSpinBox = QtWidgets.QSpinBox(QSpectrumAnalyzerSmoothing)
self.windowLengthSpinBox.setMinimum(3)
self.windowLengthSpinBox.setMaximum(1001)
self.windowLengthSpinBox.setProperty("value", 11)
self.windowLengthSpinBox.setObjectName("windowLengthSpinBox")
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.windowLengthSpinBox)
self.verticalLayout.addLayout(self.formLayout)
spacerItem = QtWidgets.QSpacerItem(20, 1, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.buttonBox = QtWidgets.QDialogButtonBox(QSpectrumAnalyzerSmoothing)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.verticalLayout.addWidget(self.buttonBox)
self.label.setBuddy(self.windowFunctionComboBox)
self.label_2.setBuddy(self.windowLengthSpinBox)
self.retranslateUi(QSpectrumAnalyzerSmoothing)
self.windowFunctionComboBox.setCurrentIndex(1)
self.buttonBox.accepted.connect(QSpectrumAnalyzerSmoothing.accept)
self.buttonBox.rejected.connect(QSpectrumAnalyzerSmoothing.reject)
QtCore.QMetaObject.connectSlotsByName(QSpectrumAnalyzerSmoothing)
QSpectrumAnalyzerSmoothing.setTabOrder(self.windowFunctionComboBox, self.windowLengthSpinBox)
QSpectrumAnalyzerSmoothing.setTabOrder(self.windowLengthSpinBox, self.buttonBox)
def retranslateUi(self, QSpectrumAnalyzerSmoothing):
_translate = QtCore.QCoreApplication.translate
QSpectrumAnalyzerSmoothing.setWindowTitle(_translate("QSpectrumAnalyzerSmoothing", "Smoothing - QSpectrumAnalyzer"))
self.label.setText(_translate("QSpectrumAnalyzerSmoothing", "&Window function:"))
self.windowFunctionComboBox.setItemText(0, _translate("QSpectrumAnalyzerSmoothing", "rectangular"))
self.windowFunctionComboBox.setItemText(1, _translate("QSpectrumAnalyzerSmoothing", "hanning"))
self.windowFunctionComboBox.setItemText(2, _translate("QSpectrumAnalyzerSmoothing", "hamming"))
self.windowFunctionComboBox.setItemText(3, _translate("QSpectrumAnalyzerSmoothing", "bartlett"))
self.windowFunctionComboBox.setItemText(4, _translate("QSpectrumAnalyzerSmoothing", "blackman"))
self.label_2.setText(_translate("QSpectrumAnalyzerSmoothing", "Window len&gth:"))

View File

@ -1,6 +1,6 @@
import numpy as np
from Qt import QtGui
from PyQt4 import QtGui
def smooth(x, window_len=11, window='hanning'):
@ -35,19 +35,3 @@ def str_to_color(color_string):
def color_to_str(color):
"""Create comma separated RGBA string from QColor"""
return ", ".join([str(color.red()), str(color.green()), str(color.blue()), str(color.alpha())])
def human_time(seconds):
"""Format time in seconds to human readable form (e.g. 1 h 2 min 3 s)"""
seconds = int(seconds)
m, s = divmod(seconds, 60)
h, m = divmod(m, 60)
if h > 0:
timestr = '{:.0f} h {:.0f} min {:.0f} s'.format(h, m, s)
elif m > 0:
timestr = '{:.0f} min {:.0f} s'.format(m, s)
else:
timestr = '{:.0f} s'.format(s)
return timestr

View File

@ -1 +1 @@
__version__ = "2.2.0"
__version__ = "1.4.0"

View File

@ -1,51 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright © Spyder Project Contributors
# Licensed under the terms of the MIT License
# (see spyder/__init__.py for details)
"""Windows-specific utilities"""
from ctypes import windll
# --- Window control ---
SW_SHOW = 5 # activate and display
SW_SHOWNA = 8 # show without activation
SW_HIDE = 0
GetConsoleWindow = windll.kernel32.GetConsoleWindow
ShowWindow = windll.user32.ShowWindow
IsWindowVisible = windll.user32.IsWindowVisible
# Handle to console window associated with current Python
# interpreter procss, 0 if there is no window
console_window_handle = GetConsoleWindow()
def set_attached_console_visible(state):
"""Show/hide system console window attached to current process.
Return it's previous state.
Availability: Windows"""
flag = {True: SW_SHOW, False: SW_HIDE}
return bool(ShowWindow(console_window_handle, flag[state]))
def is_attached_console_visible():
"""Return True if attached console window is visible"""
return IsWindowVisible(console_window_handle)
def set_windows_appusermodelid():
"""Make sure correct icon is used on Windows 7 taskbar"""
try:
return windll.shell32.SetCurrentProcessExplicitAppUserModelID("spyder.Spyder")
except AttributeError:
return "SetCurrentProcessExplicitAppUserModelID not found"
# [ ] the console state asks for a storage container
# [ ] reopen console on exit - better die open than become a zombie

26
setup-qt.py Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env python
import os, shutil
from glob import glob
package = "qspectrumanalyzer"
languages = ["cs"]
print("Rebuilding PyQt resource files...")
for f in glob("{}/*.qrc".format(package)):
os.system("pyrcc4 -o {}/qrc_{}.py {}".format(package, os.path.basename(f[:-4]), f))
print("Rebuilding PyQt UI files...")
for f in glob("{}/*.ui".format(package)):
os.system("pyuic4 -o {}/ui_{}.py {}".format(package, os.path.basename(f[:-3]), f))
print("Updating translations...")
lang_files = " ".join("{}/languages/{}_{}.ts".format(package, package, lang) for lang in languages)
os.system("pylupdate4 {}/*.py -ts {}".format(package, lang_files))
os.system("lrelease {}/languages/*.ts".format(package))
print("Regenerating .pyc files...")
shutil.rmtree("{}/__pycache__".format(package), ignore_errors=True)
for f in glob("{}/*.pyc".format(package)):
os.remove(f)
__import__("{}.__main__".format(package))

View File

@ -1,90 +1,36 @@
#!/usr/bin/env python
import setuptools
from setuptools import setup
from qspectrumanalyzer.version import __version__
setup_cmdclass = {}
setup_entry_points = {
"gui_scripts": [
"qspectrumanalyzer=qspectrumanalyzer.__main__:main",
],
}
# Allow compilation of Qt .qrc, .ui and .ts files (build_qt command)
try:
from setup_qt import build_qt
setup_cmdclass['build_qt'] = build_qt
except ImportError:
pass
# Allow building frozen executables with PyInstaller / subzero (build_exe command)
try:
from subzero import setup, Executable
setup_entry_points = {
"console_scripts": [
Executable('qspectrumanalyzer=qspectrumanalyzer.__main__:main',
console=True, icon_file='qspectrumanalyzer.ico'),
Executable('soapy_power=soapypower.__main__:main',
console=True),
],
}
except ImportError:
pass
setup(
name="QSpectrumAnalyzer",
version=__version__,
description=("Spectrum analyzer for multiple SDR platforms "
"(PyQtGraph based GUI for soapy_power, hackrf_sweep, rtl_power, rx_power and other backends)"),
long_description=open('README.rst').read(),
description="Spectrum analyzer for RTL-SDR (GUI for rtl_power based on PyQtGraph)",
author="Michal Krenek (Mikos)",
author_email="m.krenek@gmail.com",
url="https://github.com/xmikos/qspectrumanalyzer",
license="GNU GPLv3",
packages=["qspectrumanalyzer", "qspectrumanalyzer.backends"],
packages=["qspectrumanalyzer"],
package_data={
"qspectrumanalyzer": [
"qspectrumanalyzer.svg",
"*.ui",
"languages/*.qm",
"languages/*.ts",
],
"languages/*.ts"
]
},
data_files=[
("share/applications", ["qspectrumanalyzer.desktop"]),
("share/pixmaps", ["qspectrumanalyzer.png"]),
("share/pixmaps", ["qspectrumanalyzer.png"])
],
install_requires=[
"soapy_power>=1.6.0",
"pyqtgraph>=0.10.0",
"Qt.py",
],
options={
'build_qt': {
'packages': ['qspectrumanalyzer'],
'languages': ['cs'],
'replacement_bindings': 'Qt',
},
'build_exe': {
'datas': [
('qspectrumanalyzer/qspectrumanalyzer.svg', 'qspectrumanalyzer'),
('qspectrumanalyzer/*.ui', 'qspectrumanalyzer'),
('qspectrumanalyzer/languages/*.ts', 'qspectrumanalyzer/languages'),
('qspectrumanalyzer/languages/*.qm', 'qspectrumanalyzer/languages'),
('README.rst', '.'),
('LICENSE', '.'),
],
},
'bdist_msi': {
'upgrade_code': '30740ef4-84e7-4e67-8e4a-12b53492c387',
'shortcuts': [
'QSpectrumAnalyzer=qspectrumanalyzer',
],
},
entry_points={
"gui_scripts": [
"qspectrumanalyzer=qspectrumanalyzer.__main__:main"
],
},
install_requires=[
"pyqtgraph"
],
classifiers=[
"Development Status :: 4 - Beta",
"Environment :: MacOS X",
@ -98,8 +44,6 @@ setup(
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Topic :: Communications :: Ham Radio",
"Topic :: Scientific/Engineering :: Visualization",
],
entry_points=setup_entry_points,
cmdclass=setup_cmdclass,
"Topic :: Scientific/Engineering :: Visualization"
]
)