From 00d9884d321395ac5a037ea8ff226de5625835bd Mon Sep 17 00:00:00 2001 From: Holger Mueller Date: Fri, 27 May 2022 09:03:37 +0200 Subject: [PATCH] just linting --- NanoVNASaver/Analysis/Analysis.py | 12 ++++---- NanoVNASaver/Analysis/AntennaAnalysis.py | 8 ++--- NanoVNASaver/Analysis/VSWRAnalysis.py | 20 ++++++------ NanoVNASaver/Calibration.py | 34 ++++++++++----------- NanoVNASaver/Controls/Control.py | 1 + NanoVNASaver/Controls/MarkerControl.py | 4 +-- NanoVNASaver/Controls/SerialControl.py | 1 + NanoVNASaver/Formatting.py | 8 +++-- NanoVNASaver/Hardware/Hardware.py | 32 +++++++++---------- NanoVNASaver/Hardware/NanoVNA.py | 1 - NanoVNASaver/Hardware/NanoVNA_V2.py | 7 +++-- NanoVNASaver/Hardware/TinySA.py | 1 - NanoVNASaver/Hardware/VNA.py | 4 +-- NanoVNASaver/Inputs.py | 1 - NanoVNASaver/Marker/Delta.py | 7 +++-- NanoVNASaver/RFTools.py | 26 ++++------------ NanoVNASaver/SITools.py | 15 +++++---- NanoVNASaver/Settings/Sweep.py | 28 ++++++++--------- NanoVNASaver/SweepWorker.py | 1 + NanoVNASaver/Touchstone.py | 11 +++---- NanoVNASaver/Windows/CalibrationSettings.py | 28 ++++++++--------- NanoVNASaver/Windows/Files.py | 1 + NanoVNASaver/Windows/SweepSettings.py | 2 +- NanoVNASaver/__main__.py | 1 + nanovna-saver.py | 1 + test/test_formatSweepFrequency.py | 4 +-- test/test_parseFrequency.py | 2 +- test/test_rftools.py | 2 +- test/test_settings.py | 8 ++--- test/test_sitools.py | 11 +++++-- test/test_sweep.py | 1 + test/test_touchstone.py | 6 ++-- test/test_version.py | 3 ++ 33 files changed, 146 insertions(+), 146 deletions(-) diff --git a/NanoVNASaver/Analysis/Analysis.py b/NanoVNASaver/Analysis/Analysis.py index 3060156..fa0d782 100644 --- a/NanoVNASaver/Analysis/Analysis.py +++ b/NanoVNASaver/Analysis/Analysis.py @@ -30,7 +30,7 @@ class Analysis: @classmethod def find_crossing_zero(cls, data): - ''' + """ Find values crossing zero return list of tuples (before, crossing, after) @@ -44,7 +44,7 @@ class Analysis: :param cls: :param data: list of values - ''' + """ my_data = np.array(data) zeroes = np.where(my_data == 0)[0] @@ -65,7 +65,7 @@ class Analysis: @classmethod def find_minimums(cls, data, threshold): - ''' + """ Find values above threshold return list of tuples (start, lowest, end) @@ -75,7 +75,7 @@ class Analysis: :param cls: :param data: list of values :param threshold: - ''' + """ minimums = [] min_start = -1 @@ -100,7 +100,7 @@ class Analysis: @classmethod def find_maximums(cls, data, threshold=None): - ''' + """ Find peacs @@ -108,7 +108,7 @@ class Analysis: :param cls: :param data: list of values :param threshold: - ''' + """ peaks, _ = signal.find_peaks( data, width=2, distance=3, prominence=1) diff --git a/NanoVNASaver/Analysis/AntennaAnalysis.py b/NanoVNASaver/Analysis/AntennaAnalysis.py index bbc97de..d2a6130 100644 --- a/NanoVNASaver/Analysis/AntennaAnalysis.py +++ b/NanoVNASaver/Analysis/AntennaAnalysis.py @@ -34,11 +34,11 @@ logger = logging.getLogger(__name__) class MagLoopAnalysis(VSWRAnalysis): - ''' + """ Find min vswr and change sweep to zoom. Useful for tuning magloop. - ''' + """ max_dips_shown = 1 vswr_bandwith_value = 2.56 # -3 dB ?!? @@ -115,10 +115,10 @@ class MagLoopAnalysis(VSWRAnalysis): QTimer.singleShot(2000, self._safe_sweep) def _safe_sweep(self): - ''' + """ sweep only if button enabled to prevent multiple/concurrent sweep - ''' + """ if self.app.sweep_control.btn_start.isEnabled(): self.app.sweep_start() diff --git a/NanoVNASaver/Analysis/VSWRAnalysis.py b/NanoVNASaver/Analysis/VSWRAnalysis.py index 24d2f1e..bd8be17 100644 --- a/NanoVNASaver/Analysis/VSWRAnalysis.py +++ b/NanoVNASaver/Analysis/VSWRAnalysis.py @@ -220,10 +220,10 @@ class ResonanceAnalysis(Analysis): for _ in range(results_header, self.layout.rowCount()): self.layout.removeRow(self.layout.rowCount() - 1) -# if len(crossing) > max_dips_shown: -# self.layout.addRow(QtWidgets.QLabel("More than " + str(max_dips_shown) + -# " dips found. Lowest shown.")) -# self.crossing = crossing[:max_dips_shown] + # if len(crossing) > max_dips_shown: + # self.layout.addRow(QtWidgets.QLabel("More than " + str(max_dips_shown) + + # " dips found. Lowest shown.")) + # self.crossing = crossing[:max_dips_shown] if len(crossing) > 0: extended_data = [] for m in crossing: @@ -262,9 +262,9 @@ class ResonanceAnalysis(Analysis): class EFHWAnalysis(ResonanceAnalysis): - ''' + """ find only resonance when HI impedance - ''' + """ old_data = [] def reset(self): @@ -296,7 +296,7 @@ class EFHWAnalysis(ResonanceAnalysis): extended_data = OrderedDict() - #both = np.intersect1d([i[1] for i in crossing], maximums) + # both = np.intersect1d([i[1] for i in crossing], maximums) both = [] tolerance = 2 @@ -320,7 +320,6 @@ 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) @@ -366,7 +365,6 @@ class EFHWAnalysis(ResonanceAnalysis): 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']})" @@ -389,7 +387,7 @@ class EFHWAnalysis(ResonanceAnalysis): writer.writerow(row) def compare(self, old, new, fields=None): - ''' + """ Compare data to help changes NB @@ -397,7 +395,7 @@ class EFHWAnalysis(ResonanceAnalysis): ( same index must be same frequence ) :param old: :param new: - ''' + """ fields = fields or [("freq", str), ] def no_compare(): diff --git a/NanoVNASaver/Calibration.py b/NanoVNASaver/Calibration.py index 5c592d6..b084bf8 100644 --- a/NanoVNASaver/Calibration.py +++ b/NanoVNASaver/Calibration.py @@ -198,14 +198,14 @@ class Calibration: g2 * g3 * gm2 - g2 * g3 * gm3 - (g2 * gm2 - g3 * gm3) * g1) cal["e00"] = - ((g2 * gm3 - g3 * gm3) * g1 * gm2 - - (g2 * g3 * gm2 - g2 * g3 * gm3 - - (g3 * gm2 - g2 * gm3) * g1) * gm1 - ) / denominator + (g2 * g3 * gm2 - g2 * g3 * gm3 - + (g3 * gm2 - g2 * gm3) * g1) * gm1 + ) / denominator cal["e11"] = ((g2 - g3) * gm1 - g1 * (gm2 - gm3) + - g3 * gm2 - g2 * gm3) / denominator + g3 * gm2 - g2 * gm3) / denominator cal["delta_e"] = - ((g1 * (gm2 - gm3) - g2 * gm2 + g3 * - gm3) * gm1 + (g2 * gm3 - g3 * gm3) * - gm2) / denominator + gm3) * gm1 + (g2 * gm3 - g3 * gm3) * + gm2) / denominator def _calc_port_2(self, freq: int, cal: CalData): gt = self.gamma_through(freq) @@ -218,9 +218,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 +254,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 +266,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 @@ -324,8 +324,8 @@ class Calibration: kind="slinear", bounds_error=False, fill_value=(delta_e[0], delta_e[-1])), "e10e01": interp1d(freq, e10e01, - kind="slinear", bounds_error=False, - fill_value=(e10e01[0], e10e01[-1])), + kind="slinear", bounds_error=False, + fill_value=(e10e01[0], e10e01[-1])), "e30": interp1d(freq, e30, kind="slinear", bounds_error=False, fill_value=(e30[0], e30[-1])), @@ -340,13 +340,13 @@ 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 @@ -381,7 +381,7 @@ class Calibration: continue if line.startswith("#"): if not parsed_header and line == ( - "# Hz ShortR ShortI OpenR OpenI LoadR LoadI" + "# Hz ShortR ShortI OpenR OpenI LoadR LoadI" " ThroughR ThroughI ThrureflR ThrureflI IsolationR IsolationI"): parsed_header = True continue diff --git a/NanoVNASaver/Controls/Control.py b/NanoVNASaver/Controls/Control.py index ad88295..a165f42 100644 --- a/NanoVNASaver/Controls/Control.py +++ b/NanoVNASaver/Controls/Control.py @@ -22,6 +22,7 @@ from PyQt5 import QtWidgets, QtCore logger = logging.getLogger(__name__) + class Control(QtWidgets.QGroupBox): updated = QtCore.pyqtSignal(object) diff --git a/NanoVNASaver/Controls/MarkerControl.py b/NanoVNASaver/Controls/MarkerControl.py index 86f0508..3f31c4b 100644 --- a/NanoVNASaver/Controls/MarkerControl.py +++ b/NanoVNASaver/Controls/MarkerControl.py @@ -25,12 +25,11 @@ from NanoVNASaver import Defaults from NanoVNASaver.Marker import Marker from NanoVNASaver.Controls.Control import Control - logger = logging.getLogger(__name__) class ShowButton(QtWidgets.QPushButton): - def setText(self, text: str=''): + def setText(self, text: str = ''): if not text: text = ("Show data" if Defaults.cfg.gui.markers_hidden else "Hide data") @@ -87,6 +86,7 @@ class MarkerControl(Control): Defaults.cfg.gui.markers_hidden) self.showMarkerButton.setText() self.showMarkerButton.repaint() + settings(self.app.marker_frame.isHidden()) def toggle_delta(self): diff --git a/NanoVNASaver/Controls/SerialControl.py b/NanoVNASaver/Controls/SerialControl.py index cf0096f..206bed3 100644 --- a/NanoVNASaver/Controls/SerialControl.py +++ b/NanoVNASaver/Controls/SerialControl.py @@ -26,6 +26,7 @@ from NanoVNASaver.Controls.Control import Control logger = logging.getLogger(__name__) + class SerialControl(Control): def __init__(self, app: QtWidgets.QWidget): diff --git a/NanoVNASaver/Formatting.py b/NanoVNASaver/Formatting.py index 49e8aba..e429393 100644 --- a/NanoVNASaver/Formatting.py +++ b/NanoVNASaver/Formatting.py @@ -18,6 +18,7 @@ # along with this program. If not, see . import math from numbers import Number +from typing import Union from NanoVNASaver import SITools @@ -42,13 +43,14 @@ FMT_PARSE = SITools.Format(parse_sloppy_unit=True, parse_sloppy_kilo=True, parse_clamp_min=0) FMT_PARSE_VALUE = SITools.Format( parse_sloppy_unit=True, parse_sloppy_kilo=True) +FMT_VSWR = SITools.Format(max_nr_digits=3) def format_frequency(freq: Number) -> str: return str(SITools.Value(freq, "Hz", FMT_FREQ)) -def format_frequency_inputs(freq: float) -> str: +def format_frequency_inputs(freq: Union[Number, str]) -> str: return str(SITools.Value(freq, "Hz", FMT_FREQ_INPUTS)) @@ -140,7 +142,7 @@ def format_wavelength(length: Number) -> str: return str(SITools.Value(length, "m", FMT_WAVELENGTH)) -def format_y_axis(val: float, unit: str="") -> str: +def format_y_axis(val: float, unit: str = "") -> str: return str(SITools.Value(val, unit, FMT_SHORT)) @@ -152,7 +154,7 @@ def parse_frequency(freq: str) -> int: def parse_value(val: str, unit: str = "", - fmt: SITools.Format = FMT_PARSE_VALUE) -> int: + fmt: SITools.Format = FMT_PARSE_VALUE) -> float: try: val.replace(',', '.') return float(SITools.Value(val, unit, fmt)) diff --git a/NanoVNASaver/Hardware/Hardware.py b/NanoVNASaver/Hardware/Hardware.py index a609fa1..67d91a5 100644 --- a/NanoVNASaver/Hardware/Hardware.py +++ b/NanoVNASaver/Hardware/Hardware.py @@ -25,6 +25,7 @@ from typing import List import serial from serial.tools import list_ports +from NanoVNASaver.Hardware.VNA import VNA from NanoVNASaver.Hardware.AVNA import AVNA from NanoVNASaver.Hardware.NanoVNA import NanoVNA from NanoVNASaver.Hardware.NanoVNA_F import NanoVNA_F @@ -34,8 +35,6 @@ from NanoVNASaver.Hardware.NanoVNA_H4 import NanoVNA_H4 from NanoVNASaver.Hardware.NanoVNA_V2 import NanoVNA_V2 from NanoVNASaver.Hardware.TinySA import TinySA from NanoVNASaver.Hardware.Serial import drain_serial, Interface -from NanoVNASaver.Hardware.VNA import VNA - logger = logging.getLogger(__name__) @@ -51,7 +50,7 @@ TIMEOUT = 0.2 WAIT = 0.05 NAME2DEVICE = { - "S-A-A-2" : NanoVNA_V2, + "S-A-A-2": NanoVNA_V2, "AVNA": AVNA, "H4": NanoVNA_H4, "H": NanoVNA_H, @@ -62,6 +61,7 @@ NAME2DEVICE = { "Unknown": NanoVNA, } + # The USB Driver for NanoVNA V2 seems to deliver an # incompatible hardware info like: # 'PORTS\\VID_04B4&PID_0008\\DEMO' @@ -88,11 +88,7 @@ def get_interfaces() -> List[Interface]: t.name, d.vid, d.pid, d.device) iface = Interface('serial', t.name) iface.port = d.device - try: - iface.open() - except serial.SerialException: - logger.warning("Could not open serial port %s", d.device) - continue + iface.open() iface.comment = get_comment(iface) iface.close() interfaces.append(iface) @@ -101,10 +97,11 @@ def get_interfaces() -> List[Interface]: return interfaces -def get_VNA(iface: Interface) -> 'VNA': +def get_VNA(iface: Interface) -> VNA: # serial_port.timeout = TIMEOUT return NAME2DEVICE[iface.comment](iface) + def get_comment(iface: Interface) -> str: logger.info("Finding correct VNA type...") with iface.lock: @@ -116,19 +113,20 @@ def get_comment(iface: Interface) -> str: logger.info("Finding firmware variant...") info = get_info(iface) for search, name in ( - ("AVNA + Teensy", "AVNA"), - ("NanoVNA-H 4", "H4"), - ("NanoVNA-H", "H"), - ("NanoVNA-F_V2", "F_V2"), - ("NanoVNA-F", "F"), - ("NanoVNA", "NanoVNA"), - ("tinySA", "tinySA"), + ("AVNA + Teensy", "AVNA"), + ("NanoVNA-H 4", "H4"), + ("NanoVNA-H", "H"), + ("NanoVNA-F_V2", "F_V2"), + ("NanoVNA-F", "F"), + ("NanoVNA", "NanoVNA"), + ("tinySA", "tinySA"), ): if info.find(search) >= 0: - return name + return name logger.warning("Did not recognize NanoVNA type from firmware.") return "Unknown" + def detect_version(serial_port: serial.Serial) -> str: data = "" for i in range(RETRIES): diff --git a/NanoVNASaver/Hardware/NanoVNA.py b/NanoVNASaver/Hardware/NanoVNA.py index 4c36009..e572045 100644 --- a/NanoVNASaver/Hardware/NanoVNA.py +++ b/NanoVNASaver/Hardware/NanoVNA.py @@ -61,7 +61,6 @@ class NanoVNA(VNA): timeout = self.serial.timeout with self.serial.lock: drain_serial(self.serial) - timeout = self.serial.timeout self.serial.write("capture\r".encode('ascii')) self.serial.readline() self.serial.timeout = 4 diff --git a/NanoVNASaver/Hardware/NanoVNA_V2.py b/NanoVNASaver/Hardware/NanoVNA_V2.py index e87c756..d067564 100644 --- a/NanoVNASaver/Hardware/NanoVNA_V2.py +++ b/NanoVNASaver/Hardware/NanoVNA_V2.py @@ -66,6 +66,7 @@ _ADF4350_TXPOWER_DESC_MAP = { _ADF4350_TXPOWER_DESC_REV_MAP = { value: key for key, value in _ADF4350_TXPOWER_DESC_MAP.items()} + class NanoVNA_V2(VNA): name = "NanoVNA-V2" valid_datapoints = (101, 11, 51, 201, 301, 501, 1023) @@ -145,7 +146,7 @@ class NanoVNA_V2(VNA): sleep(WRITE_SLEEP) # clear sweepdata self._sweepdata = [(complex(), complex())] * ( - self.datapoints + s21hack) + self.datapoints + s21hack) pointstodo = self.datapoints + s21hack # we read at most 255 values at a time and the time required empirically is # just over 3 seconds for 101 points or 7 seconds for 255 points @@ -178,7 +179,7 @@ class NanoVNA_V2(VNA): for i in range(pointstoread): (fwd_real, fwd_imag, rev0_real, rev0_imag, rev1_real, rev1_imag, freq_index) = unpack_from( - " bool: diff --git a/NanoVNASaver/Inputs.py b/NanoVNASaver/Inputs.py index ca73605..97c0d1c 100644 --- a/NanoVNASaver/Inputs.py +++ b/NanoVNASaver/Inputs.py @@ -28,7 +28,6 @@ class FrequencyInputWidget(QtWidgets.QLineEdit): self.previousFrequency = -1 def setText(self, text: str) -> None: - # TODO: Fix wrong type here super().setText(format_frequency_inputs(text)) diff --git a/NanoVNASaver/Marker/Delta.py b/NanoVNASaver/Marker/Delta.py index f13f9b1..2d9b712 100644 --- a/NanoVNASaver/Marker/Delta.py +++ b/NanoVNASaver/Marker/Delta.py @@ -37,6 +37,7 @@ from NanoVNASaver.Formatting import ( from .Widget import Marker + class DeltaMarker(Marker): def __init__(self, name: str = "", qsettings: QtCore.QSettings = None): super().__init__(name, qsettings) @@ -71,10 +72,10 @@ class DeltaMarker(Marker): imp_p = imp_p_b - imp_p_a cap_p_str = format_capacitance( - RFTools.impedance_to_capacitance(imp_p_b, s11_b.freq)- + RFTools.impedance_to_capacitance(imp_p_b, s11_b.freq) - RFTools.impedance_to_capacitance(imp_p_a, s11_a.freq)) ind_p_str = format_inductance( - RFTools.impedance_to_inductance(imp_p_b, s11_b.freq)- + RFTools.impedance_to_inductance(imp_p_b, s11_b.freq) - RFTools.impedance_to_inductance(imp_p_a, s11_a.freq)) x_str = cap_str if imp.imag < 0 else ind_str @@ -126,5 +127,5 @@ class DeltaMarker(Marker): self.label['s21phase'].setText(format_phase( s21_b.phase - s21_a.phase)) self.label['s21polar'].setText( - f"{round(abs(s21_b.z) - abs(s21_a.z) , 2)}∠" + f"{round(abs(s21_b.z) - abs(s21_a.z), 2)}∠" f"{format_phase(s21_b.phase - s21_a.phase)}") diff --git a/NanoVNASaver/RFTools.py b/NanoVNASaver/RFTools.py index 6084b6f..1110e66 100644 --- a/NanoVNASaver/RFTools.py +++ b/NanoVNASaver/RFTools.py @@ -45,16 +45,12 @@ class Datapoint(NamedTuple): @property def gain(self) -> float: mag = abs(self.z) - if mag > 0: - return 20 * math.log10(mag) - return -math.inf + return 20 * math.log10(mag) if mag > 0 else -math.inf @property def vswr(self) -> float: mag = abs(self.z) - if mag >= 1: - return math.inf - return (1 + mag) / (1 - mag) + return (1 + mag) / (1 - mag) if mag < 1 else math.inf @property def wavelength(self) -> float: @@ -77,9 +73,7 @@ class Datapoint(NamedTuple): def qFactor(self, ref_impedance: float = 50) -> float: imp = self.impedance(ref_impedance) - if imp.real == 0.0: - return -1 - return abs(imp.imag / imp.real) + return -1 if imp.real == 0.0 else abs(imp.imag / imp.real) def capacitiveEquivalent(self, ref_impedance: float = 50) -> float: return impedance_to_capacitance(self.impedance(ref_impedance), self.freq) @@ -101,9 +95,7 @@ def groupDelay(data: List[Datapoint], index: int) -> float: idx1 = clamp_value(index + 1, 0, len(data) - 1) delta_angle = data[idx1].phase - data[idx0].phase delta_freq = data[idx1].freq - data[idx0].freq - if delta_freq == 0: - return 0 - return -delta_angle / math.tau / delta_freq + return 0 if delta_freq == 0 else -delta_angle / math.tau / delta_freq def impedance_to_capacitance(z: complex, freq: float) -> float: @@ -117,9 +109,7 @@ def impedance_to_capacitance(z: complex, freq: float) -> float: def impedance_to_inductance(z: complex, freq: float) -> float: """Calculate inductive equivalent for reactance""" - if freq == 0: - return 0 - return z.imag * 1 / (freq * 2 * math.pi) + return 0 if freq == 0 else z.imag * 1 / (freq * 2 * math.pi) def impedance_to_norm(z: complex, ref_impedance: float = 50) -> complex: @@ -134,8 +124,7 @@ def norm_to_impedance(z: complex, ref_impedance: float = 50) -> complex: def parallel_to_serial(z: complex) -> complex: """Convert parallel impedance to serial impedance equivalent""" - z_sq_sum = z.real ** 2 + z.imag ** 2 - # TODO: Fix divide by zero + z_sq_sum = z.real ** 2 + z.imag ** 2 or 10.0e-30 return complex(z.real * z.imag ** 2 / z_sq_sum, z.real ** 2 * z.imag / z_sq_sum) @@ -150,9 +139,6 @@ def serial_to_parallel(z: complex) -> complex: z_sq_sum = z.real ** 2 + z.imag ** 2 if z.real == 0 and z.imag == 0: return complex(math.inf, math.inf) - # only possible if real and imag == 0, therefor commented out - # if z_sq_sum == 0: - # return complex(0, 0) if z.imag == 0: return complex(z_sq_sum / z.real, math.copysign(math.inf, z_sq_sum)) if z.real == 0: diff --git a/NanoVNASaver/SITools.py b/NanoVNASaver/SITools.py index 5bd03f9..c2c7546 100644 --- a/NanoVNASaver/SITools.py +++ b/NanoVNASaver/SITools.py @@ -34,14 +34,17 @@ def clamp_value(value: Real, rmin: Real, rmax: Real) -> Real: return rmax return value -def round_ceil(value: Real, digits: int=0) -> Real: - factor = 10 ** digits + +def round_ceil(value: Real, digits: int = 0) -> Real: + factor = 10 ** -digits return factor * math.ceil(value / factor) -def round_floor(value: Real, digits: int=0) -> Real: - factor = 10 ** digits + +def round_floor(value: Real, digits: int = 0) -> Real: + factor = 10 ** -digits return factor * math.floor(value / factor) + class Format(NamedTuple): max_nr_digits: int = 6 fix_decimals: bool = False @@ -105,8 +108,8 @@ class Value: formstr = ".0f" else: max_digits = fmt.max_nr_digits + ( - (1 if not fmt.fix_decimals and abs(real) < 10 else 0) + - (1 if not fmt.fix_decimals and abs(real) < 100 else 0)) + (1 if not fmt.fix_decimals and abs(real) < 10 else 0) + + (1 if not fmt.fix_decimals and abs(real) < 100 else 0)) formstr = f".{max_digits - 3}f" if self.fmt.allways_signed: diff --git a/NanoVNASaver/Settings/Sweep.py b/NanoVNASaver/Settings/Sweep.py index edcad2b..fa4900c 100644 --- a/NanoVNASaver/Settings/Sweep.py +++ b/NanoVNASaver/Settings/Sweep.py @@ -31,7 +31,7 @@ class SweepMode(Enum): AVERAGE = 2 -class Properties(): +class Properties: def __init__(self, name: str = "", mode: 'SweepMode' = SweepMode.SINGLE, averages: Tuple[int, int] = (3, 0), @@ -47,7 +47,7 @@ class Properties(): f" {self.logarithmic})") -class Sweep(): +class Sweep: def __init__(self, start: int = 3600000, end: int = 30000000, points: int = 101, segments: int = 1, properties: 'Properties' = Properties()): @@ -66,11 +66,11 @@ class Sweep(): f" {self.properties})") def __eq__(self, other) -> bool: - return(self.start == other.start and - self.end == other.end and - self.points == other.points and - self.segments == other.segments and - self.properties == other.properties) + return (self.start == other.start and + self.end == other.end and + self.points == other.points and + self.segments == other.segments and + self.properties == other.properties) def copy(self) -> 'Sweep': return Sweep(self.start, self.end, self.points, self.segments, @@ -82,15 +82,15 @@ class Sweep(): @property def stepsize(self) -> int: - return round(self.span / (self.points * self.segments - 1)) + return round(self.span / (self.points * self.segments - 1)) def check(self): if ( - self.segments <= 0 - or self.points <= 0 - or self.start <= 0 - or self.end <= 0 - or self.stepsize < 1 + self.segments <= 0 + or self.points <= 0 + or self.start <= 0 + or self.end <= 0 + or self.stepsize < 1 ): raise ValueError(f"Illegal sweep settings: {self}") @@ -105,7 +105,7 @@ class Sweep(): start = round(self.start + self.span * self._exp_factor(index)) end = round(self.start + self.span * self._exp_factor(index + 1)) logger.debug("get_index_range(%s) -> (%s, %s)", index, start, end) - return (start, end) + return start, end def get_frequencies(self) -> Iterator[int]: for i in range(self.segments): diff --git a/NanoVNASaver/SweepWorker.py b/NanoVNASaver/SweepWorker.py index c4da6d7..26b8689 100644 --- a/NanoVNASaver/SweepWorker.py +++ b/NanoVNASaver/SweepWorker.py @@ -226,6 +226,7 @@ class SweepWorker(QtCore.QRunnable): logger.debug("Reading average no %d / %d", i + 1, averages) retry = 0 tmp11 = [] + tmp21 = [] while not tmp11 and retry < 5: sleep(0.5 * retry) retry += 1 diff --git a/NanoVNASaver/Touchstone.py b/NanoVNASaver/Touchstone.py index 4cd28b5..32521a0 100644 --- a/NanoVNASaver/Touchstone.py +++ b/NanoVNASaver/Touchstone.py @@ -35,10 +35,10 @@ class Options: # Fun fact: In Touchstone 1.1 spec all params are optional unordered. # Just the line has to start with "#" UNIT_TO_FACTOR = { - "ghz": 10**9, - "mhz": 10**6, - "khz": 10**3, - "hz": 10**0, + "ghz": 10 ** 9, + "mhz": 10 ** 6, + "khz": 10 ** 3, + "hz": 10 ** 0, } VALID_UNITS = UNIT_TO_FACTOR.keys() VALID_PARAMETERS = "syzgh" @@ -98,7 +98,7 @@ class Options: class Touchstone: FIELD_ORDER = ("11", "21", "12", "22") - def __init__(self, filename: str=""): + def __init__(self, filename: str = ""): self.filename = filename self.sdata = [[], [], [], []] # at max 4 data pairs self.comments = [] @@ -244,7 +244,6 @@ class Touchstone: if data_len % 2 != 0: raise TypeError("Data values aren't pairs: " + line) - # consistency checks if freq <= prev_freq: logger.warning("Frequency not ascending: %s", line) diff --git a/NanoVNASaver/Windows/CalibrationSettings.py b/NanoVNASaver/Windows/CalibrationSettings.py index 4df6f1a..6fe5866 100644 --- a/NanoVNASaver/Windows/CalibrationSettings.py +++ b/NanoVNASaver/Windows/CalibrationSettings.py @@ -187,7 +187,7 @@ class CalibrationWindow(QtWidgets.QWidget): self.load_inductance.setMinimumHeight(20) self.load_capacitance = QtWidgets.QLineEdit("0") self.load_capacitance.setMinimumHeight(20) - #self.load_capacitance.setDisabled(True) # Not yet implemented + # self.load_capacitance.setDisabled(True) # Not yet implemented self.load_length = QtWidgets.QLineEdit("0") self.load_length.setMinimumHeight(20) cal_load_form.addRow("Resistance (\N{OHM SIGN})", self.load_resistance) @@ -493,15 +493,15 @@ class CalibrationWindow(QtWidgets.QWidget): # We are using custom calibration standards try: self.app.calibration.shortL0 = self.getFloatValue( - self.short_l0_input.text())/10**12 + self.short_l0_input.text()) / 10 ** 12 self.app.calibration.shortL1 = self.getFloatValue( - self.short_l1_input.text())/10**24 + self.short_l1_input.text()) / 10 ** 24 self.app.calibration.shortL2 = self.getFloatValue( - self.short_l2_input.text())/10**33 + self.short_l2_input.text()) / 10 ** 33 self.app.calibration.shortL3 = self.getFloatValue( - self.short_l3_input.text())/10**42 + self.short_l3_input.text()) / 10 ** 42 self.app.calibration.shortLength = self.getFloatValue( - self.short_length.text())/10**12 + self.short_length.text()) / 10 ** 12 self.app.calibration.useIdealShort = False except ValueError: self.app.calibration.useIdealShort = True @@ -510,15 +510,15 @@ class CalibrationWindow(QtWidgets.QWidget): try: self.app.calibration.openC0 = self.getFloatValue( - self.open_c0_input.text())/10**15 + self.open_c0_input.text()) / 10 ** 15 self.app.calibration.openC1 = self.getFloatValue( - self.open_c1_input.text())/10**27 + self.open_c1_input.text()) / 10 ** 27 self.app.calibration.openC2 = self.getFloatValue( - self.open_c2_input.text())/10**36 + self.open_c2_input.text()) / 10 ** 36 self.app.calibration.openC3 = self.getFloatValue( - self.open_c3_input.text())/10**45 + self.open_c3_input.text()) / 10 ** 45 self.app.calibration.openLength = self.getFloatValue( - self.open_length.text())/10**12 + self.open_length.text()) / 10 ** 12 self.app.calibration.useIdealOpen = False except ValueError: self.app.calibration.useIdealOpen = True @@ -529,11 +529,11 @@ class CalibrationWindow(QtWidgets.QWidget): self.app.calibration.loadR = self.getFloatValue( self.load_resistance.text()) self.app.calibration.loadL = self.getFloatValue( - self.load_inductance.text()) / 10**12 + self.load_inductance.text()) / 10 ** 12 self.app.calibration.loadC = self.getFloatValue( self.load_capacitance.text()) / 10 ** 15 self.app.calibration.loadLength = self.getFloatValue( - self.load_length.text())/10**12 + self.load_length.text()) / 10 ** 12 self.app.calibration.useIdealLoad = False except ValueError: self.app.calibration.useIdealLoad = True @@ -542,7 +542,7 @@ class CalibrationWindow(QtWidgets.QWidget): ' Using ideal values.') try: self.app.calibration.throughLength = self.getFloatValue( - self.through_length.text())/10**12 + self.through_length.text()) / 10 ** 12 self.app.calibration.useIdealThrough = False except ValueError: self.app.calibration.useIdealThrough = True diff --git a/NanoVNASaver/Windows/Files.py b/NanoVNASaver/Windows/Files.py index 28c37e4..1e4b673 100644 --- a/NanoVNASaver/Windows/Files.py +++ b/NanoVNASaver/Windows/Files.py @@ -24,6 +24,7 @@ from NanoVNASaver.RFTools import Datapoint logger = logging.getLogger(__name__) + class FilesWindow(QtWidgets.QWidget): def __init__(self, app: QtWidgets.QWidget): super().__init__() diff --git a/NanoVNASaver/Windows/SweepSettings.py b/NanoVNASaver/Windows/SweepSettings.py index 9e6e901..17627b6 100644 --- a/NanoVNASaver/Windows/SweepSettings.py +++ b/NanoVNASaver/Windows/SweepSettings.py @@ -102,7 +102,7 @@ class SweepSettingsWindow(QtWidgets.QWidget): " amount of datapoints and many segments. Step display in" " SweepControl cannot reflect this currently.") label.setWordWrap(True) - label.setMinimumSize(600,70) + label.setMinimumSize(600, 70) layout.addRow(label) checkbox = QtWidgets.QCheckBox("Logarithmic sweep") checkbox.setMinimumHeight(20) diff --git a/NanoVNASaver/__main__.py b/NanoVNASaver/__main__.py index 817e1ba..10503c0 100644 --- a/NanoVNASaver/__main__.py +++ b/NanoVNASaver/__main__.py @@ -101,5 +101,6 @@ def main(): logger.exception("%s", exc) raise exc + if __name__ == '__main__': main() diff --git a/nanovna-saver.py b/nanovna-saver.py index 44adaa6..d6b6e51 100755 --- a/nanovna-saver.py +++ b/nanovna-saver.py @@ -17,6 +17,7 @@ from contextlib import suppress +# noinspection PyUnresolvedReferences with suppress(ImportError): # pylint: disable=no-name-in-module,import-error,unused-import # pyright: reportMissingImports=false diff --git a/test/test_formatSweepFrequency.py b/test/test_formatSweepFrequency.py index 5db3d59..925fe54 100644 --- a/test/test_formatSweepFrequency.py +++ b/test/test_formatSweepFrequency.py @@ -24,6 +24,7 @@ import unittest # Import targets to be tested from NanoVNASaver.Formatting import format_frequency_sweep + class TestCases(unittest.TestCase): def test_basicIntegerValues(self): @@ -47,7 +48,7 @@ class TestCases(unittest.TestCase): # self.assertEqual(rft.formatSweepFrequency(10000), '10.00kHz') # self.assertEqual(rft.formatSweepFrequency(100000), '100.00kHz') # self.assertEqual(rft.formatSweepFrequency(1000000), '1.00MHz') - + # def test_nonDefaultMinDigits(self): # # simple integers with trailing zeros. setting mindigit value to something # # other than default, where trailing zeros >= mindigits, the number of @@ -69,4 +70,3 @@ class TestCases(unittest.TestCase): # # TODO: Consider post-processing result for maxdigits based on SI unit. # self.assertEqual(rft.formatSweepFrequency(1000, mindigits=5), '1.00000kHz') # self.assertEqual(rft.formatSweepFrequency(1000, mindigits=10), '1.0000000000kHz') - diff --git a/test/test_parseFrequency.py b/test/test_parseFrequency.py index e273634..4e5b358 100644 --- a/test/test_parseFrequency.py +++ b/test/test_parseFrequency.py @@ -22,6 +22,7 @@ import unittest # Import targets to be tested from NanoVNASaver.Formatting import parse_frequency + # TODO: should be tested against SITools.Value # RFTools.parseFrequency will hopefully go away in future # and be specialised by input field and device, like @@ -149,4 +150,3 @@ class TestCases(unittest.TestCase): self.assertEqual(parse_frequency('123...Hz'), -1) self.assertEqual(parse_frequency('123....Hz'), -1) self.assertEqual(parse_frequency('1.23.Hz'), -1) - diff --git a/test/test_rftools.py b/test/test_rftools.py index abd9dc4..677d68f 100644 --- a/test/test_rftools.py +++ b/test/test_rftools.py @@ -75,7 +75,7 @@ class TestRFTools(unittest.TestCase): self.assertEqual(clamp_value(1, -10, -1), -1) def test_parallel_to_serial(self): - self.assertRaises(ZeroDivisionError, parallel_to_serial, 0) + self.assertEqual(parallel_to_serial(0), complex(0, 0)) self.assertAlmostEqual( parallel_to_serial(complex(52, 260)), complex(50, 10)) diff --git a/test/test_settings.py b/test/test_settings.py index d6f0f08..4b06d4d 100644 --- a/test/test_settings.py +++ b/test/test_settings.py @@ -29,7 +29,7 @@ class TConfig: my_str: str = "Hello World" my_bool: bool = True my_list: list = field(default_factory=lambda: [1, 2, 3]) - my_bytearray: bytearray = field(default_factory=lambda: bytearray((1,2,3))) + my_bytearray: bytearray = field(default_factory=lambda: bytearray((1, 2, 3))) class TestCases(unittest.TestCase): @@ -37,7 +37,7 @@ class TestCases(unittest.TestCase): def setUp(self) -> None: self.settings_1 = CFG.AppSettings( CFG.QSettings.IniFormat, - CFG.QSettings.UserScope, + CFG.QSettings.UserScope, "NanoVNASaver", "Test_1") self.settings_2 = CFG.AppSettings( CFG.QSettings.IniFormat, @@ -57,7 +57,7 @@ class TestCases(unittest.TestCase): illegal_config = TConfig( my_int=4, my_float=3.0, my_str="Goodbye World", my_bool="False", my_list=(4, 5, 6)) - with self.assertRaises(AssertionError): + with self.assertRaises(TypeError): self.settings_1.store_dataclass("SectionX", illegal_config) def test_restore_dataclass(self): @@ -85,4 +85,4 @@ class TestCases(unittest.TestCase): tc_2 = CFG.restore(self.settings_2) print(f"\n{tc_1}\n{tc_2}\n") self.assertEqual(tc_1, tc_2) - self.assertNotEqual(tc_2.gui, CFG.GUI()) \ No newline at end of file + self.assertNotEqual(tc_2.gui, CFG.GUI()) diff --git a/test/test_sitools.py b/test/test_sitools.py index f968a19..06c8b59 100644 --- a/test/test_sitools.py +++ b/test/test_sitools.py @@ -21,7 +21,7 @@ from math import inf from decimal import Decimal # Needed for test_representation() # Import targets to be tested -from NanoVNASaver.SITools import Format, Value +from NanoVNASaver.SITools import Format, Value, round_floor, round_ceil F_DEFAULT = Format() @@ -145,7 +145,6 @@ class TestTSIToolsValue(unittest.TestCase): self.assertEqual(v.parse("\N{INFINITY}").value, inf) self.assertEqual(v.parse("-\N{INFINITY}").value, -inf) - def test_format_attributes(self): v = Value("10.0", "Hz", fmt=F_DIGITS_4) self.assertEqual(v.value, 10.0) @@ -156,7 +155,13 @@ class TestTSIToolsValue(unittest.TestCase): v.parse("12 GHz") self.assertEqual(v.unit, "Hz") - + def test_rounding(self): + self.assertEqual(round_floor(123.456), 123) + self.assertEqual(round_floor(123.456, 1), 123.4) + self.assertEqual(round_floor(123.456, -1), 120) + self.assertEqual(round_ceil(123.456), 124) + self.assertEqual(round_ceil(123.456, 1), 123.5) + self.assertEqual(round_ceil(123.456, -1), 130) # TODO: test F_DIGITS_31 # F_WITH_SPACE diff --git a/test/test_sweep.py b/test/test_sweep.py index 4f1539a..e4733bb 100644 --- a/test/test_sweep.py +++ b/test/test_sweep.py @@ -21,6 +21,7 @@ import unittest # Import targets to be tested from NanoVNASaver.Settings.Sweep import Sweep, Properties + class TestCases(unittest.TestCase): def test_sweep(self): diff --git a/test/test_touchstone.py b/test/test_touchstone.py index d3e9e92..02b59c0 100644 --- a/test/test_touchstone.py +++ b/test/test_touchstone.py @@ -24,6 +24,7 @@ import os from NanoVNASaver.Touchstone import Options, Touchstone from NanoVNASaver.RFTools import Datapoint + class TestTouchstoneOptions(unittest.TestCase): def setUp(self): self.opts = Options() @@ -113,7 +114,7 @@ class TestTouchstoneTouchstone(unittest.TestCase): s11, s21, s12, s22 = ts.sdata ts.swap() s11_, s21_, s12_, s22_ = ts.sdata - self.assertEqual([s11_, s21_, s12_, s22_] ,[s22, s12, s21, s11]) + self.assertEqual([s11_, s21_, s12_, s22_], [s22, s12, s21, s11]) def test_db_conversation(self): ts_db = Touchstone("./test/data/attenuator-0643_DB.s2p") @@ -143,7 +144,7 @@ class TestTouchstoneTouchstone(unittest.TestCase): ' 15000000.0 0.849810063 -0.4147357 -0.000306106 0.0041482' ' 0.0 0.0 0.0 0.0', 'WARNING:NanoVNASaver.Touchstone:Reordering data', - ]) + ]) self.assertEqual(str(ts.opts), "# HZ S RI R 50") self.assertEqual(len(ts.s11), 101) self.assertIn("!freq ReS11 ImS11 ReS21 ImS21 ReS12 ImS12 ReS22 ImS22", @@ -165,7 +166,6 @@ class TestTouchstoneTouchstone(unittest.TestCase): ts.gen_interpolation() self.assertEqual(ts.s_freq("11", 2), Datapoint(2, 0.5, 0.5)) - def test_save(self): ts = Touchstone("./test/data/valid.s2p") self.assertEqual(ts.saves(), "# HZ S RI R 50\n") diff --git a/test/test_version.py b/test/test_version.py index ac41c17..451cb4b 100644 --- a/test/test_version.py +++ b/test/test_version.py @@ -21,6 +21,7 @@ import unittest # Import targets to be tested from NanoVNASaver.Version import Version + class TestCases(unittest.TestCase): def test_version(self): @@ -30,9 +31,11 @@ class TestCases(unittest.TestCase): self.assertFalse(ver > Version("1.2.4")) self.assertFalse(ver > Version("1.2.3-u")) self.assertTrue(Version("1.2.4") >= ver) + self.assertTrue(ver < Version("1.2.4")) self.assertFalse(Version("0.0.0") == Version("0.0.0-rc")) self.assertEqual(ver.major, 1) self.assertEqual(ver.minor, 2) self.assertEqual(ver.revision, 3) self.assertEqual(ver.note, '-test') Version("asdasd") + Version("1.2.invalid")