diff --git a/qspectrumanalyzer/__main__.py b/qspectrumanalyzer/__main__.py index 5fa3c3f..4e9ad4e 100644 --- a/qspectrumanalyzer/__main__.py +++ b/qspectrumanalyzer/__main__.py @@ -14,6 +14,7 @@ from qspectrumanalyzer.ui_qspectrumanalyzer_settings import Ui_QSpectrumAnalyzer from qspectrumanalyzer.ui_qspectrumanalyzer_settings_help import Ui_QSpectrumAnalyzerSettingsHelp from qspectrumanalyzer.ui_qspectrumanalyzer_smooth import Ui_QSpectrumAnalyzerSmooth from qspectrumanalyzer.ui_qspectrumanalyzer_persistence import Ui_QSpectrumAnalyzerPersistence +from qspectrumanalyzer.ui_qspectrumanalyzer_baseline import Ui_QSpectrumAnalyzerBaseline from qspectrumanalyzer.ui_qspectrumanalyzer_colors import Ui_QSpectrumAnalyzerColors from qspectrumanalyzer.ui_qspectrumanalyzer import Ui_QSpectrumAnalyzerMainWindow @@ -223,6 +224,7 @@ class QSpectrumAnalyzerColors(QtWidgets.QDialog, Ui_QSpectrumAnalyzerColors): 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""" @@ -232,6 +234,32 @@ class QSpectrumAnalyzerColors(QtWidgets.QDialog, Ui_QSpectrumAnalyzerColors): 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) + + +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) @@ -286,7 +314,9 @@ 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) @@ -386,6 +416,8 @@ 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"): @@ -425,6 +457,8 @@ 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()) @@ -510,14 +544,6 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai 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() @@ -529,6 +555,8 @@ 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") @@ -537,21 +565,35 @@ 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=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.start() def stop(self): @@ -613,10 +655,34 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai self.data_storage.set_smooth( checked, settings.value("smooth_length", 11, int), - settings.value("smooth_window", "hanning"), - recalculate=True + settings.value("smooth_window", "hanning") ) + @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() def on_smoothButton_clicked(self): dialog = QSpectrumAnalyzerSmooth(self) @@ -625,8 +691,7 @@ class QSpectrumAnalyzerMainWindow(QtWidgets.QMainWindow, Ui_QSpectrumAnalyzerMai self.data_storage.set_smooth( bool(self.smoothCheckBox.isChecked()), settings.value("smooth_length", 11, int), - settings.value("smooth_window", "hanning"), - recalculate=True + settings.value("smooth_window", "hanning") ) @QtCore.Slot() @@ -655,6 +720,7 @@ 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() diff --git a/qspectrumanalyzer/backends/soapy_power.py b/qspectrumanalyzer/backends/soapy_power.py index 249f6b4..3707787 100644 --- a/qspectrumanalyzer/backends/soapy_power.py +++ b/qspectrumanalyzer/backends/soapy_power.py @@ -212,3 +212,43 @@ class PowerThread(BasePowerThread): 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) diff --git a/qspectrumanalyzer/data.py b/qspectrumanalyzer/data.py index 45c4676..283237a 100644 --- a/qspectrumanalyzer/data.py +++ b/qspectrumanalyzer/data.py @@ -1,9 +1,10 @@ -import time, sys +import time, sys, os from Qt import QtCore import numpy as np from qspectrumanalyzer.utils import smooth +from qspectrumanalyzer.backends import soapy_power class HistoryBuffer: @@ -59,8 +60,10 @@ 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) @@ -70,6 +73,10 @@ 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) @@ -114,6 +121,11 @@ class DataStorage(QtCore.QObject): 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) @@ -165,16 +177,63 @@ 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", recalculate=False): + def set_smooth(self, toggle, length=11, window="hanning"): """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 - if recalculate: - self.start_task(self.recalculate_data) - else: - self.reset_data() + 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) def recalculate_data(self): """Recalculate current data from history""" diff --git a/qspectrumanalyzer/languages/qspectrumanalyzer_cs.ts b/qspectrumanalyzer/languages/qspectrumanalyzer_cs.ts index 051a707..1d0dad2 100644 --- a/qspectrumanalyzer/languages/qspectrumanalyzer_cs.ts +++ b/qspectrumanalyzer/languages/qspectrumanalyzer_cs.ts @@ -1,223 +1,261 @@ + + QSpectrumAnalyzerBaseline + + + Select baseline file - QSpectrumAnalyzer + + + + + Baseline - QSpectrumAnalyzer + + + + + Baseline &file: + + + + + ... + + + QSpectrumAnalyzerColors - + Colors - QSpectrumAnalyzer - - Main curve color: - - - - + ... - - Average color: + + &Main curve color: - - Persistence color: + + Max. peak &hold color: - - Max. peak hold color: + + M&in. peak hold color: - - Min. peak hold color: + + Average &color: + + + + + Persistence co&lor: + + + + + &Baseline color: QSpectrumAnalyzerMainWindow - + QSpectrumAnalyzer - + + About - QSpectrumAnalyzer + + + + + QSpectrumAnalyzer {} + + + + + &File + + + + + &Help + + + + + &Settings... + + + + + &Quit + + + + + Ctrl+Q + + + + + &About + + + + + Frequency hops: {} + + + + + Total time: {} | Sweep time: {:.2f} s ({:.2f} FPS) + + + + + &Start + + + + + S&top + + + + + Si&ngle shot + + + + + Start: + + + + MHz - + + Stop: + + + + + &Bin size: + + + + kHz - auto - - - - - About - QSpectrumAnalyzer - - - - - QSpectrumAnalyzer {} - - - - - &File - - - - - &Help - - - - - &Start - - - - - S&top - - - - - Si&ngle shot - - - - - Start: - - - - - Stop: - - - - - Corr. [ppm]: - - - - - Crop [%]: - - - - - Main curve - - - - - Colors... - - - - - Max. hold - - - - - Min. hold - - - - - Average - - - - - Smoothing - - - - - ... - - - - - Persistence - - - - - &Settings... - - - - - &Quit - - - - - Ctrl+Q - - - - - &About - - - - - &Bin size: - - - - &Interval [s]: - + &Gain [dB]: - - Frequency hops: {} + + Corr. [ppm]: - - Sweep time: {:.2f} s | FPS: {:.2f} + + Crop [%]: - - Controls + + Main curve - - Frequency + + Colors... - - Settings + + Max. hold - - Levels + + Min. hold + + + + + Average + + + + + Smoothing + + + + + ... + + + + + Persistence + + + + + auto + + + + + &Controls + + + + + Fre&quency + + + + + Se&ttings + + + + + Subtract baseline + + + + + &Levels + + + + + Baseline @@ -252,7 +290,7 @@ QSpectrumAnalyzerSettings - + Select executable - QSpectrumAnalyzer diff --git a/qspectrumanalyzer/plot.py b/qspectrumanalyzer/plot.py index 7cce6b0..3473bb3 100644 --- a/qspectrumanalyzer/plot.py +++ b/qspectrumanalyzer/plot.py @@ -29,6 +29,8 @@ 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() @@ -45,6 +47,7 @@ class SpectrumPlotWidget: #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() @@ -81,6 +84,11 @@ 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 @@ -99,6 +107,7 @@ 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): @@ -161,6 +170,17 @@ 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: @@ -184,6 +204,7 @@ 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)) @@ -231,6 +252,10 @@ 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 @@ -308,3 +333,16 @@ 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) diff --git a/qspectrumanalyzer/qspectrumanalyzer.ui b/qspectrumanalyzer/qspectrumanalyzer.ui index 7a74e28..4587ab4 100644 --- a/qspectrumanalyzer/qspectrumanalyzer.ui +++ b/qspectrumanalyzer/qspectrumanalyzer.ui @@ -7,7 +7,7 @@ 0 0 1200 - 840 + 892 @@ -90,7 +90,7 @@ QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable - Controls + &Controls 2 @@ -143,7 +143,7 @@ - 197 + 208 166 @@ -151,7 +151,7 @@ QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable - Frequency + Fre&quency 2 @@ -311,7 +311,7 @@ QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable - Settings + Se&ttings 2 @@ -456,7 +456,7 @@ - + Qt::Vertical @@ -501,6 +501,30 @@ + + + + Baseline + + + + + + + ... + + + false + + + + + + + Subtract baseline + + + @@ -515,7 +539,7 @@ QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable - Levels + &Levels 2 @@ -581,9 +605,12 @@ smoothButton persistenceCheckBox persistenceButton + baselineCheckBox + baselineButton + subtractBaselineCheckBox histogramPlotLayout - waterfallPlotLayout mainPlotLayout + waterfallPlotLayout diff --git a/qspectrumanalyzer/qspectrumanalyzer_colors.ui b/qspectrumanalyzer/qspectrumanalyzer_colors.ui index 5802a86..f8ddfac 100644 --- a/qspectrumanalyzer/qspectrumanalyzer_colors.ui +++ b/qspectrumanalyzer/qspectrumanalyzer_colors.ui @@ -6,8 +6,8 @@ 0 0 - 232 - 260 + 253 + 266 @@ -19,7 +19,7 @@ - Main curve color: + &Main curve color: mainColorButton @@ -42,7 +42,7 @@ - Max. peak hold color: + Max. peak &hold color: peakHoldMaxColorButton @@ -65,7 +65,7 @@ - Min. peak hold color: + M&in. peak hold color: peakHoldMinColorButton @@ -88,7 +88,7 @@ - Average color: + Average &color: averageColorButton @@ -111,7 +111,7 @@ - Persistence color: + Persistence co&lor: persistenceColorButton @@ -131,6 +131,29 @@ + + + + &Baseline color: + + + baselineColorButton + + + + + + + + 0 + 0 + + + + ... + + + @@ -171,7 +194,7 @@ peakHoldMinColorButton averageColorButton persistenceColorButton - buttonBox + baselineColorButton @@ -182,12 +205,12 @@ accept() - 248 - 254 + 246 + 259 157 - 274 + 265 @@ -198,12 +221,12 @@ reject() - 316 - 260 + 246 + 259 - 286 - 274 + 252 + 265 diff --git a/qspectrumanalyzer/ui_qspectrumanalyzer.py b/qspectrumanalyzer/ui_qspectrumanalyzer.py index 7ea23e1..2a8b1ad 100644 --- a/qspectrumanalyzer/ui_qspectrumanalyzer.py +++ b/qspectrumanalyzer/ui_qspectrumanalyzer.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer.ui' # -# Created by: PyQt5 UI code generator 5.7.1 +# Created by: PyQt5 UI code generator 5.8 # # WARNING! All changes made in this file will be lost! @@ -11,7 +11,7 @@ from Qt import QtCore, QtGui, QtWidgets class Ui_QSpectrumAnalyzerMainWindow(object): def setupUi(self, QSpectrumAnalyzerMainWindow): QSpectrumAnalyzerMainWindow.setObjectName("QSpectrumAnalyzerMainWindow") - QSpectrumAnalyzerMainWindow.resize(1200, 840) + QSpectrumAnalyzerMainWindow.resize(1200, 892) self.centralwidget = QtWidgets.QWidget(QSpectrumAnalyzerMainWindow) self.centralwidget.setObjectName("centralwidget") self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget) @@ -84,7 +84,7 @@ class Ui_QSpectrumAnalyzerMainWindow(object): sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.frequencyDockWidget.sizePolicy().hasHeightForWidth()) self.frequencyDockWidget.setSizePolicy(sizePolicy) - self.frequencyDockWidget.setMinimumSize(QtCore.QSize(197, 166)) + self.frequencyDockWidget.setMinimumSize(QtCore.QSize(208, 166)) self.frequencyDockWidget.setFeatures(QtWidgets.QDockWidget.DockWidgetFloatable|QtWidgets.QDockWidget.DockWidgetMovable) self.frequencyDockWidget.setObjectName("frequencyDockWidget") self.frequencyDockWidgetContents = QtWidgets.QWidget() @@ -216,7 +216,7 @@ class Ui_QSpectrumAnalyzerMainWindow(object): self.persistenceButton.setObjectName("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, 9, 0, 1, 1) + self.gridLayout.addItem(spacerItem2, 11, 0, 1, 1) self.cropSpinBox = QtWidgets.QSpinBox(self.settingsDockWidgetContents) self.cropSpinBox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.cropSpinBox.setObjectName("cropSpinBox") @@ -230,6 +230,16 @@ class Ui_QSpectrumAnalyzerMainWindow(object): 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) @@ -295,27 +305,30 @@ 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.histogramPlotLayout) - QSpectrumAnalyzerMainWindow.setTabOrder(self.histogramPlotLayout, self.waterfallPlotLayout) - QSpectrumAnalyzerMainWindow.setTabOrder(self.waterfallPlotLayout, self.mainPlotLayout) + 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.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.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.frequencyDockWidget.setWindowTitle(_translate("QSpectrumAnalyzerMainWindow", "Fre&quency")) 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.settingsDockWidget.setWindowTitle(_translate("QSpectrumAnalyzerMainWindow", "Se&ttings")) self.label_4.setText(_translate("QSpectrumAnalyzerMainWindow", "&Interval [s]:")) self.label_6.setText(_translate("QSpectrumAnalyzerMainWindow", "&Gain [dB]:")) self.label_5.setText(_translate("QSpectrumAnalyzerMainWindow", "Corr. [ppm]:")) @@ -330,7 +343,10 @@ class Ui_QSpectrumAnalyzerMainWindow(object): self.persistenceCheckBox.setText(_translate("QSpectrumAnalyzerMainWindow", "Persistence")) self.persistenceButton.setText(_translate("QSpectrumAnalyzerMainWindow", "...")) self.gainSpinBox.setSpecialValueText(_translate("QSpectrumAnalyzerMainWindow", "auto")) - self.levelsDockWidget.setWindowTitle(_translate("QSpectrumAnalyzerMainWindow", "Levels")) + 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")) diff --git a/qspectrumanalyzer/ui_qspectrumanalyzer_colors.py b/qspectrumanalyzer/ui_qspectrumanalyzer_colors.py index 19e105f..150b303 100644 --- a/qspectrumanalyzer/ui_qspectrumanalyzer_colors.py +++ b/qspectrumanalyzer/ui_qspectrumanalyzer_colors.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer_colors.ui' # -# Created by: PyQt5 UI code generator 5.7.1 +# Created by: PyQt5 UI code generator 5.8 # # WARNING! All changes made in this file will be lost! @@ -11,7 +11,7 @@ from Qt import QtCore, QtGui, QtWidgets class Ui_QSpectrumAnalyzerColors(object): def setupUi(self, QSpectrumAnalyzerColors): QSpectrumAnalyzerColors.setObjectName("QSpectrumAnalyzerColors") - QSpectrumAnalyzerColors.resize(232, 260) + QSpectrumAnalyzerColors.resize(253, 266) self.verticalLayout = QtWidgets.QVBoxLayout(QSpectrumAnalyzerColors) self.verticalLayout.setObjectName("verticalLayout") self.formLayout = QtWidgets.QFormLayout() @@ -71,6 +71,17 @@ class Ui_QSpectrumAnalyzerColors(object): 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.verticalLayout.addLayout(self.formLayout) spacerItem = QtWidgets.QSpacerItem(20, 2, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.verticalLayout.addItem(spacerItem) @@ -84,6 +95,7 @@ class Ui_QSpectrumAnalyzerColors(object): 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) @@ -93,20 +105,22 @@ class Ui_QSpectrumAnalyzerColors(object): QSpectrumAnalyzerColors.setTabOrder(self.peakHoldMaxColorButton, self.peakHoldMinColorButton) QSpectrumAnalyzerColors.setTabOrder(self.peakHoldMinColorButton, self.averageColorButton) QSpectrumAnalyzerColors.setTabOrder(self.averageColorButton, self.persistenceColorButton) - QSpectrumAnalyzerColors.setTabOrder(self.persistenceColorButton, self.buttonBox) + QSpectrumAnalyzerColors.setTabOrder(self.persistenceColorButton, self.baselineColorButton) def retranslateUi(self, QSpectrumAnalyzerColors): _translate = QtCore.QCoreApplication.translate QSpectrumAnalyzerColors.setWindowTitle(_translate("QSpectrumAnalyzerColors", "Colors - QSpectrumAnalyzer")) - self.label_2.setText(_translate("QSpectrumAnalyzerColors", "Main curve color:")) + 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.label_4.setText(_translate("QSpectrumAnalyzerColors", "Max. peak &hold color:")) self.peakHoldMaxColorButton.setText(_translate("QSpectrumAnalyzerColors", "...")) - self.label_6.setText(_translate("QSpectrumAnalyzerColors", "Min. peak hold color:")) + 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.label_5.setText(_translate("QSpectrumAnalyzerColors", "Average &color:")) self.averageColorButton.setText(_translate("QSpectrumAnalyzerColors", "...")) - self.label_3.setText(_translate("QSpectrumAnalyzerColors", "Persistence color:")) + 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", "...")) from pyqtgraph import ColorButton diff --git a/qspectrumanalyzer/ui_qspectrumanalyzer_persistence.py b/qspectrumanalyzer/ui_qspectrumanalyzer_persistence.py index 4fa0557..02ee4ee 100644 --- a/qspectrumanalyzer/ui_qspectrumanalyzer_persistence.py +++ b/qspectrumanalyzer/ui_qspectrumanalyzer_persistence.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer_persistence.ui' # -# Created by: PyQt5 UI code generator 5.7.1 +# Created by: PyQt5 UI code generator 5.8 # # WARNING! All changes made in this file will be lost! diff --git a/qspectrumanalyzer/ui_qspectrumanalyzer_settings.py b/qspectrumanalyzer/ui_qspectrumanalyzer_settings.py index 292f21b..e6773a5 100644 --- a/qspectrumanalyzer/ui_qspectrumanalyzer_settings.py +++ b/qspectrumanalyzer/ui_qspectrumanalyzer_settings.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer_settings.ui' # -# Created by: PyQt5 UI code generator 5.7.1 +# Created by: PyQt5 UI code generator 5.8 # # WARNING! All changes made in this file will be lost! diff --git a/qspectrumanalyzer/ui_qspectrumanalyzer_settings_help.py b/qspectrumanalyzer/ui_qspectrumanalyzer_settings_help.py index 6f383c8..06b59cf 100644 --- a/qspectrumanalyzer/ui_qspectrumanalyzer_settings_help.py +++ b/qspectrumanalyzer/ui_qspectrumanalyzer_settings_help.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer_settings_help.ui' # -# Created by: PyQt5 UI code generator 5.7.1 +# Created by: PyQt5 UI code generator 5.8 # # WARNING! All changes made in this file will be lost! diff --git a/qspectrumanalyzer/ui_qspectrumanalyzer_smooth.py b/qspectrumanalyzer/ui_qspectrumanalyzer_smooth.py index 0f26555..fc4f597 100644 --- a/qspectrumanalyzer/ui_qspectrumanalyzer_smooth.py +++ b/qspectrumanalyzer/ui_qspectrumanalyzer_smooth.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'qspectrumanalyzer/qspectrumanalyzer_smooth.ui' # -# Created by: PyQt5 UI code generator 5.7.1 +# Created by: PyQt5 UI code generator 5.8 # # WARNING! All changes made in this file will be lost!