diff --git a/NanoVNASaver/Calibration.py b/NanoVNASaver/Calibration.py
index 53f47ad..d20f94a 100644
--- a/NanoVNASaver/Calibration.py
+++ b/NanoVNASaver/Calibration.py
@@ -1,4 +1,5 @@
-# NanoVNASaver - a python program to view and export Touchstone data from a NanoVNA
+# NanoVNASaver
+# A python program to view and export Touchstone data from a NanoVNA
# Copyright (C) 2019. Rune B. Broberg
#
# This program is free software: you can redistribute it and/or modify
@@ -13,94 +14,138 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-
import logging
import math
import os
+import re
from typing import List
import numpy as np
from .RFTools import Datapoint
+RXP_CAL_LINE = re.compile(r"""^\s*
+ (?P\d+) \s+
+ (?P[-0-9Ee.]+) \s+ (?P[-0-9Ee.]+) \s+
+ (?P[-0-9Ee.]+) \s+ (?P[-0-9Ee.]+) \s+
+ (?P[-0-9Ee.]+) \s+ (?P[-0-9Ee.]+)(?: \s
+ (?P[-0-9Ee.]+) \s+ (?P[-0-9Ee.]+) \s+
+ (?P[-0-9Ee.]+) \s+ (?P[-0-9Ee.]+)
+ )?
+""", re.VERBOSE)
+
logger = logging.getLogger(__name__)
+# TODO: make a real class of calibration
class Calibration:
- notes = []
- s11short: List[Datapoint] = []
- s11open: List[Datapoint] = []
- s11load: List[Datapoint] = []
- s21through: List[Datapoint] = []
- s21isolation: List[Datapoint] = []
+ _CAL_NAMES = ("short", "open", "load", "through", "isolation",)
- frequencies = []
+ def __init__(self):
- # 1-port
- e00 = [] # Directivity
- e11 = [] # Port match
- deltaE = [] # Tracking
+ self.notes = []
+ self.cals = {}
+ self._reset_cals()
+ self.frequencies = []
+ # 1-port
+ self.e00 = [] # Directivity
+ self.e11 = [] # Port match
+ self.deltaE = [] # Tracking
- # 2-port
- e30 = [] # Port match
- e10e32 = [] # Transmission
+ # 2-port
+ self.e30 = [] # Port match
+ self.e10e32 = [] # Transmission
- shortIdeal = np.complex(-1, 0)
- useIdealShort = True
- shortL0 = 5.7 * 10E-12
- shortL1 = -8960 * 10E-24
- shortL2 = -1100 * 10E-33
- shortL3 = -41200 * 10E-42
- shortLength = -34.2 # Picoseconds
- # These numbers look very large, considering what Keysight suggests their numbers are.
+ self.shortIdeal = np.complex(-1, 0)
+ self.useIdealShort = True
+ self.shortL0 = 5.7 * 10E-12
+ self.shortL1 = -8960 * 10E-24
+ self.shortL2 = -1100 * 10E-33
+ self.shortL3 = -41200 * 10E-42
+ self.shortLength = -34.2 # Picoseconds
+ # These numbers look very large, considering what Keysight suggests their numbers are.
- useIdealOpen = True
- openIdeal = np.complex(1, 0)
- openC0 = 2.1 * 10E-14 # Subtract 50fF for the nanoVNA calibration if nanoVNA is calibrated?
- openC1 = 5.67 * 10E-23
- openC2 = -2.39 * 10E-31
- openC3 = 2.0 * 10E-40
- openLength = 0
+ self.useIdealOpen = True
+ self.openIdeal = np.complex(1, 0)
+ self.openC0 = 2.1 * 10E-14 # Subtract 50fF for the nanoVNA calibration if nanoVNA is calibrated?
+ self.openC1 = 5.67 * 10E-23
+ self.openC2 = -2.39 * 10E-31
+ self.openC3 = 2.0 * 10E-40
+ self.openLength = 0
- useIdealLoad = True
- loadR = 25
- loadL = 0
- loadC = 0
- loadLength = 0
- loadIdeal = np.complex(0, 0)
+ self.useIdealLoad = True
+ self.loadR = 25
+ self.loadL = 0
+ self.loadC = 0
+ self.loadLength = 0
+ self.loadIdeal = np.complex(0, 0)
- useIdealThrough = True
- throughLength = 0
+ self.useIdealThrough = True
+ self.throughLength = 0
- isCalculated = False
+ self.isCalculated = False
- source = "Manual"
+ self.source = "Manual"
- def isValid2Port(self):
- valid = len(self.s21through) > 0 and len(self.s21isolation) > 0 and self.isValid1Port()
- valid &= len(self.s21through) == len(self.s21isolation) == len(self.s11short)
- return valid
+ def _reset_cals(self):
+ for name in Calibration._CAL_NAMES:
+ self.cals[name] = []
+
+ @property
+ def s11short(self) -> List[Datapoint]:
+ return self.cals["short"]
+ @s11short.setter
+ def s11short(self, values: List[Datapoint]):
+ self.cals["short"] = values
+ @property
+ def s11open(self) -> List[Datapoint]:
+ return self.cals["open"]
+ @s11open.setter
+ def s11open(self, values: List[Datapoint]):
+ self.cals["open"] = values
+ @property
+ def s11load(self) -> List[Datapoint]:
+ return self.cals["load"]
+ @s11load.setter
+ def s11load(self, values: List[Datapoint]):
+ self.cals["load"] = values
+ @property
+ def s21through(self) -> List[Datapoint]:
+ return self.cals["through"]
+ @s21through.setter
+ def s21through(self, values: List[Datapoint]):
+ self.cals["through"] = values
+ @property
+ def s21isolation(self) -> List[Datapoint]:
+ return self.cals["isolation"]
+ @s21isolation.setter
+ def s21isolation(self, values: List[Datapoint]):
+ self.cals["isolation"] = values
def isValid1Port(self):
- valid = len(self.s11short) > 0 and len(self.s11open) > 0 and len(self.s11load) > 0
- valid &= len(self.s11short) == len(self.s11open) == len(self.s11load)
- return valid
+ lengths = [len(self.cals[x])
+ for x in Calibration._CAL_NAMES[:3]]
+ return min(lengths) > 0 and min(lengths) == max(lengths)
- def calculateCorrections(self) -> (bool, str):
+ def isValid2Port(self):
+ lengths = [len(self.cals[x]) for x in Calibration._CAL_NAMES]
+ return min(lengths) > 0 and min(lengths) == max(lengths)
+
+ def calc_corrections(self):
if not self.isValid1Port():
- logger.warning("Tried to calibrate from insufficient data.")
- if len(self.s11short) == 0 or len(self.s11open) == 0 or len(self.s11load) == 0:
- return (False,
- "All of short, open and load calibration steps"
- "must be completed for calibration to be applied.")
- return False, "All calibration data sets must be the same size."
- self.frequencies = [int] * len(self.s11short)
- self.e00 = [np.complex] * len(self.s11short)
- self.e11 = [np.complex] * len(self.s11short)
- self.deltaE = [np.complex] * len(self.s11short)
- self.e30 = [np.complex] * len(self.s11short)
- self.e10e32 = [np.complex] * len(self.s11short)
- logger.debug("Calculating calibration for %d points.", len(self.s11short))
+ logger.warning(
+ "Tried to calibrate from insufficient data.")
+ raise ValueError(
+ "All of short, open and load calibration steps"
+ "must be completed for calibration to be applied.")
+ nr_points = len(self.cals["short"])
+ logger.debug("Calculating calibration for %d points.", nr_points)
+ self.frequencies = []
+ self.e00 = [np.complex] * nr_points
+ self.e11 = [np.complex] * nr_points
+ self.deltaE = [np.complex] * nr_points
+ self.e30 = [np.complex] * nr_points
+ self.e10e32 = [np.complex] * nr_points
if self.useIdealShort:
logger.debug("Using ideal values.")
else:
@@ -109,9 +154,11 @@ class Calibration:
logger.debug("Calculating 2-port calibration.")
else:
logger.debug("Calculating 1-port calibration.")
- for i in range(len(self.s11short)):
- self.frequencies[i] = self.s11short[i].freq
- f = self.s11short[i].freq
+ for i, cur_short in enumerate(self.cals["short"]):
+ cur_open = self.cals["open"][i]
+ cur_load = self.cals["load"][i]
+ f = cur_short.freq
+ self.frequencies.append(f)
pi = math.pi
if self.useIdealShort:
@@ -151,9 +198,9 @@ class Calibration:
g3 = g3 * np.exp(
np.complex(0, 1) * 2 * 2 * math.pi * f * self.loadLength * -1)
- gm1 = np.complex(self.s11short[i].re, self.s11short[i].im)
- gm2 = np.complex(self.s11open[i].re, self.s11open[i].im)
- gm3 = np.complex(self.s11load[i].re, self.s11load[i].im)
+ gm1 = np.complex(cur_short.re, cur_short.im)
+ gm2 = np.complex(cur_open.re, cur_open.im)
+ gm3 = np.complex(cur_load.re, cur_load.im)
try:
denominator = (
@@ -181,52 +228,55 @@ class Calibration:
" for two of short, open and load?")
logger.debug(
"Division error at index %d"
- " Short == Load: %s"
- " Short == Open: %s"
- " Open == Load: %s",
- i,
- self.s11short[i] == self.s11load[i],
- self.s11short[i] == self.s11open[i],
- self.s11open[i] == self.s11load[i])
- return (self.isCalculated,
- f"Two of short, open and load returned the same"
- f" values at frequency {self.s11open[i].freq}Hz.")
+ " Short == Load: %s Short == Open: %s"
+ " Open == Load: %s", i,
+ cur_short == cur_load, cur_short == cur_open,
+ cur_open == cur_load)
+ raise ValueError(
+ f"Two of short, open and load returned the same"
+ f" values at frequency {f}Hz.")
if self.isValid2Port():
+ cur_through = self.cals["through"][i]
+ cur_isolation = self.cals["isolation"][i]
+
self.e30[i] = np.complex(
- self.s21isolation[i].re, self.s21isolation[i].im)
- s21m = np.complex(self.s21through[i].re, self.s21through[i].im)
+ cur_isolation.re, cur_isolation.im)
+ s21m = np.complex(cur_through.re, cur_through.im)
if not self.useIdealThrough:
gammaThrough = np.exp(
- np.complex(0, 1) * 2 * math.pi * self.throughLength * f * -1)
+ np.complex(0, 1) * 2 * math.pi *
+ self.throughLength * f * -1)
s21m = s21m / gammaThrough
- self.e10e32[i] = (s21m - self.e30[i]) * (1 - (self.e11[i]*self.e11[i]))
+ self.e10e32[i] = (s21m - self.e30[i]) * (
+ 1 - (self.e11[i] * self.e11[i]))
self.isCalculated = True
logger.debug("Calibration correctly calculated.")
- return self.isCalculated, "Calibration successful."
def correct11(self, re, im, freq):
s11m = np.complex(re, im)
distance = 10**10
index = 0
- for i in range(len(self.s11short)):
- if abs(self.s11short[i].freq - freq) < distance:
+ for i, cur_short in enumerate(self.cals["short"]):
+ if abs(cur_short.freq - freq) < distance:
index = i
- distance = abs(self.s11short[i].freq - freq)
- # TODO: Interpolate with the adjacent data point to get better corrections?
+ distance = abs(cur_short.freq - freq)
+ # TODO: Interpolate with the adjacent data point
+ # to get better corrections?
- s11 = (s11m - self.e00[index]) / ((s11m * self.e11[index]) - self.deltaE[index])
+ s11 = (s11m - self.e00[index]) / (
+ (s11m * self.e11[index]) - self.deltaE[index])
return s11.real, s11.imag
def correct21(self, re, im, freq):
s21m = np.complex(re, im)
distance = 10**10
index = 0
- for i in range(len(self.s21through)):
- if abs(self.s21through[i].freq - freq) < distance:
+ for i, cur_through in enumerate(self.cals["through"]):
+ if abs(cur_through.freq - freq) < distance:
index = i
- distance = abs(self.s21through[i].freq - freq)
+ distance = abs(cur_through.freq - freq)
s21 = (s21m - self.e30[index]) / self.e10e32[index]
return s21.real, s21.imag
@@ -242,104 +292,74 @@ class Calibration:
output = input_val * np.exp(np.complex(0, 1) * 2 * math.pi * d.freq * delay * -1)
return Datapoint(d.freq, output.real, output.imag)
- def saveCalibration(self, filename):
+ # TODO: implement tests
+ def save(self, filename: str):
# Save the calibration data to file
- if filename == "" or not self.isValid1Port():
- return False
- try:
- file = open(filename, "w+")
- file.write("# Calibration data for NanoVNA-Saver\n")
+ if not self.isValid1Port():
+ raise ValueError("Not a valid 1-Port calibration")
+ with open(filename, "w+") as calfile:
+ calfile.write("# Calibration data for NanoVNA-Saver\n")
for note in self.notes:
- file.write(f"! {note}\n")
- file.write(
+ calfile.write(f"! {note}\n")
+ calfile.write(
"# Hz ShortR ShortI OpenR OpenI LoadR LoadI"
" ThroughR ThroughI IsolationR IsolationI\n")
- for i in range(len(self.s11short)):
- freq = str(self.s11short[i].freq)
- shortr = str(self.s11short[i].re)
- shorti = str(self.s11short[i].im)
- openr = str(self.s11open[i].re)
- openi = str(self.s11open[i].im)
- loadr = str(self.s11load[i].re)
- loadi = str(self.s11load[i].im)
- file.write(" ".join((freq, shortr, shorti, openr, openi, loadr, loadi)))
+ for i, cur_short in enumerate(self.cals["short"]):
+ data = [
+ cur_short.freq,
+ cur_short.re, cur_short.im,
+ self.s11open[i].re, self.s11open[i].im,
+ self.s11load[i].re, self.s11load[i].im,
+ ]
if self.isValid2Port():
- throughr = str(self.s21through[i].re)
- throughi = str(self.s21through[i].im)
- isolationr = str(self.s21isolation[i].re)
- isolationi = str(self.s21isolation[i].im)
- file.write(" ".join((throughr, throughi, isolationr, isolationi)))
- file.write("\n")
- file.close()
- return True
- except Exception as e:
- logger.exception("Error saving calibration data: %s", e)
- return False
-
- def loadCalibration(self, filename):
- # Load calibration data from file
- if filename == "":
- return
+ data.extend([
+ self.s21through[i].re, self.s21through[i].im,
+ self.s21isolation[i].re, self.s21isolation[i].im
+ ])
+ calfile.write(" ".join([str(val) for val in data]))
+ calfile.write("\n")
+ # TODO: implement tests
+ # TODO: Exception should be catched by caller
+ def load(self, filename):
self.source = os.path.basename(filename)
-
- self.s11short = []
- self.s11open = []
- self.s11load = []
-
- self.s21through = []
- self.s21isolation = []
+ self._reset_cals()
self.notes = []
- try:
- file = open(filename, "r")
- lines = file.readlines()
- parsed_header = False
-
- for line in lines:
+ parsed_header = False
+ with open(filename) as calfile:
+ for i, line in enumerate(calfile):
line = line.strip()
if line.startswith("!"):
note = line[2:]
self.notes.append(note)
continue
- if line.startswith("#") and not parsed_header:
- # Check that this is a valid header
- if line == ("# Hz ShortR ShortI OpenR OpenI LoadR LoadI"
+ if line.startswith("#"):
+ if not parsed_header:
+ # Check that this is a valid header
+ if line == (
+ "# Hz ShortR ShortI OpenR OpenI LoadR LoadI"
" ThroughR ThroughI IsolationR IsolationI"):
- parsed_header = True
+ parsed_header = True
continue
if not parsed_header:
logger.warning(
- "Warning: Read line without having read header: %s", line)
+ "Warning: Read line without having read header: %s",
+ line)
continue
- try:
- if line.count(" ") == 6:
- freq, shortr, shorti, openr, openi, loadr, loadi = line.split(
- " ")
- self.s11short.append(
- Datapoint(int(freq), float(shortr), float(shorti)))
- self.s11open.append(
- Datapoint(int(freq), float(openr), float(openi)))
- self.s11load.append(
- Datapoint(int(freq), float(loadr), float(loadi)))
- else:
- (freq, shortr, shorti, openr, openi, loadr, loadi,
- throughr, throughi, isolationr, isolationi) = line.split(" ")
- self.s11short.append(
- Datapoint(int(freq), float(shortr), float(shorti)))
- self.s11open.append(
- Datapoint(int(freq), float(openr), float(openi)))
- self.s11load.append(
- Datapoint(int(freq), float(loadr), float(loadi)))
- self.s21through.append(
- Datapoint(int(freq), float(throughr), float(throughi)))
- self.s21isolation.append(
- Datapoint(int(freq), float(isolationr), float(isolationi)))
+ m = RXP_CAL_LINE.search(line)
+ if not m:
+ logger.warning("Illegal data in cal file. Line %i", i)
+ cal = m.groupdict()
- except ValueError as e:
- logger.exception(
- "Error parsing calibration data \"%s\": %s", line, e)
- file.close()
- except Exception as e:
- logger.exception("Failed loading calibration data: %s", e)
+ if cal["throughr"]:
+ nr_cals = 5
+ else:
+ nr_cals = 3
+
+ for name in Calibration._CAL_NAMES[:nr_cals]:
+ self.cals[name].append(
+ Datapoint(int(cal["freq"]),
+ float(cal[f"{name}r"]),
+ float(cal[f"{name}i"])))
diff --git a/NanoVNASaver/Windows/CalibrationSettings.py b/NanoVNASaver/Windows/CalibrationSettings.py
index ecc8392..bb15c53 100644
--- a/NanoVNASaver/Windows/CalibrationSettings.py
+++ b/NanoVNASaver/Windows/CalibrationSettings.py
@@ -24,6 +24,10 @@ from NanoVNASaver.Calibration import Calibration
logger = logging.getLogger(__name__)
+def _format_cal_label(data: list, prefix: str = "Set") -> str:
+ return f"{prefix} ({len(data)} points)"
+
+
class CalibrationWindow(QtWidgets.QWidget):
nextStep = -1
@@ -57,27 +61,15 @@ class CalibrationWindow(QtWidgets.QWidget):
calibration_control_group = QtWidgets.QGroupBox("Calibrate")
calibration_control_layout = QtWidgets.QFormLayout(calibration_control_group)
- btn_cal_short = QtWidgets.QPushButton("Short")
- btn_cal_short.clicked.connect(self.manualSaveShort)
- self.cal_short_label = QtWidgets.QLabel("Uncalibrated")
-
- btn_cal_open = QtWidgets.QPushButton("Open")
- btn_cal_open.clicked.connect(self.manualSaveOpen)
- self.cal_open_label = QtWidgets.QLabel("Uncalibrated")
-
- btn_cal_load = QtWidgets.QPushButton("Load")
- btn_cal_load.clicked.connect(self.manualSaveLoad)
- self.cal_load_label = QtWidgets.QLabel("Uncalibrated")
-
- btn_cal_through = QtWidgets.QPushButton("Through")
- btn_cal_through.clicked.connect(self.manualSaveThrough)
- # btn_cal_through.setDisabled(True)
- self.cal_through_label = QtWidgets.QLabel("Uncalibrated")
-
- btn_cal_isolation = QtWidgets.QPushButton("Isolation")
- btn_cal_isolation.clicked.connect(self.manualSaveIsolation)
- # btn_cal_isolation.setDisabled(True)
- self.cal_isolation_label = QtWidgets.QLabel("Uncalibrated")
+ cal_btn = {}
+ self.cal_label = {}
+ for label_name in Calibration._CAL_NAMES:
+ self.cal_label[label_name] = QtWidgets.QLabel("Uncalibrated")
+ cal_btn[label_name] = QtWidgets.QPushButton(
+ label_name.capitalize())
+ cal_btn[label_name].clicked.connect(lambda: self.manual_save(label_name))
+ calibration_control_layout.addRow(
+ cal_btn[label_name], self.cal_label[label_name])
self.input_offset_delay = QtWidgets.QDoubleSpinBox()
self.input_offset_delay.setValue(0)
@@ -86,12 +78,6 @@ class CalibrationWindow(QtWidgets.QWidget):
self.input_offset_delay.valueChanged.connect(self.setOffsetDelay)
self.input_offset_delay.setRange(-10e6, 10e6)
- calibration_control_layout.addRow(btn_cal_short, self.cal_short_label)
- calibration_control_layout.addRow(btn_cal_open, self.cal_open_label)
- calibration_control_layout.addRow(btn_cal_load, self.cal_load_label)
- calibration_control_layout.addRow(btn_cal_isolation, self.cal_isolation_label)
- calibration_control_layout.addRow(btn_cal_through, self.cal_through_label)
-
calibration_control_layout.addRow(QtWidgets.QLabel(""))
calibration_control_layout.addRow("Offset delay", self.input_offset_delay)
@@ -239,50 +225,14 @@ class CalibrationWindow(QtWidgets.QWidget):
return False
return True
- def manualSaveShort(self):
+ def cal_save(self, name):
+ self.app.calibration.cals[name] = self.app.data
+ self.cal_label[name].setText(
+ _format_cal_label(self.app.data))
+
+ def manual_save(self, name):
if self.checkExpertUser():
- self.saveShort()
-
- def saveShort(self):
- self.app.calibration.s11short = self.app.data
- self.cal_short_label.setText(
- f"Data set ({self.app.calibration.s11short} points)")
-
- def manualSaveOpen(self):
- if self.checkExpertUser():
- self.saveOpen()
-
- def saveOpen(self):
- self.app.calibration.s11open = self.app.data
- self.cal_open_label.setText(
- f"Data set ({self.app.calibration.s11open} points)")
-
- def manualSaveLoad(self):
- if self.checkExpertUser():
- self.saveLoad()
-
- def saveLoad(self):
- self.app.calibration.s11load = self.app.data
- self.cal_load_label.setText(
- f"Data set ({self.app.calibration.s11load} points)")
-
- def manualSaveIsolation(self):
- if self.checkExpertUser():
- self.saveIsolation()
-
- def saveIsolation(self):
- self.app.calibration.s21isolation = self.app.data21
- self.cal_isolation_label.setText(
- f"Data set ({self.app.calibration.s21isolation} points)")
-
- def manualSaveThrough(self):
- if self.checkExpertUser():
- self.saveThrough()
-
- def saveThrough(self):
- self.app.calibration.s21through = self.app.data21
- self.cal_through_label.setText(
- f"Data set ({self.app.calibration.s21through} points)")
+ self.cal_save(name)
def listCalibrationStandards(self):
self.cal_standard_save_selector.clear()
@@ -469,11 +419,8 @@ class CalibrationWindow(QtWidgets.QWidget):
def reset(self):
self.app.calibration = Calibration()
- self.cal_short_label.setText("Uncalibrated")
- self.cal_open_label.setText("Uncalibrated")
- self.cal_load_label.setText("Uncalibrated")
- self.cal_through_label.setText("Uncalibrated")
- self.cal_isolation_label.setText("Uncalibrated")
+ for label in self.cal_label.values():
+ label.setText("Uncalibrated")
self.calibration_status_label.setText("Device calibration")
self.calibration_source_label.setText("Device")
self.notes_textedit.clear()
@@ -572,8 +519,8 @@ class CalibrationWindow(QtWidgets.QWidget):
'Invalid data for "through" calibration standard. Using ideal values.')
logger.debug("Attempting calibration calculation.")
- valid, error = self.app.calibration.calculateCorrections()
- if valid:
+ try:
+ self.app.calibration.calc_corrections()
self.calibration_status_label.setText(
f"Application calibration ({len(self.app.calibration.s11short)} points)")
if self.use_ideal_values.isChecked():
@@ -591,9 +538,9 @@ class CalibrationWindow(QtWidgets.QWidget):
self.app.saveData(self.app.worker.data11,
self.app.worker.data21, self.app.sweepSource)
self.app.worker.signals.updated.emit()
- else:
+ except ValueError as e:
# showError here hides the calibration window, so we need to pop up our own
- QtWidgets.QMessageBox.warning(self, "Error applying calibration", error)
+ QtWidgets.QMessageBox.warning(self, "Error applying calibration", str(e))
self.calibration_status_label.setText("Applying calibration failed.")
self.calibration_source_label.setText(self.app.calibration.source)
@@ -608,24 +555,26 @@ class CalibrationWindow(QtWidgets.QWidget):
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
filter="Calibration Files (*.cal);;All files (*.*)")
if filename:
- self.app.calibration.loadCalibration(filename)
- if self.app.calibration.isValid1Port():
- self.cal_short_label.setText(
- f"Loaded ({len(self.app.calibration.s11short)})")
- self.cal_open_label.setText(
- f"Loaded ({len(self.app.calibration.s11open)})")
- self.cal_load_label.setText(
- f"Loaded ({len(self.app.calibration.s11load)})")
- if self.app.calibration.isValid2Port():
- self.cal_through_label.setText(
- f"Loaded ({len(self.app.calibration.s21through)})")
- self.cal_isolation_label.setText(
- f"Loaded ({len(self.app.calibration.s21isolation)})")
- self.calculate()
- self.notes_textedit.clear()
- for note in self.app.calibration.notes:
- self.notes_textedit.appendPlainText(note)
- self.app.settings.setValue("CalibrationFile", filename)
+ self.app.calibration.load(filename)
+ if not self.app.calibration.isValid1Port():
+ return
+ cals = (
+ ("short", self.app.calibration.s11short),
+ ("open", self.app.calibration.s11open),
+ ("load", self.app.calibration.s11load),
+ ("through", self.app.calibration.s21through),
+ ("isolation", self.app.calibration.s21isolation),
+ )
+ for i, cal in enumerate(cals):
+ self.cal_label[cal[0]].setText(
+ _format_cal_label(cal[1], "Loaded"))
+ 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)
def saveCalibration(self):
if not self.app.calibration.isCalculated:
@@ -645,9 +594,10 @@ class CalibrationWindow(QtWidgets.QWidget):
logger.debug("No file name selected.")
return
self.app.calibration.notes = self.notes_textedit.toPlainText().splitlines()
- if filename and self.app.calibration.saveCalibration(filename):
+ try:
+ self.app.calibration.save(filename)
self.app.settings.setValue("CalibrationFile", filename)
- else:
+ except IOError:
logger.error("Calibration save failed!")
self.app.showError("Calibration save failed.")
@@ -724,7 +674,7 @@ class CalibrationWindow(QtWidgets.QWidget):
if self.nextStep == 0:
# Short
- self.saveShort()
+ self.save("short")
self.nextStep = 1
open_step = QtWidgets.QMessageBox(
@@ -748,7 +698,7 @@ class CalibrationWindow(QtWidgets.QWidget):
if self.nextStep == 1:
# Open
- self.saveOpen()
+ self.save("open")
self.nextStep = 2
load_step = QtWidgets.QMessageBox(
QtWidgets.QMessageBox.Information,
@@ -769,7 +719,7 @@ class CalibrationWindow(QtWidgets.QWidget):
if self.nextStep == 2:
# Load
- self.saveLoad()
+ self.save("load")
self.nextStep = 3
continue_step = QtWidgets.QMessageBox(
QtWidgets.QMessageBox.Information,
@@ -813,7 +763,7 @@ class CalibrationWindow(QtWidgets.QWidget):
if self.nextStep == 3:
# Isolation
- self.saveIsolation()
+ self.save("isolation")
self.nextStep = 4
through_step = QtWidgets.QMessageBox(
QtWidgets.QMessageBox.Information,
@@ -835,7 +785,7 @@ class CalibrationWindow(QtWidgets.QWidget):
if self.nextStep == 4:
# Done
- self.saveThrough()
+ self.save("through")
apply_step = QtWidgets.QMessageBox(
QtWidgets.QMessageBox.Information,
"Calibrate complete",