2020-06-15 07:52:32 +00:00
|
|
|
# NanoVNASaver
|
2020-06-25 17:52:30 +00:00
|
|
|
#
|
2020-06-15 07:52:32 +00:00
|
|
|
# A python program to view and export Touchstone data from a NanoVNA
|
2020-06-25 17:52:30 +00:00
|
|
|
# Copyright (C) 2019, 2020 Rune B. Broberg
|
2021-06-30 05:21:14 +00:00
|
|
|
# Copyright (C) 2020,2021 NanoVNA-Saver Authors
|
2019-09-03 13:36:42 +00:00
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2019-09-04 16:12:38 +00:00
|
|
|
|
2019-09-18 11:45:53 +00:00
|
|
|
import logging
|
2020-06-24 21:54:59 +00:00
|
|
|
from functools import partial
|
2019-09-08 17:11:48 +00:00
|
|
|
|
2019-09-21 11:13:33 +00:00
|
|
|
from PyQt5 import QtWidgets, QtCore
|
2019-11-20 15:56:09 +00:00
|
|
|
|
2020-06-15 07:52:32 +00:00
|
|
|
from NanoVNASaver.Calibration import Calibration
|
2020-07-29 15:36:07 +00:00
|
|
|
from NanoVNASaver.Settings.Sweep import SweepMode
|
2019-09-03 13:36:42 +00:00
|
|
|
|
2019-09-18 11:45:53 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2020-06-30 10:04:50 +00:00
|
|
|
def _format_cal_label(size: int, prefix: str = "Set") -> str:
|
|
|
|
return f"{prefix} ({size} points)"
|
2020-06-24 13:02:15 +00:00
|
|
|
|
|
|
|
|
2019-09-03 13:36:42 +00:00
|
|
|
class CalibrationWindow(QtWidgets.QWidget):
|
2019-09-27 10:03:45 +00:00
|
|
|
nextStep = -1
|
|
|
|
|
2020-06-15 07:42:16 +00:00
|
|
|
def __init__(self, app: QtWidgets.QWidget):
|
2019-09-03 13:36:42 +00:00
|
|
|
super().__init__()
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app = app
|
2019-10-11 17:13:46 +00:00
|
|
|
|
2019-11-02 09:42:44 +00:00
|
|
|
self.setMinimumWidth(450)
|
2019-09-03 13:36:42 +00:00
|
|
|
self.setWindowTitle("Calibration")
|
2019-10-02 08:07:38 +00:00
|
|
|
self.setWindowIcon(self.app.icon)
|
2020-06-15 07:42:16 +00:00
|
|
|
self.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding,
|
|
|
|
QtWidgets.QSizePolicy.MinimumExpanding)
|
2019-09-21 11:13:33 +00:00
|
|
|
|
2020-06-15 07:42:16 +00:00
|
|
|
QtWidgets.QShortcut(QtCore.Qt.Key_Escape, self, self.hide)
|
2019-09-21 11:13:33 +00:00
|
|
|
|
2019-09-08 17:11:48 +00:00
|
|
|
top_layout = QtWidgets.QHBoxLayout()
|
|
|
|
left_layout = QtWidgets.QVBoxLayout()
|
|
|
|
right_layout = QtWidgets.QVBoxLayout()
|
|
|
|
top_layout.addLayout(left_layout)
|
|
|
|
top_layout.addLayout(right_layout)
|
|
|
|
self.setLayout(top_layout)
|
2019-09-03 13:36:42 +00:00
|
|
|
|
|
|
|
calibration_status_group = QtWidgets.QGroupBox("Active calibration")
|
|
|
|
calibration_status_layout = QtWidgets.QFormLayout()
|
|
|
|
self.calibration_status_label = QtWidgets.QLabel("Device calibration")
|
2019-11-02 09:42:44 +00:00
|
|
|
self.calibration_source_label = QtWidgets.QLabel("NanoVNA")
|
|
|
|
calibration_status_layout.addRow("Calibration:", self.calibration_status_label)
|
|
|
|
calibration_status_layout.addRow("Source:", self.calibration_source_label)
|
2019-09-03 13:36:42 +00:00
|
|
|
calibration_status_group.setLayout(calibration_status_layout)
|
2019-09-08 17:11:48 +00:00
|
|
|
left_layout.addWidget(calibration_status_group)
|
2019-09-03 13:36:42 +00:00
|
|
|
|
|
|
|
calibration_control_group = QtWidgets.QGroupBox("Calibrate")
|
|
|
|
calibration_control_layout = QtWidgets.QFormLayout(calibration_control_group)
|
2020-06-24 13:02:15 +00:00
|
|
|
cal_btn = {}
|
|
|
|
self.cal_label = {}
|
2020-06-24 20:34:02 +00:00
|
|
|
for label_name in Calibration.CAL_NAMES:
|
2020-06-24 13:02:15 +00:00
|
|
|
self.cal_label[label_name] = QtWidgets.QLabel("Uncalibrated")
|
|
|
|
cal_btn[label_name] = QtWidgets.QPushButton(
|
|
|
|
label_name.capitalize())
|
2021-06-29 19:42:31 +00:00
|
|
|
cal_btn[label_name].setMinimumHeight(20)
|
2020-06-24 21:54:59 +00:00
|
|
|
cal_btn[label_name].clicked.connect(partial(self.manual_save, label_name))
|
2020-06-24 13:02:15 +00:00
|
|
|
calibration_control_layout.addRow(
|
|
|
|
cal_btn[label_name], self.cal_label[label_name])
|
2019-09-03 13:36:42 +00:00
|
|
|
|
2019-11-20 14:02:03 +00:00
|
|
|
self.input_offset_delay = QtWidgets.QDoubleSpinBox()
|
2021-06-29 19:42:31 +00:00
|
|
|
self.input_offset_delay.setMinimumHeight(20)
|
2019-11-20 14:02:03 +00:00
|
|
|
self.input_offset_delay.setValue(0)
|
|
|
|
self.input_offset_delay.setSuffix(" ps")
|
|
|
|
self.input_offset_delay.setAlignment(QtCore.Qt.AlignRight)
|
|
|
|
self.input_offset_delay.valueChanged.connect(self.setOffsetDelay)
|
|
|
|
self.input_offset_delay.setRange(-10e6, 10e6)
|
|
|
|
|
2019-09-03 17:12:27 +00:00
|
|
|
calibration_control_layout.addRow(QtWidgets.QLabel(""))
|
2019-11-20 14:02:03 +00:00
|
|
|
calibration_control_layout.addRow("Offset delay", self.input_offset_delay)
|
2019-09-03 13:36:42 +00:00
|
|
|
|
2019-09-27 10:03:45 +00:00
|
|
|
self.btn_automatic = QtWidgets.QPushButton("Calibration assistant")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.btn_automatic.setMinimumHeight(20)
|
2019-09-27 10:03:45 +00:00
|
|
|
calibration_control_layout.addRow(self.btn_automatic)
|
|
|
|
self.btn_automatic.clicked.connect(self.automaticCalibration)
|
|
|
|
|
2019-11-04 15:56:31 +00:00
|
|
|
apply_reset_layout = QtWidgets.QHBoxLayout()
|
|
|
|
|
2019-09-03 17:12:27 +00:00
|
|
|
btn_apply = QtWidgets.QPushButton("Apply")
|
2021-06-29 19:42:31 +00:00
|
|
|
btn_apply.setMinimumHeight(20)
|
2019-09-03 17:12:27 +00:00
|
|
|
btn_apply.clicked.connect(self.calculate)
|
|
|
|
|
|
|
|
btn_reset = QtWidgets.QPushButton("Reset")
|
2021-06-29 19:42:31 +00:00
|
|
|
btn_reset.setMinimumHeight(20)
|
2019-09-03 17:12:27 +00:00
|
|
|
btn_reset.clicked.connect(self.reset)
|
2019-09-03 13:36:42 +00:00
|
|
|
|
2019-11-04 15:56:31 +00:00
|
|
|
apply_reset_layout.addWidget(btn_apply)
|
|
|
|
apply_reset_layout.addWidget(btn_reset)
|
|
|
|
|
|
|
|
calibration_control_layout.addRow(apply_reset_layout)
|
|
|
|
|
2019-09-08 17:11:48 +00:00
|
|
|
left_layout.addWidget(calibration_control_group)
|
2019-09-03 13:36:42 +00:00
|
|
|
|
2019-09-30 11:46:15 +00:00
|
|
|
calibration_notes_group = QtWidgets.QGroupBox("Notes")
|
|
|
|
calibration_notes_layout = QtWidgets.QVBoxLayout(calibration_notes_group)
|
|
|
|
self.notes_textedit = QtWidgets.QPlainTextEdit()
|
|
|
|
calibration_notes_layout.addWidget(self.notes_textedit)
|
|
|
|
|
|
|
|
left_layout.addWidget(calibration_notes_group)
|
|
|
|
|
|
|
|
file_box = QtWidgets.QGroupBox("Files")
|
2019-09-04 18:17:21 +00:00
|
|
|
file_layout = QtWidgets.QFormLayout(file_box)
|
|
|
|
btn_save_file = QtWidgets.QPushButton("Save calibration")
|
2021-06-29 19:42:31 +00:00
|
|
|
btn_save_file.setMinimumHeight(20)
|
2019-09-30 11:46:15 +00:00
|
|
|
btn_save_file.clicked.connect(lambda: self.saveCalibration())
|
2019-09-04 18:17:21 +00:00
|
|
|
btn_load_file = QtWidgets.QPushButton("Load calibration")
|
2021-06-29 19:42:31 +00:00
|
|
|
btn_load_file.setMinimumHeight(20)
|
2019-09-30 11:46:15 +00:00
|
|
|
btn_load_file.clicked.connect(lambda: self.loadCalibration())
|
2019-11-04 15:56:31 +00:00
|
|
|
|
|
|
|
save_load_layout = QtWidgets.QHBoxLayout()
|
|
|
|
save_load_layout.addWidget(btn_save_file)
|
|
|
|
save_load_layout.addWidget(btn_load_file)
|
|
|
|
|
|
|
|
file_layout.addRow(save_load_layout)
|
2019-09-04 18:17:21 +00:00
|
|
|
|
2019-09-08 17:11:48 +00:00
|
|
|
left_layout.addWidget(file_box)
|
|
|
|
|
|
|
|
cal_standard_box = QtWidgets.QGroupBox("Calibration standards")
|
|
|
|
cal_standard_layout = QtWidgets.QFormLayout(cal_standard_box)
|
|
|
|
self.use_ideal_values = QtWidgets.QCheckBox("Use ideal values")
|
|
|
|
self.use_ideal_values.setChecked(True)
|
|
|
|
self.use_ideal_values.stateChanged.connect(self.idealCheckboxChanged)
|
|
|
|
cal_standard_layout.addRow(self.use_ideal_values)
|
|
|
|
|
|
|
|
self.cal_short_box = QtWidgets.QGroupBox("Short")
|
|
|
|
cal_short_form = QtWidgets.QFormLayout(self.cal_short_box)
|
|
|
|
self.cal_short_box.setDisabled(True)
|
|
|
|
self.short_l0_input = QtWidgets.QLineEdit("0")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.short_l0_input.setMinimumHeight(20)
|
2019-09-08 17:11:48 +00:00
|
|
|
self.short_l1_input = QtWidgets.QLineEdit("0")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.short_l1_input.setMinimumHeight(20)
|
2019-09-08 17:11:48 +00:00
|
|
|
self.short_l2_input = QtWidgets.QLineEdit("0")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.short_l2_input.setMinimumHeight(20)
|
2019-09-08 17:11:48 +00:00
|
|
|
self.short_l3_input = QtWidgets.QLineEdit("0")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.short_l3_input.setMinimumHeight(20)
|
2019-09-08 17:11:48 +00:00
|
|
|
self.short_length = QtWidgets.QLineEdit("0")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.short_length.setMinimumHeight(20)
|
2019-10-16 07:39:40 +00:00
|
|
|
cal_short_form.addRow("L0 (H(e-12))", self.short_l0_input)
|
|
|
|
cal_short_form.addRow("L1 (H(e-24))", self.short_l1_input)
|
|
|
|
cal_short_form.addRow("L2 (H(e-33))", self.short_l2_input)
|
|
|
|
cal_short_form.addRow("L3 (H(e-42))", self.short_l3_input)
|
2019-10-01 09:19:26 +00:00
|
|
|
cal_short_form.addRow("Offset Delay (ps)", self.short_length)
|
2019-09-08 17:11:48 +00:00
|
|
|
|
|
|
|
self.cal_open_box = QtWidgets.QGroupBox("Open")
|
|
|
|
cal_open_form = QtWidgets.QFormLayout(self.cal_open_box)
|
|
|
|
self.cal_open_box.setDisabled(True)
|
|
|
|
self.open_c0_input = QtWidgets.QLineEdit("50")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.open_c0_input.setMinimumHeight(20)
|
2019-09-08 17:11:48 +00:00
|
|
|
self.open_c1_input = QtWidgets.QLineEdit("0")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.open_c1_input.setMinimumHeight(20)
|
2019-09-08 17:11:48 +00:00
|
|
|
self.open_c2_input = QtWidgets.QLineEdit("0")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.open_c2_input.setMinimumHeight(20)
|
2019-09-08 17:11:48 +00:00
|
|
|
self.open_c3_input = QtWidgets.QLineEdit("0")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.open_c3_input.setMinimumHeight(20)
|
2019-09-08 17:11:48 +00:00
|
|
|
self.open_length = QtWidgets.QLineEdit("0")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.open_length.setMinimumHeight(20)
|
2019-10-16 07:39:40 +00:00
|
|
|
cal_open_form.addRow("C0 (F(e-15))", self.open_c0_input)
|
|
|
|
cal_open_form.addRow("C1 (F(e-27))", self.open_c1_input)
|
|
|
|
cal_open_form.addRow("C2 (F(e-36))", self.open_c2_input)
|
|
|
|
cal_open_form.addRow("C3 (F(e-45))", self.open_c3_input)
|
2019-10-01 09:19:26 +00:00
|
|
|
cal_open_form.addRow("Offset Delay (ps)", self.open_length)
|
2019-09-08 17:11:48 +00:00
|
|
|
|
|
|
|
self.cal_load_box = QtWidgets.QGroupBox("Load")
|
|
|
|
cal_load_form = QtWidgets.QFormLayout(self.cal_load_box)
|
|
|
|
self.cal_load_box.setDisabled(True)
|
|
|
|
self.load_resistance = QtWidgets.QLineEdit("50")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.load_resistance.setMinimumHeight(20)
|
2019-09-08 17:11:48 +00:00
|
|
|
self.load_inductance = QtWidgets.QLineEdit("0")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.load_inductance.setMinimumHeight(20)
|
2022-01-03 16:42:17 +00:00
|
|
|
self.load_capacitance = QtWidgets.QLineEdit("0")
|
|
|
|
self.load_capacitance.setMinimumHeight(20)
|
2022-05-27 07:03:37 +00:00
|
|
|
# self.load_capacitance.setDisabled(True) # Not yet implemented
|
2019-09-30 11:46:15 +00:00
|
|
|
self.load_length = QtWidgets.QLineEdit("0")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.load_length.setMinimumHeight(20)
|
2019-09-08 17:11:48 +00:00
|
|
|
cal_load_form.addRow("Resistance (\N{OHM SIGN})", self.load_resistance)
|
2019-09-30 11:46:15 +00:00
|
|
|
cal_load_form.addRow("Inductance (H(e-12))", self.load_inductance)
|
2022-01-03 16:42:17 +00:00
|
|
|
cal_load_form.addRow("Capacitance (F(e-15))", self.load_capacitance)
|
2019-10-01 09:19:26 +00:00
|
|
|
cal_load_form.addRow("Offset Delay (ps)", self.load_length)
|
2019-09-30 11:46:15 +00:00
|
|
|
|
|
|
|
self.cal_through_box = QtWidgets.QGroupBox("Through")
|
|
|
|
cal_through_form = QtWidgets.QFormLayout(self.cal_through_box)
|
|
|
|
self.cal_through_box.setDisabled(True)
|
|
|
|
self.through_length = QtWidgets.QLineEdit("0")
|
2021-06-29 19:42:31 +00:00
|
|
|
self.through_length.setMinimumHeight(20)
|
2019-10-01 09:19:26 +00:00
|
|
|
cal_through_form.addRow("Offset Delay (ps)", self.through_length)
|
2020-06-15 07:42:16 +00:00
|
|
|
|
2019-09-08 17:11:48 +00:00
|
|
|
cal_standard_layout.addWidget(self.cal_short_box)
|
|
|
|
cal_standard_layout.addWidget(self.cal_open_box)
|
|
|
|
cal_standard_layout.addWidget(self.cal_load_box)
|
2019-09-30 11:46:15 +00:00
|
|
|
cal_standard_layout.addWidget(self.cal_through_box)
|
2019-09-30 20:20:35 +00:00
|
|
|
|
|
|
|
self.cal_standard_save_box = QtWidgets.QGroupBox("Saved settings")
|
|
|
|
cal_standard_save_layout = QtWidgets.QVBoxLayout(self.cal_standard_save_box)
|
|
|
|
self.cal_standard_save_box.setDisabled(True)
|
|
|
|
|
|
|
|
self.cal_standard_save_selector = QtWidgets.QComboBox()
|
2021-06-29 19:42:31 +00:00
|
|
|
self.cal_standard_save_selector.setMinimumHeight(20)
|
2019-09-30 20:20:35 +00:00
|
|
|
self.listCalibrationStandards()
|
|
|
|
cal_standard_save_layout.addWidget(self.cal_standard_save_selector)
|
|
|
|
cal_standard_save_button_layout = QtWidgets.QHBoxLayout()
|
|
|
|
btn_save_standard = QtWidgets.QPushButton("Save")
|
2021-06-29 19:42:31 +00:00
|
|
|
btn_save_standard.setMinimumHeight(20)
|
2019-09-30 20:20:35 +00:00
|
|
|
btn_save_standard.clicked.connect(self.saveCalibrationStandard)
|
|
|
|
btn_load_standard = QtWidgets.QPushButton("Load")
|
2021-06-29 19:42:31 +00:00
|
|
|
btn_load_standard.setMinimumHeight(20)
|
2019-09-30 20:20:35 +00:00
|
|
|
btn_load_standard.clicked.connect(self.loadCalibrationStandard)
|
|
|
|
btn_delete_standard = QtWidgets.QPushButton("Delete")
|
2021-06-29 19:42:31 +00:00
|
|
|
btn_delete_standard.setMinimumHeight(20)
|
2019-09-30 20:20:35 +00:00
|
|
|
btn_delete_standard.clicked.connect(self.deleteCalibrationStandard)
|
|
|
|
cal_standard_save_button_layout.addWidget(btn_load_standard)
|
|
|
|
cal_standard_save_button_layout.addWidget(btn_save_standard)
|
|
|
|
cal_standard_save_button_layout.addWidget(btn_delete_standard)
|
|
|
|
cal_standard_save_layout.addLayout(cal_standard_save_button_layout)
|
|
|
|
|
|
|
|
cal_standard_layout.addWidget(self.cal_standard_save_box)
|
2019-09-08 17:11:48 +00:00
|
|
|
right_layout.addWidget(cal_standard_box)
|
2019-09-04 18:17:21 +00:00
|
|
|
|
2019-11-22 12:54:14 +00:00
|
|
|
def checkExpertUser(self):
|
|
|
|
if not self.app.settings.value("ExpertCalibrationUser", False, bool):
|
2020-06-15 07:42:16 +00:00
|
|
|
response = QtWidgets.QMessageBox.question(
|
|
|
|
self, "Are you sure?",
|
|
|
|
"Use of the manual calibration buttons " +
|
|
|
|
"is non-intuitive, and primarily suited for users with very " +
|
|
|
|
"specialized needs. The buttons do not sweep for you, nor do " +
|
|
|
|
"they interact with the NanoVNA calibration.\n\n" +
|
|
|
|
"If you are trying to do a calibration of the NanoVNA, do so " +
|
|
|
|
"on the device itself instead. If you are trying to do a " +
|
|
|
|
"calibration with NanoVNA-Saver, use the Calibration Assistant " +
|
|
|
|
"if possible.\n\n" +
|
|
|
|
"If you are certain you know what you are doing, click Yes.",
|
|
|
|
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Cancel,
|
|
|
|
QtWidgets.QMessageBox.Cancel)
|
2019-11-22 12:54:14 +00:00
|
|
|
|
|
|
|
if response == QtWidgets.QMessageBox.Yes:
|
|
|
|
self.app.settings.setValue("ExpertCalibrationUser", True)
|
|
|
|
return True
|
2020-06-15 11:27:00 +00:00
|
|
|
return False
|
|
|
|
return True
|
2019-11-22 12:54:14 +00:00
|
|
|
|
2020-06-29 16:46:15 +00:00
|
|
|
def cal_save(self, name: str):
|
|
|
|
if name in ("through", "isolation"):
|
2021-06-22 20:07:36 +00:00
|
|
|
self.app.calibration.insert(name, self.app.data.s21)
|
2020-06-29 16:46:15 +00:00
|
|
|
else:
|
2021-06-22 20:07:36 +00:00
|
|
|
self.app.calibration.insert(name, self.app.data.s11)
|
2020-06-24 13:02:15 +00:00
|
|
|
self.cal_label[name].setText(
|
2021-06-22 20:07:36 +00:00
|
|
|
_format_cal_label(len(self.app.data.s11)))
|
2019-09-03 13:36:42 +00:00
|
|
|
|
2020-06-29 16:46:15 +00:00
|
|
|
def manual_save(self, name: str):
|
2019-11-22 12:54:14 +00:00
|
|
|
if self.checkExpertUser():
|
2020-06-24 13:02:15 +00:00
|
|
|
self.cal_save(name)
|
2019-09-03 13:36:42 +00:00
|
|
|
|
2019-09-30 20:20:35 +00:00
|
|
|
def listCalibrationStandards(self):
|
|
|
|
self.cal_standard_save_selector.clear()
|
|
|
|
num_standards = self.app.settings.beginReadArray("CalibrationStandards")
|
|
|
|
for i in range(num_standards):
|
|
|
|
self.app.settings.setArrayIndex(i)
|
|
|
|
name = self.app.settings.value("Name", defaultValue="INVALID NAME")
|
|
|
|
self.cal_standard_save_selector.addItem(name, userData=i)
|
|
|
|
self.app.settings.endArray()
|
|
|
|
self.cal_standard_save_selector.addItem("New", userData=-1)
|
|
|
|
self.cal_standard_save_selector.setCurrentText("New")
|
|
|
|
|
|
|
|
def saveCalibrationStandard(self):
|
2019-10-01 09:19:26 +00:00
|
|
|
num_standards = self.app.settings.beginReadArray("CalibrationStandards")
|
|
|
|
self.app.settings.endArray()
|
|
|
|
|
2019-09-30 20:20:35 +00:00
|
|
|
if self.cal_standard_save_selector.currentData() == -1:
|
|
|
|
# New cal standard
|
|
|
|
# Get a name
|
2020-06-15 07:42:16 +00:00
|
|
|
name, selected = QtWidgets.QInputDialog.getText(
|
|
|
|
self, "Calibration standard name", "Enter name to save as")
|
2019-09-30 20:20:35 +00:00
|
|
|
if not selected or not name:
|
|
|
|
return
|
|
|
|
write_num = num_standards
|
|
|
|
num_standards += 1
|
|
|
|
else:
|
|
|
|
write_num = self.cal_standard_save_selector.currentData()
|
|
|
|
name = self.cal_standard_save_selector.currentText()
|
|
|
|
|
|
|
|
self.app.settings.beginWriteArray("CalibrationStandards", num_standards)
|
|
|
|
self.app.settings.setArrayIndex(write_num)
|
|
|
|
self.app.settings.setValue("Name", name)
|
|
|
|
|
|
|
|
self.app.settings.setValue("ShortL0", self.short_l0_input.text())
|
|
|
|
self.app.settings.setValue("ShortL1", self.short_l1_input.text())
|
|
|
|
self.app.settings.setValue("ShortL2", self.short_l2_input.text())
|
|
|
|
self.app.settings.setValue("ShortL3", self.short_l3_input.text())
|
|
|
|
self.app.settings.setValue("ShortDelay", self.short_length.text())
|
|
|
|
|
|
|
|
self.app.settings.setValue("OpenC0", self.open_c0_input.text())
|
|
|
|
self.app.settings.setValue("OpenC1", self.open_c1_input.text())
|
|
|
|
self.app.settings.setValue("OpenC2", self.open_c2_input.text())
|
|
|
|
self.app.settings.setValue("OpenC3", self.open_c3_input.text())
|
|
|
|
self.app.settings.setValue("OpenDelay", self.open_length.text())
|
|
|
|
|
|
|
|
self.app.settings.setValue("LoadR", self.load_resistance.text())
|
|
|
|
self.app.settings.setValue("LoadL", self.load_inductance.text())
|
2022-01-03 16:42:17 +00:00
|
|
|
self.app.settings.setValue("LoadC", self.load_capacitance.text())
|
2019-09-30 20:20:35 +00:00
|
|
|
self.app.settings.setValue("LoadDelay", self.load_length.text())
|
|
|
|
|
|
|
|
self.app.settings.setValue("ThroughDelay", self.through_length.text())
|
|
|
|
|
|
|
|
self.app.settings.endArray()
|
|
|
|
self.app.settings.sync()
|
|
|
|
self.listCalibrationStandards()
|
|
|
|
self.cal_standard_save_selector.setCurrentText(name)
|
|
|
|
|
|
|
|
def loadCalibrationStandard(self):
|
|
|
|
if self.cal_standard_save_selector.currentData() == -1:
|
|
|
|
return
|
|
|
|
read_num = self.cal_standard_save_selector.currentData()
|
|
|
|
logger.debug("Loading calibration no %d", read_num)
|
|
|
|
self.app.settings.beginReadArray("CalibrationStandards")
|
|
|
|
self.app.settings.setArrayIndex(read_num)
|
|
|
|
|
|
|
|
name = self.app.settings.value("Name")
|
|
|
|
logger.info("Loading: %s", name)
|
|
|
|
|
|
|
|
self.short_l0_input.setText(str(self.app.settings.value("ShortL0", 0)))
|
|
|
|
self.short_l1_input.setText(str(self.app.settings.value("ShortL1", 0)))
|
|
|
|
self.short_l2_input.setText(str(self.app.settings.value("ShortL2", 0)))
|
|
|
|
self.short_l3_input.setText(str(self.app.settings.value("ShortL3", 0)))
|
|
|
|
self.short_length.setText(str(self.app.settings.value("ShortDelay", 0)))
|
|
|
|
|
|
|
|
self.open_c0_input.setText(str(self.app.settings.value("OpenC0", 50)))
|
|
|
|
self.open_c1_input.setText(str(self.app.settings.value("OpenC1", 0)))
|
|
|
|
self.open_c2_input.setText(str(self.app.settings.value("OpenC2", 0)))
|
|
|
|
self.open_c3_input.setText(str(self.app.settings.value("OpenC3", 0)))
|
|
|
|
self.open_length.setText(str(self.app.settings.value("OpenDelay", 0)))
|
|
|
|
|
|
|
|
self.load_resistance.setText(str(self.app.settings.value("LoadR", 50)))
|
|
|
|
self.load_inductance.setText(str(self.app.settings.value("LoadL", 0)))
|
2022-01-03 16:42:17 +00:00
|
|
|
self.load_capacitance.setText(str(self.app.settings.value("LoadC", 0)))
|
2019-09-30 20:20:35 +00:00
|
|
|
self.load_length.setText(str(self.app.settings.value("LoadDelay", 0)))
|
|
|
|
|
|
|
|
self.through_length.setText(str(self.app.settings.value("ThroughDelay", 0)))
|
2020-06-15 07:42:16 +00:00
|
|
|
|
2019-09-30 20:20:35 +00:00
|
|
|
self.app.settings.endArray()
|
2020-06-15 07:42:16 +00:00
|
|
|
|
2019-09-30 20:20:35 +00:00
|
|
|
def deleteCalibrationStandard(self):
|
|
|
|
if self.cal_standard_save_selector.currentData() == -1:
|
|
|
|
return
|
2019-10-03 13:00:00 +00:00
|
|
|
delete_num = self.cal_standard_save_selector.currentData()
|
|
|
|
logger.debug("Deleting calibration no %d", delete_num)
|
2019-09-30 20:20:35 +00:00
|
|
|
num_standards = self.app.settings.beginReadArray("CalibrationStandards")
|
|
|
|
self.app.settings.endArray()
|
2019-10-03 13:00:00 +00:00
|
|
|
|
|
|
|
logger.debug("Number of standards known: %d", num_standards)
|
|
|
|
|
|
|
|
if num_standards == 1:
|
|
|
|
logger.debug("Only one standard known")
|
|
|
|
self.app.settings.beginWriteArray("CalibrationStandards", 0)
|
|
|
|
self.app.settings.endArray()
|
|
|
|
else:
|
|
|
|
names = []
|
|
|
|
|
|
|
|
shortL0 = []
|
|
|
|
shortL1 = []
|
|
|
|
shortL2 = []
|
|
|
|
shortL3 = []
|
|
|
|
shortDelay = []
|
|
|
|
|
|
|
|
openC0 = []
|
|
|
|
openC1 = []
|
|
|
|
openC2 = []
|
|
|
|
openC3 = []
|
|
|
|
openDelay = []
|
|
|
|
|
|
|
|
loadR = []
|
|
|
|
loadL = []
|
|
|
|
loadC = []
|
|
|
|
loadDelay = []
|
|
|
|
|
|
|
|
throughDelay = []
|
|
|
|
|
|
|
|
self.app.settings.beginReadArray("CalibrationStandards")
|
|
|
|
for i in range(num_standards):
|
|
|
|
if i == delete_num:
|
|
|
|
continue
|
|
|
|
self.app.settings.setArrayIndex(i)
|
|
|
|
names.append(self.app.settings.value("Name"))
|
|
|
|
|
|
|
|
shortL0.append(self.app.settings.value("ShortL0"))
|
|
|
|
shortL1.append(self.app.settings.value("ShortL1"))
|
|
|
|
shortL2.append(self.app.settings.value("ShortL2"))
|
|
|
|
shortL3.append(self.app.settings.value("ShortL3"))
|
|
|
|
shortDelay.append(self.app.settings.value("ShortDelay"))
|
|
|
|
|
|
|
|
openC0.append(self.app.settings.value("OpenC0"))
|
|
|
|
openC1.append(self.app.settings.value("OpenC1"))
|
|
|
|
openC2.append(self.app.settings.value("OpenC2"))
|
|
|
|
openC3.append(self.app.settings.value("OpenC3"))
|
|
|
|
openDelay.append(self.app.settings.value("OpenDelay"))
|
|
|
|
|
|
|
|
loadR.append(self.app.settings.value("LoadR"))
|
|
|
|
loadL.append(self.app.settings.value("LoadL"))
|
|
|
|
loadC.append(self.app.settings.value("LoadC"))
|
|
|
|
loadDelay.append(self.app.settings.value("LoadDelay"))
|
|
|
|
|
|
|
|
throughDelay.append(self.app.settings.value("ThroughDelay"))
|
|
|
|
self.app.settings.endArray()
|
|
|
|
|
|
|
|
self.app.settings.beginWriteArray("CalibrationStandards")
|
|
|
|
self.app.settings.remove("")
|
|
|
|
self.app.settings.endArray()
|
|
|
|
|
|
|
|
self.app.settings.beginWriteArray("CalibrationStandards", len(names))
|
2020-06-15 07:42:16 +00:00
|
|
|
for i, name in enumerate(names):
|
2019-10-03 13:00:00 +00:00
|
|
|
self.app.settings.setArrayIndex(i)
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.settings.setValue("Name", name)
|
|
|
|
|
2019-10-03 13:00:00 +00:00
|
|
|
self.app.settings.setValue("ShortL0", shortL0[i])
|
|
|
|
self.app.settings.setValue("ShortL1", shortL1[i])
|
|
|
|
self.app.settings.setValue("ShortL2", shortL2[i])
|
|
|
|
self.app.settings.setValue("ShortL3", shortL3[i])
|
|
|
|
self.app.settings.setValue("ShortDelay", shortDelay[i])
|
|
|
|
|
2019-10-07 15:55:22 +00:00
|
|
|
self.app.settings.setValue("OpenC0", openC0[i])
|
|
|
|
self.app.settings.setValue("OpenC1", openC1[i])
|
|
|
|
self.app.settings.setValue("OpenC2", openC2[i])
|
|
|
|
self.app.settings.setValue("OpenC3", openC3[i])
|
2019-10-03 13:00:00 +00:00
|
|
|
self.app.settings.setValue("OpenDelay", openDelay[i])
|
2020-06-15 07:42:16 +00:00
|
|
|
|
2019-10-03 13:00:00 +00:00
|
|
|
self.app.settings.setValue("LoadR", loadR[i])
|
|
|
|
self.app.settings.setValue("LoadL", loadL[i])
|
|
|
|
self.app.settings.setValue("LoadC", loadC[i])
|
|
|
|
self.app.settings.setValue("LoadDelay", loadDelay[i])
|
|
|
|
|
|
|
|
self.app.settings.setValue("ThroughDelay", throughDelay[i])
|
|
|
|
self.app.settings.endArray()
|
|
|
|
|
2019-09-30 20:20:35 +00:00
|
|
|
self.app.settings.sync()
|
|
|
|
self.listCalibrationStandards()
|
|
|
|
|
2019-09-03 17:12:27 +00:00
|
|
|
def reset(self):
|
|
|
|
self.app.calibration = Calibration()
|
2020-06-24 13:02:15 +00:00
|
|
|
for label in self.cal_label.values():
|
|
|
|
label.setText("Uncalibrated")
|
2019-09-03 17:12:27 +00:00
|
|
|
self.calibration_status_label.setText("Device calibration")
|
2019-11-02 09:42:44 +00:00
|
|
|
self.calibration_source_label.setText("Device")
|
2019-09-30 11:46:15 +00:00
|
|
|
self.notes_textedit.clear()
|
2019-09-03 17:12:27 +00:00
|
|
|
|
2019-10-20 13:28:15 +00:00
|
|
|
if len(self.app.worker.rawData11) > 0:
|
|
|
|
# There's raw data, so we can get corrected data
|
|
|
|
logger.debug("Saving and displaying raw data.")
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.saveData(self.app.worker.rawData11,
|
|
|
|
self.app.worker.rawData21, self.app.sweepSource)
|
2019-10-20 13:28:15 +00:00
|
|
|
self.app.worker.signals.updated.emit()
|
|
|
|
|
2019-11-20 14:02:03 +00:00
|
|
|
def setOffsetDelay(self, value: float):
|
|
|
|
logger.debug("New offset delay value: %f ps", value)
|
2019-12-05 08:35:51 +00:00
|
|
|
self.app.worker.offsetDelay = value / 1e12
|
2019-11-20 15:37:57 +00:00
|
|
|
if len(self.app.worker.rawData11) > 0:
|
|
|
|
# There's raw data, so we can get corrected data
|
|
|
|
logger.debug("Applying new offset to existing sweep data.")
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.worker.data11, self.app.worker.data21 = \
|
|
|
|
self.app.worker.applyCalibration(
|
|
|
|
self.app.worker.rawData11, self.app.worker.rawData21)
|
2019-11-20 15:37:57 +00:00
|
|
|
logger.debug("Saving and displaying corrected data.")
|
|
|
|
self.app.saveData(self.app.worker.data11, self.app.worker.data21, self.app.sweepSource)
|
|
|
|
self.app.worker.signals.updated.emit()
|
2019-11-20 14:02:03 +00:00
|
|
|
|
2019-09-03 17:12:27 +00:00
|
|
|
def calculate(self):
|
2020-07-13 14:54:06 +00:00
|
|
|
if self.app.sweep_control.btn_stop.isEnabled():
|
2019-10-09 12:46:08 +00:00
|
|
|
# Currently sweeping
|
|
|
|
self.app.showError("Unable to apply calibration while a sweep is running. " +
|
|
|
|
"Please stop the sweep and try again.")
|
|
|
|
return
|
2019-09-08 17:11:48 +00:00
|
|
|
if self.use_ideal_values.isChecked():
|
|
|
|
self.app.calibration.useIdealShort = True
|
|
|
|
self.app.calibration.useIdealOpen = True
|
|
|
|
self.app.calibration.useIdealLoad = True
|
2019-10-20 12:04:42 +00:00
|
|
|
self.app.calibration.useIdealThrough = True
|
2019-09-08 17:11:48 +00:00
|
|
|
else:
|
|
|
|
# We are using custom calibration standards
|
2019-10-20 12:04:42 +00:00
|
|
|
try:
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.calibration.shortL0 = self.getFloatValue(
|
2022-05-27 07:03:37 +00:00
|
|
|
self.short_l0_input.text()) / 10 ** 12
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.calibration.shortL1 = self.getFloatValue(
|
2022-05-27 07:03:37 +00:00
|
|
|
self.short_l1_input.text()) / 10 ** 24
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.calibration.shortL2 = self.getFloatValue(
|
2022-05-27 07:03:37 +00:00
|
|
|
self.short_l2_input.text()) / 10 ** 33
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.calibration.shortL3 = self.getFloatValue(
|
2022-05-27 07:03:37 +00:00
|
|
|
self.short_l3_input.text()) / 10 ** 42
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.calibration.shortLength = self.getFloatValue(
|
2022-05-27 07:03:37 +00:00
|
|
|
self.short_length.text()) / 10 ** 12
|
2019-10-20 12:04:42 +00:00
|
|
|
self.app.calibration.useIdealShort = False
|
|
|
|
except ValueError:
|
|
|
|
self.app.calibration.useIdealShort = True
|
2020-06-15 07:42:16 +00:00
|
|
|
logger.warning(
|
|
|
|
'Invalid data for "short" calibration standard. Using ideal values.')
|
2019-10-20 12:04:42 +00:00
|
|
|
|
|
|
|
try:
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.calibration.openC0 = self.getFloatValue(
|
2022-05-27 07:03:37 +00:00
|
|
|
self.open_c0_input.text()) / 10 ** 15
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.calibration.openC1 = self.getFloatValue(
|
2022-05-27 07:03:37 +00:00
|
|
|
self.open_c1_input.text()) / 10 ** 27
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.calibration.openC2 = self.getFloatValue(
|
2022-05-27 07:03:37 +00:00
|
|
|
self.open_c2_input.text()) / 10 ** 36
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.calibration.openC3 = self.getFloatValue(
|
2022-05-27 07:03:37 +00:00
|
|
|
self.open_c3_input.text()) / 10 ** 45
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.calibration.openLength = self.getFloatValue(
|
2022-05-27 07:03:37 +00:00
|
|
|
self.open_length.text()) / 10 ** 12
|
2019-10-20 12:04:42 +00:00
|
|
|
self.app.calibration.useIdealOpen = False
|
|
|
|
except ValueError:
|
|
|
|
self.app.calibration.useIdealOpen = True
|
2020-06-15 07:42:16 +00:00
|
|
|
logger.warning(
|
|
|
|
'Invalid data for "open" calibration standard. Using ideal values.')
|
2019-10-20 12:04:42 +00:00
|
|
|
|
|
|
|
try:
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.calibration.loadR = self.getFloatValue(
|
|
|
|
self.load_resistance.text())
|
|
|
|
self.app.calibration.loadL = self.getFloatValue(
|
2022-05-27 07:03:37 +00:00
|
|
|
self.load_inductance.text()) / 10 ** 12
|
2022-01-03 16:42:17 +00:00
|
|
|
self.app.calibration.loadC = self.getFloatValue(
|
|
|
|
self.load_capacitance.text()) / 10 ** 15
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.calibration.loadLength = self.getFloatValue(
|
2022-05-27 07:03:37 +00:00
|
|
|
self.load_length.text()) / 10 ** 12
|
2019-10-20 12:04:42 +00:00
|
|
|
self.app.calibration.useIdealLoad = False
|
|
|
|
except ValueError:
|
|
|
|
self.app.calibration.useIdealLoad = True
|
2020-06-15 07:42:16 +00:00
|
|
|
logger.warning(
|
2020-06-24 21:54:59 +00:00
|
|
|
'Invalid data for "load" calibration standard.'
|
|
|
|
' Using ideal values.')
|
2019-10-20 12:04:42 +00:00
|
|
|
try:
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.calibration.throughLength = self.getFloatValue(
|
2022-05-27 07:03:37 +00:00
|
|
|
self.through_length.text()) / 10 ** 12
|
2019-10-20 12:04:42 +00:00
|
|
|
self.app.calibration.useIdealThrough = False
|
|
|
|
except ValueError:
|
|
|
|
self.app.calibration.useIdealThrough = True
|
2020-06-15 07:42:16 +00:00
|
|
|
logger.warning(
|
2020-06-24 21:54:59 +00:00
|
|
|
'Invalid data for "through" calibration standard.'
|
|
|
|
' Using ideal values.')
|
2019-09-30 11:46:15 +00:00
|
|
|
|
2019-10-04 10:51:20 +00:00
|
|
|
logger.debug("Attempting calibration calculation.")
|
2020-06-24 13:02:15 +00:00
|
|
|
try:
|
|
|
|
self.app.calibration.calc_corrections()
|
2020-06-15 07:42:16 +00:00
|
|
|
self.calibration_status_label.setText(
|
2020-06-30 10:04:50 +00:00
|
|
|
_format_cal_label(self.app.calibration.size(),
|
2020-06-24 21:10:35 +00:00
|
|
|
"Application calibration"))
|
2019-11-02 09:42:44 +00:00
|
|
|
if self.use_ideal_values.isChecked():
|
|
|
|
self.calibration_source_label.setText(self.app.calibration.source)
|
|
|
|
else:
|
2020-06-15 07:42:16 +00:00
|
|
|
self.calibration_source_label.setText(
|
|
|
|
self.app.calibration.source + " (Standards: Custom)")
|
2019-11-02 09:42:44 +00:00
|
|
|
|
2019-10-20 13:28:15 +00:00
|
|
|
if len(self.app.worker.rawData11) > 0:
|
|
|
|
# There's raw data, so we can get corrected data
|
|
|
|
logger.debug("Applying calibration to existing sweep data.")
|
2019-11-20 15:37:57 +00:00
|
|
|
self.app.worker.data11, self.app.worker.data21 = self.app.worker.applyCalibration(
|
|
|
|
self.app.worker.rawData11, self.app.worker.rawData21)
|
2019-10-20 13:28:15 +00:00
|
|
|
logger.debug("Saving and displaying corrected data.")
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.saveData(self.app.worker.data11,
|
|
|
|
self.app.worker.data21, self.app.sweepSource)
|
2019-10-20 13:28:15 +00:00
|
|
|
self.app.worker.signals.updated.emit()
|
2020-06-24 13:02:15 +00:00
|
|
|
except ValueError as e:
|
2019-10-20 18:34:33 +00:00
|
|
|
# showError here hides the calibration window, so we need to pop up our own
|
2020-06-24 13:02:15 +00:00
|
|
|
QtWidgets.QMessageBox.warning(self, "Error applying calibration", str(e))
|
2019-10-20 12:04:42 +00:00
|
|
|
self.calibration_status_label.setText("Applying calibration failed.")
|
2019-11-02 09:42:44 +00:00
|
|
|
self.calibration_source_label.setText(self.app.calibration.source)
|
2019-10-20 12:04:42 +00:00
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def getFloatValue(text: str) -> float:
|
|
|
|
if text == "":
|
|
|
|
# Default value is float
|
|
|
|
return 0
|
|
|
|
return float(text)
|
2019-09-04 18:17:21 +00:00
|
|
|
|
2019-09-30 11:46:15 +00:00
|
|
|
def loadCalibration(self):
|
2020-06-15 07:42:16 +00:00
|
|
|
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
|
|
|
|
filter="Calibration Files (*.cal);;All files (*.*)")
|
2019-09-30 11:46:15 +00:00
|
|
|
if filename:
|
2020-06-24 13:02:15 +00:00
|
|
|
self.app.calibration.load(filename)
|
|
|
|
if not self.app.calibration.isValid1Port():
|
|
|
|
return
|
2020-06-24 20:34:02 +00:00
|
|
|
for i, name in enumerate(
|
2022-01-16 20:37:20 +00:00
|
|
|
("short", "open", "load", "through", "isolation", "thrurefl")):
|
2020-06-24 20:34:02 +00:00
|
|
|
self.cal_label[name].setText(
|
2020-06-30 10:04:50 +00:00
|
|
|
_format_cal_label(self.app.calibration.data_size(name), "Loaded"))
|
2020-06-24 13:02:15 +00:00
|
|
|
if i == 2 and not self.app.calibration.isValid2Port():
|
|
|
|
break
|
|
|
|
self.calculate()
|
|
|
|
self.notes_textedit.clear()
|
|
|
|
for note in self.app.calibration.notes:
|
|
|
|
self.notes_textedit.appendPlainText(note)
|
|
|
|
self.app.settings.setValue("CalibrationFile", filename)
|
2019-09-30 11:46:15 +00:00
|
|
|
|
|
|
|
def saveCalibration(self):
|
|
|
|
if not self.app.calibration.isCalculated:
|
|
|
|
logger.debug("Attempted to save an uncalculated calibration.")
|
|
|
|
self.app.showError("Cannot save an unapplied calibration state.")
|
|
|
|
return
|
2019-10-01 15:08:34 +00:00
|
|
|
filedialog = QtWidgets.QFileDialog(self)
|
|
|
|
filedialog.setDefaultSuffix("cal")
|
2019-10-09 09:30:29 +00:00
|
|
|
filedialog.setNameFilter("Calibration Files (*.cal);;All files (*.*)")
|
|
|
|
filedialog.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
|
|
|
|
selected = filedialog.exec()
|
|
|
|
if selected:
|
|
|
|
filename = filedialog.selectedFiles()[0]
|
|
|
|
else:
|
|
|
|
return
|
|
|
|
if filename == "":
|
|
|
|
logger.debug("No file name selected.")
|
|
|
|
return
|
2019-09-30 11:46:15 +00:00
|
|
|
self.app.calibration.notes = self.notes_textedit.toPlainText().splitlines()
|
2020-06-24 13:02:15 +00:00
|
|
|
try:
|
|
|
|
self.app.calibration.save(filename)
|
2019-09-18 11:45:53 +00:00
|
|
|
self.app.settings.setValue("CalibrationFile", filename)
|
2020-06-24 13:02:15 +00:00
|
|
|
except IOError:
|
2019-09-30 11:46:15 +00:00
|
|
|
logger.error("Calibration save failed!")
|
|
|
|
self.app.showError("Calibration save failed.")
|
2019-09-04 18:17:21 +00:00
|
|
|
|
2019-09-08 17:11:48 +00:00
|
|
|
def idealCheckboxChanged(self):
|
|
|
|
self.cal_short_box.setDisabled(self.use_ideal_values.isChecked())
|
|
|
|
self.cal_open_box.setDisabled(self.use_ideal_values.isChecked())
|
|
|
|
self.cal_load_box.setDisabled(self.use_ideal_values.isChecked())
|
2019-09-30 11:46:15 +00:00
|
|
|
self.cal_through_box.setDisabled(self.use_ideal_values.isChecked())
|
2019-09-30 20:20:35 +00:00
|
|
|
self.cal_standard_save_box.setDisabled(self.use_ideal_values.isChecked())
|
2019-09-08 17:11:48 +00:00
|
|
|
|
2019-09-27 10:03:45 +00:00
|
|
|
def automaticCalibration(self):
|
|
|
|
self.btn_automatic.setDisabled(True)
|
2020-06-15 07:42:16 +00:00
|
|
|
introduction = QtWidgets.QMessageBox(
|
|
|
|
QtWidgets.QMessageBox.Information,
|
|
|
|
"Calibration assistant",
|
|
|
|
"This calibration assistant will help you create a calibration in the "
|
|
|
|
"NanoVNASaver application. It will sweep the standards for you, and "
|
|
|
|
"guide you through the process.<br><br>"
|
|
|
|
"Before starting, ensure you have Open, Short and Load standards "
|
|
|
|
"available, and the cables you wish to have calibrated with the device "
|
|
|
|
"connected.<br><br>"
|
|
|
|
"If you want a 2-port calibration, also have a \"through\" connector "
|
|
|
|
"to hand.<br><br>"
|
|
|
|
"<b>The best results are achieved by having the NanoVNA calibrated "
|
|
|
|
"on-device for the full span of interest and saved to save slot 0 "
|
|
|
|
"before starting.</b><br><br>"
|
|
|
|
"Once you are ready to proceed, press Ok",
|
|
|
|
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
|
2019-09-27 10:03:45 +00:00
|
|
|
response = introduction.exec()
|
|
|
|
if response != QtWidgets.QMessageBox.Ok:
|
|
|
|
self.btn_automatic.setDisabled(False)
|
|
|
|
return
|
|
|
|
logger.info("Starting automatic calibration assistant.")
|
2020-07-05 11:00:03 +00:00
|
|
|
if not self.app.vna.connected():
|
2020-06-15 07:42:16 +00:00
|
|
|
QtWidgets.QMessageBox(
|
|
|
|
QtWidgets.QMessageBox.Information,
|
|
|
|
"NanoVNA not connected",
|
|
|
|
"Please ensure the NanoVNA is connected before attempting calibration."
|
|
|
|
).exec()
|
2019-09-27 10:03:45 +00:00
|
|
|
self.btn_automatic.setDisabled(False)
|
|
|
|
return
|
|
|
|
|
2020-07-29 15:36:07 +00:00
|
|
|
if self.app.sweep.properties.mode == SweepMode.CONTINOUS:
|
2020-06-15 07:42:16 +00:00
|
|
|
QtWidgets.QMessageBox(
|
|
|
|
QtWidgets.QMessageBox.Information,
|
|
|
|
"Continuous sweep enabled",
|
|
|
|
"Please disable continuous sweeping before attempting calibration."
|
|
|
|
).exec()
|
2019-10-15 14:39:47 +00:00
|
|
|
self.btn_automatic.setDisabled(False)
|
|
|
|
return
|
|
|
|
|
2020-06-15 07:42:16 +00:00
|
|
|
short_step = QtWidgets.QMessageBox(
|
|
|
|
QtWidgets.QMessageBox.Information,
|
|
|
|
"Calibrate short",
|
|
|
|
"Please connect the \"short\" standard to port 0 of the NanoVNA.\n\n"
|
|
|
|
"Press Ok when you are ready to continue.",
|
|
|
|
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
|
2019-09-27 10:03:45 +00:00
|
|
|
|
2019-10-03 12:27:53 +00:00
|
|
|
response = short_step.exec()
|
2019-09-27 10:03:45 +00:00
|
|
|
if response != QtWidgets.QMessageBox.Ok:
|
|
|
|
self.btn_automatic.setDisabled(False)
|
|
|
|
return
|
|
|
|
self.reset()
|
2019-11-04 10:06:40 +00:00
|
|
|
self.app.calibration.source = "Calibration assistant"
|
2019-09-27 10:03:45 +00:00
|
|
|
self.nextStep = 0
|
|
|
|
self.app.worker.signals.finished.connect(self.automaticCalibrationStep)
|
2020-07-13 11:19:21 +00:00
|
|
|
self.app.sweep_start()
|
2019-09-27 10:03:45 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
def automaticCalibrationStep(self):
|
|
|
|
if self.nextStep == -1:
|
|
|
|
self.app.worker.signals.finished.disconnect(self.automaticCalibrationStep)
|
2020-06-15 11:27:00 +00:00
|
|
|
return
|
|
|
|
|
2019-09-27 10:03:45 +00:00
|
|
|
if self.nextStep == 0:
|
2019-10-03 12:27:53 +00:00
|
|
|
# Short
|
2020-06-27 19:27:52 +00:00
|
|
|
self.cal_save("short")
|
2019-09-27 10:03:45 +00:00
|
|
|
self.nextStep = 1
|
|
|
|
|
2020-06-15 07:42:16 +00:00
|
|
|
open_step = QtWidgets.QMessageBox(
|
|
|
|
QtWidgets.QMessageBox.Information,
|
|
|
|
"Calibrate open",
|
|
|
|
"Please connect the \"open\" standard to port 0 of the NanoVNA.\n\n"
|
|
|
|
"Either use a supplied open, or leave the end of the cable unconnected "
|
|
|
|
"if desired.\n\n"
|
|
|
|
"Press Ok when you are ready to continue.",
|
|
|
|
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
|
2019-10-03 12:27:53 +00:00
|
|
|
|
|
|
|
response = open_step.exec()
|
2019-09-27 10:03:45 +00:00
|
|
|
if response != QtWidgets.QMessageBox.Ok:
|
|
|
|
self.nextStep = -1
|
|
|
|
self.btn_automatic.setDisabled(False)
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.worker.signals.finished.disconnect(
|
|
|
|
self.automaticCalibrationStep)
|
2019-09-27 10:03:45 +00:00
|
|
|
return
|
2020-07-13 11:19:21 +00:00
|
|
|
self.app.sweep_start()
|
2020-06-15 11:27:00 +00:00
|
|
|
return
|
2019-09-27 10:03:45 +00:00
|
|
|
|
2020-06-15 11:27:00 +00:00
|
|
|
if self.nextStep == 1:
|
2019-10-03 12:27:53 +00:00
|
|
|
# Open
|
2020-06-27 19:27:52 +00:00
|
|
|
self.cal_save("open")
|
2019-09-27 10:03:45 +00:00
|
|
|
self.nextStep = 2
|
2020-06-15 07:42:16 +00:00
|
|
|
load_step = QtWidgets.QMessageBox(
|
|
|
|
QtWidgets.QMessageBox.Information,
|
|
|
|
"Calibrate load",
|
|
|
|
"Please connect the \"load\" standard to port 0 of the NanoVNA.\n\n"
|
|
|
|
"Press Ok when you are ready to continue.",
|
|
|
|
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
|
2019-09-27 10:03:45 +00:00
|
|
|
|
|
|
|
response = load_step.exec()
|
|
|
|
if response != QtWidgets.QMessageBox.Ok:
|
|
|
|
self.btn_automatic.setDisabled(False)
|
|
|
|
self.nextStep = -1
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.worker.signals.finished.disconnect(
|
|
|
|
self.automaticCalibrationStep)
|
2019-09-27 10:03:45 +00:00
|
|
|
return
|
2020-07-13 11:19:21 +00:00
|
|
|
self.app.sweep_start()
|
2020-06-15 11:27:00 +00:00
|
|
|
return
|
2019-09-27 10:03:45 +00:00
|
|
|
|
|
|
|
if self.nextStep == 2:
|
|
|
|
# Load
|
2020-06-27 19:27:52 +00:00
|
|
|
self.cal_save("load")
|
2019-09-27 10:03:45 +00:00
|
|
|
self.nextStep = 3
|
2020-06-15 07:42:16 +00:00
|
|
|
continue_step = QtWidgets.QMessageBox(
|
|
|
|
QtWidgets.QMessageBox.Information,
|
|
|
|
"1-port calibration complete",
|
|
|
|
"The required steps for a 1-port calibration are now complete.\n\n"
|
|
|
|
"If you wish to continue and perform a 2-port calibration, press "
|
|
|
|
"\"Yes\". To apply the 1-port calibration and stop, press \"Apply\"",
|
|
|
|
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Apply |
|
|
|
|
QtWidgets.QMessageBox.Cancel)
|
2019-09-27 10:03:45 +00:00
|
|
|
|
|
|
|
response = continue_step.exec()
|
|
|
|
if response == QtWidgets.QMessageBox.Apply:
|
|
|
|
self.calculate()
|
|
|
|
self.nextStep = -1
|
|
|
|
self.app.worker.signals.finished.disconnect(self.automaticCalibrationStep)
|
|
|
|
self.btn_automatic.setDisabled(False)
|
|
|
|
return
|
2020-06-15 11:27:00 +00:00
|
|
|
if response != QtWidgets.QMessageBox.Yes:
|
2019-09-27 10:03:45 +00:00
|
|
|
self.btn_automatic.setDisabled(False)
|
|
|
|
self.nextStep = -1
|
|
|
|
self.app.worker.signals.finished.disconnect(self.automaticCalibrationStep)
|
|
|
|
return
|
2020-06-15 11:27:00 +00:00
|
|
|
|
|
|
|
isolation_step = QtWidgets.QMessageBox(
|
|
|
|
QtWidgets.QMessageBox.Information,
|
|
|
|
"Calibrate isolation",
|
|
|
|
"Please connect the \"load\" standard to port 1 of the NanoVNA.\n\n"
|
|
|
|
"If available, also connect a load standard to port 0.\n\n"
|
|
|
|
"Press Ok when you are ready to continue.",
|
|
|
|
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
|
|
|
|
|
|
|
|
response = isolation_step.exec()
|
|
|
|
if response != QtWidgets.QMessageBox.Ok:
|
|
|
|
self.btn_automatic.setDisabled(False)
|
|
|
|
self.nextStep = -1
|
|
|
|
self.app.worker.signals.finished.disconnect(
|
|
|
|
self.automaticCalibrationStep)
|
|
|
|
return
|
2020-07-13 11:19:21 +00:00
|
|
|
self.app.sweep_start()
|
2020-06-15 11:27:00 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
if self.nextStep == 3:
|
2019-09-27 10:03:45 +00:00
|
|
|
# Isolation
|
2020-06-27 19:27:52 +00:00
|
|
|
self.cal_save("isolation")
|
2019-09-27 10:03:45 +00:00
|
|
|
self.nextStep = 4
|
2020-06-15 07:42:16 +00:00
|
|
|
through_step = QtWidgets.QMessageBox(
|
|
|
|
QtWidgets.QMessageBox.Information,
|
|
|
|
"Calibrate through",
|
|
|
|
"Please connect the \"through\" standard between port 0 and port 1 "
|
|
|
|
"of the NanoVNA.\n\n"
|
|
|
|
"Press Ok when you are ready to continue.",
|
|
|
|
QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
|
2019-09-27 10:03:45 +00:00
|
|
|
|
|
|
|
response = through_step.exec()
|
|
|
|
if response != QtWidgets.QMessageBox.Ok:
|
|
|
|
self.btn_automatic.setDisabled(False)
|
|
|
|
self.nextStep = -1
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.worker.signals.finished.disconnect(
|
|
|
|
self.automaticCalibrationStep)
|
2019-09-27 10:03:45 +00:00
|
|
|
return
|
2020-07-13 11:19:21 +00:00
|
|
|
self.app.sweep_start()
|
2020-06-15 11:27:00 +00:00
|
|
|
return
|
2019-09-27 10:03:45 +00:00
|
|
|
|
2020-06-15 11:27:00 +00:00
|
|
|
if self.nextStep == 4:
|
2019-09-27 10:03:45 +00:00
|
|
|
# Done
|
2022-01-16 20:37:20 +00:00
|
|
|
self.cal_save("thrurefl")
|
2020-06-27 19:27:52 +00:00
|
|
|
self.cal_save("through")
|
2020-06-15 07:42:16 +00:00
|
|
|
apply_step = QtWidgets.QMessageBox(
|
|
|
|
QtWidgets.QMessageBox.Information,
|
|
|
|
"Calibrate complete",
|
|
|
|
"The calibration process is now complete. Press \"Apply\" to apply "
|
|
|
|
"the calibration parameters.",
|
|
|
|
QtWidgets.QMessageBox.Apply | QtWidgets.QMessageBox.Cancel)
|
2019-09-27 10:03:45 +00:00
|
|
|
|
|
|
|
response = apply_step.exec()
|
|
|
|
if response != QtWidgets.QMessageBox.Apply:
|
|
|
|
self.btn_automatic.setDisabled(False)
|
|
|
|
self.nextStep = -1
|
2020-06-15 07:42:16 +00:00
|
|
|
self.app.worker.signals.finished.disconnect(
|
|
|
|
self.automaticCalibrationStep)
|
2019-09-27 10:03:45 +00:00
|
|
|
return
|
2020-06-15 11:27:00 +00:00
|
|
|
self.calculate()
|
|
|
|
self.btn_automatic.setDisabled(False)
|
|
|
|
self.nextStep = -1
|
|
|
|
self.app.worker.signals.finished.disconnect(
|
|
|
|
self.automaticCalibrationStep)
|
|
|
|
return
|