kopia lustrzana https://github.com/NanoVNA-Saver/nanovna-saver
pycodestyle changes
rodzic
3f8151aad7
commit
1609295bd9
|
@ -97,21 +97,16 @@ class PeakSearchAnalysis(Analysis):
|
|||
count = self.input_number_of_peaks.value()
|
||||
if self.rbtn_data_vswr.isChecked():
|
||||
fn = format_vswr
|
||||
for d in self.app.data.s11:
|
||||
data.append(d.vswr)
|
||||
data.extend(d.vswr for d in self.app.data.s11)
|
||||
elif self.rbtn_data_s21_gain.isChecked():
|
||||
fn = format_gain
|
||||
for d in self.app.data.s21:
|
||||
data.append(d.gain)
|
||||
data.extend(d.gain for d in self.app.data.s21)
|
||||
elif self.rbtn_data_resistance.isChecked():
|
||||
fn = format_resistance
|
||||
for d in self.app.data.s11:
|
||||
data.append(d.impedance().real)
|
||||
data.extend(d.impedance().real for d in self.app.data.s11)
|
||||
elif self.rbtn_data_reactance.isChecked():
|
||||
fn = str
|
||||
for d in self.app.data.s11:
|
||||
data.append(d.impedance().imag)
|
||||
|
||||
data.extend(d.impedance().imag for d in self.app.data.s11)
|
||||
else:
|
||||
logger.warning("Searching for peaks on unknown data")
|
||||
return
|
||||
|
@ -125,8 +120,10 @@ class PeakSearchAnalysis(Analysis):
|
|||
peaks, _ = signal.find_peaks(
|
||||
data, width=3, distance=3, prominence=1)
|
||||
# elif self.rbtn_peak_both.isChecked():
|
||||
# peaks_max, _ = signal.find_peaks(data, width=3, distance=3, prominence=1)
|
||||
# peaks_min, _ = signal.find_peaks(np.array(data)*-1, width=3, distance=3, prominence=1)
|
||||
# peaks_max, _ = signal.find_peaks(
|
||||
# data, width=3, distance=3, prominence=1)
|
||||
# peaks_min, _ = signal.find_peaks(
|
||||
# np.array(data)*-1, width=3, distance=3, prominence=1)
|
||||
# peaks = np.concatenate((peaks_max, peaks_min))
|
||||
else:
|
||||
# Both is not yet in
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
import os
|
||||
import csv
|
||||
import logging
|
||||
from collections import OrderedDict
|
||||
|
||||
import numpy as np
|
||||
from PyQt5 import QtWidgets
|
||||
|
@ -74,39 +73,27 @@ class VSWRAnalysis(Analysis):
|
|||
|
||||
def runAnalysis(self):
|
||||
max_dips_shown = self.max_dips_shown
|
||||
|
||||
data = [d.vswr for d in self.app.data.s11]
|
||||
|
||||
# min_idx = np.argmin(data)
|
||||
#
|
||||
# logger.debug("Minimum at %d", min_idx)
|
||||
# logger.debug("Value at minimum: %f", data[min_idx])
|
||||
# logger.debug("Frequency: %d", self.app.data.s11[min_idx].freq)
|
||||
#
|
||||
# if self.checkbox_move_marker.isChecked():
|
||||
# self.app.markers[0].setFrequency(str(self.app.data.s11[min_idx].freq))
|
||||
# self.app.markers[0].frequencyInput.setText(str(self.app.data.s11[min_idx].freq))
|
||||
|
||||
threshold = self.input_vswr_limit.value()
|
||||
minimums = self.find_minimums(data, threshold)
|
||||
|
||||
logger.debug("Found %d sections under %f threshold",
|
||||
len(minimums), threshold)
|
||||
|
||||
results_header = self.layout.indexOf(self.results_label)
|
||||
logger.debug("Results start at %d, out of %d",
|
||||
results_header, self.layout.rowCount())
|
||||
|
||||
for _ in range(results_header, self.layout.rowCount()):
|
||||
self.layout.removeRow(self.layout.rowCount() - 1)
|
||||
|
||||
if len(minimums) > max_dips_shown:
|
||||
self.layout.addRow(QtWidgets.QLabel("<b>More than " + str(max_dips_shown) +
|
||||
" dips found. Lowest shown.</b>"))
|
||||
self.layout.addRow(
|
||||
QtWidgets.QLabel(
|
||||
f"<b>More than {str(max_dips_shown)} dips found."
|
||||
" Lowest shown.</b>"))
|
||||
|
||||
dips = []
|
||||
for m in minimums:
|
||||
start, lowest, end = m
|
||||
dips.append(data[lowest])
|
||||
|
||||
best_dips = []
|
||||
for _ in range(max_dips_shown):
|
||||
min_idx = np.argmin(dips)
|
||||
|
@ -123,27 +110,26 @@ class VSWRAnalysis(Analysis):
|
|||
"Section from %d to %d, lowest at %d", start, end, lowest)
|
||||
self.layout.addRow("Start", QtWidgets.QLabel(
|
||||
format_frequency(self.app.data.s11[start].freq)))
|
||||
self.layout.addRow(
|
||||
"Minimum",
|
||||
QtWidgets.QLabel(
|
||||
f"{format_frequency(self.app.data.s11[lowest].freq)}"
|
||||
f" ({round(data[lowest], 2)})"))
|
||||
|
||||
self.layout.addRow("Minimum", QtWidgets.QLabel(
|
||||
f"{format_frequency(self.app.data.s11[lowest].freq)} ({round(data[lowest], 2)})"))
|
||||
|
||||
self.layout.addRow("End", QtWidgets.QLabel(
|
||||
format_frequency(self.app.data.s11[end].freq)))
|
||||
self.layout.addRow(
|
||||
"Span",
|
||||
QtWidgets.QLabel(
|
||||
format_frequency(self.app.data.s11[end].freq -
|
||||
self.app.data.s11[start].freq)))
|
||||
|
||||
self.layout.addRow("Span", QtWidgets.QLabel(format_frequency(
|
||||
(self.app.data.s11[end].freq - self.app.data.s11[start].freq))))
|
||||
|
||||
else:
|
||||
self.layout.addRow("Low spot", QtWidgets.QLabel(
|
||||
format_frequency(self.app.data.s11[lowest].freq)))
|
||||
|
||||
self.layout.addWidget(PeakSearchAnalysis.QHLine())
|
||||
# Remove the final separator line
|
||||
self.layout.removeRow(self.layout.rowCount() - 1)
|
||||
else:
|
||||
self.layout.addRow(QtWidgets.QLabel(
|
||||
"No areas found with VSWR below " + str(round(threshold, 2)) + "."))
|
||||
self.layout.addRow(
|
||||
QtWidgets.QLabel(
|
||||
f"No areas found with VSWR below {round(threshold, 2)}."))
|
||||
|
||||
|
||||
class ResonanceAnalysis(Analysis):
|
||||
|
@ -153,9 +139,7 @@ class ResonanceAnalysis(Analysis):
|
|||
def vswr_transformed(cls, z, ratio=49) -> float:
|
||||
refl = reflection_coefficient(z / ratio)
|
||||
mag = abs(refl)
|
||||
if mag == 1:
|
||||
return 1
|
||||
return (1 + mag) / (1 - mag)
|
||||
return 1 if mag == 1 else (1 + mag) / (1 - mag)
|
||||
|
||||
class QHLine(QtWidgets.QFrame):
|
||||
def __init__(self):
|
||||
|
@ -203,11 +187,10 @@ class ResonanceAnalysis(Analysis):
|
|||
self.reset()
|
||||
# self.results_label = QtWidgets.QLabel("<b>Results</b>")
|
||||
# max_dips_shown = self.max_dips_shown
|
||||
description = self.input_description.text()
|
||||
if description:
|
||||
filename = os.path.join("/tmp/", "{}.csv".format(description))
|
||||
else:
|
||||
filename = None
|
||||
filename = (
|
||||
os.path.join("/tmp/", f"{self.input_description.text()}.csv")
|
||||
if self.input_description.text()
|
||||
else None)
|
||||
|
||||
crossing = self._get_crossing()
|
||||
|
||||
|
@ -272,42 +255,29 @@ class EFHWAnalysis(ResonanceAnalysis):
|
|||
|
||||
def runAnalysis(self):
|
||||
self.reset()
|
||||
# self.results_label = QtWidgets.QLabel("<b>Results</b>")
|
||||
# max_dips_shown = self.max_dips_shown
|
||||
description = self.input_description.text()
|
||||
if description:
|
||||
filename = os.path.join("/tmp/", "{}.csv".format(description))
|
||||
if description := self.input_description.text():
|
||||
filename = os.path.join("/tmp/", f"{description}.csv")
|
||||
else:
|
||||
filename = None
|
||||
|
||||
crossing = self._get_crossing()
|
||||
|
||||
data = []
|
||||
for d in self.app.data.s11:
|
||||
data.append(d.impedance().real)
|
||||
|
||||
data = [d.impedance().real for d in self.app.data.s11]
|
||||
maximums = sorted(self.find_maximums(data, threshold=500))
|
||||
|
||||
results_header = self.layout.indexOf(self.results_label)
|
||||
logger.debug("Results start at %d, out of %d",
|
||||
results_header, self.layout.rowCount())
|
||||
for i in range(results_header, self.layout.rowCount()):
|
||||
|
||||
for _ in range(results_header, self.layout.rowCount()):
|
||||
self.layout.removeRow(self.layout.rowCount() - 1)
|
||||
|
||||
extended_data = OrderedDict()
|
||||
|
||||
# both = np.intersect1d([i[1] for i in crossing], maximums)
|
||||
extended_data = {}
|
||||
both = []
|
||||
|
||||
tolerance = 2
|
||||
for i in maximums:
|
||||
for l, _, h in crossing:
|
||||
if l - tolerance <= i <= h + tolerance:
|
||||
for low, _, high in crossing:
|
||||
if low - tolerance <= i <= high + tolerance:
|
||||
both.append(i)
|
||||
continue
|
||||
if l > i:
|
||||
if low > i:
|
||||
continue
|
||||
|
||||
if both:
|
||||
logger.info("%i crossing HW", len(both))
|
||||
logger.info(crossing)
|
||||
|
@ -320,67 +290,45 @@ class EFHWAnalysis(ResonanceAnalysis):
|
|||
else:
|
||||
extended_data[m] = my_data
|
||||
for i in range(min(len(both), len(self.app.markers))):
|
||||
# self.app.markers[i].label = {}
|
||||
# for l in TYPES:
|
||||
# self.app.markers[i][l.label_id] = MarkerLabel(l.name)
|
||||
# self.app.markers[i].label['actualfreq'].setMinimumWidth(
|
||||
# 100)
|
||||
# self.app.markers[i].label['returnloss'].setMinimumWidth(80)
|
||||
|
||||
self.app.markers[i].setFrequency(
|
||||
str(self.app.data.s11[both[i]].freq))
|
||||
self.app.markers[i].frequencyInput.setText(
|
||||
str(self.app.data.s11[both[i]].freq))
|
||||
|
||||
else:
|
||||
logger.info("TO DO: find near data")
|
||||
for _, lowest, _ in crossing:
|
||||
my_data = self._get_data(lowest)
|
||||
|
||||
if lowest in extended_data:
|
||||
extended_data[lowest].update(my_data)
|
||||
else:
|
||||
extended_data[lowest] = my_data
|
||||
|
||||
logger.debug("maximumx %s of type %s", maximums, type(maximums))
|
||||
for m in maximums:
|
||||
logger.debug("m %s of type %s", m, type(m))
|
||||
|
||||
my_data = self._get_data(m)
|
||||
if m in extended_data:
|
||||
extended_data[m].update(my_data)
|
||||
else:
|
||||
extended_data[m] = my_data
|
||||
|
||||
# saving and comparing
|
||||
|
||||
fields = [("freq", format_frequency_short),
|
||||
("r", format_resistence_neg),
|
||||
("lambda", round_2),
|
||||
]
|
||||
("r", format_resistence_neg), ("lambda", round_2)]
|
||||
|
||||
if self.old_data:
|
||||
diff = self.compare(
|
||||
self.old_data[-1], extended_data, fields=fields)
|
||||
else:
|
||||
diff = self.compare({}, extended_data, fields=fields)
|
||||
self.old_data.append(extended_data)
|
||||
|
||||
for i, index in enumerate(sorted(extended_data.keys())):
|
||||
self.layout.addRow(
|
||||
f"{format_frequency_short(self.app.data.s11[index].freq)}",
|
||||
QtWidgets.QLabel(f" ({diff[i]['freq']})"
|
||||
f" {format_complex_imp(self.app.data.s11[index].impedance())}"
|
||||
f" ({diff[i]['r']})"
|
||||
f" {diff[i]['lambda']} m"))
|
||||
self.layout.addRow(f"{format_frequency_short(self.app.data.s11[index].freq)}", QtWidgets.QLabel(
|
||||
f" ({diff[i]['freq']}) {format_complex_imp(self.app.data.s11[index].impedance())} ({diff[i]['r']}) {diff[i]['lambda']} m"))
|
||||
|
||||
# Remove the final separator line
|
||||
# self.layout.removeRow(self.layout.rowCount() - 1)
|
||||
if filename and extended_data:
|
||||
|
||||
with open(filename, 'w', newline='') as csvfile:
|
||||
fieldnames = extended_data[sorted(
|
||||
extended_data.keys())[0]].keys()
|
||||
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
|
||||
|
||||
writer.writeheader()
|
||||
for index in sorted(extended_data.keys()):
|
||||
row = extended_data[index]
|
||||
|
|
|
@ -120,7 +120,8 @@ class CalDataSet:
|
|||
|
||||
def complete2port(self) -> bool:
|
||||
for val in self.data.values():
|
||||
for name in ("short", "open", "load", "through", "thrurefl", "isolation"):
|
||||
for name in ("short", "open", "load", "through", "thrurefl",
|
||||
"isolation"):
|
||||
if val[name] is None:
|
||||
return False
|
||||
return any(self.data)
|
||||
|
@ -218,9 +219,9 @@ class Calibration:
|
|||
cal["e30"] = cal["isolation"].z
|
||||
cal["e10e01"] = cal["e00"] * cal["e11"] - cal["delta_e"]
|
||||
cal["e22"] = gm7 / (
|
||||
gm7 * cal["e11"] * gt ** 2 + cal["e10e01"] * gt ** 2)
|
||||
gm7 * cal["e11"] * gt ** 2 + cal["e10e01"] * gt ** 2)
|
||||
cal["e10e32"] = (gm4 - gm6) * (
|
||||
1 - cal["e11"] * cal["e22"] * gt ** 2) / gt
|
||||
1 - cal["e11"] * cal["e22"] * gt ** 2) / gt
|
||||
|
||||
def calc_corrections(self):
|
||||
if not self.isValid1Port():
|
||||
|
@ -254,8 +255,8 @@ class Calibration:
|
|||
if not self.useIdealShort:
|
||||
logger.debug("Using short calibration set values.")
|
||||
Zsp = complex(0, 2 * math.pi * freq * (
|
||||
self.shortL0 + self.shortL1 * freq +
|
||||
self.shortL2 * freq ** 2 + self.shortL3 * freq ** 3))
|
||||
self.shortL0 + self.shortL1 * freq +
|
||||
self.shortL2 * freq ** 2 + self.shortL3 * freq ** 3))
|
||||
# Referencing https://arxiv.org/pdf/1606.02446.pdf (18) - (21)
|
||||
g = (Zsp / 50 - 1) / (Zsp / 50 + 1) * cmath.exp(
|
||||
complex(0, 2 * math.pi * 2 * freq * self.shortLength * -1))
|
||||
|
@ -266,8 +267,8 @@ class Calibration:
|
|||
if not self.useIdealOpen:
|
||||
logger.debug("Using open calibration set values.")
|
||||
Zop = complex(0, 2 * math.pi * freq * (
|
||||
self.openC0 + self.openC1 * freq +
|
||||
self.openC2 * freq ** 2 + self.openC3 * freq ** 3))
|
||||
self.openC0 + self.openC1 * freq +
|
||||
self.openC2 * freq ** 2 + self.openC3 * freq ** 3))
|
||||
g = ((1 - 50 * Zop) / (1 + 50 * Zop)) * cmath.exp(
|
||||
complex(0, 2 * math.pi * 2 * freq * self.openLength * -1))
|
||||
return g
|
||||
|
@ -278,7 +279,8 @@ class Calibration:
|
|||
logger.debug("Using load calibration set values.")
|
||||
Zl = complex(self.loadR, 0)
|
||||
if self.loadC > 0:
|
||||
Zl = self.loadR / complex(1, 2 * self.loadR * math.pi * freq * self.loadC)
|
||||
Zl = self.loadR / \
|
||||
complex(1, 2 * self.loadR * math.pi * freq * self.loadC)
|
||||
if self.loadL > 0:
|
||||
Zl = Zl + complex(0, 2 * math.pi * freq * self.loadL)
|
||||
g = (Zl / 50 - 1) / (Zl / 50 + 1) * cmath.exp(
|
||||
|
@ -340,13 +342,14 @@ class Calibration:
|
|||
def correct11(self, dp: Datapoint):
|
||||
i = self.interp
|
||||
s11 = (dp.z - i["e00"](dp.freq)) / (
|
||||
(dp.z * i["e11"](dp.freq)) - i["delta_e"](dp.freq))
|
||||
(dp.z * i["e11"](dp.freq)) - i["delta_e"](dp.freq))
|
||||
return Datapoint(dp.freq, s11.real, s11.imag)
|
||||
|
||||
def correct21(self, dp: Datapoint, dp11: Datapoint):
|
||||
i = self.interp
|
||||
s21 = (dp.z - i["e30"](dp.freq)) / i["e10e32"](dp.freq)
|
||||
s21 = s21 * (i["e10e01"](dp.freq) / (i["e11"](dp.freq) * dp11.z - i["delta_e"](dp.freq)))
|
||||
s21 = s21 * (i["e10e01"](dp.freq) / (i["e11"](dp.freq)
|
||||
* dp11.z - i["delta_e"](dp.freq)))
|
||||
return Datapoint(dp.freq, s21.real, s21.imag)
|
||||
|
||||
# TODO: implement tests
|
||||
|
@ -360,7 +363,8 @@ class Calibration:
|
|||
calfile.write(f"! {note}\n")
|
||||
calfile.write(
|
||||
"# Hz ShortR ShortI OpenR OpenI LoadR LoadI"
|
||||
" ThroughR ThroughI ThrureflR ThrureflI IsolationR IsolationI\n")
|
||||
" ThroughR ThroughI ThrureflR ThrureflI"
|
||||
" IsolationR IsolationI\n")
|
||||
for freq in self.dataset.frequencies():
|
||||
calfile.write(f"{self.dataset.get(freq)}\n")
|
||||
|
||||
|
@ -382,7 +386,8 @@ class Calibration:
|
|||
if line.startswith("#"):
|
||||
if not parsed_header and line == (
|
||||
"# Hz ShortR ShortI OpenR OpenI LoadR LoadI"
|
||||
" ThroughR ThroughI ThrureflR ThrureflI IsolationR IsolationI"):
|
||||
" ThroughR ThroughI ThrureflR ThrureflI"
|
||||
" IsolationR IsolationI"):
|
||||
parsed_header = True
|
||||
continue
|
||||
if not parsed_header:
|
||||
|
|
|
@ -65,6 +65,7 @@ class Chart:
|
|||
show_bands: bool = False
|
||||
vswr_lines: list = DC.field(default_factory=lambda: [])
|
||||
|
||||
|
||||
@DC.dataclass
|
||||
class ChartColors: # pylint: disable=too-many-instance-attributes
|
||||
background: QColor = QColor(QtCore.Qt.white)
|
||||
|
@ -131,11 +132,11 @@ def from_type(data) -> str:
|
|||
type_map = {
|
||||
bytearray: lambda x: x.hex(),
|
||||
QColor: lambda x: x.getRgb(),
|
||||
QByteArray: lambda x: x.toHex(),
|
||||
QByteArray: lambda x: x.toHex()
|
||||
}
|
||||
if type(data) in type_map:
|
||||
return str(type_map[type(data)](data))
|
||||
return str(data)
|
||||
return (f"{type_map[type(data)](data)}" if
|
||||
type(data) in type_map else
|
||||
f"{data}")
|
||||
|
||||
|
||||
def to_type(data: object, data_type: type) -> object:
|
||||
|
@ -145,11 +146,11 @@ def to_type(data: object, data_type: type) -> object:
|
|||
list: literal_eval,
|
||||
tuple: literal_eval,
|
||||
QColor: lambda x: QColor.fromRgb(*literal_eval(x)),
|
||||
QByteArray: lambda x: QByteArray.fromHex(literal_eval(x)),
|
||||
QByteArray: lambda x: QByteArray.fromHex(literal_eval(x))
|
||||
}
|
||||
if data_type in type_map:
|
||||
return type_map[data_type](data)
|
||||
return data_type(data)
|
||||
return (type_map[data_type](data) if
|
||||
data_type in type_map else
|
||||
data_type(data))
|
||||
|
||||
|
||||
# noinspection PyDataclass
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
from collections import OrderedDict
|
||||
from time import sleep
|
||||
from typing import List, Iterator, Set
|
||||
|
||||
|
@ -28,19 +27,19 @@ from NanoVNASaver.Hardware.Serial import Interface, drain_serial
|
|||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
DISLORD_BW = OrderedDict((
|
||||
(10, 363),
|
||||
(33, 117),
|
||||
(50, 78),
|
||||
(100, 39),
|
||||
(200, 19),
|
||||
(250, 15),
|
||||
(333, 11),
|
||||
(500, 7),
|
||||
(1000, 3),
|
||||
(2000, 1),
|
||||
(4000, 0),
|
||||
))
|
||||
DISLORD_BW = {
|
||||
10: 363,
|
||||
33: 117,
|
||||
50: 78,
|
||||
100: 39,
|
||||
200: 19,
|
||||
250: 15,
|
||||
333: 11,
|
||||
500: 7,
|
||||
1000: 3,
|
||||
2000: 1,
|
||||
4000: 0,
|
||||
}
|
||||
WAIT = 0.05
|
||||
|
||||
|
||||
|
|
|
@ -56,17 +56,20 @@ TYPES = (
|
|||
Label("s21groupdelay", "S21 Group Delay", "S21 Group Delay", False),
|
||||
Label("s21magshunt", "S21 |Z| shunt", "S21 Z Magnitude shunt", False),
|
||||
Label("s21magseries", "S21 |Z| series", "S21 Z Magnitude series", False),
|
||||
Label("s21realimagshunt", "S21 R+jX shunt", "S21 Z Real+Imag shunt", False),
|
||||
Label("s21realimagseries", "S21 R+jX series", "S21 Z Real+Imag series", False),
|
||||
Label("s21realimagshunt", "S21 R+jX shunt",
|
||||
"S21 Z Real+Imag shunt", False),
|
||||
Label("s21realimagseries", "S21 R+jX series",
|
||||
"S21 Z Real+Imag series", False),
|
||||
)
|
||||
|
||||
|
||||
def default_label_ids() -> str:
|
||||
return [l.label_id for l in TYPES if l.default_active]
|
||||
return [label.label_id for label in TYPES if label.default_active]
|
||||
|
||||
|
||||
class Value():
|
||||
"""Contains the data area to calculate marker values from"""
|
||||
|
||||
def __init__(self, freq: int = 0,
|
||||
s11: List[Datapoint] = None,
|
||||
s21: List[Datapoint] = None):
|
||||
|
@ -87,7 +90,8 @@ class Value():
|
|||
s11 += [s11[-1], ]
|
||||
if s21:
|
||||
s21 += [s21[-1], ]
|
||||
|
||||
self.freq = s11[1].freq
|
||||
self.s11 = s11[index-1:index+2]
|
||||
self.s11 = s11[index - 1:index + 2]
|
||||
if s21:
|
||||
self.s21 = s21[index-1:index+2]
|
||||
self.s21 = s21[index - 1:index + 2]
|
||||
|
|
|
@ -98,9 +98,9 @@ class Marker(QtCore.QObject, Value):
|
|||
# Data display labels
|
||||
###############################################################
|
||||
|
||||
self.label = {}
|
||||
for l in TYPES:
|
||||
self.label[l.label_id] = MarkerLabel(l.name)
|
||||
self.label = {
|
||||
label.label_id: MarkerLabel(label.name) for label in TYPES
|
||||
}
|
||||
self.label['actualfreq'].setMinimumWidth(100)
|
||||
self.label['returnloss'].setMinimumWidth(80)
|
||||
|
||||
|
@ -201,7 +201,7 @@ class Marker(QtCore.QObject, Value):
|
|||
for label_id in self.active_labels:
|
||||
self._add_active_labels(label_id, self.left_form)
|
||||
else:
|
||||
left_half = math.ceil(len(self.active_labels)/2)
|
||||
left_half = math.ceil(len(self.active_labels) / 2)
|
||||
right_half = len(self.active_labels)
|
||||
for i in range(left_half):
|
||||
label_id = self.active_labels[i]
|
||||
|
@ -258,8 +258,8 @@ class Marker(QtCore.QObject, Value):
|
|||
upper_stepsize = data[-1].freq - data[-2].freq
|
||||
|
||||
# We are outside the bounds of the data, so we can't put in a marker
|
||||
if (self.freq + lower_stepsize/2 < min_freq or
|
||||
self.freq - upper_stepsize/2 > max_freq):
|
||||
if (self.freq + lower_stepsize / 2 < min_freq or
|
||||
self.freq - upper_stepsize / 2 > max_freq):
|
||||
return
|
||||
|
||||
min_distance = max_freq
|
||||
|
@ -268,11 +268,11 @@ class Marker(QtCore.QObject, Value):
|
|||
min_distance = abs(item.freq - self.freq)
|
||||
else:
|
||||
# We have now started moving away from the nearest point
|
||||
self.location = i-1
|
||||
self.location = i - 1
|
||||
if i < datasize:
|
||||
self.frequencyInput.nextFrequency = item.freq
|
||||
if i >= 2:
|
||||
self.frequencyInput.previousFrequency = data[i-2].freq
|
||||
self.frequencyInput.previousFrequency = data[i - 2].freq
|
||||
return
|
||||
# If we still didn't find a best spot, it was the last value
|
||||
self.location = datasize - 1
|
||||
|
@ -292,7 +292,8 @@ class Marker(QtCore.QObject, Value):
|
|||
return
|
||||
if self.location == -1: # initial position
|
||||
try:
|
||||
location = (self.index -1) / (self._instances - 1) * (len(s11) - 1)
|
||||
location = (self.index - 1) / (
|
||||
(self._instances - 1) * (len(s11) - 1))
|
||||
self.location = int(location)
|
||||
except ZeroDivisionError:
|
||||
self.location = 0
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
import logging
|
||||
import sys
|
||||
import threading
|
||||
from collections import OrderedDict
|
||||
from time import strftime, localtime
|
||||
|
||||
from PyQt5 import QtWidgets, QtCore, QtGui
|
||||
|
@ -40,7 +39,8 @@ from .Charts import (
|
|||
CapacitanceChart,
|
||||
CombinedLogMagChart, GroupDelayChart, InductanceChart,
|
||||
LogMagChart, PhaseChart,
|
||||
MagnitudeChart, MagnitudeZChart, MagnitudeZShuntChart, MagnitudeZSeriesChart,
|
||||
MagnitudeChart, MagnitudeZChart, MagnitudeZShuntChart,
|
||||
MagnitudeZSeriesChart,
|
||||
QualityFactorChart, VSWRChart, PermeabilityChart, PolarChart,
|
||||
RealImaginaryChart, RealImaginaryShuntChart, RealImaginarySeriesChart,
|
||||
SmithChart, SParameterChart, TDRChart,
|
||||
|
@ -70,9 +70,11 @@ class NanoVNASaver(QtWidgets.QWidget):
|
|||
else:
|
||||
self.icon = QtGui.QIcon("icon_48x48.png")
|
||||
self.setWindowIcon(self.icon)
|
||||
self.settings = Defaults.AppSettings(QtCore.QSettings.IniFormat,
|
||||
QtCore.QSettings.UserScope,
|
||||
"NanoVNASaver", "NanoVNASaver")
|
||||
self.settings = Defaults.AppSettings(
|
||||
QtCore.QSettings.IniFormat,
|
||||
QtCore.QSettings.UserScope,
|
||||
"NanoVNASaver",
|
||||
"NanoVNASaver")
|
||||
logger.info("Settings from: %s", self.settings.fileName())
|
||||
Defaults.cfg = Defaults.restore(self.settings)
|
||||
self.threadpool = QtCore.QThreadPool()
|
||||
|
@ -126,7 +128,8 @@ class NanoVNASaver(QtWidgets.QWidget):
|
|||
self.resize(Defaults.cfg.gui.window_width,
|
||||
Defaults.cfg.gui.window_height)
|
||||
scrollarea.setSizePolicy(
|
||||
QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
|
||||
QtWidgets.QSizePolicy.MinimumExpanding,
|
||||
QtWidgets.QSizePolicy.MinimumExpanding)
|
||||
self.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding,
|
||||
QtWidgets.QSizePolicy.MinimumExpanding)
|
||||
widget = QtWidgets.QWidget()
|
||||
|
@ -134,39 +137,40 @@ class NanoVNASaver(QtWidgets.QWidget):
|
|||
scrollarea.setWidget(widget)
|
||||
|
||||
self.charts = {
|
||||
"s11": OrderedDict((
|
||||
("capacitance", CapacitanceChart("S11 Serial C")),
|
||||
("group_delay", GroupDelayChart("S11 Group Delay")),
|
||||
("inductance", InductanceChart("S11 Serial L")),
|
||||
("log_mag", LogMagChart("S11 Return Loss")),
|
||||
("magnitude", MagnitudeChart("|S11|")),
|
||||
("magnitude_z", MagnitudeZChart("S11 |Z|")),
|
||||
("permeability", PermeabilityChart(
|
||||
"s11": {
|
||||
"capacitance": CapacitanceChart("S11 Serial C"),
|
||||
"group_delay": GroupDelayChart("S11 Group Delay"),
|
||||
"inductance": InductanceChart("S11 Serial L"),
|
||||
"log_mag": LogMagChart("S11 Return Loss"),
|
||||
"magnitude": MagnitudeChart("|S11|"),
|
||||
"magnitude_z": MagnitudeZChart("S11 |Z|"),
|
||||
"permeability": PermeabilityChart(
|
||||
"S11 R/\N{GREEK SMALL LETTER OMEGA} &"
|
||||
" X/\N{GREEK SMALL LETTER OMEGA}")),
|
||||
("phase", PhaseChart("S11 Phase")),
|
||||
("q_factor", QualityFactorChart("S11 Quality Factor")),
|
||||
("real_imag", RealImaginaryChart("S11 R+jX")),
|
||||
("smith", SmithChart("S11 Smith Chart")),
|
||||
("s_parameter", SParameterChart("S11 Real/Imaginary")),
|
||||
("vswr", VSWRChart("S11 VSWR")),
|
||||
)),
|
||||
"s21": OrderedDict((
|
||||
("group_delay", GroupDelayChart("S21 Group Delay",
|
||||
reflective=False)),
|
||||
("log_mag", LogMagChart("S21 Gain")),
|
||||
("magnitude", MagnitudeChart("|S21|")),
|
||||
("magnitude_z_shunt", MagnitudeZShuntChart("S21 |Z| shunt")),
|
||||
("magnitude_z_series", MagnitudeZSeriesChart("S21 |Z| series")),
|
||||
("real_imag_shunt", RealImaginaryShuntChart("S21 R+jX shunt")),
|
||||
("real_imag_series", RealImaginarySeriesChart("S21 R+jX series")),
|
||||
("phase", PhaseChart("S21 Phase")),
|
||||
("polar", PolarChart("S21 Polar Plot")),
|
||||
("s_parameter", SParameterChart("S21 Real/Imaginary")),
|
||||
)),
|
||||
"combined": OrderedDict((
|
||||
("log_mag", CombinedLogMagChart("S11 & S21 LogMag")),
|
||||
)),
|
||||
" X/\N{GREEK SMALL LETTER OMEGA}"),
|
||||
"phase": PhaseChart("S11 Phase"),
|
||||
"q_factor": QualityFactorChart("S11 Quality Factor"),
|
||||
"real_imag": RealImaginaryChart("S11 R+jX"),
|
||||
"smith": SmithChart("S11 Smith Chart"),
|
||||
"s_parameter": SParameterChart("S11 Real/Imaginary"),
|
||||
"vswr": VSWRChart("S11 VSWR"),
|
||||
},
|
||||
"s21": {
|
||||
"group_delay": GroupDelayChart("S21 Group Delay",
|
||||
reflective=False),
|
||||
"log_mag": LogMagChart("S21 Gain"),
|
||||
"magnitude": MagnitudeChart("|S21|"),
|
||||
"magnitude_z_shunt": MagnitudeZShuntChart("S21 |Z| shunt"),
|
||||
"magnitude_z_series": MagnitudeZSeriesChart("S21 |Z| series"),
|
||||
"real_imag_shunt": RealImaginaryShuntChart("S21 R+jX shunt"),
|
||||
"real_imag_series": RealImaginarySeriesChart(
|
||||
"S21 R+jX series"),
|
||||
"phase": PhaseChart("S21 Phase"),
|
||||
"polar": PolarChart("S21 Polar Plot"),
|
||||
"s_parameter": SParameterChart("S21 Real/Imaginary"),
|
||||
},
|
||||
"combined": {
|
||||
"log_mag": CombinedLogMagChart("S11 & S21 LogMag"),
|
||||
},
|
||||
}
|
||||
self.tdr_chart = TDRChart("TDR")
|
||||
self.tdr_mainwindow_chart = TDRChart("TDR")
|
||||
|
@ -515,7 +519,8 @@ class NanoVNASaver(QtWidgets.QWidget):
|
|||
if s11:
|
||||
min_vswr = min(s11, key=lambda data: data.vswr)
|
||||
self.s11_min_swr_label.setText(
|
||||
f"{format_vswr(min_vswr.vswr)} @ {format_frequency(min_vswr.freq)}")
|
||||
f"{format_vswr(min_vswr.vswr)} @"
|
||||
f" {format_frequency(min_vswr.freq)}")
|
||||
self.s11_min_rl_label.setText(format_gain(min_vswr.gain))
|
||||
else:
|
||||
self.s11_min_swr_label.setText("")
|
||||
|
|
|
@ -58,13 +58,16 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
calibration_status_layout = QtWidgets.QFormLayout()
|
||||
self.calibration_status_label = QtWidgets.QLabel("Device calibration")
|
||||
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)
|
||||
calibration_status_layout.addRow("Calibration:",
|
||||
self.calibration_status_label)
|
||||
calibration_status_layout.addRow("Source:",
|
||||
self.calibration_source_label)
|
||||
calibration_status_group.setLayout(calibration_status_layout)
|
||||
left_layout.addWidget(calibration_status_group)
|
||||
|
||||
calibration_control_group = QtWidgets.QGroupBox("Calibrate")
|
||||
calibration_control_layout = QtWidgets.QFormLayout(calibration_control_group)
|
||||
calibration_control_layout = QtWidgets.QFormLayout(
|
||||
calibration_control_group)
|
||||
cal_btn = {}
|
||||
self.cal_label = {}
|
||||
for label_name in Calibration.CAL_NAMES:
|
||||
|
@ -72,7 +75,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
cal_btn[label_name] = QtWidgets.QPushButton(
|
||||
label_name.capitalize())
|
||||
cal_btn[label_name].setMinimumHeight(20)
|
||||
cal_btn[label_name].clicked.connect(partial(self.manual_save, label_name))
|
||||
cal_btn[label_name].clicked.connect(
|
||||
partial(self.manual_save, label_name))
|
||||
calibration_control_layout.addRow(
|
||||
cal_btn[label_name], self.cal_label[label_name])
|
||||
|
||||
|
@ -85,7 +89,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
self.input_offset_delay.setRange(-10e6, 10e6)
|
||||
|
||||
calibration_control_layout.addRow(QtWidgets.QLabel(""))
|
||||
calibration_control_layout.addRow("Offset delay", self.input_offset_delay)
|
||||
calibration_control_layout.addRow(
|
||||
"Offset delay", self.input_offset_delay)
|
||||
|
||||
self.btn_automatic = QtWidgets.QPushButton("Calibration assistant")
|
||||
self.btn_automatic.setMinimumHeight(20)
|
||||
|
@ -110,7 +115,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
left_layout.addWidget(calibration_control_group)
|
||||
|
||||
calibration_notes_group = QtWidgets.QGroupBox("Notes")
|
||||
calibration_notes_layout = QtWidgets.QVBoxLayout(calibration_notes_group)
|
||||
calibration_notes_layout = QtWidgets.QVBoxLayout(
|
||||
calibration_notes_group)
|
||||
self.notes_textedit = QtWidgets.QPlainTextEdit()
|
||||
calibration_notes_layout.addWidget(self.notes_textedit)
|
||||
|
||||
|
@ -208,7 +214,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
cal_standard_layout.addWidget(self.cal_through_box)
|
||||
|
||||
self.cal_standard_save_box = QtWidgets.QGroupBox("Saved settings")
|
||||
cal_standard_save_layout = QtWidgets.QVBoxLayout(self.cal_standard_save_box)
|
||||
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()
|
||||
|
@ -237,15 +244,18 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
if not self.app.settings.value("ExpertCalibrationUser", False, bool):
|
||||
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.",
|
||||
(
|
||||
"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)
|
||||
|
||||
|
@ -256,7 +266,7 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
return True
|
||||
|
||||
def cal_save(self, name: str):
|
||||
if name in ("through", "isolation"):
|
||||
if name in {"through", "isolation"}:
|
||||
self.app.calibration.insert(name, self.app.data.s21)
|
||||
else:
|
||||
self.app.calibration.insert(name, self.app.data.s11)
|
||||
|
@ -269,7 +279,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
|
||||
def listCalibrationStandards(self):
|
||||
self.cal_standard_save_selector.clear()
|
||||
num_standards = self.app.settings.beginReadArray("CalibrationStandards")
|
||||
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")
|
||||
|
@ -279,7 +290,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
self.cal_standard_save_selector.setCurrentText("New")
|
||||
|
||||
def saveCalibrationStandard(self):
|
||||
num_standards = self.app.settings.beginReadArray("CalibrationStandards")
|
||||
num_standards = self.app.settings.beginReadArray(
|
||||
"CalibrationStandards")
|
||||
self.app.settings.endArray()
|
||||
|
||||
if self.cal_standard_save_selector.currentData() == -1:
|
||||
|
@ -295,7 +307,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
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.beginWriteArray(
|
||||
"CalibrationStandards", num_standards)
|
||||
self.app.settings.setArrayIndex(write_num)
|
||||
self.app.settings.setValue("Name", name)
|
||||
|
||||
|
@ -338,7 +351,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
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.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)))
|
||||
|
@ -351,7 +365,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
self.load_capacitance.setText(str(self.app.settings.value("LoadC", 0)))
|
||||
self.load_length.setText(str(self.app.settings.value("LoadDelay", 0)))
|
||||
|
||||
self.through_length.setText(str(self.app.settings.value("ThroughDelay", 0)))
|
||||
self.through_length.setText(
|
||||
str(self.app.settings.value("ThroughDelay", 0)))
|
||||
|
||||
self.app.settings.endArray()
|
||||
|
||||
|
@ -360,7 +375,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
return
|
||||
delete_num = self.cal_standard_save_selector.currentData()
|
||||
logger.debug("Deleting calibration no %d", delete_num)
|
||||
num_standards = self.app.settings.beginReadArray("CalibrationStandards")
|
||||
num_standards = self.app.settings.beginReadArray(
|
||||
"CalibrationStandards")
|
||||
self.app.settings.endArray()
|
||||
|
||||
logger.debug("Number of standards known: %d", num_standards)
|
||||
|
@ -422,7 +438,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
self.app.settings.remove("")
|
||||
self.app.settings.endArray()
|
||||
|
||||
self.app.settings.beginWriteArray("CalibrationStandards", len(names))
|
||||
self.app.settings.beginWriteArray(
|
||||
"CalibrationStandards", len(names))
|
||||
for i, name in enumerate(names):
|
||||
self.app.settings.setArrayIndex(i)
|
||||
self.app.settings.setValue("Name", name)
|
||||
|
@ -475,14 +492,21 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
self.app.worker.applyCalibration(
|
||||
self.app.worker.rawData11, self.app.worker.rawData21)
|
||||
logger.debug("Saving and displaying corrected data.")
|
||||
self.app.saveData(self.app.worker.data11, self.app.worker.data21, self.app.sweepSource)
|
||||
self.app.saveData(self.app.worker.data11,
|
||||
self.app.worker.data21, self.app.sweepSource)
|
||||
self.app.worker.signals.updated.emit()
|
||||
|
||||
def calculate(self):
|
||||
def _warn_ideal(cal_type: str) -> str:
|
||||
return (
|
||||
'Invalid data for "{cal_type}" calibration standard.'
|
||||
' Using ideal values.')
|
||||
|
||||
if self.app.sweep_control.btn_stop.isEnabled():
|
||||
# Currently sweeping
|
||||
self.app.showError("Unable to apply calibration while a sweep is running. " +
|
||||
"Please stop the sweep and try again.")
|
||||
self.app.showError(
|
||||
"Unable to apply calibration while a sweep is running."
|
||||
" Please stop the sweep and try again.")
|
||||
return
|
||||
if self.use_ideal_values.isChecked():
|
||||
self.app.calibration.useIdealShort = True
|
||||
|
@ -505,8 +529,7 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
self.app.calibration.useIdealShort = False
|
||||
except ValueError:
|
||||
self.app.calibration.useIdealShort = True
|
||||
logger.warning(
|
||||
'Invalid data for "short" calibration standard. Using ideal values.')
|
||||
logger.warning(_warn_ideal("short"))
|
||||
|
||||
try:
|
||||
self.app.calibration.openC0 = self.getFloatValue(
|
||||
|
@ -522,8 +545,7 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
self.app.calibration.useIdealOpen = False
|
||||
except ValueError:
|
||||
self.app.calibration.useIdealOpen = True
|
||||
logger.warning(
|
||||
'Invalid data for "open" calibration standard. Using ideal values.')
|
||||
logger.warning(_warn_ideal("open"))
|
||||
|
||||
try:
|
||||
self.app.calibration.loadR = self.getFloatValue(
|
||||
|
@ -537,18 +559,15 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
self.app.calibration.useIdealLoad = False
|
||||
except ValueError:
|
||||
self.app.calibration.useIdealLoad = True
|
||||
logger.warning(
|
||||
'Invalid data for "load" calibration standard.'
|
||||
' Using ideal values.')
|
||||
logger.warning(_warn_ideal("load"))
|
||||
|
||||
try:
|
||||
self.app.calibration.throughLength = self.getFloatValue(
|
||||
self.through_length.text()) / 10 ** 12
|
||||
self.app.calibration.useIdealThrough = False
|
||||
except ValueError:
|
||||
self.app.calibration.useIdealThrough = True
|
||||
logger.warning(
|
||||
'Invalid data for "through" calibration standard.'
|
||||
' Using ideal values.')
|
||||
logger.warning(_warn_ideal("through"))
|
||||
|
||||
logger.debug("Attempting calibration calculation.")
|
||||
try:
|
||||
|
@ -557,32 +576,35 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
_format_cal_label(self.app.calibration.size(),
|
||||
"Application calibration"))
|
||||
if self.use_ideal_values.isChecked():
|
||||
self.calibration_source_label.setText(self.app.calibration.source)
|
||||
self.calibration_source_label.setText(
|
||||
self.app.calibration.source)
|
||||
else:
|
||||
self.calibration_source_label.setText(
|
||||
self.app.calibration.source + " (Standards: Custom)")
|
||||
f"{self.app.calibration.source} (Standards: Custom)")
|
||||
|
||||
if len(self.app.worker.rawData11) > 0:
|
||||
if self.app.worker.rawData11:
|
||||
# There's raw data, so we can get corrected data
|
||||
logger.debug("Applying calibration to existing sweep data.")
|
||||
self.app.worker.data11, self.app.worker.data21 = self.app.worker.applyCalibration(
|
||||
self.app.worker.rawData11, self.app.worker.rawData21)
|
||||
self.app.worker.data11, self.app.worker.data21 = (
|
||||
self.app.worker.applyCalibration(
|
||||
self.app.worker.rawData11,
|
||||
self.app.worker.rawData21))
|
||||
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()
|
||||
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", str(e))
|
||||
self.calibration_status_label.setText("Applying calibration failed.")
|
||||
# showError here hides the calibration window,
|
||||
# so we need to pop up our own
|
||||
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)
|
||||
|
||||
@staticmethod
|
||||
def getFloatValue(text: str) -> float:
|
||||
if text == "":
|
||||
# Default value is float
|
||||
return 0
|
||||
return float(text)
|
||||
return float(text) if text else 0.0
|
||||
|
||||
def loadCalibration(self):
|
||||
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
|
||||
|
@ -594,7 +616,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
for i, name in enumerate(
|
||||
("short", "open", "load", "through", "isolation", "thrurefl")):
|
||||
self.cal_label[name].setText(
|
||||
_format_cal_label(self.app.calibration.data_size(name), "Loaded"))
|
||||
_format_cal_label(self.app.calibration.data_size(name),
|
||||
"Loaded"))
|
||||
if i == 2 and not self.app.calibration.isValid2Port():
|
||||
break
|
||||
self.calculate()
|
||||
|
@ -612,15 +635,15 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
filedialog.setDefaultSuffix("cal")
|
||||
filedialog.setNameFilter("Calibration Files (*.cal);;All files (*.*)")
|
||||
filedialog.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
|
||||
selected = filedialog.exec()
|
||||
if selected:
|
||||
if filedialog.exec():
|
||||
filename = filedialog.selectedFiles()[0]
|
||||
else:
|
||||
return
|
||||
if filename == "":
|
||||
if not filename:
|
||||
logger.debug("No file name selected.")
|
||||
return
|
||||
self.app.calibration.notes = self.notes_textedit.toPlainText().splitlines()
|
||||
self.app.calibration.notes = self.notes_textedit.toPlainText(
|
||||
).splitlines()
|
||||
try:
|
||||
self.app.calibration.save(filename)
|
||||
self.app.settings.setValue("CalibrationFile", filename)
|
||||
|
@ -633,25 +656,28 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
self.cal_open_box.setDisabled(self.use_ideal_values.isChecked())
|
||||
self.cal_load_box.setDisabled(self.use_ideal_values.isChecked())
|
||||
self.cal_through_box.setDisabled(self.use_ideal_values.isChecked())
|
||||
self.cal_standard_save_box.setDisabled(self.use_ideal_values.isChecked())
|
||||
self.cal_standard_save_box.setDisabled(
|
||||
self.use_ideal_values.isChecked())
|
||||
|
||||
def automaticCalibration(self):
|
||||
self.btn_automatic.setDisabled(True)
|
||||
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",
|
||||
(
|
||||
"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)
|
||||
response = introduction.exec()
|
||||
if response != QtWidgets.QMessageBox.Ok:
|
||||
|
@ -662,7 +688,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
QtWidgets.QMessageBox(
|
||||
QtWidgets.QMessageBox.Information,
|
||||
"NanoVNA not connected",
|
||||
"Please ensure the NanoVNA is connected before attempting calibration."
|
||||
("Please ensure the NanoVNA is connected before attempting"
|
||||
" calibration.")
|
||||
).exec()
|
||||
self.btn_automatic.setDisabled(False)
|
||||
return
|
||||
|
@ -671,7 +698,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
QtWidgets.QMessageBox(
|
||||
QtWidgets.QMessageBox.Information,
|
||||
"Continuous sweep enabled",
|
||||
"Please disable continuous sweeping before attempting calibration."
|
||||
("Please disable continuous sweeping before attempting"
|
||||
" calibration.")
|
||||
).exec()
|
||||
self.btn_automatic.setDisabled(False)
|
||||
return
|
||||
|
@ -679,8 +707,11 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
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.",
|
||||
(
|
||||
"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)
|
||||
|
||||
response = short_step.exec()
|
||||
|
@ -696,7 +727,8 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
|
||||
def automaticCalibrationStep(self):
|
||||
if self.nextStep == -1:
|
||||
self.app.worker.signals.finished.disconnect(self.automaticCalibrationStep)
|
||||
self.app.worker.signals.finished.disconnect(
|
||||
self.automaticCalibrationStep)
|
||||
return
|
||||
|
||||
if self.nextStep == 0:
|
||||
|
@ -707,10 +739,13 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
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.",
|
||||
(
|
||||
"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)
|
||||
|
||||
response = open_step.exec()
|
||||
|
@ -730,8 +765,11 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
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.",
|
||||
(
|
||||
"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)
|
||||
|
||||
response = load_step.exec()
|
||||
|
@ -751,9 +789,13 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
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\"",
|
||||
(
|
||||
"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)
|
||||
|
||||
|
@ -761,21 +803,27 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
if response == QtWidgets.QMessageBox.Apply:
|
||||
self.calculate()
|
||||
self.nextStep = -1
|
||||
self.app.worker.signals.finished.disconnect(self.automaticCalibrationStep)
|
||||
self.app.worker.signals.finished.disconnect(
|
||||
self.automaticCalibrationStep)
|
||||
self.btn_automatic.setDisabled(False)
|
||||
return
|
||||
if response != QtWidgets.QMessageBox.Yes:
|
||||
self.btn_automatic.setDisabled(False)
|
||||
self.nextStep = -1
|
||||
self.app.worker.signals.finished.disconnect(self.automaticCalibrationStep)
|
||||
self.app.worker.signals.finished.disconnect(
|
||||
self.automaticCalibrationStep)
|
||||
return
|
||||
|
||||
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.",
|
||||
(
|
||||
"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()
|
||||
|
@ -795,9 +843,11 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
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.",
|
||||
(
|
||||
"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)
|
||||
|
||||
response = through_step.exec()
|
||||
|
@ -817,8 +867,10 @@ class CalibrationWindow(QtWidgets.QWidget):
|
|||
apply_step = QtWidgets.QMessageBox(
|
||||
QtWidgets.QMessageBox.Information,
|
||||
"Calibrate complete",
|
||||
"The calibration process is now complete. Press \"Apply\" to apply "
|
||||
"the calibration parameters.",
|
||||
(
|
||||
"The calibration process is now complete. Press"
|
||||
" \"Apply\" to apply the calibration parameters."
|
||||
),
|
||||
QtWidgets.QMessageBox.Apply | QtWidgets.QMessageBox.Cancel)
|
||||
|
||||
response = apply_step.exec()
|
||||
|
|
|
@ -58,7 +58,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
self.returnloss_group.addButton(self.returnloss_is_positive)
|
||||
self.returnloss_group.addButton(self.returnloss_is_negative)
|
||||
|
||||
display_options_layout.addRow("Return loss is:", self.returnloss_is_negative)
|
||||
display_options_layout.addRow(
|
||||
"Return loss is:", self.returnloss_is_negative)
|
||||
display_options_layout.addRow("", self.returnloss_is_positive)
|
||||
|
||||
self.returnloss_is_positive.setChecked(
|
||||
|
@ -70,7 +71,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
self.changeReturnLoss()
|
||||
|
||||
self.show_lines_option = QtWidgets.QCheckBox("Show lines")
|
||||
show_lines_label = QtWidgets.QLabel("Displays a thin line between data points")
|
||||
show_lines_label = QtWidgets.QLabel(
|
||||
"Displays a thin line between data points")
|
||||
self.show_lines_option.stateChanged.connect(self.changeShowLines)
|
||||
display_options_layout.addRow(self.show_lines_option, show_lines_label)
|
||||
|
||||
|
@ -103,7 +105,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
self.lineThicknessInput.setSuffix(" px")
|
||||
self.lineThicknessInput.setAlignment(QtCore.Qt.AlignRight)
|
||||
self.lineThicknessInput.valueChanged.connect(self.changeLineThickness)
|
||||
display_options_layout.addRow("Line thickness", self.lineThicknessInput)
|
||||
display_options_layout.addRow(
|
||||
"Line thickness", self.lineThicknessInput)
|
||||
|
||||
self.markerSizeInput = QtWidgets.QSpinBox()
|
||||
self.markerSizeInput.setMinimumHeight(20)
|
||||
|
@ -117,18 +120,26 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
self.markerSizeInput.valueChanged.connect(self.changeMarkerSize)
|
||||
display_options_layout.addRow("Marker size", self.markerSizeInput)
|
||||
|
||||
self.show_marker_number_option = QtWidgets.QCheckBox("Show marker numbers")
|
||||
show_marker_number_label = QtWidgets.QLabel("Displays the marker number next to the marker")
|
||||
self.show_marker_number_option.stateChanged.connect(self.changeShowMarkerNumber)
|
||||
display_options_layout.addRow(self.show_marker_number_option, show_marker_number_label)
|
||||
self.show_marker_number_option = QtWidgets.QCheckBox(
|
||||
"Show marker numbers")
|
||||
show_marker_number_label = QtWidgets.QLabel(
|
||||
"Displays the marker number next to the marker")
|
||||
self.show_marker_number_option.stateChanged.connect(
|
||||
self.changeShowMarkerNumber)
|
||||
display_options_layout.addRow(
|
||||
self.show_marker_number_option, show_marker_number_label)
|
||||
|
||||
self.filled_marker_option = QtWidgets.QCheckBox("Filled markers")
|
||||
filled_marker_label = QtWidgets.QLabel("Shows the marker as a filled triangle")
|
||||
self.filled_marker_option.stateChanged.connect(self.changeFilledMarkers)
|
||||
display_options_layout.addRow(self.filled_marker_option, filled_marker_label)
|
||||
filled_marker_label = QtWidgets.QLabel(
|
||||
"Shows the marker as a filled triangle")
|
||||
self.filled_marker_option.stateChanged.connect(
|
||||
self.changeFilledMarkers)
|
||||
display_options_layout.addRow(
|
||||
self.filled_marker_option, filled_marker_label)
|
||||
|
||||
self.marker_tip_group = QtWidgets.QButtonGroup()
|
||||
self.marker_at_center = QtWidgets.QRadioButton("At the center of the marker")
|
||||
self.marker_at_center = QtWidgets.QRadioButton(
|
||||
"At the center of the marker")
|
||||
self.marker_at_tip = QtWidgets.QRadioButton("At the tip of the marker")
|
||||
self.marker_tip_group.addButton(self.marker_at_center)
|
||||
self.marker_tip_group.addButton(self.marker_at_tip)
|
||||
|
@ -170,7 +181,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
|
||||
self.show_bands = QtWidgets.QCheckBox("Show bands")
|
||||
self.show_bands.setChecked(self.app.bands.enabled)
|
||||
self.show_bands.stateChanged.connect(lambda: self.setShowBands(self.show_bands.isChecked()))
|
||||
self.show_bands.stateChanged.connect(
|
||||
lambda: self.setShowBands(self.show_bands.isChecked()))
|
||||
bands_layout.addRow(self.show_bands)
|
||||
bands_layout.addRow(
|
||||
"Chart bands",
|
||||
|
@ -187,14 +199,15 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
vswr_marker_box = QtWidgets.QGroupBox("VSWR Markers")
|
||||
vswr_marker_layout = QtWidgets.QFormLayout(vswr_marker_box)
|
||||
|
||||
self.vswrMarkers: List[float] = self.app.settings.value("VSWRMarkers", [], float)
|
||||
self.vswrMarkers: List[float] = self.app.settings.value(
|
||||
"VSWRMarkers", [], float)
|
||||
|
||||
if isinstance(self.vswrMarkers, float):
|
||||
# Single values from the .ini become floats rather than lists. Convert them.
|
||||
self.vswrMarkers = [] if self.vswrMarkers == 0.0 else [self.vswrMarkers]
|
||||
|
||||
vswr_marker_layout.addRow(
|
||||
"VSWR Markers",self.color_picker("VSWRColor", "swr"))
|
||||
"VSWR Markers", self.color_picker("VSWRColor", "swr"))
|
||||
|
||||
self.vswr_marker_dropdown = QtWidgets.QComboBox()
|
||||
self.vswr_marker_dropdown.setMinimumHeight(20)
|
||||
|
@ -416,9 +429,7 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
for c in self.app.selectable_charts:
|
||||
if c.name == chart:
|
||||
found = c
|
||||
|
||||
self.app.settings.setValue("Chart" + str(x) + str(y), chart)
|
||||
|
||||
self.app.settings.setValue(f"Chart{x}{y}", chart)
|
||||
old_widget = self.app.charts_layout.itemAtPosition(x, y)
|
||||
if old_widget is not None:
|
||||
w = old_widget.widget()
|
||||
|
@ -428,7 +439,6 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
if self.app.charts_layout.indexOf(found) > -1:
|
||||
logger.debug("%s is already shown, duplicating.", found.name)
|
||||
found = self.app.copyChart(found)
|
||||
|
||||
self.app.charts_layout.addWidget(found, x, y)
|
||||
if found.isHidden():
|
||||
found.show()
|
||||
|
@ -471,7 +481,7 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
c.setPointSize(size)
|
||||
|
||||
def changeLineThickness(self, size: int):
|
||||
Defaults.cfg.chart.line_thickness = int(size)
|
||||
Defaults.cfg.chart.line_thickness = size
|
||||
for c in self.app.subscribing_charts:
|
||||
c.setLineThickness(size)
|
||||
|
||||
|
@ -551,7 +561,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
|
||||
new_marker.updated.connect(self.app.markerUpdated)
|
||||
label, layout = new_marker.getRow()
|
||||
self.app.marker_control.layout.insertRow(Marker.count() - 1, label, layout)
|
||||
self.app.marker_control.layout.insertRow(
|
||||
Marker.count() - 1, label, layout)
|
||||
self.btn_remove_marker.setDisabled(False)
|
||||
|
||||
if Marker.count() >= 2:
|
||||
|
@ -569,7 +580,7 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
|
||||
last_marker.updated.disconnect(self.app.markerUpdated)
|
||||
self.app.marker_data_layout.removeWidget(last_marker.get_data_layout())
|
||||
self.app.marker_control.layout.removeRow(Marker.count()-1)
|
||||
self.app.marker_control.layout.removeRow(Marker.count() - 1)
|
||||
self.app.marker_frame.adjustSize()
|
||||
|
||||
last_marker.get_data_layout().hide()
|
||||
|
@ -579,7 +590,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
|
||||
def addVSWRMarker(self):
|
||||
value, selected = QtWidgets.QInputDialog.getDouble(
|
||||
self, "Add VSWR Marker", "VSWR value to show:", min=1.001, decimals=3)
|
||||
self, "Add VSWR Marker", "VSWR value to show:",
|
||||
min=1.001, decimals=3)
|
||||
if selected:
|
||||
self.vswrMarkers.append(value)
|
||||
if self.vswr_marker_dropdown.itemText(0) == "None":
|
||||
|
@ -595,7 +607,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
if value_str != "None":
|
||||
value = float(value_str)
|
||||
self.vswrMarkers.remove(value)
|
||||
self.vswr_marker_dropdown.removeItem(self.vswr_marker_dropdown.currentIndex())
|
||||
self.vswr_marker_dropdown.removeItem(
|
||||
self.vswr_marker_dropdown.currentIndex())
|
||||
if self.vswr_marker_dropdown.count() == 0:
|
||||
self.vswr_marker_dropdown.addItem("None")
|
||||
self.app.settings.remove("VSWRMarkers")
|
||||
|
@ -607,4 +620,4 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
def updateCharts(self):
|
||||
for c in self.app.subscribing_charts:
|
||||
c.update()
|
||||
Defaults.store(self.app.settings, Defaults.cfg)
|
||||
Defaults.store(self.app.settings, Defaults.cfg)
|
||||
|
|
Ładowanie…
Reference in New Issue