Implemented loading and saving of broadband plots.

This commit is contained in:
jupfi 2023-12-16 11:09:28 +01:00
parent 6ea67c7f45
commit bd842b7809
5 changed files with 125 additions and 6 deletions

View file

@ -1,5 +1,6 @@
import logging
import numpy as np
import json
from PyQt6.QtCore import pyqtSlot, pyqtSignal, QTimer
from PyQt6.QtWidgets import QApplication
from nqrduck_spectrometer.measurement import Measurement
@ -192,3 +193,32 @@ class BroadbandController(ModuleController):
self.module.nqrduck_signal.emit("start_measurement", None)
self.module.model.waiting_for_tune_and_match = False
QApplication.processEvents()
def save_measurement(self, file_name : str) -> None:
"""Saves the current broadband measurement to a file.
Args:
file_name (str): Name of the file.
"""
logger.debug("Saving measurement to file: " + file_name)
self.module.view.add_info_text("Saving measurement to file: " + file_name)
QApplication.processEvents()
with open(file_name, "w") as f:
json.dump(self.module.model.current_broadband_measurement.to_json(), f)
def load_measurement(self, file_name : str) -> None:
"""Loads a broadband measurement from a file.
Args:
file_name (str): Name of the file.
"""
logger.debug("Loading measurement from file: " + file_name)
with open(file_name, "r") as f:
measurement = json.load(f)
self.module.model.current_broadband_measurement = self.module.model.BroadbandMeasurement.from_json(measurement)
self.module.view.add_info_text("Measurement loaded.")
self.module.view.on_broadband_measurement_added()
QApplication.processEvents()

View file

@ -4,10 +4,13 @@ from collections import OrderedDict
from PyQt6.QtWidgets import QApplication
from PyQt6.QtCore import pyqtSignal, QObject
from nqrduck.module.module_model import ModuleModel
from nqrduck_spectrometer.measurement import Measurement
logger = logging.getLogger(__name__)
class BroadbandModel(ModuleModel):
FILE_EXTENSION = "broad"
MIN_FREQUENCY = 30.0
MAX_FREQUENCY = 200.0
DEFAULT_FREQUENCY_STEP = 0.1
@ -168,10 +171,10 @@ class BroadbandModel(ModuleModel):
# This interpolates the y values of the lower and upper frequency step
yf_interp_lower = np.interp(offset-self.frequency_step/2 * 1e-6, [measurement.fdx[idx_xf_lower], measurement.fdx[center]],
[abs(measurement.fdy)[idx_xf_lower][0], abs(measurement.fdy)[center][0]])
[abs(measurement.fdy)[idx_xf_lower], abs(measurement.fdy)[center]])
yf_interp_upper = np.interp(offset+self.frequency_step/2 * 1e-6, [measurement.fdx[center], measurement.fdx[idx_xf_upper]],
[abs(measurement.fdy)[center][0], abs(measurement.fdy)[idx_xf_lower][0]])
[abs(measurement.fdy)[center], abs(measurement.fdy)[idx_xf_lower]])
try:
# We take the last point of the previous spectrum and the first point of the current spectrum and average them
@ -214,6 +217,34 @@ class BroadbandModel(ModuleModel):
idx = (np.abs(array - value)).argmin()
return idx
def to_json(self):
"""Converts the broadband measurement to a json-compatible format."""
return {
"single_frequency_measurements": [measurement.to_json() for measurement in self.single_frequency_measurements.values()],
"reflection": self.reflection
}
@classmethod
def from_json(cls, json):
"""Converts the json format to a broadband measurement."""
# We create a broadband measurement object with the frequencies and frequency step from the first single frequency measurement
frequencies = [measurement["target_frequency"] for measurement in json["single_frequency_measurements"]]
# We need to calculate the frequency step from the first two measurements
frequency_step = frequencies[1] - frequencies[0]
broadband_measurement = cls(frequencies, frequency_step)
# We add all of the single frequency measurements to the broadband measurement
for measurement in json["single_frequency_measurements"]:
broadband_measurement.add_measurement(Measurement.from_json(measurement))
# We assemble the broadband spectrum
broadband_measurement.assemble_broadband_spectrum()
return broadband_measurement
@property
def single_frequency_measurements(self) -> dict:
"""This property contains the dict of all frequencies that have to be measured."""

View file

@ -222,7 +222,7 @@
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,1">
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0,1,0,0">
<item>
<widget class="QLabel" name="label_9">
<property name="font">
@ -256,7 +256,7 @@
<x>0</x>
<y>0</y>
<width>271</width>
<height>639</height>
<height>559</height>
</rect>
</property>
<property name="sizePolicy">
@ -268,6 +268,20 @@
</widget>
</widget>
</item>
<item>
<widget class="QPushButton" name="exportButton">
<property name="text">
<string>Export Measurement</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="importButton">
<property name="text">
<string>Import Measurement</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>

View file

@ -2,7 +2,7 @@ import logging
from datetime import datetime
from PyQt6.QtCore import pyqtSlot, pyqtSignal, Qt
from PyQt6.QtWidgets import QWidget, QMessageBox, QApplication, QLabel, QVBoxLayout
from nqrduck.assets.icons import Logos
from nqrduck.module.module_view import ModuleView
from .widget import Ui_Form
@ -26,6 +26,16 @@ class BroadbandView(ModuleView):
self.connect_signals()
# Add logos
self._ui_form.start_measurementButton.setIcon(Logos.Play_16x16())
self._ui_form.start_measurementButton.setIconSize(self._ui_form.start_measurementButton.size())
self._ui_form.exportButton.setIcon(Logos.Save16x16())
self._ui_form.exportButton.setIconSize(self._ui_form.exportButton.size())
self._ui_form.importButton.setIcon(Logos.Load16x16())
self._ui_form.importButton.setIconSize(self._ui_form.importButton.size())
self.init_plots()
self._ui_form.scrollAreaWidgetContents.setLayout(QVBoxLayout())
@ -78,6 +88,10 @@ class BroadbandView(ModuleView):
# On deleteLUTButton clicked
self._ui_form.deleteLUTButton.clicked.connect(self.module.controller.delete_LUT)
# Save and load buttons
self._ui_form.exportButton.clicked.connect(self.on_save_button_clicked)
self._ui_form.importButton.clicked.connect(self.on_load_button_clicked)
@pyqtSlot()
def start_measurement_clicked(self) -> None:
"""This method is called when the start measurement button is clicked.
@ -102,6 +116,28 @@ class BroadbandView(ModuleView):
if choice == QMessageBox.StandardButton.Yes:
self.start_broadband_measurement.emit()
@pyqtSlot()
def on_save_button_clicked(self) -> None:
"""This method is called when the save button is clicked.
It shows a file dialog to the user to select a file to save the measurement to.
"""
logger.debug("Save button clicked.")
file_manager = self.QFileManager(self.module.model.FILE_EXTENSION, parent=self.widget)
file_name = file_manager.saveFileDialog()
if file_name:
self.module.controller.save_measurement(file_name)
@pyqtSlot()
def on_load_button_clicked(self) -> None:
"""This method is called when the load button is clicked.
It shows a file dialog to the user to select a file to load the measurement from.
"""
logger.debug("Load button clicked.")
file_manager = self.QFileManager(self.module.model.FILE_EXTENSION, parent=self.widget)
file_name = file_manager.loadFileDialog()
if file_name:
self.module.controller.load_measurement(file_name)
def init_plots(self) -> None:
"""Initialize the plots."""
# Initialization of broadband spectrum

View file

@ -139,7 +139,7 @@ class Ui_Form(object):
self.infoBox.setWidgetResizable(True)
self.infoBox.setObjectName("infoBox")
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 271, 639))
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 271, 559))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@ -148,6 +148,12 @@ class Ui_Form(object):
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
self.infoBox.setWidget(self.scrollAreaWidgetContents)
self.verticalLayout_2.addWidget(self.infoBox)
self.exportButton = QtWidgets.QPushButton(parent=Form)
self.exportButton.setObjectName("exportButton")
self.verticalLayout_2.addWidget(self.exportButton)
self.importButton = QtWidgets.QPushButton(parent=Form)
self.importButton.setObjectName("importButton")
self.verticalLayout_2.addWidget(self.importButton)
self.verticalLayout_2.setStretch(2, 1)
self.verticalLayout_3.addLayout(self.verticalLayout_2)
self.verticalLayout_3.setStretch(3, 1)
@ -208,4 +214,6 @@ class Ui_Form(object):
self.minMatchingActive.setText(_translate("Form", "Minimum Matching (dB)"))
self.deleteLUTButton.setText(_translate("Form", "Delete LUT"))
self.label_9.setText(_translate("Form", "Info Box:"))
self.exportButton.setText(_translate("Form", "Export Measurement"))
self.importButton.setText(_translate("Form", "Import Measurement"))
from nqrduck.contrib.mplwidget import MplWidget