diff --git a/nanovna-saver.py b/nanovna-saver.py
index 9204e91..eabbcf3 100755
--- a/nanovna-saver.py
+++ b/nanovna-saver.py
@@ -28,9 +28,10 @@ try:
from NanoVNASaver.__main__ import main
except ModuleNotFoundError:
import sys
- sys.path.append('src')
+
+ sys.path.append("src")
from NanoVNASaver.__main__ import main
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/src/NanoVNASaver/About.py b/src/NanoVNASaver/About.py
index 5b864fe..b98e5c6 100644
--- a/src/NanoVNASaver/About.py
+++ b/src/NanoVNASaver/About.py
@@ -20,7 +20,8 @@
VERSION = "0.6.0-pre"
VERSION_URL = (
"https://raw.githubusercontent.com/"
- "NanoVNA-Saver/nanovna-saver/master/NanoVNASaver/About.py")
+ "NanoVNA-Saver/nanovna-saver/master/NanoVNASaver/About.py"
+)
INFO_URL = "https://github.com/NanoVNA-Saver/nanovna-saver"
INFO = f"""NanoVNASaver {VERSION}
diff --git a/src/NanoVNASaver/Analysis/AntennaAnalysis.py b/src/NanoVNASaver/Analysis/AntennaAnalysis.py
index 0be936e..248f114 100644
--- a/src/NanoVNASaver/Analysis/AntennaAnalysis.py
+++ b/src/NanoVNASaver/Analysis/AntennaAnalysis.py
@@ -35,6 +35,7 @@ class MagLoopAnalysis(VSWRAnalysis):
Useful for tuning magloop.
"""
+
max_dips_shown = 1
vswr_bandwith_value = 2.56 # -3 dB ?!?
@@ -56,12 +57,17 @@ class MagLoopAnalysis(VSWRAnalysis):
if self.min_freq is None:
self.min_freq = new_start
self.max_freq = new_end
- logger.debug("setting hard limits to %s - %s",
- self.min_freq, self.max_freq)
+ logger.debug(
+ "setting hard limits to %s - %s", self.min_freq, self.max_freq
+ )
if len(self.minimums) > 1:
- self.layout.addRow("", QtWidgets.QLabel(
- "Multiple minimums, not magloop or try to lower VSWR limit"))
+ self.layout.addRow(
+ "",
+ QtWidgets.QLabel(
+ "Multiple minimums, not magloop or try to lower VSWR limit"
+ ),
+ )
return
if len(self.minimums) == 1:
@@ -73,22 +79,25 @@ class MagLoopAnalysis(VSWRAnalysis):
logger.debug(" Zoom to %s-%s", new_start, new_end)
elif self.vswr_limit_value == self.vswr_bandwith_value:
- Q = self.app.data.s11[lowest].freq / \
- (self.app.data.s11[end].freq -
- self.app.data.s11[start].freq)
+ Q = self.app.data.s11[lowest].freq / (
+ self.app.data.s11[end].freq - self.app.data.s11[start].freq
+ )
self.layout.addRow("Q", QtWidgets.QLabel(f"{int(Q)}"))
new_start = self.app.data.s11[start].freq - self.bandwith
new_end = self.app.data.s11[end].freq + self.bandwith
- logger.debug("Single Spot, new scan on %s-%s",
- new_start, new_end)
+ logger.debug(
+ "Single Spot, new scan on %s-%s", new_start, new_end
+ )
if self.vswr_limit_value > self.vswr_bandwith_value:
self.vswr_limit_value = max(
- self.vswr_bandwith_value, self.vswr_limit_value - 1)
+ self.vswr_bandwith_value, self.vswr_limit_value - 1
+ )
self.input_vswr_limit.setValue(self.vswr_limit_value)
logger.debug(
"found higher minimum, lowering vswr search to %s",
- self.vswr_limit_value)
+ self.vswr_limit_value,
+ )
else:
new_start = new_start - 5 * self.bandwith
new_end = new_end + 5 * self.bandwith
@@ -100,14 +109,17 @@ class MagLoopAnalysis(VSWRAnalysis):
self.input_vswr_limit.setValue(self.vswr_limit_value)
logger.debug(
"no minimum found, looking for higher value %s",
- self.vswr_limit_value)
+ self.vswr_limit_value,
+ )
new_start = max(self.min_freq, new_start)
new_end = min(self.max_freq, new_end)
- logger.debug("next search will be %s - %s for vswr %s",
- new_start,
- new_end,
- self.vswr_limit_value)
+ logger.debug(
+ "next search will be %s - %s for vswr %s",
+ new_start,
+ new_end,
+ self.vswr_limit_value,
+ )
self.app.sweep_control.set_start(new_start)
self.app.sweep_control.set_end(new_end)
diff --git a/src/NanoVNASaver/Analysis/BandPassAnalysis.py b/src/NanoVNASaver/Analysis/BandPassAnalysis.py
index 45cbc63..461f8ef 100644
--- a/src/NanoVNASaver/Analysis/BandPassAnalysis.py
+++ b/src/NanoVNASaver/Analysis/BandPassAnalysis.py
@@ -33,42 +33,52 @@ class BandPassAnalysis(Analysis):
def __init__(self, app):
super().__init__(app)
- for label in ('octave_l', 'octave_r', 'decade_l', 'decade_r',
- 'freq_center', 'span_3.0dB', 'span_6.0dB', 'q_factor'):
+ for label in (
+ "octave_l",
+ "octave_r",
+ "decade_l",
+ "decade_r",
+ "freq_center",
+ "span_3.0dB",
+ "span_6.0dB",
+ "q_factor",
+ ):
self.label[label] = QtWidgets.QLabel()
for attn in CUTOFF_VALS:
self.label[f"{attn:.1f}dB_l"] = QtWidgets.QLabel()
self.label[f"{attn:.1f}dB_r"] = QtWidgets.QLabel()
layout = self.layout
- layout.addRow(self.label['titel'])
+ layout.addRow(self.label["titel"])
layout.addRow(
QtWidgets.QLabel(
f"Please place {self.app.markers[0].name}"
- f" in the filter passband."))
- layout.addRow("Result:", self.label['result'])
+ f" in the filter passband."
+ )
+ )
+ layout.addRow("Result:", self.label["result"])
layout.addRow(QtWidgets.QLabel(""))
- layout.addRow("Center frequency:", self.label['freq_center'])
- layout.addRow("Bandwidth (-3 dB):", self.label['span_3.0dB'])
- layout.addRow("Quality factor:", self.label['q_factor'])
- layout.addRow("Bandwidth (-6 dB):", self.label['span_6.0dB'])
+ layout.addRow("Center frequency:", self.label["freq_center"])
+ layout.addRow("Bandwidth (-3 dB):", self.label["span_3.0dB"])
+ layout.addRow("Quality factor:", self.label["q_factor"])
+ layout.addRow("Bandwidth (-6 dB):", self.label["span_6.0dB"])
layout.addRow(QtWidgets.QLabel(""))
layout.addRow(QtWidgets.QLabel("Lower side:"))
- layout.addRow("Cutoff frequency:", self.label['3.0dB_l'])
- layout.addRow("-6 dB point:", self.label['6.0dB_l'])
- layout.addRow("-60 dB point:", self.label['60.0dB_l'])
- layout.addRow("Roll-off:", self.label['octave_l'])
- layout.addRow("Roll-off:", self.label['decade_l'])
+ layout.addRow("Cutoff frequency:", self.label["3.0dB_l"])
+ layout.addRow("-6 dB point:", self.label["6.0dB_l"])
+ layout.addRow("-60 dB point:", self.label["60.0dB_l"])
+ layout.addRow("Roll-off:", self.label["octave_l"])
+ layout.addRow("Roll-off:", self.label["decade_l"])
layout.addRow(QtWidgets.QLabel(""))
layout.addRow(QtWidgets.QLabel("Upper side:"))
- layout.addRow("Cutoff frequency:", self.label['3.0dB_r'])
- layout.addRow("-6 dB point:", self.label['6.0dB_r'])
- layout.addRow("-60 dB point:", self.label['60.0dB_r'])
- layout.addRow("Roll-off:", self.label['octave_r'])
- layout.addRow("Roll-off:", self.label['decade_r'])
+ layout.addRow("Cutoff frequency:", self.label["3.0dB_r"])
+ layout.addRow("-6 dB point:", self.label["6.0dB_r"])
+ layout.addRow("-60 dB point:", self.label["60.0dB_r"])
+ layout.addRow("Roll-off:", self.label["octave_r"])
+ layout.addRow("Roll-off:", self.label["decade_r"])
self.set_titel("Band pass filter analysis")
@@ -103,72 +113,90 @@ class BandPassAnalysis(Analysis):
self.derive_60dB(cutoff_pos, cutoff_freq)
result = {
- 'span_3.0dB': cutoff_freq['3.0dB_r'] - cutoff_freq['3.0dB_l'],
- 'span_6.0dB': cutoff_freq['6.0dB_r'] - cutoff_freq['6.0dB_l'],
- 'freq_center':
- math.sqrt(cutoff_freq['3.0dB_l'] * cutoff_freq['3.0dB_r']),
+ "span_3.0dB": cutoff_freq["3.0dB_r"] - cutoff_freq["3.0dB_l"],
+ "span_6.0dB": cutoff_freq["6.0dB_r"] - cutoff_freq["6.0dB_l"],
+ "freq_center": math.sqrt(
+ cutoff_freq["3.0dB_l"] * cutoff_freq["3.0dB_r"]
+ ),
}
- result['q_factor'] = result['freq_center'] / result['span_3.0dB']
+ result["q_factor"] = result["freq_center"] / result["span_3.0dB"]
- result['octave_l'], result['decade_l'] = at.calculate_rolloff(
- s21, cutoff_pos["10.0dB_l"], cutoff_pos["20.0dB_l"])
- result['octave_r'], result['decade_r'] = at.calculate_rolloff(
- s21, cutoff_pos["10.0dB_r"], cutoff_pos["20.0dB_r"])
+ result["octave_l"], result["decade_l"] = at.calculate_rolloff(
+ s21, cutoff_pos["10.0dB_l"], cutoff_pos["20.0dB_l"]
+ )
+ result["octave_r"], result["decade_r"] = at.calculate_rolloff(
+ s21, cutoff_pos["10.0dB_r"], cutoff_pos["20.0dB_r"]
+ )
for label, val in cutoff_freq.items():
self.label[label].setText(
- f"{format_frequency(val)}"
- f" ({cutoff_gain[label]:.1f} dB)")
- for label in ('freq_center', 'span_3.0dB', 'span_6.0dB'):
+ f"{format_frequency(val)}" f" ({cutoff_gain[label]:.1f} dB)"
+ )
+ for label in ("freq_center", "span_3.0dB", "span_6.0dB"):
self.label[label].setText(format_frequency(result[label]))
- self.label['q_factor'].setText(f"{result['q_factor']:.2f}")
+ self.label["q_factor"].setText(f"{result['q_factor']:.2f}")
- for label in ('octave_l', 'decade_l', 'octave_r', 'decade_r'):
+ for label in ("octave_l", "decade_l", "octave_r", "decade_r"):
self.label[label].setText(f"{result[label]:.3f}dB/{label[:-2]}")
self.app.markers[0].setFrequency(f"{result['freq_center']}")
self.app.markers[1].setFrequency(f"{cutoff_freq['3.0dB_l']}")
self.app.markers[2].setFrequency(f"{cutoff_freq['3.0dB_r']}")
- if cutoff_gain['3.0dB_l'] < -4 or cutoff_gain['3.0dB_r'] < -4:
+ if cutoff_gain["3.0dB_l"] < -4 or cutoff_gain["3.0dB_r"] < -4:
logger.warning(
"Data points insufficient for true -3 dB points."
- "Cutoff gains: %fdB, %fdB", cutoff_gain['3.0dB_l'],
- cutoff_gain['3.0dB_r'])
+ "Cutoff gains: %fdB, %fdB",
+ cutoff_gain["3.0dB_l"],
+ cutoff_gain["3.0dB_r"],
+ )
self.set_result(
f"Analysis complete ({len(s21)} points)\n"
- f"Insufficient data for analysis. Increase segment count.")
+ f"Insufficient data for analysis. Increase segment count."
+ )
return
self.set_result(f"Analysis complete ({len(s21)} points)")
- def derive_60dB(self,
- cutoff_pos: Dict[str, int],
- cutoff_freq: Dict[str, float]):
+ def derive_60dB(
+ self, cutoff_pos: Dict[str, int], cutoff_freq: Dict[str, float]
+ ):
"""derive 60dB cutoff if needed an possible
Args:
cutoff_pos (Dict[str, int])
cutoff_freq (Dict[str, float])
"""
- if (math.isnan(cutoff_freq['60.0dB_l']) and
- cutoff_pos['20.0dB_l'] != -1 and cutoff_pos['10.0dB_l'] != -1):
- cutoff_freq['60.0dB_l'] = (
- cutoff_freq["10.0dB_l"] *
- 10 ** (5 * (math.log10(cutoff_pos['20.0dB_l']) -
- math.log10(cutoff_pos['10.0dB_l']))))
- if (math.isnan(cutoff_freq['60.0dB_r']) and
- cutoff_pos['20.0dB_r'] != -1 and cutoff_pos['10.0dB_r'] != -1):
- cutoff_freq['60.0dB_r'] = (
- cutoff_freq["10.0dB_r"] *
- 10 ** (5 * (math.log10(cutoff_pos['20.0dB_r']) -
- math.log10(cutoff_pos['10.0dB_r'])
- )))
+ if (
+ math.isnan(cutoff_freq["60.0dB_l"])
+ and cutoff_pos["20.0dB_l"] != -1
+ and cutoff_pos["10.0dB_l"] != -1
+ ):
+ cutoff_freq["60.0dB_l"] = cutoff_freq["10.0dB_l"] * 10 ** (
+ 5
+ * (
+ math.log10(cutoff_pos["20.0dB_l"])
+ - math.log10(cutoff_pos["10.0dB_l"])
+ )
+ )
+ if (
+ math.isnan(cutoff_freq["60.0dB_r"])
+ and cutoff_pos["20.0dB_r"] != -1
+ and cutoff_pos["10.0dB_r"] != -1
+ ):
+ cutoff_freq["60.0dB_r"] = cutoff_freq["10.0dB_r"] * 10 ** (
+ 5
+ * (
+ math.log10(cutoff_pos["20.0dB_r"])
+ - math.log10(cutoff_pos["10.0dB_r"])
+ )
+ )
def find_center(self, gains: List[float]) -> int:
marker = self.app.markers[0]
if marker.location <= 0 or marker.location >= len(gains) - 1:
- logger.debug("No valid location for %s (%s)",
- marker.name, marker.location)
+ logger.debug(
+ "No valid location for %s (%s)", marker.name, marker.location
+ )
self.set_result(f"Please place {marker.name} in the passband.")
return -1
@@ -178,13 +206,15 @@ class BandPassAnalysis(Analysis):
return -1
return peak
- def find_bounderies(self,
- gains: List[float],
- peak: int, peak_db: float) -> Dict[str, int]:
+ def find_bounderies(
+ self, gains: List[float], peak: int, peak_db: float
+ ) -> Dict[str, int]:
cutoff_pos = {}
for attn in CUTOFF_VALS:
cutoff_pos[f"{attn:.1f}dB_l"] = at.cut_off_left(
- gains, peak, peak_db, attn)
+ gains, peak, peak_db, attn
+ )
cutoff_pos[f"{attn:.1f}dB_r"] = at.cut_off_right(
- gains, peak, peak_db, attn)
+ gains, peak, peak_db, attn
+ )
return cutoff_pos
diff --git a/src/NanoVNASaver/Analysis/BandStopAnalysis.py b/src/NanoVNASaver/Analysis/BandStopAnalysis.py
index fd3a982..da4395f 100644
--- a/src/NanoVNASaver/Analysis/BandStopAnalysis.py
+++ b/src/NanoVNASaver/Analysis/BandStopAnalysis.py
@@ -34,11 +34,13 @@ class BandStopAnalysis(BandPassAnalysis):
def find_center(self, gains: List[float]) -> int:
return max(enumerate(gains), key=lambda i: i[1])[0]
- def find_bounderies(self,
- gains: List[float],
- _: int, peak_db: float) -> Dict[str, int]:
+ def find_bounderies(
+ self, gains: List[float], _: int, peak_db: float
+ ) -> Dict[str, int]:
cutoff_pos = {}
for attn in CUTOFF_VALS:
- cutoff_pos[f"{attn:.1f}dB_l"], cutoff_pos[f"{attn:.1f}dB_r"] = (
- at.dip_cut_offs(gains, peak_db, attn))
+ (
+ cutoff_pos[f"{attn:.1f}dB_l"],
+ cutoff_pos[f"{attn:.1f}dB_r"],
+ ) = at.dip_cut_offs(gains, peak_db, attn)
return cutoff_pos
diff --git a/src/NanoVNASaver/Analysis/Base.py b/src/NanoVNASaver/Analysis/Base.py
index 0f4e6a9..a47cae2 100644
--- a/src/NanoVNASaver/Analysis/Base.py
+++ b/src/NanoVNASaver/Analysis/Base.py
@@ -35,8 +35,8 @@ class Analysis:
def __init__(self, app: QtWidgets.QWidget):
self.app = app
self.label: Dict[str, QtWidgets.QLabel] = {
- 'titel': QtWidgets.QLabel(),
- 'result': QtWidgets.QLabel(),
+ "titel": QtWidgets.QLabel(),
+ "result": QtWidgets.QLabel(),
}
self.layout = QtWidgets.QFormLayout()
self._widget = QtWidgets.QWidget()
@@ -53,7 +53,7 @@ class Analysis:
label.clear()
def set_result(self, text):
- self.label['result'].setText(text)
+ self.label["result"].setText(text)
def set_titel(self, text):
- self.label['titel'].setText(text)
+ self.label["titel"].setText(text)
diff --git a/src/NanoVNASaver/Analysis/EFHWAnalysis.py b/src/NanoVNASaver/Analysis/EFHWAnalysis.py
index 2eca1b9..37d7517 100644
--- a/src/NanoVNASaver/Analysis/EFHWAnalysis.py
+++ b/src/NanoVNASaver/Analysis/EFHWAnalysis.py
@@ -23,10 +23,14 @@ from PyQt5 import QtWidgets
import NanoVNASaver.AnalyticTools as at
from NanoVNASaver.Analysis.ResonanceAnalysis import (
- ResonanceAnalysis, format_resistence_neg
+ ResonanceAnalysis,
+ format_resistence_neg,
)
from NanoVNASaver.Formatting import (
- format_frequency, format_complex_imp, format_frequency_short)
+ format_frequency,
+ format_complex_imp,
+ format_frequency_short,
+)
logger = logging.getLogger(__name__)
@@ -43,8 +47,8 @@ class EFHWAnalysis(ResonanceAnalysis):
def do_resonance_analysis(self):
s11 = self.app.data.s11
maximums = sorted(
- at.maxima([d.impedance().real for d in s11],
- threshold=500))
+ at.maxima([d.impedance().real for d in s11], threshold=500)
+ )
extended_data = {}
logger.info("TO DO: find near data")
for lowest in self.crossings:
@@ -61,12 +65,14 @@ class EFHWAnalysis(ResonanceAnalysis):
extended_data[m].update(my_data)
else:
extended_data[m] = my_data
- fields = [("freq", format_frequency_short),
- ("r", format_resistence_neg), ("lambda", lambda x: round(x, 2))]
+ fields = [
+ ("freq", format_frequency_short),
+ ("r", format_resistence_neg),
+ ("lambda", lambda x: round(x, 2)),
+ ]
if self.old_data:
- diff = self.compare(
- self.old_data[-1], extended_data, fields=fields)
+ 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)
@@ -76,14 +82,17 @@ class EFHWAnalysis(ResonanceAnalysis):
QtWidgets.QLabel(
f" ({diff[i]['freq']})"
f" {format_complex_imp(s11[idx].impedance())}"
- f" ({diff[i]['r']}) {diff[i]['lambda']} m"))
+ f" ({diff[i]['r']}) {diff[i]['lambda']} m"
+ ),
+ )
if self.filename and extended_data:
with open(
- self.filename, 'w', newline='', encoding='utf-8'
+ self.filename, "w", newline="", encoding="utf-8"
) as csvfile:
- fieldnames = extended_data[sorted(
- extended_data.keys())[0]].keys()
+ fieldnames = extended_data[
+ sorted(extended_data.keys())[0]
+ ].keys()
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for idx in sorted(extended_data.keys()):
@@ -99,10 +108,11 @@ class EFHWAnalysis(ResonanceAnalysis):
:param old:
:param new:
"""
- fields = fields or [("freq", str), ]
+ fields = fields or [
+ ("freq", str),
+ ]
def no_compare():
-
return {k: "-" for k, _ in fields}
old_idx = sorted(old.keys())
@@ -113,8 +123,9 @@ class EFHWAnalysis(ResonanceAnalysis):
i_tot = max(len(old_idx), len(new_idx))
if i_max != i_tot:
- logger.warning("resonances changed from %s to %s",
- len(old_idx), len(new_idx))
+ logger.warning(
+ "resonances changed from %s to %s", len(old_idx), len(new_idx)
+ )
split = 0
max_delta_f = 1_000_000
@@ -135,15 +146,19 @@ class EFHWAnalysis(ResonanceAnalysis):
logger.debug("Deltas %s", diff[i])
continue
- logger.debug("can't compare, %s is too much ",
- format_frequency(delta_f))
+ logger.debug(
+ "can't compare, %s is too much ", format_frequency(delta_f)
+ )
if delta_f > 0:
logger.debug("possible missing band, ")
if len(old_idx) > (i + split + 1):
- if (abs(new[k]["freq"] -
- old[old_idx[i + split + 1]]["freq"]) <
- max_delta_f):
+ if (
+ abs(
+ new[k]["freq"] - old[old_idx[i + split + 1]]["freq"]
+ )
+ < max_delta_f
+ ):
logger.debug("new is missing band, compare next ")
split += 1
# FIXME: manage 2 or more band missing ?!?
diff --git a/src/NanoVNASaver/Analysis/HighPassAnalysis.py b/src/NanoVNASaver/Analysis/HighPassAnalysis.py
index a8aeba5..fd4419f 100644
--- a/src/NanoVNASaver/Analysis/HighPassAnalysis.py
+++ b/src/NanoVNASaver/Analysis/HighPassAnalysis.py
@@ -41,9 +41,12 @@ class HighPassAnalysis(Analysis):
layout = self.layout
layout.addRow(self.label["titel"])
- layout.addRow(QtWidgets.QLabel(
- f"Please place {self.app.markers[0].name}"
- f" in the filter passband."))
+ layout.addRow(
+ QtWidgets.QLabel(
+ f"Please place {self.app.markers[0].name}"
+ f" in the filter passband."
+ )
+ )
layout.addRow("Result:", self.label["result"])
layout.addRow("Cutoff frequency:", self.label["3.0dB"])
layout.addRow("-6 dB point:", self.label["6.0dB"])
@@ -51,7 +54,7 @@ class HighPassAnalysis(Analysis):
layout.addRow("Roll-off:", self.label["octave"])
layout.addRow("Roll-off:", self.label["decade"])
- self.set_titel('Highpass analysis')
+ self.set_titel("Highpass analysis")
def runAnalysis(self):
if not self.app.data.s21:
@@ -81,25 +84,28 @@ class HighPassAnalysis(Analysis):
logger.debug("Cuttoff gains: %s", cutoff_gain)
octave, decade = at.calculate_rolloff(
- s21, cutoff_pos["10.0dB"], cutoff_pos["20.0dB"])
+ s21, cutoff_pos["10.0dB"], cutoff_pos["20.0dB"]
+ )
- if cutoff_gain['3.0dB'] < -4:
- logger.debug("Cutoff frequency found at %f dB"
- " - insufficient data points for true -3 dB point.",
- cutoff_gain)
- logger.debug("Found true cutoff frequency at %d", cutoff_freq['3.0dB'])
+ if cutoff_gain["3.0dB"] < -4:
+ logger.debug(
+ "Cutoff frequency found at %f dB"
+ " - insufficient data points for true -3 dB point.",
+ cutoff_gain,
+ )
+ logger.debug("Found true cutoff frequency at %d", cutoff_freq["3.0dB"])
for label, val in cutoff_freq.items():
self.label[label].setText(
- f"{format_frequency(val)}"
- f" ({cutoff_gain[label]:.1f} dB)")
+ f"{format_frequency(val)}" f" ({cutoff_gain[label]:.1f} dB)"
+ )
- self.label['octave'].setText(f'{octave:.3f}dB/octave')
- self.label['decade'].setText(f'{decade:.3f}dB/decade')
+ self.label["octave"].setText(f"{octave:.3f}dB/octave")
+ self.label["decade"].setText(f"{decade:.3f}dB/decade")
self.app.markers[0].setFrequency(str(s21[peak].freq))
- self.app.markers[1].setFrequency(str(cutoff_freq['3.0dB']))
- self.app.markers[2].setFrequency(str(cutoff_freq['6.0dB']))
+ self.app.markers[1].setFrequency(str(cutoff_freq["3.0dB"]))
+ self.app.markers[2].setFrequency(str(cutoff_freq["6.0dB"]))
self.set_result(f"Analysis complete ({len(s21)}) points)")
@@ -111,11 +117,10 @@ class HighPassAnalysis(Analysis):
return -1
return at.center_from_idx(gains, marker.location)
- def find_cutoffs(self,
- gains: List[float],
- peak: int, peak_db: float) -> Dict[str, int]:
+ def find_cutoffs(
+ self, gains: List[float], peak: int, peak_db: float
+ ) -> Dict[str, int]:
return {
- f"{attn:.1f}dB": at.cut_off_left(
- gains, peak, peak_db, attn)
+ f"{attn:.1f}dB": at.cut_off_left(gains, peak, peak_db, attn)
for attn in CUTOFF_VALS
}
diff --git a/src/NanoVNASaver/Analysis/LowPassAnalysis.py b/src/NanoVNASaver/Analysis/LowPassAnalysis.py
index 9516bb9..764e791 100644
--- a/src/NanoVNASaver/Analysis/LowPassAnalysis.py
+++ b/src/NanoVNASaver/Analysis/LowPassAnalysis.py
@@ -30,13 +30,12 @@ class LowPassAnalysis(HighPassAnalysis):
def __init__(self, app):
super().__init__(app)
- self.set_titel('Lowpass filter analysis')
+ self.set_titel("Lowpass filter analysis")
- def find_cutoffs(self,
- gains: List[float],
- peak: int, peak_db: float) -> Dict[str, int]:
+ def find_cutoffs(
+ self, gains: List[float], peak: int, peak_db: float
+ ) -> Dict[str, int]:
return {
- f"{attn:.1f}dB": at.cut_off_right(
- gains, peak, peak_db, attn)
+ f"{attn:.1f}dB": at.cut_off_right(gains, peak, peak_db, attn)
for attn in CUTOFF_VALS
}
diff --git a/src/NanoVNASaver/Analysis/PeakSearchAnalysis.py b/src/NanoVNASaver/Analysis/PeakSearchAnalysis.py
index 65c5742..815d988 100644
--- a/src/NanoVNASaver/Analysis/PeakSearchAnalysis.py
+++ b/src/NanoVNASaver/Analysis/PeakSearchAnalysis.py
@@ -20,12 +20,14 @@ import logging
from PyQt5 import QtWidgets
import numpy as np
+
# pylint: disable=import-error, no-name-in-module
from scipy.signal import find_peaks, peak_prominences
from NanoVNASaver.Analysis.Base import QHLine
from NanoVNASaver.Analysis.SimplePeakSearchAnalysis import (
- SimplePeakSearchAnalysis)
+ SimplePeakSearchAnalysis,
+)
from NanoVNASaver.Formatting import format_frequency_short
@@ -34,7 +36,6 @@ logger = logging.getLogger(__name__)
class PeakSearchAnalysis(SimplePeakSearchAnalysis):
-
def __init__(self, app):
super().__init__(app)
@@ -48,7 +49,7 @@ class PeakSearchAnalysis(SimplePeakSearchAnalysis):
self.layout.addRow(QtWidgets.QLabel("Results"))
self.results_header = self.layout.rowCount()
- self.set_titel('Peak search')
+ self.set_titel("Peak search")
def runAnalysis(self):
if not self.app.data.s11:
@@ -59,14 +60,14 @@ class PeakSearchAnalysis(SimplePeakSearchAnalysis):
data, fmt_fnc = self.data_and_format()
inverted = False
- if self.button['peak_l'].isChecked():
+ if self.button["peak_l"].isChecked():
inverted = True
peaks, _ = find_peaks(
- -np.array(data), width=3, distance=3, prominence=1)
+ -np.array(data), width=3, distance=3, prominence=1
+ )
else:
- self.button['peak_h'].setChecked(True)
- peaks, _ = find_peaks(
- data, width=3, distance=3, prominence=1)
+ self.button["peak_h"].setChecked(True)
+ peaks, _ = find_peaks(data, width=3, distance=3, prominence=1)
# Having found the peaks, get the prominence data
for i, p in np.ndenumerate(peaks):
@@ -89,19 +90,24 @@ class PeakSearchAnalysis(SimplePeakSearchAnalysis):
f"Freq: {format_frequency_short(s11[pos].freq)}",
QtWidgets.QLabel(
f" Value: {fmt_fnc(-data[pos] if inverted else data[pos])}"
- ))
+ ),
+ )
- if self.button['move_marker'].isChecked():
+ if self.button["move_marker"].isChecked():
if count > len(self.app.markers):
logger.warning("More peaks found than there are markers")
for i in range(min(count, len(self.app.markers))):
self.app.markers[i].setFrequency(
- str(s11[peaks[indices[i]]].freq))
+ str(s11[peaks[indices[i]]].freq)
+ )
def reset(self):
super().reset()
- logger.debug("Results start at %d, out of %d",
- self.results_header, self.layout.rowCount())
+ logger.debug(
+ "Results start at %d, out of %d",
+ self.results_header,
+ self.layout.rowCount(),
+ )
for _ in range(self.results_header, self.layout.rowCount()):
logger.debug("deleting %s", self.layout.rowCount())
self.layout.removeRow(self.layout.rowCount() - 1)
diff --git a/src/NanoVNASaver/Analysis/ResonanceAnalysis.py b/src/NanoVNASaver/Analysis/ResonanceAnalysis.py
index 00d8dac..b427067 100644
--- a/src/NanoVNASaver/Analysis/ResonanceAnalysis.py
+++ b/src/NanoVNASaver/Analysis/ResonanceAnalysis.py
@@ -25,9 +25,7 @@ from PyQt5 import QtWidgets
import NanoVNASaver.AnalyticTools as at
from NanoVNASaver.Analysis.Base import Analysis, QHLine
-from NanoVNASaver.Formatting import (
- format_frequency, format_complex_imp,
- format_resistance)
+from NanoVNASaver.Formatting import format_frequency, format_resistance
from NanoVNASaver.RFTools import reflection_coefficient
logger = logging.getLogger(__name__)
@@ -44,7 +42,6 @@ def vswr_transformed(z, ratio=49) -> float:
class ResonanceAnalysis(Analysis):
-
def __init__(self, app):
super().__init__(app)
self.crossings: List[int] = []
@@ -72,10 +69,8 @@ class ResonanceAnalysis(Analysis):
"impedance": s11[index].impedance(),
"vswr": s11[index].vswr,
}
- my_data["vswr_49"] = vswr_transformed(
- my_data["impedance"], 49)
- my_data["vswr_4"] = vswr_transformed(
- my_data["impedance"], 4)
+ my_data["vswr_49"] = vswr_transformed(my_data["impedance"], 49)
+ my_data["vswr_4"] = vswr_transformed(my_data["impedance"], 4)
my_data["r"] = my_data["impedance"].real
my_data["x"] = my_data["impedance"].imag
@@ -83,24 +78,28 @@ class ResonanceAnalysis(Analysis):
def runAnalysis(self):
self.reset()
- self.filename = os.path.join(
- "/tmp/", f"{self.input_description.text()}.csv"
- ) if self.input_description.text() else ""
+ self.filename = (
+ os.path.join("/tmp/", f"{self.input_description.text()}.csv")
+ if self.input_description.text()
+ else ""
+ )
results_header = self.layout.indexOf(self.results_label)
- logger.debug("Results start at %d, out of %d",
- results_header, self.layout.rowCount())
+ 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)
self.crossings = sorted(
- set(at.zero_crossings([d.phase for d in self.app.data.s11])))
- logger.debug("Found %d sections ",
- len(self.crossings))
+ set(at.zero_crossings([d.phase for d in self.app.data.s11]))
+ )
+ logger.debug("Found %d sections ", len(self.crossings))
if not self.crossings:
- self.layout.addRow(QtWidgets.QLabel(
- "No resonance found"))
+ self.layout.addRow(QtWidgets.QLabel("No resonance found"))
return
self
@@ -111,14 +110,18 @@ class ResonanceAnalysis(Analysis):
extended_data = []
for crossing in self.crossings:
extended_data.append(self._get_data(crossing))
- self.layout.addRow("Resonance", QtWidgets.QLabel(
- format_frequency(self.app.data.s11[crossing].freq)))
+ self.layout.addRow(
+ "Resonance",
+ QtWidgets.QLabel(
+ format_frequency(self.app.data.s11[crossing].freq)
+ ),
+ )
self.layout.addWidget(QHLine())
# Remove the final separator line
self.layout.removeRow(self.layout.rowCount() - 1)
if self.filename and extended_data:
with open(
- self.filename, 'w', encoding='utf-8', newline=''
+ self.filename, "w", encoding="utf-8", newline=""
) as csvfile:
fieldnames = extended_data[0].keys()
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
diff --git a/src/NanoVNASaver/Analysis/SimplePeakSearchAnalysis.py b/src/NanoVNASaver/Analysis/SimplePeakSearchAnalysis.py
index eabcf4e..91d4cb7 100644
--- a/src/NanoVNASaver/Analysis/SimplePeakSearchAnalysis.py
+++ b/src/NanoVNASaver/Analysis/SimplePeakSearchAnalysis.py
@@ -24,7 +24,11 @@ import numpy as np
from NanoVNASaver.Analysis.Base import Analysis, QHLine
from NanoVNASaver.Formatting import (
- format_frequency, format_gain, format_resistance, format_vswr)
+ format_frequency,
+ format_gain,
+ format_resistance,
+ format_vswr,
+)
logger = logging.getLogger(__name__)
@@ -33,51 +37,51 @@ class SimplePeakSearchAnalysis(Analysis):
def __init__(self, app):
super().__init__(app)
- self.label['peak_freq'] = QtWidgets.QLabel()
- self.label['peak_db'] = QtWidgets.QLabel()
+ self.label["peak_freq"] = QtWidgets.QLabel()
+ self.label["peak_db"] = QtWidgets.QLabel()
self.button = {
- 'vswr': QtWidgets.QRadioButton("VSWR"),
- 'resistance': QtWidgets.QRadioButton("Resistance"),
- 'reactance': QtWidgets.QRadioButton("Reactance"),
- 'gain': QtWidgets.QRadioButton("S21 Gain"),
- 'peak_h': QtWidgets.QRadioButton("Highest value"),
- 'peak_l': QtWidgets.QRadioButton("Lowest value"),
- 'move_marker': QtWidgets.QCheckBox()
+ "vswr": QtWidgets.QRadioButton("VSWR"),
+ "resistance": QtWidgets.QRadioButton("Resistance"),
+ "reactance": QtWidgets.QRadioButton("Reactance"),
+ "gain": QtWidgets.QRadioButton("S21 Gain"),
+ "peak_h": QtWidgets.QRadioButton("Highest value"),
+ "peak_l": QtWidgets.QRadioButton("Lowest value"),
+ "move_marker": QtWidgets.QCheckBox(),
}
- self.button['gain'].setChecked(True)
- self.button['peak_h'].setChecked(True)
+ self.button["gain"].setChecked(True)
+ self.button["peak_h"].setChecked(True)
self.btn_group = {
- 'data': QtWidgets.QButtonGroup(),
- 'peak': QtWidgets.QButtonGroup(),
+ "data": QtWidgets.QButtonGroup(),
+ "peak": QtWidgets.QButtonGroup(),
}
- for btn in ('vswr', 'resistance', 'reactance', 'gain'):
- self.btn_group['data'].addButton(self.button[btn])
- self.btn_group['peak'].addButton(self.button['peak_h'])
- self.btn_group['peak'].addButton(self.button['peak_l'])
+ for btn in ("vswr", "resistance", "reactance", "gain"):
+ self.btn_group["data"].addButton(self.button[btn])
+ self.btn_group["peak"].addButton(self.button["peak_h"])
+ self.btn_group["peak"].addButton(self.button["peak_l"])
layout = self.layout
- layout.addRow(self.label['titel'])
+ layout.addRow(self.label["titel"])
layout.addRow(QHLine())
layout.addRow(QtWidgets.QLabel("Settings"))
- layout.addRow("Data source", self.button['vswr'])
- layout.addRow("", self.button['resistance'])
- layout.addRow("", self.button['reactance'])
- layout.addRow("", self.button['gain'])
+ layout.addRow("Data source", self.button["vswr"])
+ layout.addRow("", self.button["resistance"])
+ layout.addRow("", self.button["reactance"])
+ layout.addRow("", self.button["gain"])
layout.addRow(QHLine())
- layout.addRow("Peak type", self.button['peak_h'])
- layout.addRow("", self.button['peak_l'])
+ layout.addRow("Peak type", self.button["peak_h"])
+ layout.addRow("", self.button["peak_l"])
layout.addRow(QHLine())
- layout.addRow("Move marker to peak", self.button['move_marker'])
+ layout.addRow("Move marker to peak", self.button["move_marker"])
layout.addRow(QHLine())
- layout.addRow(self.label['result'])
- layout.addRow("Peak frequency:", self.label['peak_freq'])
- layout.addRow("Peak value:", self.label['peak_db'])
+ layout.addRow(self.label["result"])
+ layout.addRow("Peak frequency:", self.label["peak_freq"])
+ layout.addRow("Peak value:", self.label["peak_db"])
- self.set_titel('Simple peak search')
+ self.set_titel("Simple peak search")
def runAnalysis(self):
if not self.app.data.s11:
@@ -86,16 +90,16 @@ class SimplePeakSearchAnalysis(Analysis):
s11 = self.app.data.s11
data, fmt_fnc = self.data_and_format()
- if self.button['peak_l'].isChecked():
+ if self.button["peak_l"].isChecked():
idx_peak = np.argmin(data)
else:
- self.button['peak_h'].setChecked(True)
+ self.button["peak_h"].setChecked(True)
idx_peak = np.argmax(data)
- self.label['peak_freq'].setText(format_frequency(s11[idx_peak].freq))
- self.label['peak_db'].setText(fmt_fnc(data[idx_peak]))
+ self.label["peak_freq"].setText(format_frequency(s11[idx_peak].freq))
+ self.label["peak_db"].setText(fmt_fnc(data[idx_peak]))
- if self.button['move_marker'].isChecked() and self.app.markers:
+ if self.button["move_marker"].isChecked() and self.app.markers:
self.app.markers[0].setFrequency(f"{s11[idx_peak].freq}")
def data_and_format(self) -> Tuple[List[float], Callable]:
@@ -103,17 +107,17 @@ class SimplePeakSearchAnalysis(Analysis):
s21 = self.app.data.s21
if not s21:
- self.button['gain'].setEnabled(False)
- if self.button['gain'].isChecked():
- self.button['vswr'].setChecked(True)
+ self.button["gain"].setEnabled(False)
+ if self.button["gain"].isChecked():
+ self.button["vswr"].setChecked(True)
else:
- self.button['gain'].setEnabled(True)
+ self.button["gain"].setEnabled(True)
- if self.button['gain'].isChecked():
+ if self.button["gain"].isChecked():
return ([d.gain for d in s21], format_gain)
- if self.button['resistance'].isChecked():
+ if self.button["resistance"].isChecked():
return ([d.impedance().real for d in s11], format_resistance)
- if self.button['reactance'].isChecked():
+ if self.button["reactance"].isChecked():
return ([d.impedance().imag for d in s11], format_resistance)
# default
return ([d.vswr for d in s11], format_vswr)
diff --git a/src/NanoVNASaver/Analysis/VSWRAnalysis.py b/src/NanoVNASaver/Analysis/VSWRAnalysis.py
index 9939fce..0081b49 100644
--- a/src/NanoVNASaver/Analysis/VSWRAnalysis.py
+++ b/src/NanoVNASaver/Analysis/VSWRAnalysis.py
@@ -64,34 +64,50 @@ class VSWRAnalysis(Analysis):
data = [d.vswr for d in s11]
threshold = self.input_vswr_limit.value()
- minima = sorted(at.minima(data, threshold),
- key=lambda i: data[i])[:VSWRAnalysis.max_dips_shown]
+ minima = sorted(at.minima(data, threshold), key=lambda i: data[i])[
+ : VSWRAnalysis.max_dips_shown
+ ]
self.minimums = minima
results_header = self.layout.indexOf(self.results_label)
- logger.debug("Results start at %d, out of %d",
- results_header, self.layout.rowCount())
+ 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 not minima:
- self.layout.addRow(QtWidgets.QLabel(
- f"No areas found with VSWR below {format_vswr(threshold)}."))
+ self.layout.addRow(
+ QtWidgets.QLabel(
+ f"No areas found with VSWR below {format_vswr(threshold)}."
+ )
+ )
return
for idx in minima:
rng = at.take_from_idx(data, idx, lambda i: i[1] < threshold)
begin, end = rng[0], rng[-1]
- self.layout.addRow("Start", QtWidgets.QLabel(
- format_frequency(s11[begin].freq)))
- self.layout.addRow("Minimum", QtWidgets.QLabel(
- f"{format_frequency(s11[idx].freq)}"
- f" ({round(s11[idx].vswr, 2)})"))
- self.layout.addRow("End", QtWidgets.QLabel(
- format_frequency(s11[end].freq)))
self.layout.addRow(
- "Span", QtWidgets.QLabel(format_frequency(
- (s11[end].freq - s11[begin].freq))))
+ "Start", QtWidgets.QLabel(format_frequency(s11[begin].freq))
+ )
+ self.layout.addRow(
+ "Minimum",
+ QtWidgets.QLabel(
+ f"{format_frequency(s11[idx].freq)}"
+ f" ({round(s11[idx].vswr, 2)})"
+ ),
+ )
+ self.layout.addRow(
+ "End", QtWidgets.QLabel(format_frequency(s11[end].freq))
+ )
+ self.layout.addRow(
+ "Span",
+ QtWidgets.QLabel(
+ format_frequency((s11[end].freq - s11[begin].freq))
+ ),
+ )
self.layout.addWidget(QHLine())
self.layout.removeRow(self.layout.rowCount() - 1)
diff --git a/src/NanoVNASaver/AnalyticTools.py b/src/NanoVNASaver/AnalyticTools.py
index 9551f72..c68b8b3 100644
--- a/src/NanoVNASaver/AnalyticTools.py
+++ b/src/NanoVNASaver/AnalyticTools.py
@@ -21,6 +21,7 @@ import math
from typing import Callable, List, Tuple
import numpy as np
+
# pylint: disable=import-error, no-name-in-module
from scipy.signal import find_peaks
@@ -42,8 +43,9 @@ def zero_crossings(data: List[float]) -> List[int]:
np_data = np.array(data)
# start with real zeros (ignore first and last element)
- real_zeros = [n for n in np.where(np_data == 0.0)[0] if
- n not in {0, np_data.size - 1}]
+ real_zeros = [
+ n for n in np.where(np_data == 0.0)[0] if n not in {0, np_data.size - 1}
+ ]
# now multipy elements to find change in signess
crossings = [
n if abs(np_data[n]) < abs(np_data[n + 1]) else n + 1
@@ -61,11 +63,8 @@ def maxima(data: List[float], threshold: float = 0.0) -> List[int]:
Returns:
List[int]: indices of maxima
"""
- peaks = find_peaks(
- data, width=2, distance=3, prominence=1)[0].tolist()
- return [
- i for i in peaks if data[i] > threshold
- ] if threshold else peaks
+ peaks = find_peaks(data, width=2, distance=3, prominence=1)[0].tolist()
+ return [i for i in peaks if data[i] > threshold] if threshold else peaks
def minima(data: List[float], threshold: float = 0.0) -> List[int]:
@@ -77,16 +76,15 @@ def minima(data: List[float], threshold: float = 0.0) -> List[int]:
Returns:
List[int]: indices of minima
"""
- bottoms = find_peaks(
- -np.array(data), width=2, distance=3, prominence=1)[0].tolist()
- return [
- i for i in bottoms if data[i] < threshold
- ] if threshold else bottoms
+ bottoms = find_peaks(-np.array(data), width=2, distance=3, prominence=1)[
+ 0
+ ].tolist()
+ return [i for i in bottoms if data[i] < threshold] if threshold else bottoms
-def take_from_idx(data: List[float],
- idx: int,
- predicate: Callable) -> List[int]:
+def take_from_idx(
+ data: List[float], idx: int, predicate: Callable
+) -> List[int]:
"""take_from_center
Args:
@@ -99,18 +97,21 @@ def take_from_idx(data: List[float],
List[int]: indices of element matching predicate left
and right from index
"""
- lower = list(reversed(
- [i for i, _ in
- it.takewhile(predicate,
- reversed(list(enumerate(data[:idx]))))]))
- upper = [i for i, _ in
- it.takewhile(predicate,
- enumerate(data[idx:], idx))]
+ lower = list(
+ reversed(
+ [
+ i
+ for i, _ in it.takewhile(
+ predicate, reversed(list(enumerate(data[:idx])))
+ )
+ ]
+ )
+ )
+ upper = [i for i, _ in it.takewhile(predicate, enumerate(data[idx:], idx))]
return lower + upper
-def center_from_idx(gains: List[float],
- idx: int, delta: float = 3.0) -> int:
+def center_from_idx(gains: List[float], idx: int, delta: float = 3.0) -> int:
"""find maximum from index postion of gains in a attn dB gain span
Args:
@@ -122,13 +123,13 @@ def center_from_idx(gains: List[float],
int: position of highest gain from start in range (-1 if no data)
"""
peak_db = gains[idx]
- rng = take_from_idx(gains, idx,
- lambda i: abs(peak_db - i[1]) < delta)
+ rng = take_from_idx(gains, idx, lambda i: abs(peak_db - i[1]) < delta)
return max(rng, key=lambda i: gains[i]) if rng else -1
-def cut_off_left(gains: List[float], idx: int,
- peak_gain: float, attn: float = 3.0) -> int:
+def cut_off_left(
+ gains: List[float], idx: int, peak_gain: float, attn: float = 3.0
+) -> int:
"""find first position in list where gain in attn lower then peak
left from index
@@ -143,13 +144,13 @@ def cut_off_left(gains: List[float], idx: int,
int: position of attenuation point. (-1 if no data)
"""
return next(
- (i for i in range(idx, -1, -1) if
- (peak_gain - gains[i]) > attn),
- -1)
+ (i for i in range(idx, -1, -1) if (peak_gain - gains[i]) > attn), -1
+ )
-def cut_off_right(gains: List[float], idx: int,
- peak_gain: float, attn: float = 3.0) -> int:
+def cut_off_right(
+ gains: List[float], idx: int, peak_gain: float, attn: float = 3.0
+) -> int:
"""find first position in list where gain in attn lower then peak
right from index
@@ -165,19 +166,20 @@ def cut_off_right(gains: List[float], idx: int,
"""
return next(
- (i for i in range(idx, len(gains)) if
- (peak_gain - gains[i]) > attn),
- -1)
+ (i for i in range(idx, len(gains)) if (peak_gain - gains[i]) > attn), -1
+ )
-def dip_cut_offs(gains: List[float], peak_gain: float,
- attn: float = 3.0) -> Tuple[int, int]:
+def dip_cut_offs(
+ gains: List[float], peak_gain: float, attn: float = 3.0
+) -> Tuple[int, int]:
rng = np.where(np.array(gains) < (peak_gain - attn))[0].tolist()
return (rng[0], rng[-1]) if rng else (math.nan, math.nan)
-def calculate_rolloff(s21: List[Datapoint],
- idx_1: int, idx_2: int) -> Tuple[float, float]:
+def calculate_rolloff(
+ s21: List[Datapoint], idx_1: int, idx_2: int
+) -> Tuple[float, float]:
if idx_1 == idx_2:
return (math.nan, math.nan)
freq_1, freq_2 = s21[idx_1].freq, s21[idx_2].freq
diff --git a/src/NanoVNASaver/Calibration.py b/src/NanoVNASaver/Calibration.py
index ec93d32..2ab6979 100644
--- a/src/NanoVNASaver/Calibration.py
+++ b/src/NanoVNASaver/Calibration.py
@@ -35,7 +35,8 @@ IDEAL_OPEN = complex(1, 0)
IDEAL_LOAD = complex(0, 0)
IDEAL_THROUGH = complex(1, 0)
-RXP_CAL_HEADER = re.compile(r"""
+RXP_CAL_HEADER = re.compile(
+ r"""
^ \# \s+ Hz \s+
ShortR \s+ ShortI \s+ OpenR \s+ OpenI \s+
LoadR \s+ LoadI
@@ -43,9 +44,12 @@ RXP_CAL_HEADER = re.compile(r"""
(?P \s+ ThrureflR \s+ ThrureflI)?
(?P \s+ IsolationR \s+ IsolationI)?
\s* $
-""", re.VERBOSE | re.IGNORECASE)
+""",
+ re.VERBOSE | re.IGNORECASE,
+)
-RXP_CAL_LINE = re.compile(r"""
+RXP_CAL_LINE = re.compile(
+ r"""
^ \s*
(?P\d+) \s+
(?P[-0-9Ee.]+) \s+ (?P[-0-9Ee.]+) \s+
@@ -55,7 +59,9 @@ RXP_CAL_LINE = re.compile(r"""
( \s+ (?P[-0-9Ee.]+) \s+ (?P[-0-9Ee.]+))?
( \s+ (?P[-0-9Ee.]+) \s+ (?P[-0-9Ee.]+))?
\s* $
-""", re.VERBOSE)
+""",
+ re.VERBOSE,
+)
logger = logging.getLogger(__name__)
@@ -63,7 +69,8 @@ logger = logging.getLogger(__name__)
def correct_delay(d: Datapoint, delay: float, reflect: bool = False):
mult = 2 if reflect else 1
corr_data = d.z * cmath.exp(
- complex(0, 1) * 2 * math.pi * d.freq * delay * -1 * mult)
+ complex(0, 1) * 2 * math.pi * d.freq * delay * -1 * mult
+ )
return Datapoint(d.freq, corr_data.real, corr_data.imag)
@@ -88,14 +95,16 @@ class CalData:
def __str__(self):
return (
- f'{self.freq}'
- f' {self.short.real} {self.short.imag}'
- f' {self.open.real} {self.open.imag}'
- f' {self.load.real} {self.load.imag}' + (
- f' {self.through.real} {self.through.imag}'
- f' {self.thrurefl.real} {self.thrurefl.imag}'
- f' {self.isolation.real} {self.isolation.imag}'
- if self.through else ''
+ f"{self.freq}"
+ f" {self.short.real} {self.short.imag}"
+ f" {self.open.real} {self.open.imag}"
+ f" {self.load.real} {self.load.imag}"
+ + (
+ f" {self.through.real} {self.through.imag}"
+ f" {self.thrurefl.real} {self.thrurefl.imag}"
+ f" {self.isolation.real} {self.isolation.imag}"
+ if self.through
+ else ""
)
)
@@ -138,26 +147,32 @@ class CalDataSet(UserDict):
(
"# Calibration data for NanoVNA-Saver\n"
+ "\n".join([f"! {note}" for note in self.notes.splitlines()])
- + "\n" + "# Hz ShortR ShortI OpenR OpenI LoadR LoadI"
- + (" ThroughR ThroughI ThrureflR"
- " ThrureflI IsolationR IsolationI\n"
- if self.complete2port() else "\n")
- + "\n".join([
- f"{self.data.get(freq)}" for freq in self.frequencies()
- ]) + "\n"
+ + "\n"
+ + "# Hz ShortR ShortI OpenR OpenI LoadR LoadI"
+ + (
+ " ThroughR ThroughI ThrureflR"
+ " ThrureflI IsolationR IsolationI\n"
+ if self.complete2port()
+ else "\n"
+ )
+ + "\n".join(
+ [f"{self.data.get(freq)}" for freq in self.frequencies()]
+ )
+ + "\n"
)
- if self.complete1port() else ""
+ if self.complete1port()
+ else ""
)
- def _append_match(self, m: re.Match, header: str,
- line_nr: int, line: str) -> None:
+ def _append_match(
+ self, m: re.Match, header: str, line_nr: int, line: str
+ ) -> None:
cal = m.groupdict()
- columns = {
- col[:-1] for col in cal.keys() if cal[col] and col != "freq"
- }
+ columns = {col[:-1] for col in cal.keys() if cal[col] and col != "freq"}
if "through" in columns and header == "sol":
- logger.warning("Through data with sol header. %i: %s",
- line_nr, line)
+ logger.warning(
+ "Through data with sol header. %i: %s", line_nr, line
+ )
# fix short data (without thrurefl)
if "thrurefl" in columns and "isolation" not in columns:
cal["isolationr"] = cal["thrureflr"]
@@ -166,11 +181,14 @@ class CalDataSet(UserDict):
for name in columns:
self.insert(
name,
- Datapoint(int(cal["freq"]),
- float(cal[f"{name}r"]),
- float(cal[f"{name}i"])))
+ Datapoint(
+ int(cal["freq"]),
+ float(cal[f"{name}r"]),
+ float(cal[f"{name}i"]),
+ ),
+ )
- def from_str(self, text: str) -> 'CalDataSet':
+ def from_str(self, text: str) -> "CalDataSet":
# reset data
self.notes = ""
self.data = defaultdict(CalData)
@@ -185,7 +203,8 @@ class CalDataSet(UserDict):
if m := RXP_CAL_HEADER.search(line):
if header:
logger.warning(
- "Duplicate header in cal data. %i: %s", i, line)
+ "Duplicate header in cal data. %i: %s", i, line
+ )
header = "through" if m.group("through") else "sol"
continue
if not line or line.startswith("#"):
@@ -197,13 +216,20 @@ class CalDataSet(UserDict):
continue
if not header:
logger.warning(
- "Caldata without having read header: %i: %s", i, line)
+ "Caldata without having read header: %i: %s", i, line
+ )
self._append_match(m, header, line, i)
return self
def insert(self, name: str, dp: Datapoint):
- if name not in {'short', 'open', 'load',
- 'through', 'thrurefl', 'isolation'}:
+ if name not in {
+ "short",
+ "open",
+ "load",
+ "through",
+ "thrurefl",
+ "isolation",
+ }:
raise KeyError(name)
freq = dp.freq
setattr(self.data[freq], name, (dp.z))
@@ -223,9 +249,7 @@ class CalDataSet(UserDict):
yield self.get(freq)
def size_of(self, name: str) -> int:
- return len(
- [True for val in self.data.values() if getattr(val, name)]
- )
+ return len([True for val in self.data.values() if getattr(val, name)])
def complete1port(self) -> bool:
for val in self.data.values():
@@ -244,7 +268,6 @@ class CalDataSet(UserDict):
class Calibration:
def __init__(self):
-
self.notes = []
self.dataset = CalDataSet()
self.cal_element = CalElement()
@@ -278,18 +301,30 @@ class Calibration:
gm2 = cal.open
gm3 = cal.load
- denominator = (g1 * (g2 - g3) * gm1 +
- 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
- cal.e11 = ((g2 - g3) * gm1 - g1 * (gm2 - gm3) +
- g3 * gm2 - g2 * gm3) / denominator
- cal.delta_e = - ((g1 * (gm2 - gm3) - g2 * gm2 + g3 *
- gm3) * gm1 + (g2 * gm3 - g3 * gm3) *
- gm2) / denominator
+ denominator = (
+ g1 * (g2 - g3) * gm1
+ + 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
+ )
+ cal.e11 = (
+ (g2 - g3) * gm1 - g1 * (gm2 - gm3) + g3 * gm2 - g2 * gm3
+ ) / denominator
+ cal.delta_e = (
+ -(
+ (g1 * (gm2 - gm3) - g2 * gm2 + g3 * gm3) * gm1
+ + (g2 * gm3 - g3 * gm3) * gm2
+ )
+ / denominator
+ )
def _calc_port_2(self, freq: int, cal: CalData):
gt = self.gamma_through(freq)
@@ -301,18 +336,16 @@ class Calibration:
cal.e30 = cal.isolation
cal.e10e01 = cal.e00 * cal.e11 - cal.delta_e
- cal.e22 = gm7 / (
- gm7 * cal.e11 * gt ** 2 + cal.e10e01 * gt ** 2)
- cal.e10e32 = (gm4 - gm6) * (
- 1 - cal.e11 * cal.e22 * gt ** 2) / gt
+ cal.e22 = gm7 / (gm7 * cal.e11 * gt**2 + cal.e10e01 * gt**2)
+ cal.e10e32 = (gm4 - gm6) * (1 - cal.e11 * cal.e22 * gt**2) / gt
def calc_corrections(self):
if not self.isValid1Port():
- logger.warning(
- "Tried to calibrate from insufficient data.")
+ logger.warning("Tried to calibrate from insufficient data.")
raise ValueError(
"All of short, open and load calibration steps"
- "must be completed for calibration to be applied.")
+ "must be completed for calibration to be applied."
+ )
logger.debug("Calculating calibration for %d points.", self.size())
for freq, caldata in self.dataset.items():
@@ -324,10 +357,12 @@ class Calibration:
self.isCalculated = False
logger.error(
"Division error - did you use the same measurement"
- " for two of short, open and load?")
+ " for two of short, open and load?"
+ )
raise ValueError(
f"Two of short, open and load returned the same"
- f" values at frequency {freq}Hz.") from exc
+ f" values at frequency {freq}Hz."
+ ) from exc
self.gen_interpolation()
self.isCalculated = True
@@ -338,25 +373,47 @@ class Calibration:
return IDEAL_SHORT
logger.debug("Using short calibration set values.")
cal_element = self.cal_element
- Zsp = complex(0.0, 2.0 * math.pi * freq * (
- cal_element.short_l0 + cal_element.short_l1 * freq +
- cal_element.short_l2 * freq**2 + cal_element.short_l3 * freq**3))
+ Zsp = complex(
+ 0.0,
+ 2.0
+ * math.pi
+ * freq
+ * (
+ cal_element.short_l0
+ + cal_element.short_l1 * freq
+ + cal_element.short_l2 * freq**2
+ + cal_element.short_l3 * freq**3
+ ),
+ )
# Referencing https://arxiv.org/pdf/1606.02446.pdf (18) - (21)
- return (Zsp / 50.0 - 1.0) / (Zsp / 50.0 + 1.0) * cmath.exp(
- complex(0.0,
- -4.0 * math.pi * freq * cal_element.short_length))
+ return (
+ (Zsp / 50.0 - 1.0)
+ / (Zsp / 50.0 + 1.0)
+ * cmath.exp(
+ complex(0.0, -4.0 * math.pi * freq * cal_element.short_length)
+ )
+ )
def gamma_open(self, freq: int) -> complex:
if self.cal_element.open_is_ideal:
return IDEAL_OPEN
logger.debug("Using open calibration set values.")
cal_element = self.cal_element
- Zop = complex(0.0, 2.0 * math.pi * freq * (
- cal_element.open_c0 + cal_element.open_c1 * freq +
- cal_element.open_c2 * freq**2 + cal_element.open_c3 * freq**3))
+ Zop = complex(
+ 0.0,
+ 2.0
+ * math.pi
+ * freq
+ * (
+ cal_element.open_c0
+ + cal_element.open_c1 * freq
+ + cal_element.open_c2 * freq**2
+ + cal_element.open_c3 * freq**3
+ ),
+ )
return ((1.0 - 50.0 * Zop) / (1.0 + 50.0 * Zop)) * cmath.exp(
- complex(0.0,
- -4.0 * math.pi * freq * cal_element.open_length))
+ complex(0.0, -4.0 * math.pi * freq * cal_element.open_length)
+ )
def gamma_load(self, freq: int) -> complex:
if self.cal_element.load_is_ideal:
@@ -367,11 +424,17 @@ class Calibration:
if cal_element.load_c > 0.0:
Zl = cal_element.load_r / complex(
1.0,
- 2.0 * cal_element.load_r * math.pi * freq * cal_element.load_c)
+ 2.0 * cal_element.load_r * math.pi * freq * cal_element.load_c,
+ )
if cal_element.load_l > 0.0:
Zl = Zl + complex(0.0, 2 * math.pi * freq * cal_element.load_l)
- return (Zl / 50.0 - 1.0) / (Zl / 50.0 + 1.0) * cmath.exp(
- complex(0.0, -4 * math.pi * freq * cal_element.load_length))
+ return (
+ (Zl / 50.0 - 1.0)
+ / (Zl / 50.0 + 1.0)
+ * cmath.exp(
+ complex(0.0, -4 * math.pi * freq * cal_element.load_length)
+ )
+ )
def gamma_through(self, freq: int) -> complex:
if self.cal_element.through_is_ideal:
@@ -379,59 +442,103 @@ class Calibration:
logger.debug("Using through calibration set values.")
cal_element = self.cal_element
return cmath.exp(
- complex(0.0, -2.0 * math.pi * cal_element.through_length * freq))
+ complex(0.0, -2.0 * math.pi * cal_element.through_length * freq)
+ )
def gen_interpolation(self):
- (freq, e00, e11, delta_e, e10e01, e30, e22, e10e32) = zip(*[
- (c.freq, c.e00, c.e11, c.delta_e, c.e10e01, c.e30, c.e22, c.e10e32)
- for c in self.dataset.values()])
+ (freq, e00, e11, delta_e, e10e01, e30, e22, e10e32) = zip(
+ *[
+ (
+ c.freq,
+ c.e00,
+ c.e11,
+ c.delta_e,
+ c.e10e01,
+ c.e30,
+ c.e22,
+ c.e10e32,
+ )
+ for c in self.dataset.values()
+ ]
+ )
self.interp = {
- "e00": interp1d(freq, e00,
- kind="slinear", bounds_error=False,
- fill_value=(e00[0], e00[-1])),
- "e11": interp1d(freq, e11,
- kind="slinear", bounds_error=False,
- fill_value=(e11[0], e11[-1])),
- "delta_e": interp1d(freq, delta_e,
- 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])),
- "e30": interp1d(freq, e30,
- kind="slinear", bounds_error=False,
- fill_value=(e30[0], e30[-1])),
- "e22": interp1d(freq, e22,
- kind="slinear", bounds_error=False,
- fill_value=(e22[0], e22[-1])),
- "e10e32": interp1d(freq, e10e32,
- kind="slinear", bounds_error=False,
- fill_value=(e10e32[0], e10e32[-1])),
+ "e00": interp1d(
+ freq,
+ e00,
+ kind="slinear",
+ bounds_error=False,
+ fill_value=(e00[0], e00[-1]),
+ ),
+ "e11": interp1d(
+ freq,
+ e11,
+ kind="slinear",
+ bounds_error=False,
+ fill_value=(e11[0], e11[-1]),
+ ),
+ "delta_e": interp1d(
+ freq,
+ delta_e,
+ 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]),
+ ),
+ "e30": interp1d(
+ freq,
+ e30,
+ kind="slinear",
+ bounds_error=False,
+ fill_value=(e30[0], e30[-1]),
+ ),
+ "e22": interp1d(
+ freq,
+ e22,
+ kind="slinear",
+ bounds_error=False,
+ fill_value=(e22[0], e22[-1]),
+ ),
+ "e10e32": interp1d(
+ freq,
+ e10e32,
+ kind="slinear",
+ bounds_error=False,
+ fill_value=(e10e32[0], e10e32[-1]),
+ ),
}
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)
def save(self, filename: str):
self.dataset.notes = "\n".join(self.notes)
if not self.isValid1Port():
raise ValueError("Not a valid calibration")
- with open(filename, mode="w", encoding='utf-8') as calfile:
+ with open(filename, mode="w", encoding="utf-8") as calfile:
calfile.write(str(self.dataset))
def load(self, filename):
self.source = os.path.basename(filename)
- with open(filename, encoding='utf-8') as calfile:
+ with open(filename, encoding="utf-8") as calfile:
self.dataset = CalDataSet().from_str(calfile.read())
self.notes = self.dataset.notes.splitlines()
diff --git a/src/NanoVNASaver/Charts/CLogMag.py b/src/NanoVNASaver/Charts/CLogMag.py
index 2975b16..dd45203 100644
--- a/src/NanoVNASaver/Charts/CLogMag.py
+++ b/src/NanoVNASaver/Charts/CLogMag.py
@@ -61,20 +61,24 @@ class CombinedLogMagChart(LogMagChart):
def drawChart(self, qp: QtGui.QPainter):
qp.setPen(QtGui.QPen(Chart.color.text))
- qp.drawText(int(self.dim.width // 2) - 20,
- 15,
- f"{self.name} {self.name_unit}")
+ qp.drawText(
+ int(self.dim.width // 2) - 20, 15, f"{self.name} {self.name_unit}"
+ )
qp.drawText(10, 15, "S11")
qp.drawText(self.leftMargin + self.dim.width - 8, 15, "S21")
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin,
- self.topMargin - 5,
- self.leftMargin,
- self.topMargin + self.dim.height + 5)
- qp.drawLine(self.leftMargin - 5,
- self.topMargin + self.dim.height,
- self.leftMargin + self.dim.width,
- self.topMargin + self.dim.height)
+ qp.drawLine(
+ self.leftMargin,
+ self.topMargin - 5,
+ self.leftMargin,
+ self.topMargin + self.dim.height + 5,
+ )
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin + self.dim.height,
+ self.leftMargin + self.dim.width,
+ self.topMargin + self.dim.height,
+ )
def drawValues(self, qp: QtGui.QPainter):
if len(self.data11) == 0 and len(self.reference11) == 0:
@@ -117,8 +121,12 @@ class CombinedLogMagChart(LogMagChart):
pen = QtGui.QPen(c)
pen.setWidth(2)
qp.setPen(pen)
- qp.drawLine(self.leftMargin + self.dim.width - 20, 9,
- self.leftMargin + self.dim.width - 15, 9)
+ qp.drawLine(
+ self.leftMargin + self.dim.width - 20,
+ 9,
+ self.leftMargin + self.dim.width - 15,
+ 9,
+ )
if self.reference11:
c = QtGui.QColor(Chart.color.reference)
@@ -132,8 +140,12 @@ class CombinedLogMagChart(LogMagChart):
pen = QtGui.QPen(c)
pen.setWidth(2)
qp.setPen(pen)
- qp.drawLine(self.leftMargin + self.dim.width - 20, 14,
- self.leftMargin + self.dim.width - 15, 14)
+ qp.drawLine(
+ self.leftMargin + self.dim.width - 20,
+ 14,
+ self.leftMargin + self.dim.width - 15,
+ 14,
+ )
self.drawData(qp, self.data11, Chart.color.sweep)
self.drawData(qp, self.data21, Chart.color.sweep_secondary)
diff --git a/src/NanoVNASaver/Charts/Chart.py b/src/NanoVNASaver/Charts/Chart.py
index 1687120..739858c 100644
--- a/src/NanoVNASaver/Charts/Chart.py
+++ b/src/NanoVNASaver/Charts/Chart.py
@@ -36,13 +36,16 @@ logger = logging.getLogger(__name__)
class ChartColors: # pylint: disable=too-many-instance-attributes
background: QColor = field(default_factory=lambda: QColor(QtCore.Qt.white))
foreground: QColor = field(
- default_factory=lambda: QColor(QtCore.Qt.lightGray))
+ default_factory=lambda: QColor(QtCore.Qt.lightGray)
+ )
reference: QColor = field(default_factory=lambda: QColor(0, 0, 255, 64))
reference_secondary: QColor = field(
- default_factory=lambda: QColor(0, 0, 192, 48))
+ default_factory=lambda: QColor(0, 0, 192, 48)
+ )
sweep: QColor = field(default_factory=lambda: QColor(QtCore.Qt.darkYellow))
sweep_secondary: QColor = field(
- default_factory=lambda: QColor(QtCore.Qt.darkMagenta))
+ default_factory=lambda: QColor(QtCore.Qt.darkMagenta)
+ )
swr: QColor = field(default_factory=lambda: QColor(255, 0, 0, 128))
text: QColor = field(default_factory=lambda: QColor(QtCore.Qt.black))
bands: QColor = field(default_factory=lambda: QColor(128, 128, 128, 48))
@@ -97,8 +100,7 @@ class ChartMarker(QtWidgets.QWidget):
if text and Defaults.cfg.chart.marker_label:
text_width = self.qp.fontMetrics().horizontalAdvance(text)
- self.qp.drawText(x - int(text_width // 2),
- y - 3 - offset, text)
+ self.qp.drawText(x - int(text_width // 2), y - 3 - offset, text)
class Chart(QtWidgets.QWidget):
@@ -109,7 +111,7 @@ class Chart(QtWidgets.QWidget):
def __init__(self, name):
super().__init__()
self.name = name
- self.sweepTitle = ''
+ self.sweepTitle = ""
self.leftMargin = 30
self.rightMargin = 20
@@ -130,7 +132,8 @@ class Chart(QtWidgets.QWidget):
self.action_popout = QtWidgets.QAction("Popout chart")
self.action_popout.triggered.connect(
- lambda: self.popoutRequested.emit(self))
+ lambda: self.popoutRequested.emit(self)
+ )
self.addAction(self.action_popout)
self.action_save_screenshot = QtWidgets.QAction("Save image")
@@ -230,7 +233,9 @@ class Chart(QtWidgets.QWidget):
self.zoomTo(
self.dragbox.pos_start[0],
self.dragbox.pos_start[1],
- a0.x(), a0.y())
+ a0.x(),
+ a0.y(),
+ )
self.dragbox.state = False
self.dragbox.pos = (-1, -1)
self.dragbox.pos_start = (0, 0)
@@ -262,7 +267,7 @@ class Chart(QtWidgets.QWidget):
int(self.leftMargin + ratio_x * factor_x),
int(self.topMargin + ratio_y * factor_y),
int(self.leftMargin + self.dim.width - (1 - ratio_x) * factor_x),
- int(self.topMargin + self.dim.height - (1 - ratio_y) * factor_y)
+ int(self.topMargin + self.dim.height - (1 - ratio_y) * factor_y),
)
a0.accept()
@@ -272,8 +277,10 @@ class Chart(QtWidgets.QWidget):
def saveScreenshot(self):
logger.info("Saving %s to file...", self.name)
filename, _ = QtWidgets.QFileDialog.getSaveFileName(
- parent=self, caption="Save image",
- filter="PNG (*.png);;All files (*.*)")
+ parent=self,
+ caption="Save image",
+ filter="PNG (*.png);;All files (*.*)",
+ )
logger.debug("Filename: %s", filename)
if not filename:
@@ -314,9 +321,9 @@ class Chart(QtWidgets.QWidget):
self.update()
@staticmethod
- def drawMarker(x: int, y: int,
- qp: QtGui.QPainter, color: QtGui.QColor,
- number: int = 0):
+ def drawMarker(
+ x: int, y: int, qp: QtGui.QPainter, color: QtGui.QColor, number: int = 0
+ ):
cmarker = ChartMarker(qp)
cmarker.draw(x, y, color, f"{number}")
diff --git a/src/NanoVNASaver/Charts/Frequency.py b/src/NanoVNASaver/Charts/Frequency.py
index aa0fc5c..dff4ad4 100644
--- a/src/NanoVNASaver/Charts/Frequency.py
+++ b/src/NanoVNASaver/Charts/Frequency.py
@@ -25,9 +25,12 @@ from PyQt5 import QtWidgets, QtGui, QtCore
from NanoVNASaver.Charts.Chart import Chart
from NanoVNASaver.Formatting import (
- parse_frequency, parse_value,
- format_frequency_chart, format_frequency_chart_2,
- format_y_axis)
+ parse_frequency,
+ parse_value,
+ format_frequency_chart,
+ format_frequency_chart_2,
+ format_y_axis,
+)
from NanoVNASaver.RFTools import Datapoint
from NanoVNASaver.SITools import Format, Value
@@ -35,7 +38,6 @@ logger = logging.getLogger(__name__)
class FrequencyChart(Chart):
-
def __init__(self, name):
super().__init__(name)
self.maxFrequency = 100000000
@@ -79,11 +81,13 @@ class FrequencyChart(Chart):
self.action_automatic.setCheckable(True)
self.action_automatic.setChecked(True)
self.action_automatic.changed.connect(
- lambda: self.setFixedSpan(self.action_fixed_span.isChecked()))
+ lambda: self.setFixedSpan(self.action_fixed_span.isChecked())
+ )
self.action_fixed_span = QtWidgets.QAction("Fixed span")
self.action_fixed_span.setCheckable(True)
self.action_fixed_span.changed.connect(
- lambda: self.setFixedSpan(self.action_fixed_span.isChecked()))
+ lambda: self.setFixedSpan(self.action_fixed_span.isChecked())
+ )
mode_group.addAction(self.action_automatic)
mode_group.addAction(self.action_fixed_span)
self.x_menu.addAction(self.action_automatic)
@@ -91,11 +95,13 @@ class FrequencyChart(Chart):
self.x_menu.addSeparator()
self.action_set_fixed_start = QtWidgets.QAction(
- f"Start ({format_frequency_chart(self.minFrequency)})")
+ f"Start ({format_frequency_chart(self.minFrequency)})"
+ )
self.action_set_fixed_start.triggered.connect(self.setMinimumFrequency)
self.action_set_fixed_stop = QtWidgets.QAction(
- f"Stop ({format_frequency_chart(self.maxFrequency)})")
+ f"Stop ({format_frequency_chart(self.maxFrequency)})"
+ )
self.action_set_fixed_stop.triggered.connect(self.setMaximumFrequency)
self.x_menu.addAction(self.action_set_fixed_start)
@@ -110,9 +116,11 @@ class FrequencyChart(Chart):
frequency_mode_group.addAction(self.action_set_linear_x)
frequency_mode_group.addAction(self.action_set_logarithmic_x)
self.action_set_linear_x.triggered.connect(
- lambda: self.setLogarithmicX(False))
+ lambda: self.setLogarithmicX(False)
+ )
self.action_set_logarithmic_x.triggered.connect(
- lambda: self.setLogarithmicX(True))
+ lambda: self.setLogarithmicX(True)
+ )
self.action_set_linear_x.setChecked(True)
self.x_menu.addAction(self.action_set_linear_x)
self.x_menu.addAction(self.action_set_logarithmic_x)
@@ -122,11 +130,13 @@ class FrequencyChart(Chart):
self.y_action_automatic.setCheckable(True)
self.y_action_automatic.setChecked(True)
self.y_action_automatic.changed.connect(
- lambda: self.setFixedValues(self.y_action_fixed_span.isChecked()))
+ lambda: self.setFixedValues(self.y_action_fixed_span.isChecked())
+ )
self.y_action_fixed_span = QtWidgets.QAction("Fixed span")
self.y_action_fixed_span.setCheckable(True)
self.y_action_fixed_span.changed.connect(
- lambda: self.setFixedValues(self.y_action_fixed_span.isChecked()))
+ lambda: self.setFixedValues(self.y_action_fixed_span.isChecked())
+ )
mode_group = QtWidgets.QActionGroup(self)
mode_group.addAction(self.y_action_automatic)
mode_group.addAction(self.y_action_fixed_span)
@@ -135,11 +145,13 @@ class FrequencyChart(Chart):
self.y_menu.addSeparator()
self.action_set_fixed_minimum = QtWidgets.QAction(
- f"Minimum ({self.minDisplayValue})")
+ f"Minimum ({self.minDisplayValue})"
+ )
self.action_set_fixed_minimum.triggered.connect(self.setMinimumValue)
self.action_set_fixed_maximum = QtWidgets.QAction(
- f"Maximum ({self.maxDisplayValue})")
+ f"Maximum ({self.maxDisplayValue})"
+ )
self.action_set_fixed_maximum.triggered.connect(self.setMaximumValue)
self.y_menu.addAction(self.action_set_fixed_maximum)
@@ -155,9 +167,11 @@ class FrequencyChart(Chart):
vertical_mode_group.addAction(self.action_set_linear_y)
vertical_mode_group.addAction(self.action_set_logarithmic_y)
self.action_set_linear_y.triggered.connect(
- lambda: self.setLogarithmicY(False))
+ lambda: self.setLogarithmicY(False)
+ )
self.action_set_logarithmic_y.triggered.connect(
- lambda: self.setLogarithmicY(True))
+ lambda: self.setLogarithmicY(True)
+ )
self.action_set_linear_y.setChecked(True)
self.y_menu.addAction(self.action_set_linear_y)
self.y_menu.addAction(self.action_set_logarithmic_y)
@@ -168,16 +182,21 @@ class FrequencyChart(Chart):
self.menu.addAction(self.action_save_screenshot)
self.action_popout = QtWidgets.QAction("Popout chart")
self.action_popout.triggered.connect(
- lambda: self.popoutRequested.emit(self))
+ lambda: self.popoutRequested.emit(self)
+ )
self.menu.addAction(self.action_popout)
self.setFocusPolicy(QtCore.Qt.ClickFocus)
self.setMinimumSize(
self.dim.width + self.rightMargin + self.leftMargin,
- self.dim.height + self.topMargin + self.bottomMargin)
+ self.dim.height + self.topMargin + self.bottomMargin,
+ )
self.setSizePolicy(
- QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding,
- QtWidgets.QSizePolicy.MinimumExpanding))
+ QtWidgets.QSizePolicy(
+ QtWidgets.QSizePolicy.MinimumExpanding,
+ QtWidgets.QSizePolicy.MinimumExpanding,
+ )
+ )
pal = QtGui.QPalette()
pal.setColor(QtGui.QPalette.Background, Chart.color.background)
self.setPalette(pal)
@@ -197,13 +216,17 @@ class FrequencyChart(Chart):
def contextMenuEvent(self, event):
self.action_set_fixed_start.setText(
- f"Start ({format_frequency_chart(self.minFrequency)})")
+ f"Start ({format_frequency_chart(self.minFrequency)})"
+ )
self.action_set_fixed_stop.setText(
- f"Stop ({format_frequency_chart(self.maxFrequency)})")
+ f"Stop ({format_frequency_chart(self.maxFrequency)})"
+ )
self.action_set_fixed_minimum.setText(
- f"Minimum ({self.minDisplayValue})")
+ f"Minimum ({self.minDisplayValue})"
+ )
self.action_set_fixed_maximum.setText(
- f"Maximum ({self.maxDisplayValue})")
+ f"Maximum ({self.maxDisplayValue})"
+ )
if self.fixedSpan:
self.action_fixed_span.setChecked(True)
@@ -242,8 +265,11 @@ class FrequencyChart(Chart):
def setMinimumFrequency(self):
min_freq_str, selected = QtWidgets.QInputDialog.getText(
- self, "Start frequency",
- "Set start frequency", text=str(self.minFrequency))
+ self,
+ "Start frequency",
+ "Set start frequency",
+ text=str(self.minFrequency),
+ )
if not selected:
return
span = abs(self.maxFrequency - self.minFrequency)
@@ -258,8 +284,11 @@ class FrequencyChart(Chart):
def setMaximumFrequency(self):
max_freq_str, selected = QtWidgets.QInputDialog.getText(
- self, "Stop frequency",
- "Set stop frequency", text=str(self.maxFrequency))
+ self,
+ "Stop frequency",
+ "Set stop frequency",
+ text=str(self.maxFrequency),
+ )
if not selected:
return
span = abs(self.maxFrequency - self.minFrequency)
@@ -274,9 +303,11 @@ class FrequencyChart(Chart):
def setMinimumValue(self):
text, selected = QtWidgets.QInputDialog.getText(
- self, "Minimum value",
+ self,
+ "Minimum value",
"Set minimum value",
- text=format_y_axis(self.minDisplayValue, self.name_unit))
+ text=format_y_axis(self.minDisplayValue, self.name_unit),
+ )
if not selected:
return
min_val = parse_value(text)
@@ -292,9 +323,11 @@ class FrequencyChart(Chart):
def setMaximumValue(self):
text, selected = QtWidgets.QInputDialog.getText(
- self, "Maximum value",
+ self,
+ "Maximum value",
"Set maximum value",
- text=format_y_axis(self.maxDisplayValue, self.name_unit))
+ text=format_y_axis(self.maxDisplayValue, self.name_unit),
+ )
if not selected:
return
max_val = parse_value(text)
@@ -323,18 +356,21 @@ class FrequencyChart(Chart):
if self.logarithmicX:
span = math.log(self.fstop) - math.log(self.fstart)
return self.leftMargin + round(
- self.dim.width * (math.log(d.freq) -
- math.log(self.fstart)) / span)
+ self.dim.width
+ * (math.log(d.freq) - math.log(self.fstart))
+ / span
+ )
return self.leftMargin + round(
- self.dim.width * (d.freq - self.fstart) / span)
+ self.dim.width * (d.freq - self.fstart) / span
+ )
return math.floor(self.width() / 2)
def getYPosition(self, d: Datapoint) -> int:
try:
- return (
- self.topMargin + round(
- (self.maxValue - self.value_function(d)) /
- self.span * self.dim.height)
+ return self.topMargin + round(
+ (self.maxValue - self.value_function(d))
+ / self.span
+ * self.dim.height
)
except ValueError:
return self.topMargin
@@ -410,9 +446,12 @@ class FrequencyChart(Chart):
if self.dragbox.move_x != -1 and self.dragbox.move_y != -1:
dx = self.dragbox.move_x - a0.x()
dy = self.dragbox.move_y - a0.y()
- self.zoomTo(self.leftMargin + dx, self.topMargin + dy,
- self.leftMargin + self.dim.width + dx,
- self.topMargin + self.dim.height + dy)
+ self.zoomTo(
+ self.leftMargin + dx,
+ self.topMargin + dy,
+ self.leftMargin + self.dim.width + dx,
+ self.topMargin + self.dim.height + dy,
+ )
self.dragbox.move_x = a0.x()
self.dragbox.move_y = a0.y()
@@ -436,10 +475,10 @@ class FrequencyChart(Chart):
m.setFrequency(str(f))
def resizeEvent(self, a0: QtGui.QResizeEvent) -> None:
- self.dim.width = (
- a0.size().width() - self.rightMargin - self.leftMargin)
+ self.dim.width = a0.size().width() - self.rightMargin - self.leftMargin
self.dim.height = (
- a0.size().height() - self.bottomMargin - self.topMargin)
+ a0.size().height() - self.bottomMargin - self.topMargin
+ )
self.update()
def paintEvent(self, _: QtGui.QPaintEvent) -> None:
@@ -452,24 +491,30 @@ class FrequencyChart(Chart):
qp.end()
def _data_oob(self, data: List[Datapoint]) -> bool:
- return (data[0].freq > self.fstop or self.data[-1].freq < self.fstart)
+ return data[0].freq > self.fstop or self.data[-1].freq < self.fstart
def _check_frequency_boundaries(self, qp: QtGui.QPainter):
- if (self.data and self._data_oob(self.data) and
- (not self.reference or self._data_oob(self.reference))):
+ if (
+ self.data
+ and self._data_oob(self.data)
+ and (not self.reference or self._data_oob(self.reference))
+ ):
# Data outside frequency range
qp.setBackgroundMode(QtCore.Qt.OpaqueMode)
qp.setBackground(Chart.color.background)
qp.setPen(Chart.color.text)
- qp.drawText(self.leftMargin + int(self.dim.width // 2) - 70,
- self.topMargin + int(self.dim.height // 2) - 20,
- "Data outside frequency span")
+ qp.drawText(
+ self.leftMargin + int(self.dim.width // 2) - 70,
+ self.topMargin + int(self.dim.height // 2) - 20,
+ "Data outside frequency span",
+ )
def drawDragbog(self, qp: QtGui.QPainter):
dashed_pen = QtGui.QPen(Chart.color.foreground, 1, QtCore.Qt.DashLine)
qp.setPen(dashed_pen)
top_left = QtCore.QPoint(
- self.dragbox.pos_start[0], self.dragbox.pos_start[1])
+ self.dragbox.pos_start[0], self.dragbox.pos_start[1]
+ )
bottom_right = QtCore.QPoint(self.dragbox.pos[0], self.dragbox.pos[1])
rect = QtCore.QRect(top_left, bottom_right)
qp.drawRect(rect)
@@ -481,14 +526,18 @@ class FrequencyChart(Chart):
headline += f" ({self.name_unit})"
qp.drawText(3, 15, headline)
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin,
- 20,
- self.leftMargin,
- self.topMargin + self.dim.height + 5)
- qp.drawLine(self.leftMargin - 5,
- self.topMargin + self.dim.height,
- self.leftMargin + self.dim.width,
- self.topMargin + self.dim.height)
+ qp.drawLine(
+ self.leftMargin,
+ 20,
+ self.leftMargin,
+ self.topMargin + self.dim.height + 5,
+ )
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin + self.dim.height,
+ self.leftMargin + self.dim.width,
+ self.topMargin + self.dim.height,
+ )
self.drawTitle(qp)
def drawValues(self, qp: QtGui.QPainter):
@@ -514,7 +563,8 @@ class FrequencyChart(Chart):
if span == 0:
logger.info(
"Span is zero for %s-Chart, setting to a small value.",
- self.name)
+ self.name,
+ )
span = 1e-15
self.span = span
@@ -522,23 +572,30 @@ class FrequencyChart(Chart):
fmt = Format(max_nr_digits=1)
for i in range(target_ticks):
val = min_value + (i / target_ticks) * span
- y = self.topMargin + \
- round((self.maxValue - val) / self.span * self.dim.height)
+ y = self.topMargin + round(
+ (self.maxValue - val) / self.span * self.dim.height
+ )
qp.setPen(Chart.color.text)
if val != min_value:
valstr = str(Value(val, fmt=fmt))
qp.drawText(3, y + 3, valstr)
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, y,
- self.leftMargin + self.dim.width, y)
+ qp.drawLine(
+ self.leftMargin - 5, y, self.leftMargin + self.dim.width, y
+ )
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, self.topMargin,
- self.leftMargin + self.dim.width, self.topMargin)
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin,
+ self.leftMargin + self.dim.width,
+ self.topMargin,
+ )
qp.setPen(Chart.color.text)
qp.drawText(3, self.topMargin + 4, str(Value(max_value, fmt=fmt)))
- qp.drawText(3, self.dim.height + self.topMargin,
- str(Value(min_value, fmt=fmt)))
+ qp.drawText(
+ 3, self.dim.height + self.topMargin, str(Value(min_value, fmt=fmt))
+ )
self.drawFrequencyTicks(qp)
self.drawData(qp, self.data, Chart.color.sweep)
@@ -574,27 +631,31 @@ class FrequencyChart(Chart):
else:
my_format_frequency = format_frequency_chart_2
- qp.drawText(self.leftMargin - 20,
- self.topMargin + self.dim.height + 15,
- my_format_frequency(self.fstart))
+ qp.drawText(
+ self.leftMargin - 20,
+ self.topMargin + self.dim.height + 15,
+ my_format_frequency(self.fstart),
+ )
for i in range(ticks):
x = self.leftMargin + round((i + 1) * self.dim.width / ticks)
if self.logarithmicX:
fspan = math.log(self.fstop) - math.log(self.fstart)
freq = round(
- math.exp(
- ((i + 1) * fspan / ticks) +
- math.log(self.fstart)))
+ math.exp(((i + 1) * fspan / ticks) + math.log(self.fstart))
+ )
else:
freq = round(fspan / ticks * (i + 1) + self.fstart)
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(x, self.topMargin, x,
- self.topMargin + self.dim.height + 5)
+ qp.drawLine(
+ x, self.topMargin, x, self.topMargin + self.dim.height + 5
+ )
qp.setPen(Chart.color.text)
- qp.drawText(x - 20,
- self.topMargin + self.dim.height + 15,
- my_format_frequency(freq))
+ qp.drawText(
+ x - 20,
+ self.topMargin + self.dim.height + 15,
+ my_format_frequency(freq),
+ )
def drawBands(self, qp, fstart, fstop):
qp.setBrush(self.bands.color)
@@ -608,17 +669,24 @@ class FrequencyChart(Chart):
# don't draw if either band not in chart or completely in band
if start < fstart < fstop < end or end < fstart or start > fstop:
continue
- x_start = max(self.leftMargin + 1,
- self.getXPosition(Datapoint(start, 0, 0)))
- x_stop = min(self.leftMargin + self.dim.width,
- self.getXPosition(Datapoint(end, 0, 0)))
- qp.drawRect(x_start,
- self.topMargin,
- x_stop - x_start,
- self.dim.height)
+ x_start = max(
+ self.leftMargin + 1, self.getXPosition(Datapoint(start, 0, 0))
+ )
+ x_stop = min(
+ self.leftMargin + self.dim.width,
+ self.getXPosition(Datapoint(end, 0, 0)),
+ )
+ qp.drawRect(
+ x_start, self.topMargin, x_stop - x_start, self.dim.height
+ )
- def drawData(self, qp: QtGui.QPainter, data: List[Datapoint],
- color: QtGui.QColor, y_function=None):
+ def drawData(
+ self,
+ qp: QtGui.QPainter,
+ data: List[Datapoint],
+ color: QtGui.QColor,
+ y_function=None,
+ ):
if y_function is None:
y_function = self.getYPosition
pen = QtGui.QPen(color)
@@ -643,8 +711,7 @@ class FrequencyChart(Chart):
if self.isPlotable(prevx, prevy):
qp.drawLine(x, y, prevx, prevy)
else:
- new_x, new_y = self.getPlotable(
- x, y, prevx, prevy)
+ new_x, new_y = self.getPlotable(x, y, prevx, prevy)
qp.drawLine(x, y, new_x, new_y)
elif self.isPlotable(prevx, prevy):
new_x, new_y = self.getPlotable(prevx, prevy, x, y)
@@ -663,13 +730,17 @@ class FrequencyChart(Chart):
x = self.getXPosition(data[m.location])
y = y_function(data[m.location])
if self.isPlotable(x, y):
- self.drawMarker(x, y, qp, m.color,
- self.markers.index(m) + 1)
+ self.drawMarker(
+ x, y, qp, m.color, self.markers.index(m) + 1
+ )
def isPlotable(self, x, y):
- return y is not None and x is not None and \
- self.leftMargin <= x <= self.leftMargin + self.dim.width and \
- self.topMargin <= y <= self.topMargin + self.dim.height
+ return (
+ y is not None
+ and x is not None
+ and self.leftMargin <= x <= self.leftMargin + self.dim.width
+ and self.topMargin <= y <= self.topMargin + self.dim.height
+ )
def getPlotable(self, x, y, distantx, distanty):
p1 = np.array([x, y])
@@ -680,8 +751,12 @@ class FrequencyChart(Chart):
p4 = np.array([self.leftMargin + self.dim.width, self.topMargin])
elif distanty > self.topMargin + self.dim.height:
p3 = np.array([self.leftMargin, self.topMargin + self.dim.height])
- p4 = np.array([self.leftMargin + self.dim.width,
- self.topMargin + self.dim.height])
+ p4 = np.array(
+ [
+ self.leftMargin + self.dim.width,
+ self.topMargin + self.dim.height,
+ ]
+ )
else:
return x, y
@@ -730,10 +805,14 @@ class FrequencyChart(Chart):
m = self.getActiveMarker()
if m is not None and a0.modifiers() == QtCore.Qt.NoModifier:
if a0.key() in [QtCore.Qt.Key_Down, QtCore.Qt.Key_Left]:
- m.frequencyInput.keyPressEvent(QtGui.QKeyEvent(
- a0.type(), QtCore.Qt.Key_Down, a0.modifiers()))
+ m.frequencyInput.keyPressEvent(
+ QtGui.QKeyEvent(
+ a0.type(), QtCore.Qt.Key_Down, a0.modifiers()
+ )
+ )
elif a0.key() in [QtCore.Qt.Key_Up, QtCore.Qt.Key_Right]:
- m.frequencyInput.keyPressEvent(QtGui.QKeyEvent(
- a0.type(), QtCore.Qt.Key_Up, a0.modifiers()))
+ m.frequencyInput.keyPressEvent(
+ QtGui.QKeyEvent(a0.type(), QtCore.Qt.Key_Up, a0.modifiers())
+ )
else:
super().keyPressEvent(a0)
diff --git a/src/NanoVNASaver/Charts/GroupDelay.py b/src/NanoVNASaver/Charts/GroupDelay.py
index 3ebac16..1ef3ad0 100644
--- a/src/NanoVNASaver/Charts/GroupDelay.py
+++ b/src/NanoVNASaver/Charts/GroupDelay.py
@@ -27,6 +27,7 @@ from PyQt5 import QtGui
from NanoVNASaver.Charts.Chart import Chart
from NanoVNASaver.RFTools import Datapoint
from .Frequency import FrequencyChart
+
logger = logging.getLogger(__name__)
@@ -124,23 +125,30 @@ class GroupDelayChart(FrequencyChart):
tickcount = math.floor(self.dim.height / 60)
for i in range(tickcount):
delay = min_delay + span * i / tickcount
- y = self.topMargin + \
- round((self.maxDelay - delay) / self.span * self.dim.height)
+ y = self.topMargin + round(
+ (self.maxDelay - delay) / self.span * self.dim.height
+ )
if delay not in {min_delay, max_delay}:
qp.setPen(QtGui.QPen(Chart.color.text))
# TODO use format class
- digits = 0 if delay == 0 else max(
- 0, min(2, math.floor(3 - math.log10(abs(delay)))))
+ digits = (
+ 0
+ if delay == 0
+ else max(0, min(2, math.floor(3 - math.log10(abs(delay)))))
+ )
delaystr = str(round(delay, digits if digits != 0 else None))
qp.drawText(3, y + 3, delaystr)
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, y,
- self.leftMargin + self.dim.width, y)
+ qp.drawLine(
+ self.leftMargin - 5, y, self.leftMargin + self.dim.width, y
+ )
- qp.drawLine(self.leftMargin - 5,
- self.topMargin,
- self.leftMargin + self.dim.width,
- self.topMargin)
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin,
+ self.leftMargin + self.dim.width,
+ self.topMargin,
+ )
qp.setPen(Chart.color.text)
qp.drawText(3, self.topMargin + 5, str(max_delay))
qp.drawText(3, self.dim.height + self.topMargin, str(min_delay))
@@ -153,15 +161,20 @@ class GroupDelayChart(FrequencyChart):
self.drawFrequencyTicks(qp)
- self.draw_data(qp, Chart.color.sweep,
- self.data, self.groupDelay)
- self.draw_data(qp, Chart.color.reference,
- self.reference, self.groupDelayReference)
+ self.draw_data(qp, Chart.color.sweep, self.data, self.groupDelay)
+ self.draw_data(
+ qp, Chart.color.reference, self.reference, self.groupDelayReference
+ )
self.drawMarkers(qp)
- def draw_data(self, qp: QtGui.QPainter, color: QtGui.QColor,
- data: List[Datapoint], delay: List[Datapoint]):
+ def draw_data(
+ self,
+ qp: QtGui.QPainter,
+ color: QtGui.QColor,
+ data: List[Datapoint],
+ delay: List[Datapoint],
+ ):
pen = QtGui.QPen(color)
pen.setWidth(self.dim.point)
line_pen = QtGui.QPen(color)
@@ -200,7 +213,8 @@ class GroupDelayChart(FrequencyChart):
def getYPositionFromDelay(self, delay: float) -> int:
return self.topMargin + int(
- (self.maxDelay - delay) / self.span * self.dim.height)
+ (self.maxDelay - delay) / self.span * self.dim.height
+ )
def valueAtPosition(self, y) -> List[float]:
absy = y - self.topMargin
diff --git a/src/NanoVNASaver/Charts/LogMag.py b/src/NanoVNASaver/Charts/LogMag.py
index da8099f..5237d1c 100644
--- a/src/NanoVNASaver/Charts/LogMag.py
+++ b/src/NanoVNASaver/Charts/LogMag.py
@@ -115,8 +115,12 @@ class LogMagChart(FrequencyChart):
self.draw_db_lines(qp, self.maxValue, self.minValue, ticks)
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, self.topMargin,
- self.leftMargin + self.dim.width, self.topMargin)
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin,
+ self.leftMargin + self.dim.width,
+ self.topMargin,
+ )
qp.setPen(Chart.color.text)
qp.drawText(3, self.topMargin + 4, f"{self.maxValue}")
qp.drawText(3, self.dim.height + self.topMargin, f"{self.minValue}")
@@ -127,14 +131,17 @@ class LogMagChart(FrequencyChart):
for i in range(ticks.count):
db = ticks.first + i * ticks.step
y = self.topMargin + round(
- (maxValue - db) / self.span * self.dim.height)
+ (maxValue - db) / self.span * self.dim.height
+ )
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, y,
- self.leftMargin + self.dim.width, y)
+ qp.drawLine(
+ self.leftMargin - 5, y, self.leftMargin + self.dim.width, y
+ )
if db > minValue and db != maxValue:
qp.setPen(QtGui.QPen(Chart.color.text))
- qp.drawText(3, y + 4,
- f"{round(db, 1)}" if ticks.step < 1 else f"{db}")
+ qp.drawText(
+ 3, y + 4, f"{round(db, 1)}" if ticks.step < 1 else f"{db}"
+ )
def draw_swr_markers(self, qp) -> None:
qp.setPen(Chart.color.swr)
@@ -145,9 +152,9 @@ class LogMagChart(FrequencyChart):
if self.isInverted:
logMag = logMag * -1
y = self.topMargin + round(
- (self.maxValue - logMag) / self.span * self.dim.height)
- qp.drawLine(self.leftMargin, y,
- self.leftMargin + self.dim.width, y)
+ (self.maxValue - logMag) / self.span * self.dim.height
+ )
+ qp.drawLine(self.leftMargin, y, self.leftMargin + self.dim.width, y)
qp.drawText(self.leftMargin + 3, y - 1, f"VSWR: {vswr}")
def getYPosition(self, d: Datapoint) -> int:
@@ -155,7 +162,8 @@ class LogMagChart(FrequencyChart):
if math.isinf(logMag):
return self.topMargin
return self.topMargin + int(
- (self.maxValue - logMag) / self.span * self.dim.height)
+ (self.maxValue - logMag) / self.span * self.dim.height
+ )
def valueAtPosition(self, y) -> List[float]:
absy = y - self.topMargin
diff --git a/src/NanoVNASaver/Charts/Magnitude.py b/src/NanoVNASaver/Charts/Magnitude.py
index 0c8c9df..15404c7 100644
--- a/src/NanoVNASaver/Charts/Magnitude.py
+++ b/src/NanoVNASaver/Charts/Magnitude.py
@@ -25,6 +25,7 @@ from PyQt5 import QtGui
from NanoVNASaver.RFTools import Datapoint
from NanoVNASaver.Charts.Chart import Chart
from NanoVNASaver.Charts.Frequency import FrequencyChart
+
logger = logging.getLogger(__name__)
@@ -78,21 +79,28 @@ class MagnitudeChart(FrequencyChart):
target_ticks = int(self.dim.height // 60)
for i in range(target_ticks):
val = min_value + i / target_ticks * self.span
- y = self.topMargin + int((self.maxValue - val) / self.span
- * self.dim.height)
+ y = self.topMargin + int(
+ (self.maxValue - val) / self.span * self.dim.height
+ )
qp.setPen(Chart.color.text)
if val != min_value:
digits = max(0, min(2, math.floor(3 - math.log10(abs(val)))))
- vswrstr = (str(round(val)) if digits == 0 else
- str(round(val, digits)))
+ vswrstr = (
+ str(round(val)) if digits == 0 else str(round(val, digits))
+ )
qp.drawText(3, y + 3, vswrstr)
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, y,
- self.leftMargin + self.dim.width, y)
+ qp.drawLine(
+ self.leftMargin - 5, y, self.leftMargin + self.dim.width, y
+ )
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, self.topMargin,
- self.leftMargin + self.dim.width, self.topMargin)
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin,
+ self.leftMargin + self.dim.width,
+ self.topMargin,
+ )
qp.setPen(Chart.color.text)
qp.drawText(3, self.topMargin + 4, str(max_value))
qp.drawText(3, self.dim.height + self.topMargin, str(min_value))
@@ -103,10 +111,10 @@ class MagnitudeChart(FrequencyChart):
if vswr <= 1:
continue
mag = (vswr - 1) / (vswr + 1)
- y = self.topMargin + int((self.maxValue - mag) / self.span
- * self.dim.height)
- qp.drawLine(self.leftMargin, y,
- self.leftMargin + self.dim.width, y)
+ y = self.topMargin + int(
+ (self.maxValue - mag) / self.span * self.dim.height
+ )
+ qp.drawLine(self.leftMargin, y, self.leftMargin + self.dim.width, y)
qp.drawText(self.leftMargin + 3, y - 1, f"VSWR: {vswr}")
self.drawData(qp, self.data, Chart.color.sweep)
@@ -116,7 +124,8 @@ class MagnitudeChart(FrequencyChart):
def getYPosition(self, d: Datapoint) -> int:
mag = self.magnitude(d)
return self.topMargin + int(
- (self.maxValue - mag) / self.span * self.dim.height)
+ (self.maxValue - mag) / self.span * self.dim.height
+ )
def valueAtPosition(self, y) -> List[float]:
absy = y - self.topMargin
diff --git a/src/NanoVNASaver/Charts/MagnitudeZ.py b/src/NanoVNASaver/Charts/MagnitudeZ.py
index a6fd2ac..4e4fb85 100644
--- a/src/NanoVNASaver/Charts/MagnitudeZ.py
+++ b/src/NanoVNASaver/Charts/MagnitudeZ.py
@@ -23,8 +23,7 @@ from typing import List
from PyQt5 import QtGui
from NanoVNASaver.RFTools import Datapoint
-from NanoVNASaver.SITools import (
- Format, Value, round_ceil, round_floor)
+from NanoVNASaver.SITools import Format, Value, round_ceil, round_floor
from NanoVNASaver.Charts.Chart import Chart
from NanoVNASaver.Charts.Frequency import FrequencyChart
from NanoVNASaver.Charts.LogMag import LogMagChart
@@ -57,8 +56,10 @@ class MagnitudeZChart(FrequencyChart):
if self.fixedValues:
self.maxValue = self.maxDisplayValue
self.minValue = (
- max(self.minDisplayValue, 0.01) if self.logarithmicY else
- self.minDisplayValue)
+ max(self.minDisplayValue, 0.01)
+ if self.logarithmicY
+ else self.minDisplayValue
+ )
else:
# Find scaling
self.minValue = 100
@@ -92,15 +93,18 @@ class MagnitudeZChart(FrequencyChart):
for i in range(horizontal_ticks):
y = self.topMargin + round(i * self.dim.height / horizontal_ticks)
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, y,
- self.leftMargin + self.dim.width + 5, y)
+ qp.drawLine(
+ self.leftMargin - 5, y, self.leftMargin + self.dim.width + 5, y
+ )
qp.setPen(QtGui.QPen(Chart.color.text))
val = Value(self.valueAtPosition(y)[0], fmt=fmt)
qp.drawText(3, y + 4, str(val))
- qp.drawText(3,
- self.dim.height + self.topMargin,
- str(Value(self.minValue, fmt=fmt)))
+ qp.drawText(
+ 3,
+ self.dim.height + self.topMargin,
+ str(Value(self.minValue, fmt=fmt)),
+ )
self.drawFrequencyTicks(qp)
@@ -116,18 +120,22 @@ class MagnitudeZChart(FrequencyChart):
if self.logarithmicY:
span = math.log(self.maxValue) - math.log(self.minValue)
return self.topMargin + int(
- (math.log(self.maxValue) - math.log(mag)) /
- span * self.dim.height)
+ (math.log(self.maxValue) - math.log(mag))
+ / span
+ * self.dim.height
+ )
return self.topMargin + int(
- (self.maxValue - mag) / self.span * self.dim.height)
+ (self.maxValue - mag) / self.span * self.dim.height
+ )
return self.topMargin
def valueAtPosition(self, y) -> List[float]:
absy = y - self.topMargin
if self.logarithmicY:
span = math.log(self.maxValue) - math.log(self.minValue)
- val = math.exp(math.log(self.maxValue) -
- absy * span / self.dim.height)
+ val = math.exp(
+ math.log(self.maxValue) - absy * span / self.dim.height
+ )
else:
val = self.maxValue - (absy / self.dim.height * self.span)
return [val]
diff --git a/src/NanoVNASaver/Charts/MagnitudeZSeries.py b/src/NanoVNASaver/Charts/MagnitudeZSeries.py
index 816ca83..983bbd5 100644
--- a/src/NanoVNASaver/Charts/MagnitudeZSeries.py
+++ b/src/NanoVNASaver/Charts/MagnitudeZSeries.py
@@ -1,4 +1,3 @@
-
# NanoVNASaver
#
# A python program to view and export Touchstone data from a NanoVNA
@@ -27,7 +26,6 @@ logger = logging.getLogger(__name__)
class MagnitudeZSeriesChart(MagnitudeZChart):
-
@staticmethod
def magnitude(p: Datapoint) -> float:
return abs(p.seriesImpedance())
diff --git a/src/NanoVNASaver/Charts/MagnitudeZShunt.py b/src/NanoVNASaver/Charts/MagnitudeZShunt.py
index 3736e3d..8c59760 100644
--- a/src/NanoVNASaver/Charts/MagnitudeZShunt.py
+++ b/src/NanoVNASaver/Charts/MagnitudeZShunt.py
@@ -1,4 +1,3 @@
-
# NanoVNASaver
#
# A python program to view and export Touchstone data from a NanoVNA
@@ -26,7 +25,6 @@ logger = logging.getLogger(__name__)
class MagnitudeZShuntChart(MagnitudeZChart):
-
@staticmethod
def magnitude(p: Datapoint) -> float:
return abs(p.shuntImpedance())
diff --git a/src/NanoVNASaver/Charts/Permeability.py b/src/NanoVNASaver/Charts/Permeability.py
index d8cbc4c..025e8a8 100644
--- a/src/NanoVNASaver/Charts/Permeability.py
+++ b/src/NanoVNASaver/Charts/Permeability.py
@@ -27,6 +27,7 @@ from NanoVNASaver.RFTools import Datapoint
from NanoVNASaver.SITools import Format, Value
from NanoVNASaver.Charts.Chart import Chart
from NanoVNASaver.Charts.Frequency import FrequencyChart
+
logger = logging.getLogger(__name__)
@@ -50,19 +51,26 @@ class PermeabilityChart(FrequencyChart):
def drawChart(self, qp: QtGui.QPainter):
qp.setPen(QtGui.QPen(Chart.color.text))
- qp.drawText(self.leftMargin + 5, 15, self.name +
- " (\N{MICRO SIGN}\N{OHM SIGN} / Hz)")
+ qp.drawText(
+ self.leftMargin + 5,
+ 15,
+ self.name + " (\N{MICRO SIGN}\N{OHM SIGN} / Hz)",
+ )
qp.drawText(10, 15, "R")
qp.drawText(self.leftMargin + self.dim.width + 10, 15, "X")
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin,
- self.topMargin - 5,
- self.leftMargin,
- self.topMargin + self.dim.height + 5)
- qp.drawLine(self.leftMargin - 5,
- self.topMargin + self.dim.height,
- self.leftMargin + self.dim.width + 5,
- self.topMargin + self.dim.height)
+ qp.drawLine(
+ self.leftMargin,
+ self.topMargin - 5,
+ self.leftMargin,
+ self.topMargin + self.dim.height + 5,
+ )
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin + self.dim.height,
+ self.leftMargin + self.dim.width + 5,
+ self.topMargin + self.dim.height,
+ )
self.drawTitle(qp)
def drawValues(self, qp: QtGui.QPainter):
@@ -121,15 +129,16 @@ class PermeabilityChart(FrequencyChart):
for i in range(horizontal_ticks):
y = self.topMargin + round(i * self.dim.height / horizontal_ticks)
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, y,
- self.leftMargin + self.dim.width + 5, y)
+ qp.drawLine(
+ self.leftMargin - 5, y, self.leftMargin + self.dim.width + 5, y
+ )
qp.setPen(QtGui.QPen(Chart.color.text))
val = Value(self.valueAtPosition(y)[0], fmt=fmt)
qp.drawText(3, y + 4, str(val))
- qp.drawText(3,
- self.dim.height + self.topMargin,
- str(Value(min_val, fmt=fmt)))
+ qp.drawText(
+ 3, self.dim.height + self.topMargin, str(Value(min_val, fmt=fmt))
+ )
self.drawFrequencyTicks(qp)
@@ -147,8 +156,11 @@ class PermeabilityChart(FrequencyChart):
pen.setColor(c)
qp.setPen(pen)
qp.drawLine(
- self.leftMargin + self.dim.width, 9,
- self.leftMargin + self.dim.width + 5, 9)
+ self.leftMargin + self.dim.width,
+ 9,
+ self.leftMargin + self.dim.width + 5,
+ 9,
+ )
primary_pen.setWidth(self.dim.point)
secondary_pen.setWidth(self.dim.point)
@@ -177,7 +189,8 @@ class PermeabilityChart(FrequencyChart):
qp.drawLine(x, y_re, prev_x, prev_y_re)
else:
new_x, new_y = self.getPlotable(
- x, y_re, prev_x, prev_y_re)
+ x, y_re, prev_x, prev_y_re
+ )
qp.drawLine(x, y_re, new_x, new_y)
elif self.isPlotable(prev_x, prev_y_re):
new_x, new_y = self.getPlotable(prev_x, prev_y_re, x, y_re)
@@ -191,7 +204,8 @@ class PermeabilityChart(FrequencyChart):
qp.drawLine(x, y_im, prev_x, prev_y_im)
else:
new_x, new_y = self.getPlotable(
- x, y_im, prev_x, prev_y_im)
+ x, y_im, prev_x, prev_y_im
+ )
qp.drawLine(x, y_im, new_x, new_y)
elif self.isPlotable(prev_x, prev_y_im):
new_x, new_y = self.getPlotable(prev_x, prev_y_im, x, y_im)
@@ -213,8 +227,12 @@ class PermeabilityChart(FrequencyChart):
pen = QtGui.QPen(c)
pen.setWidth(2)
qp.setPen(pen)
- qp.drawLine(self.leftMargin + self.dim.width, 14,
- self.leftMargin + self.dim.width + 5, 14)
+ qp.drawLine(
+ self.leftMargin + self.dim.width,
+ 14,
+ self.leftMargin + self.dim.width + 5,
+ 14,
+ )
for i, reference in enumerate(self.reference):
if reference.freq < self.fstart or reference.freq > self.fstop:
@@ -241,7 +259,8 @@ class PermeabilityChart(FrequencyChart):
qp.drawLine(x, y_re, prev_x, prev_y_re)
else:
new_x, new_y = self.getPlotable(
- x, y_re, prev_x, prev_y_re)
+ x, y_re, prev_x, prev_y_re
+ )
qp.drawLine(x, y_re, new_x, new_y)
elif self.isPlotable(prev_x, prev_y_re):
new_x, new_y = self.getPlotable(prev_x, prev_y_re, x, y_re)
@@ -255,7 +274,8 @@ class PermeabilityChart(FrequencyChart):
qp.drawLine(x, y_im, prev_x, prev_y_im)
else:
new_x, new_y = self.getPlotable(
- x, y_im, prev_x, prev_y_im)
+ x, y_im, prev_x, prev_y_im
+ )
qp.drawLine(x, y_im, new_x, new_y)
elif self.isPlotable(prev_x, prev_y_im):
new_x, new_y = self.getPlotable(prev_x, prev_y_im, x, y_im)
@@ -268,10 +288,8 @@ class PermeabilityChart(FrequencyChart):
y_re = self.getReYPosition(self.data[m.location])
y_im = self.getImYPosition(self.data[m.location])
- self.drawMarker(x, y_re, qp, m.color,
- self.markers.index(m) + 1)
- self.drawMarker(x, y_im, qp, m.color,
- self.markers.index(m) + 1)
+ self.drawMarker(x, y_re, qp, m.color, self.markers.index(m) + 1)
+ self.drawMarker(x, y_im, qp, m.color, self.markers.index(m) + 1)
def getImYPosition(self, d: Datapoint) -> int:
im = d.impedance().imag
@@ -283,10 +301,12 @@ class PermeabilityChart(FrequencyChart):
else:
return -1
return int(
- self.topMargin + (math.log(self.max) - math.log(im)) /
- span * self.dim.height)
- return int(self.topMargin + (self.max - im) /
- self.span * self.dim.height)
+ self.topMargin
+ + (math.log(self.max) - math.log(im)) / span * self.dim.height
+ )
+ return int(
+ self.topMargin + (self.max - im) / self.span * self.dim.height
+ )
def getReYPosition(self, d: Datapoint) -> int:
re = d.impedance().real
@@ -298,10 +318,12 @@ class PermeabilityChart(FrequencyChart):
else:
return -1
return int(
- self.topMargin + (math.log(self.max) - math.log(re)) /
- span * self.dim.height)
+ self.topMargin
+ + (math.log(self.max) - math.log(re)) / span * self.dim.height
+ )
return int(
- self.topMargin + (self.max - re) / self.span * self.dim.height)
+ self.topMargin + (self.max - re) / self.span * self.dim.height
+ )
def valueAtPosition(self, y) -> List[float]:
absy = y - self.topMargin
diff --git a/src/NanoVNASaver/Charts/Phase.py b/src/NanoVNASaver/Charts/Phase.py
index 582afc1..6f93c35 100644
--- a/src/NanoVNASaver/Charts/Phase.py
+++ b/src/NanoVNASaver/Charts/Phase.py
@@ -50,7 +50,8 @@ class PhaseChart(FrequencyChart):
self.action_unwrap = QtWidgets.QAction("Unwrap")
self.action_unwrap.setCheckable(True)
self.action_unwrap.triggered.connect(
- lambda: self.setUnwrap(self.action_unwrap.isChecked()))
+ lambda: self.setUnwrap(self.action_unwrap.isChecked())
+ )
self.y_menu.addAction(self.action_unwrap)
def copy(self):
@@ -98,24 +99,32 @@ class PhaseChart(FrequencyChart):
for i in range(tickcount):
angle = minAngle + span * i / tickcount
y = self.topMargin + int(
- (self.maxAngle - angle) / self.span * self.dim.height)
+ (self.maxAngle - angle) / self.span * self.dim.height
+ )
if angle not in [minAngle, maxAngle]:
qp.setPen(QtGui.QPen(Chart.color.text))
if angle != 0:
digits = max(
- 0, min(2, math.floor(3 - math.log10(abs(angle)))))
- anglestr = str(round(angle)) if digits == 0 else str(
- round(angle, digits))
+ 0, min(2, math.floor(3 - math.log10(abs(angle))))
+ )
+ anglestr = (
+ str(round(angle))
+ if digits == 0
+ else str(round(angle, digits))
+ )
else:
anglestr = "0"
qp.drawText(3, y + 3, f"{anglestr}°")
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, y,
- self.leftMargin + self.dim.width, y)
- qp.drawLine(self.leftMargin - 5,
- self.topMargin,
- self.leftMargin + self.dim.width,
- self.topMargin)
+ qp.drawLine(
+ self.leftMargin - 5, y, self.leftMargin + self.dim.width, y
+ )
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin,
+ self.leftMargin + self.dim.width,
+ self.topMargin,
+ )
qp.setPen(Chart.color.text)
qp.drawText(3, self.topMargin + 5, f"{maxAngle}°")
qp.drawText(3, self.dim.height + self.topMargin, f"{minAngle}°")
@@ -139,7 +148,8 @@ class PhaseChart(FrequencyChart):
else:
angle = math.degrees(d.phase)
return self.topMargin + int(
- (self.maxAngle - angle) / self.span * self.dim.height)
+ (self.maxAngle - angle) / self.span * self.dim.height
+ )
def valueAtPosition(self, y) -> List[float]:
absy = y - self.topMargin
diff --git a/src/NanoVNASaver/Charts/Polar.py b/src/NanoVNASaver/Charts/Polar.py
index 4d863f4..a3d9f0d 100644
--- a/src/NanoVNASaver/Charts/Polar.py
+++ b/src/NanoVNASaver/Charts/Polar.py
@@ -39,16 +39,25 @@ class PolarChart(SquareChart):
qp.setPen(QtGui.QPen(Chart.color.foreground))
qp.drawEllipse(QtCore.QPoint(center_x, center_y), width_2, height_2)
- qp.drawEllipse(QtCore.QPoint(center_x, center_y),
- width_2 // 2, height_2 // 2)
+ qp.drawEllipse(
+ QtCore.QPoint(center_x, center_y), width_2 // 2, height_2 // 2
+ )
- qp.drawLine(center_x - width_2, center_y,
- center_x + width_2, center_y)
- qp.drawLine(center_x, center_y - height_2,
- center_x, center_y + height_2)
- qp.drawLine(center_x + width_45, center_y + height_45,
- center_x - width_45, center_y - height_45)
- qp.drawLine(center_x + width_45, center_y - height_45,
- center_x - width_45, center_y + height_45)
+ qp.drawLine(center_x - width_2, center_y, center_x + width_2, center_y)
+ qp.drawLine(
+ center_x, center_y - height_2, center_x, center_y + height_2
+ )
+ qp.drawLine(
+ center_x + width_45,
+ center_y + height_45,
+ center_x - width_45,
+ center_y - height_45,
+ )
+ qp.drawLine(
+ center_x + width_45,
+ center_y - height_45,
+ center_x - width_45,
+ center_y + height_45,
+ )
self.drawTitle(qp)
diff --git a/src/NanoVNASaver/Charts/QFactor.py b/src/NanoVNASaver/Charts/QFactor.py
index b8e620e..be14ab5 100644
--- a/src/NanoVNASaver/Charts/QFactor.py
+++ b/src/NanoVNASaver/Charts/QFactor.py
@@ -57,7 +57,7 @@ class QualityFactorChart(FrequencyChart):
scale = 0
if maxQ > 0:
scale = max(scale, math.floor(math.log10(maxQ)))
- maxQ = math.ceil(maxQ / 10 ** scale) * 10 ** scale
+ maxQ = math.ceil(maxQ / 10**scale) * 10**scale
self.minQ = self.minDisplayValue
self.maxQ = maxQ
@@ -69,8 +69,9 @@ class QualityFactorChart(FrequencyChart):
for i in range(tickcount):
q = self.minQ + i * self.span / tickcount
- y = self.topMargin + int((self.maxQ - q) / self.span *
- self.dim.height)
+ y = self.topMargin + int(
+ (self.maxQ - q) / self.span * self.dim.height
+ )
q = round(q)
if q < 10:
q = round(q, 2)
@@ -79,12 +80,15 @@ class QualityFactorChart(FrequencyChart):
qp.setPen(QtGui.QPen(Chart.color.text))
qp.drawText(3, y + 3, str(q))
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, y,
- self.leftMargin + self.dim.width, y)
- qp.drawLine(self.leftMargin - 5,
- self.topMargin,
- self.leftMargin + self.dim.width,
- self.topMargin)
+ qp.drawLine(
+ self.leftMargin - 5, y, self.leftMargin + self.dim.width, y
+ )
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin,
+ self.leftMargin + self.dim.width,
+ self.topMargin,
+ )
qp.setPen(Chart.color.text)
max_q = round(maxQ)
@@ -119,8 +123,9 @@ class QualityFactorChart(FrequencyChart):
def getYPosition(self, d: Datapoint) -> int:
Q = d.qFactor()
- return self.topMargin + int((self.maxQ - Q) / self.span *
- self.dim.height)
+ return self.topMargin + int(
+ (self.maxQ - Q) / self.span * self.dim.height
+ )
def valueAtPosition(self, y) -> List[float]:
absy = y - self.topMargin
diff --git a/src/NanoVNASaver/Charts/RI.py b/src/NanoVNASaver/Charts/RI.py
index 0d65b4a..9c875c3 100644
--- a/src/NanoVNASaver/Charts/RI.py
+++ b/src/NanoVNASaver/Charts/RI.py
@@ -62,11 +62,13 @@ class RealImaginaryChart(FrequencyChart):
self.y_action_automatic.setCheckable(True)
self.y_action_automatic.setChecked(True)
self.y_action_automatic.changed.connect(
- lambda: self.setFixedValues(self.y_action_fixed_span.isChecked()))
+ lambda: self.setFixedValues(self.y_action_fixed_span.isChecked())
+ )
self.y_action_fixed_span = QtWidgets.QAction("Fixed span")
self.y_action_fixed_span.setCheckable(True)
self.y_action_fixed_span.changed.connect(
- lambda: self.setFixedValues(self.y_action_fixed_span.isChecked()))
+ lambda: self.setFixedValues(self.y_action_fixed_span.isChecked())
+ )
mode_group = QtWidgets.QActionGroup(self)
mode_group.addAction(self.y_action_automatic)
mode_group.addAction(self.y_action_fixed_span)
@@ -110,11 +112,14 @@ class RealImaginaryChart(FrequencyChart):
self.drawHorizontalTicks(qp)
fmt = Format(max_nr_digits=3)
- qp.drawText(3, self.dim.height + self.topMargin,
- str(Value(min_real, fmt=fmt)))
- qp.drawText(self.leftMargin + self.dim.width + 8,
- self.dim.height + self.topMargin,
- str(Value(min_imag, fmt=fmt)))
+ qp.drawText(
+ 3, self.dim.height + self.topMargin, str(Value(min_real, fmt=fmt))
+ )
+ qp.drawText(
+ self.leftMargin + self.dim.width + 8,
+ self.dim.height + self.topMargin,
+ str(Value(min_imag, fmt=fmt)),
+ )
self.drawFrequencyTicks(qp)
@@ -131,8 +136,12 @@ class RealImaginaryChart(FrequencyChart):
c.setAlpha(255)
pen.setColor(c)
qp.setPen(pen)
- qp.drawLine(self.leftMargin + self.dim.width, 9,
- self.leftMargin + self.dim.width + 5, 9)
+ qp.drawLine(
+ self.leftMargin + self.dim.width,
+ 9,
+ self.leftMargin + self.dim.width + 5,
+ 9,
+ )
primary_pen.setWidth(self.dim.point)
secondary_pen.setWidth(self.dim.point)
@@ -161,7 +170,8 @@ class RealImaginaryChart(FrequencyChart):
qp.drawLine(x, y_re, prev_x, prev_y_re)
else:
new_x, new_y = self.getPlotable(
- x, y_re, prev_x, prev_y_re)
+ x, y_re, prev_x, prev_y_re
+ )
qp.drawLine(x, y_re, new_x, new_y)
elif self.isPlotable(prev_x, prev_y_re):
new_x, new_y = self.getPlotable(prev_x, prev_y_re, x, y_re)
@@ -175,7 +185,8 @@ class RealImaginaryChart(FrequencyChart):
qp.drawLine(x, y_im, prev_x, prev_y_im)
else:
new_x, new_y = self.getPlotable(
- x, y_im, prev_x, prev_y_im)
+ x, y_im, prev_x, prev_y_im
+ )
qp.drawLine(x, y_im, new_x, new_y)
elif self.isPlotable(prev_x, prev_y_im):
new_x, new_y = self.getPlotable(prev_x, prev_y_im, x, y_im)
@@ -197,8 +208,12 @@ class RealImaginaryChart(FrequencyChart):
pen = QtGui.QPen(c)
pen.setWidth(2)
qp.setPen(pen)
- qp.drawLine(self.leftMargin + self.dim.width, 14,
- self.leftMargin + self.dim.width + 5, 14)
+ qp.drawLine(
+ self.leftMargin + self.dim.width,
+ 14,
+ self.leftMargin + self.dim.width + 5,
+ 14,
+ )
for i, reference in enumerate(self.reference):
if reference.freq < self.fstart or reference.freq > self.fstop:
@@ -225,7 +240,8 @@ class RealImaginaryChart(FrequencyChart):
qp.drawLine(x, y_re, prev_x, prev_y_re)
else:
new_x, new_y = self.getPlotable(
- x, y_re, prev_x, prev_y_re)
+ x, y_re, prev_x, prev_y_re
+ )
qp.drawLine(x, y_re, new_x, new_y)
elif self.isPlotable(prev_x, prev_y_re):
new_x, new_y = self.getPlotable(prev_x, prev_y_re, x, y_re)
@@ -239,7 +255,8 @@ class RealImaginaryChart(FrequencyChart):
qp.drawLine(x, y_im, prev_x, prev_y_im)
else:
new_x, new_y = self.getPlotable(
- x, y_im, prev_x, prev_y_im)
+ x, y_im, prev_x, prev_y_im
+ )
qp.drawLine(x, y_im, new_x, new_y)
elif self.isPlotable(prev_x, prev_y_im):
new_x, new_y = self.getPlotable(prev_x, prev_y_im, x, y_im)
@@ -252,10 +269,8 @@ class RealImaginaryChart(FrequencyChart):
y_re = self.getReYPosition(self.data[m.location])
y_im = self.getImYPosition(self.data[m.location])
- self.drawMarker(x, y_re, qp, m.color,
- self.markers.index(m) + 1)
- self.drawMarker(x, y_im, qp, m.color,
- self.markers.index(m) + 1)
+ self.drawMarker(x, y_re, qp, m.color, self.markers.index(m) + 1)
+ self.drawMarker(x, y_im, qp, m.color, self.markers.index(m) + 1)
def drawHorizontalTicks(self, qp):
# We want one horizontal tick per 50 pixels, at most
@@ -264,8 +279,9 @@ class RealImaginaryChart(FrequencyChart):
for i in range(horizontal_ticks):
y = self.topMargin + i * self.dim.height // horizontal_ticks
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, y,
- self.leftMargin + self.dim.width + 5, y)
+ qp.drawLine(
+ self.leftMargin - 5, y, self.leftMargin + self.dim.width + 5, y
+ )
qp.setPen(QtGui.QPen(Chart.color.text))
re = self.max_real - i * self.span_real / horizontal_ticks
im = self.max_imag - i * self.span_imag / horizontal_ticks
@@ -273,7 +289,8 @@ class RealImaginaryChart(FrequencyChart):
qp.drawText(
self.leftMargin + self.dim.width + 8,
y + 4,
- f"{Value(im, fmt=fmt)}")
+ f"{Value(im, fmt=fmt)}",
+ )
def find_scaling(self):
# Find scaling
@@ -350,20 +367,24 @@ class RealImaginaryChart(FrequencyChart):
def getImYPosition(self, d: Datapoint) -> int:
im = self.value(d).imag
- return int(self.topMargin + (self.max_imag - im) / self.span_imag
- * self.dim.height)
+ return int(
+ self.topMargin
+ + (self.max_imag - im) / self.span_imag * self.dim.height
+ )
def getReYPosition(self, d: Datapoint) -> int:
re = self.value(d).real
- return int(self.topMargin + (self.max_real - re) / self.span_real
- * self.dim.height if math.isfinite(re) else self.topMargin)
+ return int(
+ self.topMargin
+ + (self.max_real - re) / self.span_real * self.dim.height
+ if math.isfinite(re)
+ else self.topMargin
+ )
def valueAtPosition(self, y) -> List[float]:
absy = y - self.topMargin
- valRe = -1 * ((absy / self.dim.height *
- self.span_real) - self.max_real)
- valIm = -1 * ((absy / self.dim.height *
- self.span_imag) - self.max_imag)
+ valRe = -1 * ((absy / self.dim.height * self.span_real) - self.max_real)
+ valIm = -1 * ((absy / self.dim.height * self.span_imag) - self.max_imag)
return [valRe, valIm]
def zoomTo(self, x1, y1, x2, y2):
@@ -406,9 +427,12 @@ class RealImaginaryChart(FrequencyChart):
def setMinimumRealValue(self):
min_val, selected = QtWidgets.QInputDialog.getDouble(
- self, "Minimum real value",
- "Set minimum real value", value=self.minDisplayReal,
- decimals=2)
+ self,
+ "Minimum real value",
+ "Set minimum real value",
+ value=self.minDisplayReal,
+ decimals=2,
+ )
if not selected:
return
if not (self.fixedValues and min_val >= self.maxDisplayReal):
@@ -418,9 +442,12 @@ class RealImaginaryChart(FrequencyChart):
def setMaximumRealValue(self):
max_val, selected = QtWidgets.QInputDialog.getDouble(
- self, "Maximum real value",
- "Set maximum real value", value=self.maxDisplayReal,
- decimals=2)
+ self,
+ "Maximum real value",
+ "Set maximum real value",
+ value=self.maxDisplayReal,
+ decimals=2,
+ )
if not selected:
return
if not (self.fixedValues and max_val <= self.minDisplayReal):
@@ -430,9 +457,12 @@ class RealImaginaryChart(FrequencyChart):
def setMinimumImagValue(self):
min_val, selected = QtWidgets.QInputDialog.getDouble(
- self, "Minimum imaginary value",
- "Set minimum imaginary value", value=self.minDisplayImag,
- decimals=2)
+ self,
+ "Minimum imaginary value",
+ "Set minimum imaginary value",
+ value=self.minDisplayImag,
+ decimals=2,
+ )
if not selected:
return
if not (self.fixedValues and min_val >= self.maxDisplayImag):
@@ -442,9 +472,12 @@ class RealImaginaryChart(FrequencyChart):
def setMaximumImagValue(self):
max_val, selected = QtWidgets.QInputDialog.getDouble(
- self, "Maximum imaginary value",
- "Set maximum imaginary value", value=self.maxDisplayImag,
- decimals=2)
+ self,
+ "Maximum imaginary value",
+ "Set maximum imaginary value",
+ value=self.maxDisplayImag,
+ decimals=2,
+ )
if not selected:
return
if not (self.fixedValues and max_val <= self.minDisplayImag):
@@ -454,9 +487,10 @@ class RealImaginaryChart(FrequencyChart):
def setFixedValues(self, fixed_values: bool):
self.fixedValues = fixed_values
- if (fixed_values and
- (self.minDisplayReal >= self.maxDisplayReal or
- self.minDisplayImag > self.maxDisplayImag)):
+ if fixed_values and (
+ self.minDisplayReal >= self.maxDisplayReal
+ or self.minDisplayImag > self.maxDisplayImag
+ ):
self.fixedValues = False
self.y_action_automatic.setChecked(True)
self.y_action_fixed_span.setChecked(False)
@@ -464,17 +498,23 @@ class RealImaginaryChart(FrequencyChart):
def contextMenuEvent(self, event):
self.action_set_fixed_start.setText(
- f"Start ({format_frequency_chart(self.minFrequency)})")
+ f"Start ({format_frequency_chart(self.minFrequency)})"
+ )
self.action_set_fixed_stop.setText(
- f"Stop ({format_frequency_chart(self.maxFrequency)})")
+ f"Stop ({format_frequency_chart(self.maxFrequency)})"
+ )
self.action_set_fixed_minimum_real.setText(
- f"Minimum R ({self.minDisplayReal})")
+ f"Minimum R ({self.minDisplayReal})"
+ )
self.action_set_fixed_maximum_real.setText(
- f"Maximum R ({self.maxDisplayReal})")
+ f"Maximum R ({self.maxDisplayReal})"
+ )
self.action_set_fixed_minimum_imag.setText(
- f"Minimum jX ({self.minDisplayImag})")
+ f"Minimum jX ({self.minDisplayImag})"
+ )
self.action_set_fixed_maximum_imag.setText(
- f"Maximum jX ({self.maxDisplayImag})")
+ f"Maximum jX ({self.maxDisplayImag})"
+ )
self.menu.exec_(event.globalPos())
def value(self, p: Datapoint) -> complex:
diff --git a/src/NanoVNASaver/Charts/RIMu.py b/src/NanoVNASaver/Charts/RIMu.py
index 7282a06..bdf88b8 100644
--- a/src/NanoVNASaver/Charts/RIMu.py
+++ b/src/NanoVNASaver/Charts/RIMu.py
@@ -34,30 +34,37 @@ MU = "\N{GREEK SMALL LETTER MU}"
class RealImaginaryMuChart(RealImaginaryChart):
-
def __init__(self, name=""):
super().__init__(name)
self.y_menu.addSeparator()
self.action_set_fixed_maximum_real = QtWidgets.QAction(
- f"Maximum {MU}' ({self.maxDisplayReal})")
+ f"Maximum {MU}' ({self.maxDisplayReal})"
+ )
self.action_set_fixed_maximum_real.triggered.connect(
- self.setMaximumRealValue)
+ self.setMaximumRealValue
+ )
self.action_set_fixed_minimum_real = QtWidgets.QAction(
- f"Minimum {MU}' ({self.minDisplayReal})")
+ f"Minimum {MU}' ({self.minDisplayReal})"
+ )
self.action_set_fixed_minimum_real.triggered.connect(
- self.setMinimumRealValue)
+ self.setMinimumRealValue
+ )
self.action_set_fixed_maximum_imag = QtWidgets.QAction(
- f"Maximum {MU}'' ({self.maxDisplayImag})")
+ f"Maximum {MU}'' ({self.maxDisplayImag})"
+ )
self.action_set_fixed_maximum_imag.triggered.connect(
- self.setMaximumImagValue)
+ self.setMaximumImagValue
+ )
self.action_set_fixed_minimum_imag = QtWidgets.QAction(
- f"Minimum {MU}'' ({self.minDisplayImag})")
+ f"Minimum {MU}'' ({self.minDisplayImag})"
+ )
self.action_set_fixed_minimum_imag.triggered.connect(
- self.setMinimumImagValue)
+ self.setMinimumImagValue
+ )
self.y_menu.addAction(self.action_set_fixed_maximum_real)
self.y_menu.addAction(self.action_set_fixed_minimum_real)
@@ -67,25 +74,21 @@ class RealImaginaryMuChart(RealImaginaryChart):
# Manage core parameters
# TODO pick some sane default values?
- self.coreLength = 1.
- self.coreArea = 1.
+ self.coreLength = 1.0
+ self.coreArea = 1.0
self.coreWindings = 1
self.menu.addSeparator()
- self.action_set_core_length = QtWidgets.QAction(
- "Core effective length")
- self.action_set_core_length.triggered.connect(
- self.setCoreLength)
+ self.action_set_core_length = QtWidgets.QAction("Core effective length")
+ self.action_set_core_length.triggered.connect(self.setCoreLength)
- self.action_set_core_area = QtWidgets.QAction(
- "Core area")
- self.action_set_core_area.triggered.connect(
- self.setCoreArea)
+ self.action_set_core_area = QtWidgets.QAction("Core area")
+ self.action_set_core_area.triggered.connect(self.setCoreArea)
self.action_set_core_windings = QtWidgets.QAction(
- "Core number of windings")
- self.action_set_core_windings.triggered.connect(
- self.setCoreWindings)
+ "Core number of windings"
+ )
+ self.action_set_core_windings.triggered.connect(self.setCoreWindings)
self.menu.addAction(self.action_set_core_length)
self.menu.addAction(self.action_set_core_area)
@@ -102,41 +105,53 @@ class RealImaginaryMuChart(RealImaginaryChart):
def drawChart(self, qp: QtGui.QPainter):
qp.setPen(QtGui.QPen(Chart.color.text))
- qp.drawText(self.leftMargin + 5, 15,
- f"{self.name}")
+ qp.drawText(self.leftMargin + 5, 15, f"{self.name}")
qp.drawText(5, 15, f"{MU}'")
qp.drawText(self.leftMargin + self.dim.width + 10, 15, f"{MU}''")
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin,
- self.topMargin - 5,
- self.leftMargin,
- self.topMargin + self.dim.height + 5)
- qp.drawLine(self.leftMargin - 5,
- self.topMargin + self.dim.height,
- self.leftMargin + self.dim.width + 5,
- self.topMargin + self.dim.height)
+ qp.drawLine(
+ self.leftMargin,
+ self.topMargin - 5,
+ self.leftMargin,
+ self.topMargin + self.dim.height + 5,
+ )
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin + self.dim.height,
+ self.leftMargin + self.dim.width + 5,
+ self.topMargin + self.dim.height,
+ )
self.drawTitle(qp)
def contextMenuEvent(self, event):
self.action_set_fixed_start.setText(
- f"Start ({format_frequency_chart(self.minFrequency)})")
+ f"Start ({format_frequency_chart(self.minFrequency)})"
+ )
self.action_set_fixed_stop.setText(
- f"Stop ({format_frequency_chart(self.maxFrequency)})")
+ f"Stop ({format_frequency_chart(self.maxFrequency)})"
+ )
self.action_set_fixed_minimum_real.setText(
- f"Minimum {MU}' ({self.minDisplayReal})")
+ f"Minimum {MU}' ({self.minDisplayReal})"
+ )
self.action_set_fixed_maximum_real.setText(
- f"Maximum {MU}' ({self.maxDisplayReal})")
+ f"Maximum {MU}' ({self.maxDisplayReal})"
+ )
self.action_set_fixed_minimum_imag.setText(
- f"Minimum {MU}'' ({self.minDisplayImag})")
+ f"Minimum {MU}'' ({self.minDisplayImag})"
+ )
self.action_set_fixed_maximum_imag.setText(
- f"Maximum {MU}'' ({self.maxDisplayImag})")
+ f"Maximum {MU}'' ({self.maxDisplayImag})"
+ )
self.menu.exec_(event.globalPos())
def setCoreLength(self):
val, selected = QtWidgets.QInputDialog.getDouble(
- self, "Core effective length",
- "Set core effective length in mm", value=self.coreLength,
- decimals=2)
+ self,
+ "Core effective length",
+ "Set core effective length in mm",
+ value=self.coreLength,
+ decimals=2,
+ )
if not selected:
return
if not (self.fixedValues and val >= 0):
@@ -146,9 +161,12 @@ class RealImaginaryMuChart(RealImaginaryChart):
def setCoreArea(self):
val, selected = QtWidgets.QInputDialog.getDouble(
- self, "Core effective area",
+ self,
+ "Core effective area",
"Set core cross section area length in mm\N{SUPERSCRIPT TWO}",
- value=self.coreArea, decimals=2)
+ value=self.coreArea,
+ decimals=2,
+ )
if not selected:
return
if not (self.fixedValues and val >= 0):
@@ -158,8 +176,11 @@ class RealImaginaryMuChart(RealImaginaryChart):
def setCoreWindings(self):
val, selected = QtWidgets.QInputDialog.getInt(
- self, "Core number of windings",
- "Set core number of windings", value=self.coreWindings)
+ self,
+ "Core number of windings",
+ "Set core number of windings",
+ value=self.coreWindings,
+ )
if not selected:
return
if not (self.fixedValues and val >= 0):
@@ -176,6 +197,7 @@ class RealImaginaryMuChart(RealImaginaryChart):
# Core length and core area are in mm and mm2 respectively
# note: mu_r = mu' - j * mu ''
return np.conj(
- inductance * (self.coreLength / 1e3) /
- (mu_0 * self.coreWindings**2 * (self.coreArea / 1e6))
+ inductance
+ * (self.coreLength / 1e3)
+ / (mu_0 * self.coreWindings**2 * (self.coreArea / 1e6))
)
diff --git a/src/NanoVNASaver/Charts/RIZ.py b/src/NanoVNASaver/Charts/RIZ.py
index ecc9894..42c3be9 100644
--- a/src/NanoVNASaver/Charts/RIZ.py
+++ b/src/NanoVNASaver/Charts/RIZ.py
@@ -35,24 +35,32 @@ class RealImaginaryZChart(RealImaginaryChart):
self.y_menu.addSeparator()
self.action_set_fixed_maximum_real = QtWidgets.QAction(
- f"Maximum R ({self.maxDisplayReal})")
+ f"Maximum R ({self.maxDisplayReal})"
+ )
self.action_set_fixed_maximum_real.triggered.connect(
- self.setMaximumRealValue)
+ self.setMaximumRealValue
+ )
self.action_set_fixed_minimum_real = QtWidgets.QAction(
- f"Minimum R ({self.minDisplayReal})")
+ f"Minimum R ({self.minDisplayReal})"
+ )
self.action_set_fixed_minimum_real.triggered.connect(
- self.setMinimumRealValue)
+ self.setMinimumRealValue
+ )
self.action_set_fixed_maximum_imag = QtWidgets.QAction(
- f"Maximum jX ({self.maxDisplayImag})")
+ f"Maximum jX ({self.maxDisplayImag})"
+ )
self.action_set_fixed_maximum_imag.triggered.connect(
- self.setMaximumImagValue)
+ self.setMaximumImagValue
+ )
self.action_set_fixed_minimum_imag = QtWidgets.QAction(
- f"Minimum jX ({self.minDisplayImag})")
+ f"Minimum jX ({self.minDisplayImag})"
+ )
self.action_set_fixed_minimum_imag.triggered.connect(
- self.setMinimumImagValue)
+ self.setMinimumImagValue
+ )
self.y_menu.addAction(self.action_set_fixed_maximum_real)
self.y_menu.addAction(self.action_set_fixed_minimum_real)
@@ -62,34 +70,43 @@ class RealImaginaryZChart(RealImaginaryChart):
def drawChart(self, qp: QtGui.QPainter):
qp.setPen(QtGui.QPen(Chart.color.text))
- qp.drawText(self.leftMargin + 5, 15,
- f"{self.name} (\N{OHM SIGN})")
+ qp.drawText(self.leftMargin + 5, 15, f"{self.name} (\N{OHM SIGN})")
qp.drawText(10, 15, "R")
qp.drawText(self.leftMargin + self.dim.width + 10, 15, "X")
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin,
- self.topMargin - 5,
- self.leftMargin,
- self.topMargin + self.dim.height + 5)
- qp.drawLine(self.leftMargin - 5,
- self.topMargin + self.dim.height,
- self.leftMargin + self.dim.width + 5,
- self.topMargin + self.dim.height)
+ qp.drawLine(
+ self.leftMargin,
+ self.topMargin - 5,
+ self.leftMargin,
+ self.topMargin + self.dim.height + 5,
+ )
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin + self.dim.height,
+ self.leftMargin + self.dim.width + 5,
+ self.topMargin + self.dim.height,
+ )
self.drawTitle(qp)
def contextMenuEvent(self, event):
self.action_set_fixed_start.setText(
- f"Start ({format_frequency_chart(self.minFrequency)})")
+ f"Start ({format_frequency_chart(self.minFrequency)})"
+ )
self.action_set_fixed_stop.setText(
- f"Stop ({format_frequency_chart(self.maxFrequency)})")
+ f"Stop ({format_frequency_chart(self.maxFrequency)})"
+ )
self.action_set_fixed_minimum_real.setText(
- f"Minimum R ({self.minDisplayReal})")
+ f"Minimum R ({self.minDisplayReal})"
+ )
self.action_set_fixed_maximum_real.setText(
- f"Maximum R ({self.maxDisplayReal})")
+ f"Maximum R ({self.maxDisplayReal})"
+ )
self.action_set_fixed_minimum_imag.setText(
- f"Minimum jX ({self.minDisplayImag})")
+ f"Minimum jX ({self.minDisplayImag})"
+ )
self.action_set_fixed_maximum_imag.setText(
- f"Maximum jX ({self.maxDisplayImag})")
+ f"Maximum jX ({self.maxDisplayImag})"
+ )
self.menu.exec_(event.globalPos())
def value(self, p: Datapoint) -> complex:
diff --git a/src/NanoVNASaver/Charts/RIZSeries.py b/src/NanoVNASaver/Charts/RIZSeries.py
index 60f18fc..5d15ed7 100644
--- a/src/NanoVNASaver/Charts/RIZSeries.py
+++ b/src/NanoVNASaver/Charts/RIZSeries.py
@@ -25,6 +25,5 @@ logger = logging.getLogger(__name__)
class RealImaginaryZSeriesChart(RealImaginaryZChart):
-
def impedance(self, p: Datapoint) -> complex:
return p.seriesImpedance()
diff --git a/src/NanoVNASaver/Charts/RIZShunt.py b/src/NanoVNASaver/Charts/RIZShunt.py
index 1609282..387b8ab 100644
--- a/src/NanoVNASaver/Charts/RIZShunt.py
+++ b/src/NanoVNASaver/Charts/RIZShunt.py
@@ -25,6 +25,5 @@ logger = logging.getLogger(__name__)
class RealImaginaryZShuntChart(RealImaginaryZChart):
-
def impedance(self, p: Datapoint) -> complex:
return p.shuntImpedance()
diff --git a/src/NanoVNASaver/Charts/SParam.py b/src/NanoVNASaver/Charts/SParam.py
index 297af5d..30363b8 100644
--- a/src/NanoVNASaver/Charts/SParam.py
+++ b/src/NanoVNASaver/Charts/SParam.py
@@ -52,14 +52,18 @@ class SParameterChart(FrequencyChart):
qp.drawText(10, 15, "Real")
qp.drawText(self.leftMargin + self.dim.width - 15, 15, "Imag")
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin,
- self.topMargin - 5,
- self.leftMargin,
- self.topMargin + self.dim.height + 5)
- qp.drawLine(self.leftMargin - 5,
- self.topMargin + self.dim.height,
- self.leftMargin + self.dim.width,
- self.topMargin + self.dim.height)
+ qp.drawLine(
+ self.leftMargin,
+ self.topMargin - 5,
+ self.leftMargin,
+ self.topMargin + self.dim.height + 5,
+ )
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin + self.dim.height,
+ self.leftMargin + self.dim.width,
+ self.topMargin + self.dim.height,
+ )
def drawValues(self, qp: QtGui.QPainter):
if len(self.data) == 0 and len(self.reference) == 0:
@@ -85,44 +89,58 @@ class SParameterChart(FrequencyChart):
val = int(minValue + i * tick_step)
y = self.topMargin + (maxValue - val) // span * self.dim.height
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, y,
- self.leftMargin + self.dim.width, y)
+ qp.drawLine(
+ self.leftMargin - 5, y, self.leftMargin + self.dim.width, y
+ )
if val > minValue and val != maxValue:
qp.setPen(QtGui.QPen(Chart.color.text))
qp.drawText(3, y + 4, str(round(val, 2)))
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, self.topMargin,
- self.leftMargin + self.dim.width, self.topMargin)
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin,
+ self.leftMargin + self.dim.width,
+ self.topMargin,
+ )
qp.setPen(Chart.color.text)
qp.drawText(3, self.topMargin + 4, f"{maxValue}")
qp.drawText(3, self.dim.height + self.topMargin, f"{minValue}")
self.drawFrequencyTicks(qp)
self.drawData(qp, self.data, Chart.color.sweep, self.getReYPosition)
- self.drawData(qp, self.reference, Chart.color.reference,
- self.getReYPosition)
- self.drawData(qp, self.data, Chart.color.sweep_secondary,
- self.getImYPosition)
- self.drawData(qp, self.reference,
- Chart.color.reference_secondary, self.getImYPosition)
+ self.drawData(
+ qp, self.reference, Chart.color.reference, self.getReYPosition
+ )
+ self.drawData(
+ qp, self.data, Chart.color.sweep_secondary, self.getImYPosition
+ )
+ self.drawData(
+ qp,
+ self.reference,
+ Chart.color.reference_secondary,
+ self.getImYPosition,
+ )
self.drawMarkers(qp, y_function=self.getReYPosition)
self.drawMarkers(qp, y_function=self.getImYPosition)
def getYPosition(self, d: Datapoint) -> int:
return int(
- self.topMargin + (self.maxValue - d.re) / self.span *
- self.dim.height)
+ self.topMargin
+ + (self.maxValue - d.re) / self.span * self.dim.height
+ )
def getReYPosition(self, d: Datapoint) -> int:
return int(
- self.topMargin + (self.maxValue - d.re) / self.span *
- self.dim.height)
+ self.topMargin
+ + (self.maxValue - d.re) / self.span * self.dim.height
+ )
def getImYPosition(self, d: Datapoint) -> int:
return int(
- self.topMargin + (self.maxValue - d.im) / self.span *
- self.dim.height)
+ self.topMargin
+ + (self.maxValue - d.im) / self.span * self.dim.height
+ )
def valueAtPosition(self, y) -> List[float]:
absy = y - self.topMargin
diff --git a/src/NanoVNASaver/Charts/Smith.py b/src/NanoVNASaver/Charts/Smith.py
index 43b7c51..4009987 100644
--- a/src/NanoVNASaver/Charts/Smith.py
+++ b/src/NanoVNASaver/Charts/Smith.py
@@ -35,58 +35,119 @@ class SmithChart(SquareChart):
qp.drawText(3, 15, self.name)
qp.setPen(QtGui.QPen(Chart.color.foreground))
qp.drawEllipse(QtCore.QPoint(center_x, center_y), width_2, height_2)
- qp.drawLine(center_x - width_2, center_y,
- center_x + width_2, center_y)
+ qp.drawLine(center_x - width_2, center_y, center_x + width_2, center_y)
qp.drawEllipse(
QtCore.QPoint(center_x + int(self.dim.width / 4), center_y),
- self.dim.width // 4, self.dim.height // 4) # Re(Z) = 1
+ self.dim.width // 4,
+ self.dim.height // 4,
+ ) # Re(Z) = 1
qp.drawEllipse(
QtCore.QPoint(center_x + self.dim.width // 3, center_y),
- self.dim.width // 6, self.dim.height // 6) # Re(Z) = 2
+ self.dim.width // 6,
+ self.dim.height // 6,
+ ) # Re(Z) = 2
qp.drawEllipse(
QtCore.QPoint(center_x + 3 * self.dim.width // 8, center_y),
- self.dim.width // 8, self.dim.height // 8) # Re(Z) = 3
+ self.dim.width // 8,
+ self.dim.height // 8,
+ ) # Re(Z) = 3
qp.drawEllipse(
QtCore.QPoint(center_x + 5 * self.dim.width // 12, center_y),
- self.dim.width // 12, self.dim.height // 12) # Re(Z) = 5
+ self.dim.width // 12,
+ self.dim.height // 12,
+ ) # Re(Z) = 5
qp.drawEllipse(
QtCore.QPoint(center_x + self.dim.width // 6, center_y),
- self.dim.width // 3, self.dim.height // 3) # Re(Z) = 0.5
+ self.dim.width // 3,
+ self.dim.height // 3,
+ ) # Re(Z) = 0.5
qp.drawEllipse(
QtCore.QPoint(center_x + self.dim.width // 12, center_y),
- 5 * self.dim.width // 12, 5 * self.dim.height // 12) # Re(Z) = 0.2
+ 5 * self.dim.width // 12,
+ 5 * self.dim.height // 12,
+ ) # Re(Z) = 0.2
- qp.drawArc(center_x + 3 * self.dim.width // 8, center_y,
- self.dim.width // 4, self.dim.width // 4,
- 90 * 16, 152 * 16) # Im(Z) = -5
- qp.drawArc(center_x + 3 * self.dim.width // 8, center_y,
- self.dim.width // 4, -self.dim.width // 4,
- -90 * 16, -152 * 16) # Im(Z) = 5
- qp.drawArc(center_x + self.dim.width // 4, center_y,
- width_2, height_2,
- 90 * 16, 127 * 16) # Im(Z) = -2
- qp.drawArc(center_x + self.dim.width // 4, center_y,
- width_2, -height_2,
- -90 * 16, -127 * 16) # Im(Z) = 2
- qp.drawArc(center_x, center_y,
- self.dim.width, self.dim.height,
- 90 * 16, 90 * 16) # Im(Z) = -1
- qp.drawArc(center_x, center_y,
- self.dim.width, - self.dim.height,
- -90 * 16, -90 * 16) # Im(Z) = 1
- qp.drawArc(center_x - width_2, center_y,
- self.dim.width * 2, self.dim.height * 2,
- int(99.5 * 16), int(43.5 * 16)) # Im(Z) = -0.5
- qp.drawArc(center_x - width_2, center_y,
- self.dim.width * 2, -self.dim.height * 2,
- int(-99.5 * 16), int(-43.5 * 16)) # Im(Z) = 0.5
- qp.drawArc(center_x - self.dim.width * 2, center_y,
- self.dim.width * 5, self.dim.height * 5,
- int(93.85 * 16), int(18.85 * 16)) # Im(Z) = -0.2
- qp.drawArc(center_x - self.dim.width * 2, center_y,
- self.dim.width * 5, -self.dim.height * 5,
- int(-93.85 * 16), int(-18.85 * 16)) # Im(Z) = 0.2
+ qp.drawArc(
+ center_x + 3 * self.dim.width // 8,
+ center_y,
+ self.dim.width // 4,
+ self.dim.width // 4,
+ 90 * 16,
+ 152 * 16,
+ ) # Im(Z) = -5
+ qp.drawArc(
+ center_x + 3 * self.dim.width // 8,
+ center_y,
+ self.dim.width // 4,
+ -self.dim.width // 4,
+ -90 * 16,
+ -152 * 16,
+ ) # Im(Z) = 5
+ qp.drawArc(
+ center_x + self.dim.width // 4,
+ center_y,
+ width_2,
+ height_2,
+ 90 * 16,
+ 127 * 16,
+ ) # Im(Z) = -2
+ qp.drawArc(
+ center_x + self.dim.width // 4,
+ center_y,
+ width_2,
+ -height_2,
+ -90 * 16,
+ -127 * 16,
+ ) # Im(Z) = 2
+ qp.drawArc(
+ center_x,
+ center_y,
+ self.dim.width,
+ self.dim.height,
+ 90 * 16,
+ 90 * 16,
+ ) # Im(Z) = -1
+ qp.drawArc(
+ center_x,
+ center_y,
+ self.dim.width,
+ -self.dim.height,
+ -90 * 16,
+ -90 * 16,
+ ) # Im(Z) = 1
+ qp.drawArc(
+ center_x - width_2,
+ center_y,
+ self.dim.width * 2,
+ self.dim.height * 2,
+ int(99.5 * 16),
+ int(43.5 * 16),
+ ) # Im(Z) = -0.5
+ qp.drawArc(
+ center_x - width_2,
+ center_y,
+ self.dim.width * 2,
+ -self.dim.height * 2,
+ int(-99.5 * 16),
+ int(-43.5 * 16),
+ ) # Im(Z) = 0.5
+ qp.drawArc(
+ center_x - self.dim.width * 2,
+ center_y,
+ self.dim.width * 5,
+ self.dim.height * 5,
+ int(93.85 * 16),
+ int(18.85 * 16),
+ ) # Im(Z) = -0.2
+ qp.drawArc(
+ center_x - self.dim.width * 2,
+ center_y,
+ self.dim.width * 5,
+ -self.dim.height * 5,
+ int(-93.85 * 16),
+ int(-18.85 * 16),
+ ) # Im(Z) = 0.2
self.drawTitle(qp)
@@ -99,4 +160,6 @@ class SmithChart(SquareChart):
qp.drawEllipse(QtCore.QPoint(center_x, center_y), r, r)
qp.drawText(
QtCore.QRect(center_x - 50, center_y - 4 + r, 100, 20),
- QtCore.Qt.AlignCenter, f"{swr}")
+ QtCore.Qt.AlignCenter,
+ f"{swr}",
+ )
diff --git a/src/NanoVNASaver/Charts/Square.py b/src/NanoVNASaver/Charts/Square.py
index 2d01486..f654212 100644
--- a/src/NanoVNASaver/Charts/Square.py
+++ b/src/NanoVNASaver/Charts/Square.py
@@ -29,11 +29,11 @@ logger = logging.getLogger(__name__)
class SquareChart(Chart):
- def __init__(self, name=''):
+ def __init__(self, name=""):
super().__init__(name)
sizepolicy = QtWidgets.QSizePolicy(
- QtWidgets.QSizePolicy.Fixed,
- QtWidgets.QSizePolicy.MinimumExpanding)
+ QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.MinimumExpanding
+ )
self.setSizePolicy(sizepolicy)
self.dim.width = 250
self.dim.height = 250
@@ -53,8 +53,14 @@ class SquareChart(Chart):
def drawChart(self, qp: QtGui.QPainter) -> None:
raise NotImplementedError()
- def draw_data(self, qp: QtGui.QPainter, color: QtGui.QColor,
- data: List[Datapoint], fstart: int = 0, fstop: int = 0):
+ def draw_data(
+ self,
+ qp: QtGui.QPainter,
+ color: QtGui.QColor,
+ data: List[Datapoint],
+ fstart: int = 0,
+ fstop: int = 0,
+ ):
if not data:
return
fstop = fstop or data[-1].freq
@@ -65,8 +71,7 @@ class SquareChart(Chart):
qp.setPen(pen)
prev_x = self.getXPosition(data[0])
- prev_y = int(self.height() / 2 + data[0].im * -1 *
- self.dim.height / 2)
+ prev_y = int(self.height() / 2 + data[0].im * -1 * self.dim.height / 2)
for i, d in enumerate(data):
x = self.getXPosition(d)
y = int(self.height() / 2 + d.im * -1 * self.dim.height / 2)
@@ -85,14 +90,15 @@ class SquareChart(Chart):
fstart = self.data[0].freq if self.data else 0
fstop = self.data[-1].freq if self.data else 0
- self.draw_data(qp, Chart.color.reference,
- self.reference, fstart, fstop)
+ self.draw_data(qp, Chart.color.reference, self.reference, fstart, fstop)
for m in self.markers:
if m.location != -1 and m.location < len(self.data):
x = self.getXPosition(self.data[m.location])
- y = int(self.height() // 2 -
- self.data[m.location].im * self.dim.height // 2)
+ y = int(
+ self.height() // 2
+ - self.data[m.location].im * self.dim.height // 2
+ )
self.drawMarker(x, y, qp, m.color, self.markers.index(m) + 1)
def resizeEvent(self, a0: QtGui.QResizeEvent) -> None:
@@ -114,11 +120,13 @@ class SquareChart(Chart):
y = a0.y()
absx = x - (self.width() - self.dim.width) / 2
absy = y - (self.height() - self.dim.height) / 2
- if (absx < 0 or
- absx > self.dim.width or
- absy < 0 or
- absy > self.dim.height or
- (not self.data and not self.reference)):
+ if (
+ absx < 0
+ or absx > self.dim.width
+ or absy < 0
+ or absy > self.dim.height
+ or (not self.data and not self.reference)
+ ):
a0.ignore()
return
a0.accept()
@@ -133,8 +141,9 @@ class SquareChart(Chart):
positions = [
math.sqrt(
- (x - (width_2 + d.re * dim_x_2))**2 +
- (y - (height_2 - d.im * dim_y_2))**2)
+ (x - (width_2 + d.re * dim_x_2)) ** 2
+ + (y - (height_2 - d.im * dim_y_2)) ** 2
+ )
for d in target
]
diff --git a/src/NanoVNASaver/Charts/TDR.py b/src/NanoVNASaver/Charts/TDR.py
index 0530d1f..b0fe301 100644
--- a/src/NanoVNASaver/Charts/TDR.py
+++ b/src/NanoVNASaver/Charts/TDR.py
@@ -49,7 +49,9 @@ class TDRChart(Chart):
self.setSizePolicy(
QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding,
- QtWidgets.QSizePolicy.MinimumExpanding))
+ QtWidgets.QSizePolicy.MinimumExpanding,
+ )
+ )
pal = QtGui.QPalette()
pal.setColor(QtGui.QPalette.Background, Chart.color.background)
self.setPalette(pal)
@@ -68,11 +70,13 @@ class TDRChart(Chart):
self.action_automatic.setCheckable(True)
self.action_automatic.setChecked(True)
self.action_automatic.changed.connect(
- lambda: self.setFixedSpan(self.action_fixed_span.isChecked()))
+ lambda: self.setFixedSpan(self.action_fixed_span.isChecked())
+ )
self.action_fixed_span = QtWidgets.QAction("Fixed span")
self.action_fixed_span.setCheckable(True)
self.action_fixed_span.changed.connect(
- lambda: self.setFixedSpan(self.action_fixed_span.isChecked()))
+ lambda: self.setFixedSpan(self.action_fixed_span.isChecked())
+ )
self.mode_group.addAction(self.action_automatic)
self.mode_group.addAction(self.action_fixed_span)
self.x_menu.addAction(self.action_automatic)
@@ -80,11 +84,13 @@ class TDRChart(Chart):
self.x_menu.addSeparator()
self.action_set_fixed_start = QtWidgets.QAction(
- f"Start ({self.minDisplayLength})")
+ f"Start ({self.minDisplayLength})"
+ )
self.action_set_fixed_start.triggered.connect(self.setMinimumLength)
self.action_set_fixed_stop = QtWidgets.QAction(
- f"Stop ({self.maxDisplayLength})")
+ f"Stop ({self.maxDisplayLength})"
+ )
self.action_set_fixed_stop.triggered.connect(self.setMaximumLength)
self.x_menu.addAction(self.action_set_fixed_start)
@@ -96,11 +102,13 @@ class TDRChart(Chart):
self.y_action_automatic.setCheckable(True)
self.y_action_automatic.setChecked(True)
self.y_action_automatic.changed.connect(
- lambda: self.setFixedValues(self.y_action_fixed.isChecked()))
+ lambda: self.setFixedValues(self.y_action_fixed.isChecked())
+ )
self.y_action_fixed = QtWidgets.QAction("Fixed")
self.y_action_fixed.setCheckable(True)
self.y_action_fixed.changed.connect(
- lambda: self.setFixedValues(self.y_action_fixed.isChecked()))
+ lambda: self.setFixedValues(self.y_action_fixed.isChecked())
+ )
self.y_mode_group.addAction(self.y_action_automatic)
self.y_mode_group.addAction(self.y_action_fixed)
self.y_menu.addAction(self.y_action_automatic)
@@ -108,14 +116,18 @@ class TDRChart(Chart):
self.y_menu.addSeparator()
self.y_action_set_fixed_maximum = QtWidgets.QAction(
- f"Maximum ({self.maxImpedance})")
+ f"Maximum ({self.maxImpedance})"
+ )
self.y_action_set_fixed_maximum.triggered.connect(
- self.setMaximumImpedance)
+ self.setMaximumImpedance
+ )
self.y_action_set_fixed_minimum = QtWidgets.QAction(
- f"Minimum ({self.minImpedance})")
+ f"Minimum ({self.minImpedance})"
+ )
self.y_action_set_fixed_minimum.triggered.connect(
- self.setMinimumImpedance)
+ self.setMinimumImpedance
+ )
self.y_menu.addAction(self.y_action_set_fixed_maximum)
self.y_menu.addAction(self.y_action_set_fixed_minimum)
@@ -126,26 +138,29 @@ class TDRChart(Chart):
self.menu.addAction(self.action_save_screenshot)
self.action_popout = QtWidgets.QAction("Popout chart")
self.action_popout.triggered.connect(
- lambda: self.popoutRequested.emit(self))
+ lambda: self.popoutRequested.emit(self)
+ )
self.menu.addAction(self.action_popout)
self.dim.width = self.width() - self.leftMargin - self.rightMargin
self.dim.height = self.height() - self.bottomMargin - self.topMargin
def contextMenuEvent(self, event):
- self.action_set_fixed_start.setText(
- f"Start ({self.minDisplayLength})")
- self.action_set_fixed_stop.setText(
- f"Stop ({self.maxDisplayLength})")
+ self.action_set_fixed_start.setText(f"Start ({self.minDisplayLength})")
+ self.action_set_fixed_stop.setText(f"Stop ({self.maxDisplayLength})")
self.y_action_set_fixed_minimum.setText(
- f"Minimum ({self.minImpedance})")
+ f"Minimum ({self.minImpedance})"
+ )
self.y_action_set_fixed_maximum.setText(
- f"Maximum ({self.maxImpedance})")
+ f"Maximum ({self.maxImpedance})"
+ )
self.menu.exec_(event.globalPos())
def isPlotable(self, x, y):
- return self.leftMargin <= x <= self.width() - self.rightMargin and \
- self.topMargin <= y <= self.height() - self.bottomMargin
+ return (
+ self.leftMargin <= x <= self.width() - self.rightMargin
+ and self.topMargin <= y <= self.height() - self.bottomMargin
+ )
def resetDisplayLimits(self):
self.fixedSpan = False
@@ -162,9 +177,13 @@ class TDRChart(Chart):
def setMinimumLength(self):
min_val, selected = QtWidgets.QInputDialog.getDouble(
- self, "Start length (m)",
- "Set start length (m)", value=self.minDisplayLength,
- min=0, decimals=1)
+ self,
+ "Start length (m)",
+ "Set start length (m)",
+ value=self.minDisplayLength,
+ min=0,
+ decimals=1,
+ )
if not selected:
return
if not (self.fixedSpan and min_val >= self.maxDisplayLength):
@@ -174,9 +193,13 @@ class TDRChart(Chart):
def setMaximumLength(self):
max_val, selected = QtWidgets.QInputDialog.getDouble(
- self, "Stop length (m)",
- "Set stop length (m)", value=self.minDisplayLength,
- min=0.1, decimals=1)
+ self,
+ "Stop length (m)",
+ "Set stop length (m)",
+ value=self.minDisplayLength,
+ min=0.1,
+ decimals=1,
+ )
if not selected:
return
if not (self.fixedSpan and max_val <= self.minDisplayLength):
@@ -190,10 +213,13 @@ class TDRChart(Chart):
def setMinimumImpedance(self):
min_val, selected = QtWidgets.QInputDialog.getDouble(
- self, "Minimum impedance (\N{OHM SIGN})",
+ self,
+ "Minimum impedance (\N{OHM SIGN})",
"Set minimum impedance (\N{OHM SIGN})",
value=self.minDisplayLength,
- min=0, decimals=1)
+ min=0,
+ decimals=1,
+ )
if not selected:
return
if not (self.fixedValues and min_val >= self.maxImpedance):
@@ -203,10 +229,13 @@ class TDRChart(Chart):
def setMaximumImpedance(self):
max_val, selected = QtWidgets.QInputDialog.getDouble(
- self, "Maximum impedance (\N{OHM SIGN})",
+ self,
+ "Maximum impedance (\N{OHM SIGN})",
"Set maximum impedance (\N{OHM SIGN})",
value=self.minDisplayLength,
- min=0.1, decimals=1)
+ min=0.1,
+ decimals=1,
+ )
if not selected:
return
if not (self.fixedValues and max_val <= self.minImpedance):
@@ -236,9 +265,12 @@ class TDRChart(Chart):
if self.dragbox.move_x != -1 and self.dragbox.move_y != -1:
dx = self.dragbox.move_x - a0.x()
dy = self.dragbox.move_y - a0.y()
- self.zoomTo(self.leftMargin + dx, self.topMargin + dy,
- self.leftMargin + self.dim.width + dx,
- self.topMargin + self.dim.height + dy)
+ self.zoomTo(
+ self.leftMargin + dx,
+ self.topMargin + dy,
+ self.leftMargin + self.dim.width + dx,
+ self.topMargin + self.dim.height + dy,
+ )
self.dragbox.move_x = a0.x()
self.dragbox.move_y = a0.y()
return
@@ -261,13 +293,14 @@ class TDRChart(Chart):
if self.tdrWindow.td:
if self.fixedSpan:
max_index = np.searchsorted(
- self.tdrWindow.distance_axis, self.maxDisplayLength * 2)
+ self.tdrWindow.distance_axis, self.maxDisplayLength * 2
+ )
min_index = np.searchsorted(
- self.tdrWindow.distance_axis, self.minDisplayLength * 2)
+ self.tdrWindow.distance_axis, self.minDisplayLength * 2
+ )
x_step = (max_index - min_index) / width
else:
- max_index = math.ceil(
- len(self.tdrWindow.distance_axis) / 2)
+ max_index = math.ceil(len(self.tdrWindow.distance_axis) / 2)
x_step = max_index / width
self.markerLocation = int(round(absx * x_step))
@@ -282,17 +315,21 @@ class TDRChart(Chart):
qp.setPen(QtGui.QPen(Chart.color.foreground))
qp.drawLine(x, self.topMargin, x, self.topMargin + height)
qp.setPen(QtGui.QPen(Chart.color.text))
- distance = self.tdrWindow.distance_axis[
- min_index +
- int((x - self.leftMargin) * x_step) - 1] / 2
- qp.drawText(x - 15, self.topMargin + height + 15,
- f"{round(distance, 1)}m")
+ distance = (
+ self.tdrWindow.distance_axis[
+ min_index + int((x - self.leftMargin) * x_step) - 1
+ ]
+ / 2
+ )
+ qp.drawText(
+ x - 15, self.topMargin + height + 15, f"{round(distance, 1)}m"
+ )
qp.setPen(QtGui.QPen(Chart.color.text))
qp.drawText(
self.leftMargin - 10,
self.topMargin + height + 15,
- str(round(self.tdrWindow.distance_axis[min_index] / 2,
- 1)) + "m")
+ str(round(self.tdrWindow.distance_axis[min_index] / 2, 1)) + "m",
+ )
def _draw_y_ticks(self, height, width, min_impedance, max_impedance):
qp = QtGui.QPainter(self)
@@ -308,7 +345,8 @@ class TDRChart(Chart):
qp.drawText(3, y + 3, str(round(y_val, 1)))
qp.setPen(Chart.color.text)
qp.drawText(
- 3, self.topMargin + height + 3, f"{round(min_impedance, 1)}")
+ 3, self.topMargin + height + 3, f"{round(min_impedance, 1)}"
+ )
def _draw_max_point(self, height, x_step, y_step, min_index):
qp = QtGui.QPainter(self)
@@ -316,22 +354,25 @@ class TDRChart(Chart):
max_point = QtCore.QPoint(
self.leftMargin + int((id_max - min_index) / x_step),
- (self.topMargin + height) - int(
- self.tdrWindow.td[id_max] / y_step))
+ (self.topMargin + height) - int(self.tdrWindow.td[id_max] / y_step),
+ )
qp.setPen(self.markers[0].color)
qp.drawEllipse(max_point, 2, 2)
qp.setPen(Chart.color.text)
- qp.drawText(max_point.x() - 10, max_point.y() - 5,
- f"{round(self.tdrWindow.distance_axis[id_max] / 2, 2)}m")
+ qp.drawText(
+ max_point.x() - 10,
+ max_point.y() - 5,
+ f"{round(self.tdrWindow.distance_axis[id_max] / 2, 2)}m",
+ )
def _draw_marker(self, height, x_step, y_step, min_index):
qp = QtGui.QPainter(self)
marker_point = QtCore.QPoint(
- self.leftMargin +
- int((self.markerLocation - min_index) / x_step),
- (self.topMargin + height) -
- int(self.tdrWindow.td[self.markerLocation] / y_step))
+ self.leftMargin + int((self.markerLocation - min_index) / x_step),
+ (self.topMargin + height)
+ - int(self.tdrWindow.td[self.markerLocation] / y_step),
+ )
qp.setPen(Chart.color.text)
qp.drawEllipse(marker_point, 2, 2)
qp.drawText(
@@ -339,19 +380,21 @@ class TDRChart(Chart):
marker_point.y() - 5,
f"""{round(
self.tdrWindow.distance_axis[self.markerLocation] / 2,
- 2)}m""")
+ 2)}m""",
+ )
def _draw_graph(self, height, width):
min_index = 0
- max_index = math.ceil(
- len(self.tdrWindow.distance_axis) / 2)
+ max_index = math.ceil(len(self.tdrWindow.distance_axis) / 2)
if self.fixedSpan:
max_length = max(0.1, self.maxDisplayLength)
max_index = np.searchsorted(
- self.tdrWindow.distance_axis, max_length * 2)
+ self.tdrWindow.distance_axis, max_length * 2
+ )
min_index = np.searchsorted(
- self.tdrWindow.distance_axis, self.minDisplayLength * 2)
+ self.tdrWindow.distance_axis, self.minDisplayLength * 2
+ )
if max_index == min_index:
if max_index < len(self.tdrWindow.distance_axis) - 1:
max_index += 1
@@ -361,8 +404,7 @@ class TDRChart(Chart):
# TODO: Limit the search to the selected span?
min_impedance = max(0, np.min(self.tdrWindow.step_response_Z) / 1.05)
- max_impedance = min(1000, np.max(
- self.tdrWindow.step_response_Z) * 1.05)
+ max_impedance = min(1000, np.max(self.tdrWindow.step_response_Z) * 1.05)
if self.fixedValues:
min_impedance = max(0, self.minImpedance)
max_impedance = max(0.1, self.maxImpedance)
@@ -370,7 +412,7 @@ class TDRChart(Chart):
y_step = max(self.tdrWindow.td) * 1.1 / height or 1.0e-30
self._draw_ticks(height, width, x_step, min_index)
- self._draw_y_ticks(height, width, min_impedance, max_impedance)
+ self._draw_y_ticks(height, width, min_impedance, max_impedance)
qp = QtGui.QPainter(self)
pen = QtGui.QPen(Chart.color.sweep)
@@ -388,7 +430,8 @@ class TDRChart(Chart):
x = self.leftMargin + int((i - min_index) / x_step)
y = (self.topMargin + height) - int(
- (self.tdrWindow.step_response_Z[i] - min_impedance) / y_step)
+ (self.tdrWindow.step_response_Z[i] - min_impedance) / y_step
+ )
if self.isPlotable(x, y):
pen.setColor(Chart.color.sweep_secondary)
qp.setPen(pen)
@@ -408,14 +451,18 @@ class TDRChart(Chart):
height = self.height() - self.bottomMargin - self.topMargin
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5,
- self.height() - self.bottomMargin,
- self.width() - self.rightMargin,
- self.height() - self.bottomMargin)
- qp.drawLine(self.leftMargin,
- self.topMargin - 5,
- self.leftMargin,
- self.height() - self.bottomMargin + 5)
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.height() - self.bottomMargin,
+ self.width() - self.rightMargin,
+ self.height() - self.bottomMargin,
+ )
+ qp.drawLine(
+ self.leftMargin,
+ self.topMargin - 5,
+ self.leftMargin,
+ self.height() - self.bottomMargin + 5,
+ )
# Number of ticks does not include the origin
self.drawTitle(qp)
@@ -424,12 +471,13 @@ class TDRChart(Chart):
if self.dragbox.state and self.dragbox.pos[0] != -1:
dashed_pen = QtGui.QPen(
- Chart.color.foreground, 1, QtCore.Qt.DashLine)
+ Chart.color.foreground, 1, QtCore.Qt.DashLine
+ )
qp.setPen(dashed_pen)
qp.drawRect(
QtCore.QRect(
QtCore.QPoint(*self.dragbox.pos_start),
- QtCore.QPoint(*self.dragbox.pos)
+ QtCore.QPoint(*self.dragbox.pos),
)
)
@@ -444,11 +492,11 @@ class TDRChart(Chart):
max_impedance = self.maxImpedance
else:
min_impedance = max(
- 0,
- np.min(self.tdrWindow.step_response_Z) / 1.05)
+ 0, np.min(self.tdrWindow.step_response_Z) / 1.05
+ )
max_impedance = min(
- 1000,
- np.max(self.tdrWindow.step_response_Z) * 1.05)
+ 1000, np.max(self.tdrWindow.step_response_Z) * 1.05
+ )
y_step = (max_impedance - min_impedance) / height
return y_step * absy + min_impedance
return 0
@@ -459,20 +507,28 @@ class TDRChart(Chart):
width = self.width() - self.leftMargin - self.rightMargin
absx = x - self.leftMargin
min_length = self.minDisplayLength if self.fixedSpan else 0
- max_length = self.maxDisplayLength if self.fixedSpan else (
- self.tdrWindow.distance_axis[
- math.ceil(len(self.tdrWindow.distance_axis) / 2)
- ] / 2)
+ max_length = (
+ self.maxDisplayLength
+ if self.fixedSpan
+ else (
+ self.tdrWindow.distance_axis[
+ math.ceil(len(self.tdrWindow.distance_axis) / 2)
+ ]
+ / 2
+ )
+ )
x_step = (max_length - min_length) / width
if limit and absx < 0:
return min_length
- return (max_length if limit and absx > width else
- absx * x_step + min_length)
+ return (
+ max_length if limit and absx > width else absx * x_step + min_length
+ )
def zoomTo(self, x1, y1, x2, y2):
logger.debug(
- "Zoom to (x,y) by (x,y): (%d, %d) by (%d, %d)", x1, y1, x2, y2)
+ "Zoom to (x,y) by (x,y): (%d, %d) by (%d, %d)", x1, y1, x2, y2
+ )
val1 = self.valueAtPosition(y1)
val2 = self.valueAtPosition(y2)
diff --git a/src/NanoVNASaver/Charts/VSWR.py b/src/NanoVNASaver/Charts/VSWR.py
index cc962e4..cd3bf44 100644
--- a/src/NanoVNASaver/Charts/VSWR.py
+++ b/src/NanoVNASaver/Charts/VSWR.py
@@ -30,7 +30,6 @@ logger = logging.getLogger(__name__)
class VSWRChart(FrequencyChart):
-
def __init__(self, name=""):
super().__init__(name)
@@ -90,19 +89,22 @@ class VSWRChart(FrequencyChart):
qp.setPen(Chart.color.text)
if vswr != 0:
digits = max(
- 0, min(2, math.floor(3 - math.log10(abs(vswr)))))
+ 0, min(2, math.floor(3 - math.log10(abs(vswr))))
+ )
v_text = f"{round(vswr, digits)}" if digits else "0"
qp.drawText(3, y + 3, v_text)
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, y,
- self.leftMargin + self.dim.width, y)
- qp.drawLine(self.leftMargin - 5,
- self.topMargin + self.dim.height,
- self.leftMargin + self.dim.width,
- self.topMargin + self.dim.height)
+ qp.drawLine(
+ self.leftMargin - 5, y, self.leftMargin + self.dim.width, y
+ )
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin + self.dim.height,
+ self.leftMargin + self.dim.width,
+ self.topMargin + self.dim.height,
+ )
qp.setPen(Chart.color.text)
- digits = max(
- 0, min(2, math.floor(3 - math.log10(abs(minVSWR)))))
+ digits = max(0, min(2, math.floor(3 - math.log10(abs(minVSWR)))))
v_text = f"{round(minVSWR, digits)}" if digits else "0"
qp.drawText(3, self.topMargin + self.dim.height, v_text)
else:
@@ -112,16 +114,20 @@ class VSWRChart(FrequencyChart):
qp.setPen(Chart.color.text)
if vswr != 0:
digits = max(
- 0, min(2, math.floor(3 - math.log10(abs(vswr)))))
+ 0, min(2, math.floor(3 - math.log10(abs(vswr))))
+ )
vswrstr = f"{round(vswr, digits)}" if digits else "0"
qp.drawText(3, y + 3, vswrstr)
qp.setPen(QtGui.QPen(Chart.color.foreground))
- qp.drawLine(self.leftMargin - 5, y,
- self.leftMargin + self.dim.width, y)
- qp.drawLine(self.leftMargin - 5,
- self.topMargin,
- self.leftMargin + self.dim.width,
- self.topMargin)
+ qp.drawLine(
+ self.leftMargin - 5, y, self.leftMargin + self.dim.width, y
+ )
+ qp.drawLine(
+ self.leftMargin - 5,
+ self.topMargin,
+ self.leftMargin + self.dim.width,
+ self.topMargin,
+ )
qp.setPen(Chart.color.text)
digits = max(0, min(2, math.floor(3 - math.log10(abs(maxVSWR)))))
v_text = f"{round(maxVSWR, digits)}" if digits else "0"
@@ -130,8 +136,7 @@ class VSWRChart(FrequencyChart):
qp.setPen(Chart.color.swr)
for vswr in self.swrMarkers:
y = self.getYPositionFromValue(vswr)
- qp.drawLine(self.leftMargin, y,
- self.leftMargin + self.dim.width, y)
+ qp.drawLine(self.leftMargin, y, self.leftMargin + self.dim.width, y)
qp.drawText(self.leftMargin + 3, y - 1, str(vswr))
self.drawFrequencyTicks(qp)
@@ -146,13 +151,15 @@ class VSWRChart(FrequencyChart):
span = math.log(self.maxVSWR) - math.log(min_val)
else:
return -1
- return (
- self.topMargin + int(
- (math.log(self.maxVSWR) - math.log(vswr)) /
- span * self.dim.height))
+ return self.topMargin + int(
+ (math.log(self.maxVSWR) - math.log(vswr))
+ / span
+ * self.dim.height
+ )
try:
return self.topMargin + int(
- (self.maxVSWR - vswr) / self.span * self.dim.height)
+ (self.maxVSWR - vswr) / self.span * self.dim.height
+ )
except OverflowError:
return self.topMargin
diff --git a/src/NanoVNASaver/Charts/__init__.py b/src/NanoVNASaver/Charts/__init__.py
index 80076a3..10635a6 100644
--- a/src/NanoVNASaver/Charts/__init__.py
+++ b/src/NanoVNASaver/Charts/__init__.py
@@ -23,30 +23,31 @@ from .Smith import SmithChart
from .SParam import SParameterChart
from .TDR import TDRChart
from .VSWR import VSWRChart
+
__all__ = [
- 'Chart',
- 'FrequencyChart',
- 'PolarChart',
- 'SquareChart',
- 'CapacitanceChart',
- 'InductanceChart',
- 'GroupDelayChart',
- 'LogMagChart',
- 'CombinedLogMagChart',
- 'MagnitudeChart',
- 'MagnitudeZChart',
- 'MagnitudeZShuntChart',
- 'MagnitudeZSeriesChart',
- 'PermeabilityChart',
- 'PhaseChart',
- 'QualityFactorChart',
- 'RealImaginaryChart',
- 'RealImaginaryMuChart',
- 'RealImaginaryZChart',
- 'RealImaginaryZShuntChart',
- 'RealImaginaryZSeriesChart',
- 'SmithChart',
- 'SParameterChart',
- 'TDRChart',
- 'VSWRChart',
+ "Chart",
+ "FrequencyChart",
+ "PolarChart",
+ "SquareChart",
+ "CapacitanceChart",
+ "InductanceChart",
+ "GroupDelayChart",
+ "LogMagChart",
+ "CombinedLogMagChart",
+ "MagnitudeChart",
+ "MagnitudeZChart",
+ "MagnitudeZShuntChart",
+ "MagnitudeZSeriesChart",
+ "PermeabilityChart",
+ "PhaseChart",
+ "QualityFactorChart",
+ "RealImaginaryChart",
+ "RealImaginaryMuChart",
+ "RealImaginaryZChart",
+ "RealImaginaryZShuntChart",
+ "RealImaginaryZSeriesChart",
+ "SmithChart",
+ "SParameterChart",
+ "TDRChart",
+ "VSWRChart",
]
diff --git a/src/NanoVNASaver/Controls/MarkerControl.py b/src/NanoVNASaver/Controls/MarkerControl.py
index 54d18f2..9172c5c 100644
--- a/src/NanoVNASaver/Controls/MarkerControl.py
+++ b/src/NanoVNASaver/Controls/MarkerControl.py
@@ -29,16 +29,16 @@ 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")
+ text = (
+ "Show data" if Defaults.cfg.gui.markers_hidden else "Hide data"
+ )
super().setText(text)
self.setToolTip("Toggle visibility of marker readings area")
class MarkerControl(Control):
-
def __init__(self, app: QtWidgets.QWidget):
super().__init__(app, "Markers")
@@ -72,7 +72,8 @@ class MarkerControl(Control):
lock_radiobutton = QtWidgets.QRadioButton("Locked")
lock_radiobutton.setLayoutDirection(QtCore.Qt.RightToLeft)
lock_radiobutton.setSizePolicy(
- QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
+ QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred
+ )
hbox = QtWidgets.QHBoxLayout()
hbox.addWidget(self.showMarkerButton)
@@ -82,8 +83,7 @@ class MarkerControl(Control):
def toggle_frame(self):
def settings(hidden: bool):
Defaults.cfg.gui.markers_hidden = not hidden
- self.app.marker_frame.setHidden(
- Defaults.cfg.gui.markers_hidden)
+ self.app.marker_frame.setHidden(Defaults.cfg.gui.markers_hidden)
self.showMarkerButton.setText()
self.showMarkerButton.repaint()
diff --git a/src/NanoVNASaver/Controls/SerialControl.py b/src/NanoVNASaver/Controls/SerialControl.py
index a861251..4113510 100644
--- a/src/NanoVNASaver/Controls/SerialControl.py
+++ b/src/NanoVNASaver/Controls/SerialControl.py
@@ -28,7 +28,6 @@ logger = logging.getLogger(__name__)
class SerialControl(Control):
-
def __init__(self, app: QtWidgets.QWidget):
super().__init__(app, "Serial port control")
@@ -58,7 +57,8 @@ class SerialControl(Control):
self.btn_settings.setMinimumHeight(20)
self.btn_settings.setFixedWidth(60)
self.btn_settings.clicked.connect(
- lambda: self.app.display_window("device_settings"))
+ lambda: self.app.display_window("device_settings")
+ )
button_layout.addWidget(self.btn_settings, stretch=0)
self.layout.addRow(button_layout)
@@ -82,8 +82,9 @@ class SerialControl(Control):
try:
self.interface.open()
except (IOError, AttributeError) as exc:
- logger.error("Tried to open %s and failed: %s",
- self.interface, exc)
+ logger.error(
+ "Tried to open %s and failed: %s", self.interface, exc
+ )
return
if not self.interface.isOpen():
logger.error("Unable to open port %s", self.interface)
@@ -96,7 +97,8 @@ class SerialControl(Control):
logger.error("Unable to connect to VNA: %s", exc)
self.app.vna.validateInput = self.app.settings.value(
- "SerialInputValidation", True, bool)
+ "SerialInputValidation", True, bool
+ )
# connected
self.btn_toggle.setText("Disconnect")
@@ -106,16 +108,20 @@ class SerialControl(Control):
if not frequencies:
logger.warning("No frequencies read")
return
- logger.info("Read starting frequency %s and end frequency %s",
- frequencies[0], frequencies[-1])
+ logger.info(
+ "Read starting frequency %s and end frequency %s",
+ frequencies[0],
+ frequencies[-1],
+ )
self.app.sweep_control.set_start(frequencies[0])
if frequencies[0] < frequencies[-1]:
self.app.sweep_control.set_end(frequencies[-1])
else:
self.app.sweep_control.set_end(
- frequencies[0] +
- self.app.vna.datapoints *
- self.app.sweep_control.get_segments())
+ frequencies[0]
+ + self.app.vna.datapoints
+ * self.app.sweep_control.get_segments()
+ )
self.app.sweep_control.set_segments(1) # speed up things
self.app.sweep_control.update_center_span()
diff --git a/src/NanoVNASaver/Controls/SweepControl.py b/src/NanoVNASaver/Controls/SweepControl.py
index 959e215..b32a969 100644
--- a/src/NanoVNASaver/Controls/SweepControl.py
+++ b/src/NanoVNASaver/Controls/SweepControl.py
@@ -21,8 +21,10 @@ import logging
from PyQt5 import QtWidgets, QtCore
from NanoVNASaver.Formatting import (
- format_frequency_sweep, format_frequency_short,
- parse_frequency)
+ format_frequency_sweep,
+ format_frequency_short,
+ parse_frequency,
+)
from NanoVNASaver.Inputs import FrequencyInputWidget
from NanoVNASaver.Controls.Control import Control
@@ -30,7 +32,6 @@ logger = logging.getLogger(__name__)
class SweepControl(Control):
-
def __init__(self, app: QtWidgets.QWidget):
super().__init__(app, "Sweep control")
@@ -66,8 +67,7 @@ class SweepControl(Control):
self.input_center.setAlignment(QtCore.Qt.AlignRight)
self.input_center.textEdited.connect(self.update_start_end)
- input_right_layout.addRow(QtWidgets.QLabel(
- "Center"), self.input_center)
+ input_right_layout.addRow(QtWidgets.QLabel("Center"), self.input_center)
self.input_span = FrequencyInputWidget()
self.input_span.setFixedHeight(20)
@@ -77,7 +77,8 @@ class SweepControl(Control):
input_right_layout.addRow(QtWidgets.QLabel("Span"), self.input_span)
self.input_segments = QtWidgets.QLineEdit(
- self.app.settings.value("Segments", "1"))
+ self.app.settings.value("Segments", "1")
+ )
self.input_segments.setAlignment(QtCore.Qt.AlignRight)
self.input_segments.setFixedHeight(20)
self.input_segments.setFixedWidth(60)
@@ -85,7 +86,8 @@ class SweepControl(Control):
self.label_step = QtWidgets.QLabel("Hz/step")
self.label_step.setAlignment(
- QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+ QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter
+ )
segment_layout = QtWidgets.QHBoxLayout()
segment_layout.addWidget(self.input_segments)
@@ -95,7 +97,8 @@ class SweepControl(Control):
btn_settings_window = QtWidgets.QPushButton("Sweep settings ...")
btn_settings_window.setFixedHeight(20)
btn_settings_window.clicked.connect(
- lambda: self.app.display_window("sweep_settings"))
+ lambda: self.app.display_window("sweep_settings")
+ )
self.layout.addRow(btn_settings_window)
@@ -206,8 +209,7 @@ class SweepControl(Control):
segments = self.get_segments()
if segments > 0:
fstep = fspan / (segments * self.app.vna.datapoints - 1)
- self.label_step.setText(
- f"{format_frequency_short(fstep)}/step")
+ self.label_step.setText(f"{format_frequency_short(fstep)}/step")
self.update_sweep()
def update_sweep(self):
diff --git a/src/NanoVNASaver/Defaults.py b/src/NanoVNASaver/Defaults.py
index 68d4901..38bcdd4 100644
--- a/src/NanoVNASaver/Defaults.py
+++ b/src/NanoVNASaver/Defaults.py
@@ -43,12 +43,12 @@ class GUI:
@DC.dataclass
class ChartsSelected:
- chart_00: str = 'S11 Smith Chart'
- chart_01: str = 'S11 Return Loss'
- chart_02: str = 'None'
- chart_10: str = 'S21 Polar Plot'
- chart_11: str = 'S21 Gain'
- chart_12: str = 'None'
+ chart_00: str = "S11 Smith Chart"
+ chart_01: str = "S11 Return Loss"
+ chart_02: str = "None"
+ chart_10: str = "S21 Polar Plot"
+ chart_11: str = "S21 Gain"
+ chart_12: str = "None"
@DC.dataclass
@@ -69,33 +69,49 @@ class Chart:
@DC.dataclass
class ChartColors: # pylint: disable=too-many-instance-attributes
background: QColor = DC.field(
- default_factory=lambda: QColor(QtCore.Qt.white))
+ default_factory=lambda: QColor(QtCore.Qt.white)
+ )
foreground: QColor = DC.field(
- default_factory=lambda: QColor(QtCore.Qt.lightGray))
+ default_factory=lambda: QColor(QtCore.Qt.lightGray)
+ )
reference: QColor = DC.field(default_factory=lambda: QColor(0, 0, 255, 64))
reference_secondary: QColor = DC.field(
- default_factory=lambda: QColor(0, 0, 192, 48))
+ default_factory=lambda: QColor(0, 0, 192, 48)
+ )
sweep: QColor = DC.field(
- default_factory=lambda: QColor(QtCore.Qt.darkYellow))
+ default_factory=lambda: QColor(QtCore.Qt.darkYellow)
+ )
sweep_secondary: QColor = DC.field(
- default_factory=lambda: QColor(QtCore.Qt.darkMagenta))
- swr: QColor = DC.field(
- default_factory=lambda: QColor(255, 0, 0, 128))
- text: QColor = DC.field(
- default_factory=lambda: QColor(QtCore.Qt.black))
- bands: QColor = DC.field(
- default_factory=lambda: QColor(128, 128, 128, 48))
+ default_factory=lambda: QColor(QtCore.Qt.darkMagenta)
+ )
+ swr: QColor = DC.field(default_factory=lambda: QColor(255, 0, 0, 128))
+ text: QColor = DC.field(default_factory=lambda: QColor(QtCore.Qt.black))
+ bands: QColor = DC.field(default_factory=lambda: QColor(128, 128, 128, 48))
@DC.dataclass
class Markers:
- active_labels: list = DC.field(default_factory=lambda: [
- "actualfreq", "impedance", "serr", "serl", "serc", "parr", "parlc",
- "vswr", "returnloss", "s11q", "s11phase", "s21gain", "s21phase",
- ])
+ active_labels: list = DC.field(
+ default_factory=lambda: [
+ "actualfreq",
+ "impedance",
+ "serr",
+ "serl",
+ "serc",
+ "parr",
+ "parlc",
+ "vswr",
+ "returnloss",
+ "s11q",
+ "s11phase",
+ "s21gain",
+ "s21phase",
+ ]
+ )
colored_names: bool = True
color_0: QColor = DC.field(
- default_factory=lambda: QColor(QtCore.Qt.darkGray))
+ default_factory=lambda: QColor(QtCore.Qt.darkGray)
+ )
color_1: QColor = DC.field(default_factory=lambda: QColor(255, 0, 0))
color_2: QColor = DC.field(default_factory=lambda: QColor(0, 255, 0))
color_3: QColor = DC.field(default_factory=lambda: QColor(0, 0, 255))
@@ -103,37 +119,34 @@ class Markers:
color_5: QColor = DC.field(default_factory=lambda: QColor(255, 0, 255))
color_6: QColor = DC.field(default_factory=lambda: QColor(255, 255, 0))
color_7: QColor = DC.field(
- default_factory=lambda: QColor(QtCore.Qt.lightGray))
+ default_factory=lambda: QColor(QtCore.Qt.lightGray)
+ )
@DC.dataclass
class CFG:
- gui: object = DC.field(
- default_factory=lambda: GUI())
- charts_selected: object = DC.field(
- default_factory=lambda: ChartsSelected())
- chart: object = DC.field(
- default_factory=lambda: Chart())
- chart_colors: object = DC.field(
- default_factory=lambda: ChartColors())
- markers: object = DC.field(
- default_factory=lambda: Markers())
+ gui: object = DC.field(default_factory=lambda: GUI())
+ charts_selected: object = DC.field(default_factory=lambda: ChartsSelected())
+ chart: object = DC.field(default_factory=lambda: Chart())
+ chart_colors: object = DC.field(default_factory=lambda: ChartColors())
+ markers: object = DC.field(default_factory=lambda: Markers())
cfg = CFG()
-def restore(settings: 'AppSettings') -> CFG:
+def restore(settings: "AppSettings") -> CFG:
result = CFG()
for field in DC.fields(result):
- value = settings.restore_dataclass(field.name.upper(),
- getattr(result, field.name))
+ value = settings.restore_dataclass(
+ field.name.upper(), getattr(result, field.name)
+ )
setattr(result, field.name, value)
logger.debug("restored\n(\n%s\n)", result)
return result
-def store(settings: 'AppSettings', data: CFG = None) -> None:
+def store(settings: "AppSettings", data: CFG = None) -> None:
data = data or cfg
logger.debug("storing\n(\n%s\n)", data)
assert isinstance(data, CFG)
@@ -147,25 +160,25 @@ 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(),
}
- return (f"{type_map[type(data)](data)}" if
- type(data) in type_map else
- f"{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:
type_map = {
- bool: lambda x: x.lower() == 'true',
+ bool: lambda x: x.lower() == "true",
bytearray: bytearray.fromhex,
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)),
}
- return (type_map[data_type](data) if
- data_type in type_map else
- data_type(data))
+ return (
+ type_map[data_type](data) if data_type in type_map else data_type(data)
+ )
# noinspection PyDataclass
@@ -178,8 +191,13 @@ class AppSettings(QSettings):
try:
assert isinstance(value, field.type)
except AssertionError as exc:
- logger.error("%s: %s of type %s is not a %s",
- name, field.name, type(value), field.type)
+ logger.error(
+ "%s: %s of type %s is not a %s",
+ name,
+ field.name,
+ type(value),
+ field.type,
+ )
raise TypeError from exc
self.setValue(field.name, from_type(value))
self.endGroup()
diff --git a/src/NanoVNASaver/Formatting.py b/src/NanoVNASaver/Formatting.py
index e429393..6a1093a 100644
--- a/src/NanoVNASaver/Formatting.py
+++ b/src/NanoVNASaver/Formatting.py
@@ -27,22 +27,27 @@ FMT_FREQ_SHORT = SITools.Format(max_nr_digits=4)
FMT_FREQ_SPACE = SITools.Format(space_str=" ")
FMT_FREQ_SWEEP = SITools.Format(max_nr_digits=9, allow_strip=True)
FMT_FREQ_INPUTS = SITools.Format(
- max_nr_digits=10, allow_strip=True,
- printable_min=0, unprintable_under="- ")
+ max_nr_digits=10, allow_strip=True, printable_min=0, unprintable_under="- "
+)
FMT_Q_FACTOR = SITools.Format(
- max_nr_digits=4, assume_infinity=False,
- min_offset=0, max_offset=0, allow_strip=True)
+ max_nr_digits=4,
+ assume_infinity=False,
+ min_offset=0,
+ max_offset=0,
+ allow_strip=True,
+)
FMT_GROUP_DELAY = SITools.Format(max_nr_digits=5, space_str=" ")
FMT_REACT = SITools.Format(max_nr_digits=5, space_str=" ", allow_strip=True)
-FMT_COMPLEX = SITools.Format(max_nr_digits=3, allow_strip=True,
- printable_min=0, unprintable_under="- ")
+FMT_COMPLEX = SITools.Format(
+ max_nr_digits=3, allow_strip=True, printable_min=0, unprintable_under="- "
+)
FMT_COMPLEX_NEG = SITools.Format(max_nr_digits=3, allow_strip=True)
FMT_SHORT = SITools.Format(max_nr_digits=4)
FMT_WAVELENGTH = SITools.Format(max_nr_digits=4, space_str=" ")
-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_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)
@@ -117,7 +122,7 @@ def format_group_delay(val: float) -> str:
def format_phase(val: float) -> str:
- return f"{math.degrees(val):.2f}""\N{DEGREE SIGN}"
+ return f"{math.degrees(val):.2f}" "\N{DEGREE SIGN}"
def format_complex_adm(z: complex, allow_negative: bool = False) -> str:
@@ -135,7 +140,7 @@ def format_complex_imp(z: complex, allow_negative: bool = False) -> str:
fmt_re = FMT_COMPLEX_NEG if allow_negative else FMT_COMPLEX
re = SITools.Value(z.real, fmt=fmt_re)
im = SITools.Value(abs(z.imag), fmt=FMT_COMPLEX)
- return f"{re}{'-' if z.imag < 0 else '+'}j{im} ""\N{OHM SIGN}"
+ return f"{re}{'-' if z.imag < 0 else '+'}j{im} " "\N{OHM SIGN}"
def format_wavelength(length: Number) -> str:
@@ -153,10 +158,11 @@ def parse_frequency(freq: str) -> int:
return -1
-def parse_value(val: str, unit: str = "",
- fmt: SITools.Format = FMT_PARSE_VALUE) -> float:
+def parse_value(
+ val: str, unit: str = "", fmt: SITools.Format = FMT_PARSE_VALUE
+) -> float:
try:
- val.replace(',', '.')
+ val.replace(",", ".")
return float(SITools.Value(val, unit, fmt))
except (ValueError, IndexError):
return 0.0
diff --git a/src/NanoVNASaver/Hardware/Hardware.py b/src/NanoVNASaver/Hardware/Hardware.py
index 32f31f1..ed751f9 100644
--- a/src/NanoVNASaver/Hardware/Hardware.py
+++ b/src/NanoVNASaver/Hardware/Hardware.py
@@ -43,8 +43,8 @@ USBDevice = namedtuple("Device", "vid pid name")
USBDEVICETYPES = (
USBDevice(0x0483, 0x5740, "NanoVNA"),
- USBDevice(0x16c0, 0x0483, "AVNA"),
- USBDevice(0x04b4, 0x0008, "S-A-A-2"),
+ USBDevice(0x16C0, 0x0483, "AVNA"),
+ USBDevice(0x04B4, 0x0008, "S-A-A-2"),
)
RETRIES = 3
TIMEOUT = 0.2
@@ -71,15 +71,21 @@ NAME2DEVICE = {
def _fix_v2_hwinfo(dev):
# if dev.hwid == r'PORTS\VID_04B4&PID_0008\DEMO':
- if r'PORTS\VID_04B4&PID_0008' in dev.hwid:
- dev.vid, dev.pid = 0x04b4, 0x0008
+ if r"PORTS\VID_04B4&PID_0008" in dev.hwid:
+ dev.vid, dev.pid = 0x04B4, 0x0008
return dev
def usb_typename(device: ListPortInfo) -> str:
- return next((t.name for t in USBDEVICETYPES if
- device.vid == t.vid and device.pid == t.pid),
- "")
+ return next(
+ (
+ t.name
+ for t in USBDEVICETYPES
+ if device.vid == t.vid and device.pid == t.pid
+ ),
+ "",
+ )
+
# Get list of interfaces with VNAs connected
@@ -88,13 +94,18 @@ def get_interfaces() -> List[Interface]:
interfaces = []
# serial like usb interfaces
for d in list_ports.comports():
- if platform.system() == 'Windows' and d.vid is None:
+ if platform.system() == "Windows" and d.vid is None:
d = _fix_v2_hwinfo(d)
if not (typename := usb_typename(d)):
continue
- logger.debug("Found %s USB:(%04x:%04x) on port %s",
- typename, d.vid, d.pid, d.device)
- iface = Interface('serial', typename)
+ logger.debug(
+ "Found %s USB:(%04x:%04x) on port %s",
+ typename,
+ d.vid,
+ d.pid,
+ d.device,
+ )
+ iface = Interface("serial", typename)
iface.port = d.device
iface.open()
iface.comment = get_comment(iface)
@@ -109,9 +120,8 @@ def get_portinfos() -> List[str]:
portinfos = []
# serial like usb interfaces
for d in list_ports.comports():
- logger.debug("Found USB:(%04x:%04x) on port %s",
- d.vid, d.pid, d.device)
- iface = Interface('serial', "DEBUG")
+ logger.debug("Found USB:(%04x:%04x) on port %s", d.vid, d.pid, d.device)
+ iface = Interface("serial", "DEBUG")
iface.port = d.device
iface.open()
version = detect_version(iface)
@@ -130,19 +140,19 @@ def get_comment(iface: Interface) -> str:
with iface.lock:
vna_version = detect_version(iface)
- if vna_version == 'v2':
+ if vna_version == "v2":
return "S-A-A-2"
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
@@ -171,7 +181,7 @@ def detect_version(serial_port: serial.Serial) -> str:
if data.startswith("2"):
return "v2"
logger.debug("Retry detection: %s", i + 1)
- logger.error('No VNA detected. Hardware responded to CR with: %s', data)
+ logger.error("No VNA detected. Hardware responded to CR with: %s", data)
return ""
diff --git a/src/NanoVNASaver/Hardware/NanoVNA.py b/src/NanoVNASaver/Hardware/NanoVNA.py
index e572045..15eae04 100644
--- a/src/NanoVNASaver/Hardware/NanoVNA.py
+++ b/src/NanoVNASaver/Hardware/NanoVNA.py
@@ -46,7 +46,6 @@ class NanoVNA(VNA):
self._sweepdata = []
def _get_running_frequencies(self):
-
logger.debug("Reading values: frequencies")
try:
frequencies = super().readValues("frequencies")
@@ -61,24 +60,27 @@ class NanoVNA(VNA):
timeout = self.serial.timeout
with self.serial.lock:
drain_serial(self.serial)
- self.serial.write("capture\r".encode('ascii'))
+ self.serial.write("capture\r".encode("ascii"))
self.serial.readline()
self.serial.timeout = 4
image_data = self.serial.read(
- self.screenwidth * self.screenheight * 2)
+ self.screenwidth * self.screenheight * 2
+ )
self.serial.timeout = timeout
self.serial.timeout = timeout
return image_data
def _convert_data(self, image_data: bytes) -> bytes:
rgb_data = struct.unpack(
- f">{self.screenwidth * self.screenheight}H",
- image_data)
+ f">{self.screenwidth * self.screenheight}H", image_data
+ )
rgb_array = np.array(rgb_data, dtype=np.uint32)
- return (0xFF000000 +
- ((rgb_array & 0xF800) << 8) +
- ((rgb_array & 0x07E0) << 5) +
- ((rgb_array & 0x001F) << 3))
+ return (
+ 0xFF000000
+ + ((rgb_array & 0xF800) << 8)
+ + ((rgb_array & 0x07E0) << 5)
+ + ((rgb_array & 0x001F) << 3)
+ )
def getScreenshot(self) -> QtGui.QPixmap:
logger.debug("Capturing screenshot...")
@@ -90,12 +92,12 @@ class NanoVNA(VNA):
rgba_array,
self.screenwidth,
self.screenheight,
- QtGui.QImage.Format_ARGB32)
+ QtGui.QImage.Format_ARGB32,
+ )
logger.debug("Captured screenshot")
return QtGui.QPixmap(image)
except serial.SerialException as exc:
- logger.exception(
- "Exception while capturing screenshot: %s", exc)
+ logger.exception("Exception while capturing screenshot: %s", exc)
return QtGui.QPixmap()
def resetSweep(self, start: int, stop: int):
@@ -125,8 +127,12 @@ class NanoVNA(VNA):
logger.debug("readFrequencies: %s", self.sweep_method)
if self.sweep_method != "scan_mask":
return super().readFrequencies()
- return [int(line) for line in self.exec_command(
- f"scan {self.start} {self.stop} {self.datapoints} 0b001")]
+ return [
+ int(line)
+ for line in self.exec_command(
+ f"scan {self.start} {self.stop} {self.datapoints} 0b001"
+ )
+ ]
def readValues(self, value) -> List[str]:
if self.sweep_method != "scan_mask":
@@ -137,11 +143,12 @@ class NanoVNA(VNA):
if value == "data 0":
self._sweepdata = []
for line in self.exec_command(
- f"scan {self.start} {self.stop} {self.datapoints} 0b110"):
+ f"scan {self.start} {self.stop} {self.datapoints} 0b110"
+ ):
data = line.split()
- self._sweepdata.append((
- f"{data[0]} {data[1]}",
- f"{data[2]} {data[3]}"))
+ self._sweepdata.append(
+ (f"{data[0]} {data[1]}", f"{data[2]} {data[3]}")
+ )
if value == "data 0":
return [x[0] for x in self._sweepdata]
if value == "data 1":
diff --git a/src/NanoVNASaver/Hardware/NanoVNA_F_V2.py b/src/NanoVNASaver/Hardware/NanoVNA_F_V2.py
index b23d44f..4d4b9fa 100644
--- a/src/NanoVNASaver/Hardware/NanoVNA_F_V2.py
+++ b/src/NanoVNASaver/Hardware/NanoVNA_F_V2.py
@@ -46,10 +46,10 @@ class NanoVNA_F_V2(NanoVNA):
rgba_array,
self.screenwidth,
self.screenheight,
- QtGui.QImage.Format_RGB16)
+ QtGui.QImage.Format_RGB16,
+ )
logger.debug("Captured screenshot")
return QtGui.QPixmap(image)
except serial.SerialException as exc:
- logger.exception(
- "Exception while capturing screenshot: %s", exc)
+ logger.exception("Exception while capturing screenshot: %s", exc)
return QtGui.QPixmap()
diff --git a/src/NanoVNASaver/Hardware/NanoVNA_V2.py b/src/NanoVNASaver/Hardware/NanoVNA_V2.py
index f60e1e0..d49364b 100644
--- a/src/NanoVNASaver/Hardware/NanoVNA_V2.py
+++ b/src/NanoVNASaver/Hardware/NanoVNA_V2.py
@@ -26,13 +26,13 @@ from NanoVNASaver.Hardware.Serial import Interface
from NanoVNASaver.Hardware.VNA import VNA
from NanoVNASaver.Version import Version
-if platform.system() != 'Windows':
+if platform.system() != "Windows":
import tty
logger = logging.getLogger(__name__)
_CMD_NOP = 0x00
-_CMD_INDICATE = 0x0d
+_CMD_INDICATE = 0x0D
_CMD_READ = 0x10
_CMD_READ2 = 0x11
_CMD_READ4 = 0x12
@@ -49,22 +49,23 @@ _ADDR_SWEEP_POINTS = 0x20
_ADDR_SWEEP_VALS_PER_FREQ = 0x22
_ADDR_RAW_SAMPLES_MODE = 0x26
_ADDR_VALUES_FIFO = 0x30
-_ADDR_DEVICE_VARIANT = 0xf0
-_ADDR_PROTOCOL_VERSION = 0xf1
-_ADDR_HARDWARE_REVISION = 0xf2
-_ADDR_FW_MAJOR = 0xf3
-_ADDR_FW_MINOR = 0xf4
+_ADDR_DEVICE_VARIANT = 0xF0
+_ADDR_PROTOCOL_VERSION = 0xF1
+_ADDR_HARDWARE_REVISION = 0xF2
+_ADDR_FW_MAJOR = 0xF3
+_ADDR_FW_MINOR = 0xF4
WRITE_SLEEP = 0.05
_ADF4350_TXPOWER_DESC_MAP = {
- 0: '9dB attenuation',
- 1: '6dB attenuation',
- 2: '3dB attenuation',
- 3: 'Maximum',
+ 0: "9dB attenuation",
+ 1: "6dB attenuation",
+ 2: "3dB attenuation",
+ 3: "Maximum",
}
_ADF4350_TXPOWER_DESC_REV_MAP = {
- value: key for key, value in _ADF4350_TXPOWER_DESC_MAP.items()}
+ value: key for key, value in _ADF4350_TXPOWER_DESC_MAP.items()
+}
class NanoVNA_V2(VNA):
@@ -76,7 +77,7 @@ class NanoVNA_V2(VNA):
def __init__(self, iface: Interface):
super().__init__(iface)
- if platform.system() != 'Windows':
+ if platform.system() != "Windows":
tty.setraw(self.serial.fd)
# reset protocol to known state
@@ -85,8 +86,8 @@ class NanoVNA_V2(VNA):
sleep(WRITE_SLEEP)
# firmware major version of 0xff indicates dfu mode
- if self.version.data["major"] == 0xff:
- raise IOError('Device is in DFU mode')
+ if self.version.data["major"] == 0xFF:
+ raise IOError("Device is in DFU mode")
if "S21 hack" in self.features:
self.valid_datapoints = (101, 11, 51, 201, 301, 501, 1021)
@@ -116,8 +117,13 @@ class NanoVNA_V2(VNA):
self.features.update({"Set TX power partial", "Set Average"})
# Can only set ADF4350 power, i.e. for >= 140MHz
self.txPowerRanges = [
- ((140e6, self.sweep_max_freq_Hz),
- [_ADF4350_TXPOWER_DESC_MAP[value] for value in (3, 2, 1, 0)]),
+ (
+ (140e6, self.sweep_max_freq_Hz),
+ [
+ _ADF4350_TXPOWER_DESC_MAP[value]
+ for value in (3, 2, 1, 0)
+ ],
+ ),
]
def readFirmware(self) -> str:
@@ -135,9 +141,15 @@ class NanoVNA_V2(VNA):
freq_index = -1
for i in range(pointstoread):
- (fwd_real, fwd_imag, rev0_real, rev0_imag, rev1_real,
- rev1_imag, freq_index) = unpack_from(
- " 'Version':
- result = self._read_version(_ADDR_FW_MAJOR,
- _ADDR_FW_MINOR)
+ def readVersion(self) -> "Version":
+ result = self._read_version(_ADDR_FW_MAJOR, _ADDR_FW_MINOR)
logger.debug("readVersion: %s", result)
return result
- def read_board_revision(self) -> 'Version':
- result = self._read_version(_ADDR_DEVICE_VARIANT,
- _ADDR_HARDWARE_REVISION)
+ def read_board_revision(self) -> "Version":
+ result = self._read_version(
+ _ADDR_DEVICE_VARIANT, _ADDR_HARDWARE_REVISION
+ )
logger.debug("read_board_revision: %s", result)
return result
@@ -243,34 +261,41 @@ class NanoVNA_V2(VNA):
return
self.sweepStartHz = start
self.sweepStepHz = step
- logger.info('NanoVNAV2: set sweep start %d step %d',
- self.sweepStartHz, self.sweepStepHz)
+ logger.info(
+ "NanoVNAV2: set sweep start %d step %d",
+ self.sweepStartHz,
+ self.sweepStepHz,
+ )
self._updateSweep()
return
def _updateSweep(self):
s21hack = "S21 hack" in self.features
- cmd = pack(" ADF4350
self._set_register(0x42, _ADF4350_TXPOWER_DESC_REV_MAP[power_desc], 1)
def _set_register(self, addr, value, size):
- packet = b''
+ packet = b""
if size == 1:
packet = pack(" bytes:
rgb_data = struct.unpack(
- f">{self.screenwidth * self.screenheight}H",
- image_data)
+ f">{self.screenwidth * self.screenheight}H", image_data
+ )
rgb_array = np.array(rgb_data, dtype=np.uint32)
- return (0xFF000000 +
- ((rgb_array & 0xF800) << 8) +
- ((rgb_array & 0x07E0) << 5) +
- ((rgb_array & 0x001F) << 3))
+ return (
+ 0xFF000000
+ + ((rgb_array & 0xF800) << 8)
+ + ((rgb_array & 0x07E0) << 5)
+ + ((rgb_array & 0x001F) << 3)
+ )
def getScreenshot(self) -> QtGui.QPixmap:
logger.debug("Capturing screenshot...")
@@ -89,12 +91,12 @@ class TinySA(VNA):
rgba_array,
self.screenwidth,
self.screenheight,
- QtGui.QImage.Format_ARGB32)
+ QtGui.QImage.Format_ARGB32,
+ )
logger.debug("Captured screenshot")
return QtGui.QPixmap(image)
except serial.SerialException as exc:
- logger.exception(
- "Exception while capturing screenshot: %s", exc)
+ logger.exception("Exception while capturing screenshot: %s", exc)
return QtGui.QPixmap()
def resetSweep(self, start: int, stop: int):
@@ -113,6 +115,7 @@ class TinySA(VNA):
def readValues(self, value) -> List[str]:
logger.debug("Read: %s", value)
if value == "data 0":
- self._sweepdata = [f"0 {line.strip()}"
- for line in self.exec_command("data")]
+ self._sweepdata = [
+ f"0 {line.strip()}" for line in self.exec_command("data")
+ ]
return self._sweepdata
diff --git a/src/NanoVNASaver/Hardware/VNA.py b/src/NanoVNASaver/Hardware/VNA.py
index edf04fa..6434394 100644
--- a/src/NanoVNASaver/Hardware/VNA.py
+++ b/src/NanoVNASaver/Hardware/VNA.py
@@ -44,8 +44,11 @@ WAIT = 0.05
def _max_retries(bandwidth: int, datapoints: int) -> int:
- return round(20 + 20 * (datapoints / 101) +
- (1000 / bandwidth) ** 1.30 * (datapoints / 101))
+ return round(
+ 20
+ + 20 * (datapoints / 101)
+ + (1000 / bandwidth) ** 1.30 * (datapoints / 101)
+ )
class VNA:
@@ -94,7 +97,7 @@ class VNA:
logger.debug("exec_command(%s)", command)
with self.serial.lock:
drain_serial(self.serial)
- self.serial.write(f"{command}\r".encode('ascii'))
+ self.serial.write(f"{command}\r".encode("ascii"))
sleep(wait)
retries = 0
max_retries = _max_retries(self.bandwidth, self.datapoints)
@@ -137,11 +140,14 @@ class VNA:
result = result.split(" {")[1].strip("}")
return sorted([int(i) for i in result.split("|")])
except IndexError:
- return [1000, ]
+ return [
+ 1000,
+ ]
def set_bandwidth(self, bandwidth: int):
- bw_val = DISLORD_BW[bandwidth] \
- if self.bw_method == "dislord" else bandwidth
+ bw_val = (
+ DISLORD_BW[bandwidth] if self.bw_method == "dislord" else bandwidth
+ )
result = " ".join(self.exec_command(f"bandwidth {bw_val}"))
if self.bw_method == "ttrftech" and result:
raise IOError(f"set_bandwith({bandwidth}: {result}")
@@ -191,11 +197,10 @@ class VNA:
def readValues(self, value) -> List[str]:
logger.debug("VNA reading %s", value)
result = list(self.exec_command(value))
- logger.debug("VNA done reading %s (%d values)",
- value, len(result))
+ logger.debug("VNA done reading %s (%d values)", value, len(result))
return result
- def readVersion(self) -> 'Version':
+ def readVersion(self) -> "Version":
result = list(self.exec_command("version"))
logger.debug("result:\n%s", result)
return Version(result[0])
diff --git a/src/NanoVNASaver/Marker/Delta.py b/src/NanoVNASaver/Marker/Delta.py
index ba76093..7c2de90 100644
--- a/src/NanoVNASaver/Marker/Delta.py
+++ b/src/NanoVNASaver/Marker/Delta.py
@@ -61,71 +61,91 @@ class DeltaMarker(Marker):
imp = imp_b - imp_a
cap_str = format_capacitance(
- RFTools.impedance_to_capacitance(imp_b, s11_b.freq) -
- RFTools.impedance_to_capacitance(imp_a, s11_a.freq))
+ RFTools.impedance_to_capacitance(imp_b, s11_b.freq)
+ - RFTools.impedance_to_capacitance(imp_a, s11_a.freq)
+ )
ind_str = format_inductance(
- RFTools.impedance_to_inductance(imp_b, s11_b.freq) -
- RFTools.impedance_to_inductance(imp_a, s11_a.freq))
+ RFTools.impedance_to_inductance(imp_b, s11_b.freq)
+ - RFTools.impedance_to_inductance(imp_a, s11_a.freq)
+ )
imp_p_a = RFTools.serial_to_parallel(imp_a)
imp_p_b = RFTools.serial_to_parallel(imp_b)
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_a, s11_a.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_a, s11_a.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
x_p_str = cap_p_str if imp_p.imag < 0 else ind_p_str
- self.label['actualfreq'].setText(
- format_frequency_space(s11_b.freq - s11_a.freq))
- self.label['lambda'].setText(
- format_wavelength(s11_b.wavelength - s11_a.wavelength))
- self.label['admittance'].setText(format_complex_adm(imp_p, True))
- self.label['impedance'].setText(format_complex_imp(imp, True))
+ self.label["actualfreq"].setText(
+ format_frequency_space(s11_b.freq - s11_a.freq)
+ )
+ self.label["lambda"].setText(
+ format_wavelength(s11_b.wavelength - s11_a.wavelength)
+ )
+ self.label["admittance"].setText(format_complex_adm(imp_p, True))
+ self.label["impedance"].setText(format_complex_imp(imp, True))
- self.label['parc'].setText(cap_p_str)
- self.label['parl'].setText(ind_p_str)
- self.label['parlc'].setText(x_p_str)
+ self.label["parc"].setText(cap_p_str)
+ self.label["parl"].setText(ind_p_str)
+ self.label["parlc"].setText(x_p_str)
- self.label['parr'].setText(format_resistance(imp_p.real, True))
- self.label['returnloss'].setText(
- format_gain(s11_b.gain - s11_a.gain, self.returnloss_is_positive))
- self.label['s11groupdelay'].setText(format_group_delay(
- RFTools.groupDelay(b.s11, 1) -
- RFTools.groupDelay(a.s11, 1)))
+ self.label["parr"].setText(format_resistance(imp_p.real, True))
+ self.label["returnloss"].setText(
+ format_gain(s11_b.gain - s11_a.gain, self.returnloss_is_positive)
+ )
+ self.label["s11groupdelay"].setText(
+ format_group_delay(
+ RFTools.groupDelay(b.s11, 1) - RFTools.groupDelay(a.s11, 1)
+ )
+ )
- self.label['s11mag'].setText(
- format_magnitude(abs(s11_b.z) - abs(s11_a.z)))
- self.label['s11phase'].setText(format_phase(s11_b.phase - s11_a.phase))
- self.label['s11polar'].setText(
+ self.label["s11mag"].setText(
+ format_magnitude(abs(s11_b.z) - abs(s11_a.z))
+ )
+ self.label["s11phase"].setText(format_phase(s11_b.phase - s11_a.phase))
+ self.label["s11polar"].setText(
f"{round(abs(s11_b.z) - abs(s11_a.z), 2)}∠"
- f"{format_phase(s11_b.phase - s11_a.phase)}")
- self.label['s11q'].setText(format_q_factor(
- s11_b.qFactor() - s11_a.qFactor(), True))
- self.label['s11z'].setText(format_resistance(abs(imp)))
- self.label['serc'].setText(cap_str)
- self.label['serl'].setText(ind_str)
- self.label['serlc'].setText(x_str)
- self.label['serr'].setText(format_resistance(imp.real, True))
- self.label['vswr'].setText(format_vswr(s11_b.vswr - s11_a.vswr))
+ f"{format_phase(s11_b.phase - s11_a.phase)}"
+ )
+ self.label["s11q"].setText(
+ format_q_factor(s11_b.qFactor() - s11_a.qFactor(), True)
+ )
+ self.label["s11z"].setText(format_resistance(abs(imp)))
+ self.label["serc"].setText(cap_str)
+ self.label["serl"].setText(ind_str)
+ self.label["serlc"].setText(x_str)
+ self.label["serr"].setText(format_resistance(imp.real, True))
+ self.label["vswr"].setText(format_vswr(s11_b.vswr - s11_a.vswr))
if len(a.s21) == len(a.s11):
s21_a = a.s21[1]
s21_b = b.s21[1]
- self.label['s21gain'].setText(format_gain(
- s21_b.gain - s21_a.gain))
- self.label['s21groupdelay'].setText(format_group_delay(
- (RFTools.groupDelay(b.s21, 1) -
- RFTools.groupDelay(a.s21, 1)) / 2))
- self.label['s21mag'].setText(format_magnitude(
- abs(s21_b.z) - abs(s21_a.z)))
- self.label['s21phase'].setText(format_phase(
- s21_b.phase - s21_a.phase))
- self.label['s21polar'].setText(
+ self.label["s21gain"].setText(format_gain(s21_b.gain - s21_a.gain))
+ self.label["s21groupdelay"].setText(
+ format_group_delay(
+ (
+ RFTools.groupDelay(b.s21, 1)
+ - RFTools.groupDelay(a.s21, 1)
+ )
+ / 2
+ )
+ )
+ self.label["s21mag"].setText(
+ format_magnitude(abs(s21_b.z) - abs(s21_a.z))
+ )
+ 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"{format_phase(s21_b.phase - s21_a.phase)}")
+ f"{format_phase(s21_b.phase - s21_a.phase)}"
+ )
diff --git a/src/NanoVNASaver/Marker/Values.py b/src/NanoVNASaver/Marker/Values.py
index 44d4a6e..97b0a81 100644
--- a/src/NanoVNASaver/Marker/Values.py
+++ b/src/NanoVNASaver/Marker/Values.py
@@ -56,10 +56,10 @@ 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
+ ),
)
@@ -67,31 +67,40 @@ def default_label_ids() -> str:
return [label.label_id for label in TYPES if label.default_active]
-class Value():
+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):
+ def __init__(
+ self,
+ freq: int = 0,
+ s11: List[Datapoint] = None,
+ s21: List[Datapoint] = None,
+ ):
self.freq = freq
self.s11 = [] if s11 is None else s11[:]
self.s21 = [] if s21 is None else s21[:]
- def store(self, index: int,
- s11: List[Datapoint],
- s21: List[Datapoint]):
+ def store(self, index: int, s11: List[Datapoint], s21: List[Datapoint]):
# handle boundaries
if index == 0:
index = 1
- s11 = [s11[0], ] + s11
+ s11 = [
+ s11[0],
+ ] + s11
if s21:
- s21 = [s21[0], ] + s21
+ s21 = [
+ s21[0],
+ ] + s21
if index == len(s11):
- s11 += [s11[-1], ]
+ s11 += [
+ s11[-1],
+ ]
if s21:
- s21 += [s21[-1], ]
+ 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]
diff --git a/src/NanoVNASaver/Marker/Widget.py b/src/NanoVNASaver/Marker/Widget.py
index 4411609..634c816 100644
--- a/src/NanoVNASaver/Marker/Widget.py
+++ b/src/NanoVNASaver/Marker/Widget.py
@@ -81,7 +81,8 @@ class Marker(QtCore.QObject, Value):
if self.qsettings:
Marker._instances += 1
Marker.active_labels = self.qsettings.value(
- "MarkerFields", defaultValue=default_label_ids())
+ "MarkerFields", defaultValue=default_label_ids()
+ )
self.index = Marker._instances
if not self.name:
@@ -92,7 +93,9 @@ class Marker(QtCore.QObject, Value):
self.frequencyInput.setAlignment(QtCore.Qt.AlignRight)
self.frequencyInput.editingFinished.connect(
lambda: self.setFrequency(
- parse_frequency(self.frequencyInput.text())))
+ parse_frequency(self.frequencyInput.text())
+ )
+ )
###############################################################
# Data display labels
@@ -101,8 +104,8 @@ class Marker(QtCore.QObject, Value):
self.label = {
label.label_id: MarkerLabel(label.name) for label in TYPES
}
- self.label['actualfreq'].setMinimumWidth(100)
- self.label['returnloss'].setMinimumWidth(80)
+ self.label["actualfreq"].setMinimumWidth(100)
+ self.label["returnloss"].setMinimumWidth(80)
###############################################################
# Marker control layout
@@ -112,8 +115,11 @@ class Marker(QtCore.QObject, Value):
self.btnColorPicker.setMinimumHeight(20)
self.btnColorPicker.setFixedWidth(20)
self.btnColorPicker.clicked.connect(
- lambda: self.setColor(QtWidgets.QColorDialog.getColor(
- self.color, options=QtWidgets.QColorDialog.ShowAlphaChannel))
+ lambda: self.setColor(
+ QtWidgets.QColorDialog.getColor(
+ self.color, options=QtWidgets.QColorDialog.ShowAlphaChannel
+ )
+ )
)
self.isMouseControlledRadioButton = QtWidgets.QRadioButton()
@@ -133,7 +139,9 @@ class Marker(QtCore.QObject, Value):
try:
self.setColor(
self.qsettings.value(
- f"Marker{self.count()}Color", COLORS[self.count()]))
+ f"Marker{self.count()}Color", COLORS[self.count()]
+ )
+ )
except AttributeError: # happens when qsettings == None
self.setColor(COLORS[1])
except IndexError:
@@ -159,8 +167,7 @@ class Marker(QtCore.QObject, Value):
def _add_active_labels(self, label_id, form):
if label_id in self.label:
- form.addRow(
- f"{self.label[label_id].name}:", self.label[label_id])
+ form.addRow(f"{self.label[label_id].name}:", self.label[label_id])
self.label[label_id].show()
def _size_str(self) -> str:
@@ -171,9 +178,9 @@ class Marker(QtCore.QObject, Value):
def setScale(self, scale):
self.group_box.setMaximumWidth(int(340 * scale))
- self.label['actualfreq'].setMinimumWidth(int(100 * scale))
- self.label['actualfreq'].setMinimumWidth(int(100 * scale))
- self.label['returnloss'].setMinimumWidth(int(80 * scale))
+ self.label["actualfreq"].setMinimumWidth(int(100 * scale))
+ self.label["actualfreq"].setMinimumWidth(int(100 * scale))
+ self.label["returnloss"].setMinimumWidth(int(80 * scale))
if self.coloredText:
color_string = QtCore.QVariant(self.color)
color_string.convert(QtCore.QVariant.String)
@@ -259,8 +266,10 @@ 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
@@ -286,15 +295,16 @@ class Marker(QtCore.QObject, Value):
for v in self.label.values():
v.setText("")
- def updateLabels(self,
- s11: List[RFTools.Datapoint],
- s21: List[RFTools.Datapoint]):
+ def updateLabels(
+ self, s11: List[RFTools.Datapoint], s21: List[RFTools.Datapoint]
+ ):
if not s11:
return
if self.location == -1: # initial position
try:
location = (self.index - 1) / (
- (self._instances - 1) * (len(s11) - 1))
+ (self._instances - 1) * (len(s11) - 1)
+ )
self.location = int(location)
except ZeroDivisionError:
self.location = 0
@@ -309,63 +319,72 @@ class Marker(QtCore.QObject, Value):
imp = _s11.impedance()
cap_str = format_capacitance(
- RFTools.impedance_to_capacitance(imp, _s11.freq))
+ RFTools.impedance_to_capacitance(imp, _s11.freq)
+ )
ind_str = format_inductance(
- RFTools.impedance_to_inductance(imp, _s11.freq))
+ RFTools.impedance_to_inductance(imp, _s11.freq)
+ )
imp_p = RFTools.serial_to_parallel(imp)
cap_p_str = format_capacitance(
- RFTools.impedance_to_capacitance(imp_p, _s11.freq))
+ RFTools.impedance_to_capacitance(imp_p, _s11.freq)
+ )
ind_p_str = format_inductance(
- RFTools.impedance_to_inductance(imp_p, _s11.freq))
+ RFTools.impedance_to_inductance(imp_p, _s11.freq)
+ )
x_str = cap_str if imp.imag < 0 else ind_str
x_p_str = cap_p_str if imp_p.imag < 0 else ind_p_str
- self.label['actualfreq'].setText(format_frequency_space(_s11.freq))
- self.label['lambda'].setText(format_wavelength(_s11.wavelength))
- self.label['admittance'].setText(format_complex_adm(imp))
- self.label['impedance'].setText(format_complex_imp(imp))
- self.label['parc'].setText(cap_p_str)
- self.label['parl'].setText(ind_p_str)
- self.label['parlc'].setText(x_p_str)
- self.label['parr'].setText(format_resistance(imp_p.real))
- self.label['returnloss'].setText(
- format_gain(_s11.gain, self.returnloss_is_positive))
- self.label['s11groupdelay'].setText(
- format_group_delay(RFTools.groupDelay(s11, self.location)))
- self.label['s11mag'].setText(format_magnitude(abs(_s11.z)))
- self.label['s11phase'].setText(format_phase(_s11.phase))
- self.label['s11polar'].setText(
- f'{str(round(abs(_s11.z), 2))}∠{format_phase(_s11.phase)}'
+ self.label["actualfreq"].setText(format_frequency_space(_s11.freq))
+ self.label["lambda"].setText(format_wavelength(_s11.wavelength))
+ self.label["admittance"].setText(format_complex_adm(imp))
+ self.label["impedance"].setText(format_complex_imp(imp))
+ self.label["parc"].setText(cap_p_str)
+ self.label["parl"].setText(ind_p_str)
+ self.label["parlc"].setText(x_p_str)
+ self.label["parr"].setText(format_resistance(imp_p.real))
+ self.label["returnloss"].setText(
+ format_gain(_s11.gain, self.returnloss_is_positive)
+ )
+ self.label["s11groupdelay"].setText(
+ format_group_delay(RFTools.groupDelay(s11, self.location))
+ )
+ self.label["s11mag"].setText(format_magnitude(abs(_s11.z)))
+ self.label["s11phase"].setText(format_phase(_s11.phase))
+ self.label["s11polar"].setText(
+ f"{str(round(abs(_s11.z), 2))}∠{format_phase(_s11.phase)}"
)
- self.label['s11q'].setText(format_q_factor(_s11.qFactor()))
- self.label['s11z'].setText(format_resistance(abs(imp)))
- self.label['serc'].setText(cap_str)
- self.label['serl'].setText(ind_str)
- self.label['serlc'].setText(x_str)
- self.label['serr'].setText(format_resistance(imp.real))
- self.label['vswr'].setText(format_vswr(_s11.vswr))
+ self.label["s11q"].setText(format_q_factor(_s11.qFactor()))
+ self.label["s11z"].setText(format_resistance(abs(imp)))
+ self.label["serc"].setText(cap_str)
+ self.label["serl"].setText(ind_str)
+ self.label["serlc"].setText(x_str)
+ self.label["serr"].setText(format_resistance(imp.real))
+ self.label["vswr"].setText(format_vswr(_s11.vswr))
if len(s21) == len(s11):
_s21 = s21[self.location]
- self.label['s21gain'].setText(format_gain(_s21.gain))
- self.label['s21groupdelay'].setText(
- format_group_delay(RFTools.groupDelay(s21, self.location) / 2))
- self.label['s21mag'].setText(format_magnitude(abs(_s21.z)))
- self.label['s21phase'].setText(format_phase(_s21.phase))
- self.label['s21polar'].setText(
- f'{str(round(abs(_s21.z), 2))}∠{format_phase(_s21.phase)}'
+ self.label["s21gain"].setText(format_gain(_s21.gain))
+ self.label["s21groupdelay"].setText(
+ format_group_delay(RFTools.groupDelay(s21, self.location) / 2)
+ )
+ self.label["s21mag"].setText(format_magnitude(abs(_s21.z)))
+ self.label["s21phase"].setText(format_phase(_s21.phase))
+ self.label["s21polar"].setText(
+ f"{str(round(abs(_s21.z), 2))}∠{format_phase(_s21.phase)}"
)
- self.label['s21magshunt'].setText(
- format_magnitude(abs(_s21.shuntImpedance())))
- self.label['s21magseries'].setText(
- format_magnitude(abs(_s21.seriesImpedance())))
- self.label['s21realimagshunt'].setText(
- format_complex_imp(
- _s21.shuntImpedance(), allow_negative=True))
- self.label['s21realimagseries'].setText(
- format_complex_imp(
- _s21.seriesImpedance(), allow_negative=True))
+ self.label["s21magshunt"].setText(
+ format_magnitude(abs(_s21.shuntImpedance()))
+ )
+ self.label["s21magseries"].setText(
+ format_magnitude(abs(_s21.seriesImpedance()))
+ )
+ self.label["s21realimagshunt"].setText(
+ format_complex_imp(_s21.shuntImpedance(), allow_negative=True)
+ )
+ self.label["s21realimagseries"].setText(
+ format_complex_imp(_s21.seriesImpedance(), allow_negative=True)
+ )
diff --git a/src/NanoVNASaver/NanoVNASaver.py b/src/NanoVNASaver/NanoVNASaver.py
index fb41e31..21aa3f2 100644
--- a/src/NanoVNASaver/NanoVNASaver.py
+++ b/src/NanoVNASaver/NanoVNASaver.py
@@ -26,9 +26,14 @@ from PyQt5 import QtWidgets, QtCore, QtGui
from NanoVNASaver import Defaults
from .Windows import (
- AboutWindow, AnalysisWindow, CalibrationWindow,
- DeviceSettingsWindow, DisplaySettingsWindow, SweepSettingsWindow,
- TDRWindow, FilesWindow
+ AboutWindow,
+ AnalysisWindow,
+ CalibrationWindow,
+ DeviceSettingsWindow,
+ DisplaySettingsWindow,
+ SweepSettingsWindow,
+ TDRWindow,
+ FilesWindow,
)
from .Controls.MarkerControl import MarkerControl
from .Controls.SweepControl import SweepControl
@@ -40,14 +45,26 @@ from .RFTools import corr_att_data
from .Charts.Chart import Chart
from .Charts import (
CapacitanceChart,
- CombinedLogMagChart, GroupDelayChart, InductanceChart,
- LogMagChart, PhaseChart,
- MagnitudeChart, MagnitudeZChart, MagnitudeZShuntChart,
+ CombinedLogMagChart,
+ GroupDelayChart,
+ InductanceChart,
+ LogMagChart,
+ PhaseChart,
+ MagnitudeChart,
+ MagnitudeZChart,
+ MagnitudeZShuntChart,
MagnitudeZSeriesChart,
- QualityFactorChart, VSWRChart, PermeabilityChart, PolarChart,
+ QualityFactorChart,
+ VSWRChart,
+ PermeabilityChart,
+ PolarChart,
RealImaginaryMuChart,
- RealImaginaryZChart, RealImaginaryZShuntChart, RealImaginaryZSeriesChart,
- SmithChart, SParameterChart, TDRChart,
+ RealImaginaryZChart,
+ RealImaginaryZShuntChart,
+ RealImaginaryZSeriesChart,
+ SmithChart,
+ SParameterChart,
+ TDRChart,
)
from .Calibration import Calibration
from .Marker.Widget import Marker
@@ -69,10 +86,11 @@ class NanoVNASaver(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.s21att = 0.0
- if getattr(sys, 'frozen', False):
+ if getattr(sys, "frozen", False):
logger.debug("Running from pyinstaller bundle")
self.icon = QtGui.QIcon(
- f"{sys._MEIPASS}/icon_48x48.png") # pylint: disable=no-member
+ f"{sys._MEIPASS}/icon_48x48.png"
+ ) # pylint: disable=no-member
else:
self.icon = QtGui.QIcon("icon_48x48.png")
self.setWindowIcon(self.icon)
@@ -80,7 +98,8 @@ class NanoVNASaver(QtWidgets.QWidget):
QtCore.QSettings.IniFormat,
QtCore.QSettings.UserScope,
"NanoVNASaver",
- "NanoVNASaver")
+ "NanoVNASaver",
+ )
logger.info("Settings from: %s", self.settings.fileName())
Defaults.cfg = Defaults.restore(self.settings)
self.threadpool = QtCore.QThreadPool()
@@ -128,13 +147,17 @@ class NanoVNASaver(QtWidgets.QWidget):
outer.addWidget(scrollarea)
self.setLayout(outer)
scrollarea.setWidgetResizable(True)
- self.resize(Defaults.cfg.gui.window_width,
- Defaults.cfg.gui.window_height)
+ self.resize(
+ Defaults.cfg.gui.window_width, Defaults.cfg.gui.window_height
+ )
scrollarea.setSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding,
- QtWidgets.QSizePolicy.MinimumExpanding)
- self.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding,
- QtWidgets.QSizePolicy.MinimumExpanding)
+ QtWidgets.QSizePolicy.MinimumExpanding,
+ )
+ self.setSizePolicy(
+ QtWidgets.QSizePolicy.MinimumExpanding,
+ QtWidgets.QSizePolicy.MinimumExpanding,
+ )
widget = QtWidgets.QWidget()
widget.setLayout(layout)
scrollarea.setWidget(widget)
@@ -149,25 +172,30 @@ class NanoVNASaver(QtWidgets.QWidget):
"magnitude_z": MagnitudeZChart("S11 |Z|"),
"permeability": PermeabilityChart(
"S11 R/\N{GREEK SMALL LETTER OMEGA} &"
- " X/\N{GREEK SMALL LETTER OMEGA}"),
+ " X/\N{GREEK SMALL LETTER OMEGA}"
+ ),
"phase": PhaseChart("S11 Phase"),
"q_factor": QualityFactorChart("S11 Quality Factor"),
"real_imag": RealImaginaryZChart("S11 R+jX"),
- "real_imag_mu": RealImaginaryMuChart("S11 \N{GREEK SMALL LETTER MU}"),
+ "real_imag_mu": RealImaginaryMuChart(
+ "S11 \N{GREEK SMALL LETTER MU}"
+ ),
"smith": SmithChart("S11 Smith Chart"),
"s_parameter": SParameterChart("S11 Real/Imaginary"),
"vswr": VSWRChart("S11 VSWR"),
},
"s21": {
- "group_delay": GroupDelayChart("S21 Group Delay",
- reflective=False),
+ "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": RealImaginaryZShuntChart("S21 R+jX shunt"),
"real_imag_series": RealImaginaryZSeriesChart(
- "S21 R+jX series"),
+ "S21 R+jX series"
+ ),
"phase": PhaseChart("S21 Phase"),
"polar": PolarChart("S21 Polar Plot"),
"s_parameter": SParameterChart("S21 Real/Imaginary"),
@@ -190,8 +218,13 @@ class NanoVNASaver(QtWidgets.QWidget):
# List of all charts that can be selected for display
self.selectable_charts = (
- self.s11charts + self.s21charts +
- self.combinedCharts + [self.tdr_mainwindow_chart, ])
+ self.s11charts
+ + self.s21charts
+ + self.combinedCharts
+ + [
+ self.tdr_mainwindow_chart,
+ ]
+ )
# List of all charts that subscribe to updates (including duplicates!)
self.subscribing_charts = []
@@ -314,7 +347,8 @@ class NanoVNASaver(QtWidgets.QWidget):
btn_show_analysis = QtWidgets.QPushButton("Analysis ...")
btn_show_analysis.setMinimumHeight(20)
btn_show_analysis.clicked.connect(
- lambda: self.display_window("analysis"))
+ lambda: self.display_window("analysis")
+ )
self.marker_column.addWidget(btn_show_analysis)
###############################################################
@@ -335,10 +369,10 @@ class NanoVNASaver(QtWidgets.QWidget):
self.tdr_result_label = QtWidgets.QLabel()
self.tdr_result_label.setMinimumHeight(20)
tdr_control_layout.addRow(
- "Estimated cable length:", self.tdr_result_label)
+ "Estimated cable length:", self.tdr_result_label
+ )
- self.tdr_button = QtWidgets.QPushButton(
- "Time Domain Reflectometry ...")
+ self.tdr_button = QtWidgets.QPushButton("Time Domain Reflectometry ...")
self.tdr_button.setMinimumHeight(20)
self.tdr_button.clicked.connect(lambda: self.display_window("tdr"))
@@ -351,8 +385,13 @@ class NanoVNASaver(QtWidgets.QWidget):
###############################################################
left_column.addSpacerItem(
- QtWidgets.QSpacerItem(1, 1, QtWidgets.QSizePolicy.Fixed,
- QtWidgets.QSizePolicy.Expanding))
+ QtWidgets.QSpacerItem(
+ 1,
+ 1,
+ QtWidgets.QSizePolicy.Fixed,
+ QtWidgets.QSizePolicy.Expanding,
+ )
+ )
###############################################################
# Reference control
@@ -390,7 +429,8 @@ class NanoVNASaver(QtWidgets.QWidget):
btnOpenCalibrationWindow.setMinimumHeight(20)
self.calibrationWindow = CalibrationWindow(self)
btnOpenCalibrationWindow.clicked.connect(
- lambda: self.display_window("calibration"))
+ lambda: self.display_window("calibration")
+ )
###############################################################
# Display setup
@@ -399,22 +439,21 @@ class NanoVNASaver(QtWidgets.QWidget):
btn_display_setup = QtWidgets.QPushButton("Display setup ...")
btn_display_setup.setMinimumHeight(20)
btn_display_setup.setMaximumWidth(240)
- btn_display_setup.clicked.connect(
- lambda: self.display_window("setup"))
+ btn_display_setup.clicked.connect(lambda: self.display_window("setup"))
btn_about = QtWidgets.QPushButton("About ...")
btn_about.setMinimumHeight(20)
btn_about.setMaximumWidth(240)
- btn_about.clicked.connect(
- lambda: self.display_window("about"))
+ btn_about.clicked.connect(lambda: self.display_window("about"))
btn_open_file_window = QtWidgets.QPushButton("Files")
btn_open_file_window.setMinimumHeight(20)
btn_open_file_window.setMaximumWidth(240)
btn_open_file_window.clicked.connect(
- lambda: self.display_window("file"))
+ lambda: self.display_window("file")
+ )
button_grid = QtWidgets.QGridLayout()
button_grid.addWidget(btn_open_file_window, 0, 0)
@@ -484,8 +523,7 @@ class NanoVNASaver(QtWidgets.QWidget):
m2 = Marker("Reference")
m2.location = self.markers[0].location
m2.resetLabels()
- m2.updateLabels(self.ref_data.s11,
- self.ref_data.s21)
+ m2.updateLabels(self.ref_data.s11, self.ref_data.s21)
else:
logger.warning("No reference data for marker")
@@ -525,7 +563,8 @@ class NanoVNASaver(QtWidgets.QWidget):
min_vswr = min(s11, key=lambda data: data.vswr)
self.s11_min_swr_label.setText(
f"{format_vswr(min_vswr.vswr)} @"
- f" {format_frequency(min_vswr.freq)}")
+ f" {format_frequency(min_vswr.freq)}"
+ )
self.s11_min_rl_label.setText(format_gain(min_vswr.gain))
else:
self.s11_min_swr_label.setText("")
@@ -536,10 +575,12 @@ class NanoVNASaver(QtWidgets.QWidget):
max_gain = max(s21, key=lambda data: data.gain)
self.s21_min_gain_label.setText(
f"{format_gain(min_gain.gain)}"
- f" @ {format_frequency(min_gain.freq)}")
+ f" @ {format_frequency(min_gain.freq)}"
+ )
self.s21_max_gain_label.setText(
f"{format_gain(max_gain.gain)}"
- f" @ {format_frequency(max_gain.freq)}")
+ f" @ {format_frequency(max_gain.freq)}"
+ )
else:
self.s21_min_gain_label.setText("")
self.s21_max_gain_label.setText("")
@@ -551,8 +592,7 @@ class NanoVNASaver(QtWidgets.QWidget):
self._sweep_control(start=False)
for marker in self.markers:
- marker.frequencyInput.textEdited.emit(
- marker.frequencyInput.text())
+ marker.frequencyInput.textEdited.emit(marker.frequencyInput.text())
def setReference(self, s11=None, s21=None, source=None):
if not s11:
@@ -581,11 +621,13 @@ class NanoVNASaver(QtWidgets.QWidget):
if self.sweepSource != "":
insert += (
f"Sweep: {self.sweepSource} @ {len(self.data.s11)} points"
- f"{', ' if self.referenceSource else ''}")
+ f"{', ' if self.referenceSource else ''}"
+ )
if self.referenceSource != "":
insert += (
f"Reference: {self.referenceSource} @"
- f" {len(self.ref_data.s11)} points")
+ f" {len(self.ref_data.s11)} points"
+ )
insert += ")"
title = f"{self.baseTitle} {insert or ''}"
self.setWindowTitle(title)
@@ -612,7 +654,7 @@ class NanoVNASaver(QtWidgets.QWidget):
self.showError(self.worker.error_message)
with contextlib.suppress(IOError):
self.vna.flushSerialBuffers() # Remove any left-over data
- self.vna.reconnect() # try reconnection
+ self.vna.reconnect() # try reconnection
self.sweepFinished()
def popoutChart(self, chart: Chart):
@@ -661,8 +703,12 @@ class NanoVNASaver(QtWidgets.QWidget):
new_width = qf_new.horizontalAdvance(standard_string)
old_width = qf_normal.horizontalAdvance(standard_string)
self.scaleFactor = new_width / old_width
- logger.debug("New font width: %f, normal font: %f, factor: %f",
- new_width, old_width, self.scaleFactor)
+ logger.debug(
+ "New font width: %f, normal font: %f, factor: %f",
+ new_width,
+ old_width,
+ self.scaleFactor,
+ )
# TODO: Update all the fixed widths to account for the scaling
for m in self.markers:
m.get_data_layout().setFont(font)
diff --git a/src/NanoVNASaver/RFTools.py b/src/NanoVNASaver/RFTools.py
index ca12040..7dfcf27 100644
--- a/src/NanoVNASaver/RFTools.py
+++ b/src/NanoVNASaver/RFTools.py
@@ -34,12 +34,12 @@ class Datapoint(NamedTuple):
@property
def z(self) -> complex:
- """ return the s value complex number """
+ """return the s value complex number"""
return complex(self.re, self.im)
@property
def phase(self) -> float:
- """ return the datapoint's phase value """
+ """return the datapoint's phase value"""
return cmath.phase(self.z)
@property
@@ -77,11 +77,11 @@ class Datapoint(NamedTuple):
def capacitiveEquivalent(self, ref_impedance: float = 50) -> float:
return impedance_to_capacitance(
- self.impedance(ref_impedance), self.freq)
+ self.impedance(ref_impedance), self.freq
+ )
def inductiveEquivalent(self, ref_impedance: float = 50) -> float:
- return impedance_to_inductance(
- self.impedance(ref_impedance), self.freq)
+ return impedance_to_inductance(self.impedance(ref_impedance), self.freq)
def gamma_to_impedance(gamma: complex, ref_impedance: float = 50) -> complex:
@@ -124,9 +124,10 @@ 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 or 10.0e-30
- return complex(z.real * z.imag ** 2 / z_sq_sum,
- z.real ** 2 * z.imag / z_sq_sum)
+ 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
+ )
def reflection_coefficient(z: complex, ref_impedance: float = 50) -> complex:
@@ -136,7 +137,7 @@ def reflection_coefficient(z: complex, ref_impedance: float = 50) -> complex:
def serial_to_parallel(z: complex) -> complex:
"""Convert serial impedance to parallel impedance equivalent"""
- z_sq_sum = z.real ** 2 + z.imag ** 2
+ z_sq_sum = z.real**2 + z.imag**2
if z.real == 0 and z.imag == 0:
return complex(math.inf, math.inf)
if z.imag == 0:
@@ -150,7 +151,7 @@ def corr_att_data(data: List[Datapoint], att: float) -> List[Datapoint]:
"""Correct the ratio for a given attenuation on s21 input"""
if att <= 0:
return data
- att = 10**(att / 20)
+ att = 10 ** (att / 20)
ndata = []
for dp in data:
corrected = dp.z * att
diff --git a/src/NanoVNASaver/SITools.py b/src/NanoVNASaver/SITools.py
index 233cfa6..7749650 100644
--- a/src/NanoVNASaver/SITools.py
+++ b/src/NanoVNASaver/SITools.py
@@ -22,8 +22,29 @@ from decimal import Context, Decimal, InvalidOperation
from typing import NamedTuple
from numbers import Number, Real
-PREFIXES = ("q", "r", "y", "z", "a", "f", "p", "n", "µ", "m",
- "", "k", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q")
+PREFIXES = (
+ "q",
+ "r",
+ "y",
+ "z",
+ "a",
+ "f",
+ "p",
+ "n",
+ "µ",
+ "m",
+ "",
+ "k",
+ "M",
+ "G",
+ "T",
+ "P",
+ "E",
+ "Z",
+ "Y",
+ "R",
+ "Q",
+)
def clamp_value(value: Real, rmin: Real, rmax: Real) -> Real:
@@ -32,17 +53,17 @@ def clamp_value(value: Real, rmin: Real, rmax: Real) -> Real:
def round_ceil(value: Real, digits: int = 0) -> Real:
- factor = 10 ** -digits
+ factor = 10**-digits
return factor * math.ceil(value / factor)
def round_floor(value: Real, digits: int = 0) -> Real:
- factor = 10 ** -digits
+ factor = 10**-digits
return factor * math.floor(value / factor)
def log_floor_125(x: float) -> float:
- log_base = 10**(math.floor(math.log10(x)))
+ log_base = 10 ** (math.floor(math.log10(x)))
log_factor = x / log_base
if log_factor >= 5:
return 5 * log_base
@@ -80,31 +101,44 @@ class Value:
self.fmt = fmt
if isinstance(value, str):
self._value = Decimal(math.nan)
- if value.lower() != 'nan':
+ if value.lower() != "nan":
self.parse(value)
else:
self._value = Decimal(value, context=Value.CTX)
def __repr__(self) -> str:
- return (f"{self.__class__.__name__}("
- f"{repr(self._value)}, '{self._unit}', {self.fmt})")
+ return (
+ f"{self.__class__.__name__}("
+ f"{repr(self._value)}, '{self._unit}', {self.fmt})"
+ )
def __str__(self) -> str:
fmt = self.fmt
if math.isnan(self._value):
return f"-{fmt.space_str}{self._unit}"
- if (fmt.assume_infinity and
- abs(self._value) >= 10 ** ((fmt.max_offset + 1) * 3)):
- return (("-" if self._value < 0 else "") +
- "\N{INFINITY}" + fmt.space_str + self._unit)
+ if fmt.assume_infinity and abs(self._value) >= 10 ** (
+ (fmt.max_offset + 1) * 3
+ ):
+ return (
+ ("-" if self._value < 0 else "")
+ + "\N{INFINITY}"
+ + fmt.space_str
+ + self._unit
+ )
if self._value < fmt.printable_min:
return fmt.unprintable_under + self._unit
if self._value > fmt.printable_max:
return fmt.unprintable_over + self._unit
- offset = clamp_value(
- int(math.log10(abs(self._value)) // 3),
- fmt.min_offset, fmt.max_offset) if self._value else 0
+ offset = (
+ clamp_value(
+ int(math.log10(abs(self._value)) // 3),
+ fmt.min_offset,
+ fmt.max_offset,
+ )
+ if self._value
+ else 0
+ )
real = float(self._value) / (10 ** (offset * 3))
@@ -112,8 +146,9 @@ 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:
@@ -150,10 +185,13 @@ class Value:
value = value.replace(" ", "") # Ignore spaces
if self._unit and (
- value.endswith(self._unit) or
- (self.fmt.parse_sloppy_unit and
- value.lower().endswith(self._unit.lower()))): # strip unit
- value = value[:-len(self._unit)]
+ value.endswith(self._unit)
+ or (
+ self.fmt.parse_sloppy_unit
+ and value.lower().endswith(self._unit.lower())
+ )
+ ): # strip unit
+ value = value[: -len(self._unit)]
factor = 1
# fix for e.g. KHz, mHz gHz as milli-Hertz mostly makes no
@@ -170,13 +208,14 @@ class Value:
self._value = -math.inf
else:
try:
- self._value = (Decimal(value, context=Value.CTX)
- * Decimal(factor, context=Value.CTX))
+ self._value = Decimal(value, context=Value.CTX) * Decimal(
+ factor, context=Value.CTX
+ )
except InvalidOperation as exc:
raise ValueError() from exc
- self._value = clamp_value(self._value,
- self.fmt.parse_clamp_min,
- self.fmt.parse_clamp_max)
+ self._value = clamp_value(
+ self._value, self.fmt.parse_clamp_min, self.fmt.parse_clamp_max
+ )
return self
@property
diff --git a/src/NanoVNASaver/Settings/Bands.py b/src/NanoVNASaver/Settings/Bands.py
index 1e73206..fd18d5b 100644
--- a/src/NanoVNASaver/Settings/Bands.py
+++ b/src/NanoVNASaver/Settings/Bands.py
@@ -57,9 +57,12 @@ class BandsModel(QtCore.QAbstractTableModel):
# These bands correspond broadly to the Danish Amateur Radio allocation
def __init__(self):
super().__init__()
- self.settings = QtCore.QSettings(QtCore.QSettings.IniFormat,
- QtCore.QSettings.UserScope,
- "NanoVNASaver", "Bands")
+ self.settings = QtCore.QSettings(
+ QtCore.QSettings.IniFormat,
+ QtCore.QSettings.UserScope,
+ "NanoVNASaver",
+ "Bands",
+ )
self.settings.setIniCodec("UTF-8")
self.enabled = self.settings.value("ShowBands", False, bool)
@@ -71,7 +74,8 @@ class BandsModel(QtCore.QAbstractTableModel):
def saveSettings(self):
self.settings.setValue(
"bands",
- [f"{name};{start};{end}" for name, start, end in self.bands])
+ [f"{name};{start};{end}" for name, start, end in self.bands],
+ )
self.settings.sync()
def resetBands(self):
@@ -87,18 +91,22 @@ class BandsModel(QtCore.QAbstractTableModel):
def data(self, index: QModelIndex, role: int = ...) -> QtCore.QVariant:
if role in [
- QtCore.Qt.DisplayRole, QtCore.Qt.ItemDataRole, QtCore.Qt.EditRole,
+ QtCore.Qt.DisplayRole,
+ QtCore.Qt.ItemDataRole,
+ QtCore.Qt.EditRole,
]:
return QtCore.QVariant(self.bands[index.row()][index.column()])
if role == QtCore.Qt.TextAlignmentRole:
if index.column() == 0:
return QtCore.QVariant(QtCore.Qt.AlignCenter)
return QtCore.QVariant(
- QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
+ QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter
+ )
return QtCore.QVariant()
- def setData(self, index: QModelIndex,
- value: typing.Any, role: int = ...) -> bool:
+ def setData(
+ self, index: QModelIndex, value: typing.Any, role: int = ...
+ ) -> bool:
if role == QtCore.Qt.EditRole and index.isValid():
t = self.bands[index.row()]
name = t[0]
@@ -116,14 +124,14 @@ class BandsModel(QtCore.QAbstractTableModel):
return True
return False
- def index(self, row: int,
- column: int, _: QModelIndex = ...) -> QModelIndex:
+ def index(self, row: int, column: int, _: QModelIndex = ...) -> QModelIndex:
return self.createIndex(row, column)
def addRow(self):
self.bands.append(("New", 0, 0))
- self.dataChanged.emit(self.index(len(self.bands), 0),
- self.index(len(self.bands), 2))
+ self.dataChanged.emit(
+ self.index(len(self.bands), 0), self.index(len(self.bands), 2)
+ )
self.layoutChanged.emit()
def removeRow(self, row: int, _: QModelIndex = ...) -> bool:
@@ -132,10 +140,13 @@ class BandsModel(QtCore.QAbstractTableModel):
self.saveSettings()
return True
- def headerData(self, section: int,
- orientation: QtCore.Qt.Orientation, role: int = ...):
- if (role == QtCore.Qt.DisplayRole and
- orientation == QtCore.Qt.Horizontal):
+ def headerData(
+ self, section: int, orientation: QtCore.Qt.Orientation, role: int = ...
+ ):
+ if (
+ role == QtCore.Qt.DisplayRole
+ and orientation == QtCore.Qt.Horizontal
+ ):
with contextlib.suppress(IndexError):
return _HEADER_DATA[section]
return None
@@ -143,9 +154,10 @@ class BandsModel(QtCore.QAbstractTableModel):
def flags(self, index: QModelIndex) -> QtCore.Qt.ItemFlags:
if index.isValid():
return QtCore.Qt.ItemFlags(
- QtCore.Qt.ItemIsEditable |
- QtCore.Qt.ItemIsEnabled |
- QtCore.Qt.ItemIsSelectable)
+ QtCore.Qt.ItemIsEditable
+ | QtCore.Qt.ItemIsEnabled
+ | QtCore.Qt.ItemIsSelectable
+ )
super().flags(index)
def setColor(self, color):
diff --git a/src/NanoVNASaver/Settings/Sweep.py b/src/NanoVNASaver/Settings/Sweep.py
index fa4900c..4f9b44c 100644
--- a/src/NanoVNASaver/Settings/Sweep.py
+++ b/src/NanoVNASaver/Settings/Sweep.py
@@ -32,10 +32,13 @@ class SweepMode(Enum):
class Properties:
- def __init__(self, name: str = "",
- mode: 'SweepMode' = SweepMode.SINGLE,
- averages: Tuple[int, int] = (3, 0),
- logarithmic: bool = False):
+ def __init__(
+ self,
+ name: str = "",
+ mode: "SweepMode" = SweepMode.SINGLE,
+ averages: Tuple[int, int] = (3, 0),
+ logarithmic: bool = False,
+ ):
self.name = name
self.mode = mode
self.averages = averages
@@ -44,13 +47,19 @@ class Properties:
def __repr__(self):
return (
f"Properties('{self.name}', {self.mode}, {self.averages},"
- f" {self.logarithmic})")
+ f" {self.logarithmic})"
+ )
class Sweep:
- def __init__(self, start: int = 3600000, end: int = 30000000,
- points: int = 101, segments: int = 1,
- properties: 'Properties' = Properties()):
+ def __init__(
+ self,
+ start: int = 3600000,
+ end: int = 30000000,
+ points: int = 101,
+ segments: int = 1,
+ properties: "Properties" = Properties(),
+ ):
self.start = start
self.end = end
self.points = points
@@ -63,18 +72,22 @@ class Sweep:
def __repr__(self) -> str:
return (
f"Sweep({self.start}, {self.end}, {self.points}, {self.segments},"
- f" {self.properties})")
+ 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,
- self.properties)
+ def copy(self) -> "Sweep":
+ return Sweep(
+ self.start, self.end, self.points, self.segments, self.properties
+ )
@property
def span(self) -> int:
@@ -86,11 +99,11 @@ class Sweep:
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}")
diff --git a/src/NanoVNASaver/SweepWorker.py b/src/NanoVNASaver/SweepWorker.py
index 8f3e531..e06b04d 100644
--- a/src/NanoVNASaver/SweepWorker.py
+++ b/src/NanoVNASaver/SweepWorker.py
@@ -42,9 +42,8 @@ def truncate(values: List[List[Tuple]], count: int) -> List[List[Tuple]]:
for valueset in np.swapaxes(values, 0, 1).tolist():
avg = complex(*np.average(valueset, 0))
truncated.append(
- sorted(valueset,
- key=lambda v, a=avg:
- abs(a - complex(*v)))[:keep])
+ sorted(valueset, key=lambda v, a=avg: abs(a - complex(*v)))[:keep]
+ )
return np.swapaxes(truncated, 0, 1).tolist()
@@ -87,7 +86,8 @@ class SweepWorker(QtCore.QRunnable):
logger.info("Initializing SweepWorker")
if not self.app.vna.connected():
logger.debug(
- "Attempted to run without being connected to the NanoVNA")
+ "Attempted to run without being connected to the NanoVNA"
+ )
self.running = False
return
@@ -106,8 +106,9 @@ class SweepWorker(QtCore.QRunnable):
if sweep.segments > 1:
start = sweep.start
end = sweep.end
- logger.debug("Resetting NanoVNA sweep to full range: %d to %d",
- start, end)
+ logger.debug(
+ "Resetting NanoVNA sweep to full range: %d to %d", start, end
+ )
self.app.vna.resetSweep(start, end)
self.percentage = 100
@@ -117,9 +118,11 @@ class SweepWorker(QtCore.QRunnable):
def _run_loop(self) -> None:
sweep = self.sweep
- averages = (sweep.properties.averages[0]
- if sweep.properties.mode == SweepMode.AVERAGE
- else 1)
+ averages = (
+ sweep.properties.averages[0]
+ if sweep.properties.mode == SweepMode.AVERAGE
+ else 1
+ )
logger.info("%d averages", averages)
while True:
@@ -131,7 +134,8 @@ class SweepWorker(QtCore.QRunnable):
start, stop = sweep.get_index_range(i)
freq, values11, values21 = self.readAveragedSegment(
- start, stop, averages)
+ start, stop, averages
+ )
self.percentage = (i + 1) * 100 / sweep.segments
self.updateData(freq, values11, values21, i)
if sweep.properties.mode != SweepMode.CONTINOUS or self.stopped:
@@ -152,14 +156,18 @@ class SweepWorker(QtCore.QRunnable):
def updateData(self, frequencies, values11, values21, index):
# Update the data from (i*101) to (i+1)*101
logger.debug(
- "Calculating data and inserting in existing data at index %d",
- index)
+ "Calculating data and inserting in existing data at index %d", index
+ )
offset = self.sweep.points * index
- raw_data11 = [Datapoint(freq, values11[i][0], values11[i][1])
- for i, freq in enumerate(frequencies)]
- raw_data21 = [Datapoint(freq, values21[i][0], values21[i][1])
- for i, freq in enumerate(frequencies)]
+ raw_data11 = [
+ Datapoint(freq, values11[i][0], values11[i][1])
+ for i, freq in enumerate(frequencies)
+ ]
+ raw_data21 = [
+ Datapoint(freq, values21[i][0], values21[i][1])
+ for i, freq in enumerate(frequencies)
+ ]
data11, data21 = self.applyCalibration(raw_data11, raw_data21)
logger.debug("update Freqs: %s, Offset: %s", len(frequencies), offset)
@@ -169,16 +177,18 @@ class SweepWorker(QtCore.QRunnable):
self.rawData11[offset + i] = raw_data11[i]
self.rawData21[offset + i] = raw_data21[i]
- logger.debug("Saving data to application (%d and %d points)",
- len(self.data11), len(self.data21))
+ logger.debug(
+ "Saving data to application (%d and %d points)",
+ len(self.data11),
+ len(self.data21),
+ )
self.app.saveData(self.data11, self.data21)
logger.debug('Sending "updated" signal')
self.signals.updated.emit()
- def applyCalibration(self,
- raw_data11: List[Datapoint],
- raw_data21: List[Datapoint]
- ) -> Tuple[List[Datapoint], List[Datapoint]]:
+ def applyCalibration(
+ self, raw_data11: List[Datapoint], raw_data21: List[Datapoint]
+ ) -> Tuple[List[Datapoint], List[Datapoint]]:
data11: List[Datapoint] = []
data21: List[Datapoint] = []
@@ -186,8 +196,9 @@ class SweepWorker(QtCore.QRunnable):
data11 = raw_data11.copy()
data21 = raw_data21.copy()
elif self.app.calibration.isValid1Port():
- data11.extend(self.app.calibration.correct11(dp)
- for dp in raw_data11)
+ data11.extend(
+ self.app.calibration.correct11(dp) for dp in raw_data11
+ )
else:
data11 = raw_data11.copy()
@@ -199,8 +210,10 @@ class SweepWorker(QtCore.QRunnable):
data21 = raw_data21
if self.offsetDelay != 0:
- data11 = [correct_delay(dp, self.offsetDelay, reflect=True)
- for dp in data11]
+ data11 = [
+ correct_delay(dp, self.offsetDelay, reflect=True)
+ for dp in data11
+ ]
data21 = [correct_delay(dp, self.offsetDelay) for dp in data21]
return data11, data21
@@ -209,8 +222,9 @@ class SweepWorker(QtCore.QRunnable):
values11 = []
values21 = []
freq = []
- logger.info("Reading from %d to %d. Averaging %d values",
- start, stop, averages)
+ logger.info(
+ "Reading from %d to %d. Averaging %d values", start, stop, averages
+ )
for i in range(averages):
if self.stopped:
logger.debug("Stopping averaging as signalled.")
@@ -227,8 +241,9 @@ class SweepWorker(QtCore.QRunnable):
retry += 1
freq, tmp11, tmp21 = self.readSegment(start, stop)
if retry > 1:
- logger.error("retry %s readSegment(%s,%s)",
- retry, start, stop)
+ logger.error(
+ "retry %s readSegment(%s,%s)", retry, start, stop
+ )
sleep(0.5)
values11.append(tmp11)
values21.append(tmp21)
@@ -240,8 +255,7 @@ class SweepWorker(QtCore.QRunnable):
truncates = self.sweep.properties.averages[1]
if truncates > 0 and averages > 1:
- logger.debug("Truncating %d values by %d",
- len(values11), truncates)
+ logger.debug("Truncating %d values by %d", len(values11), truncates)
values11 = truncate(values11, truncates)
values21 = truncate(values21, truncates)
@@ -278,36 +292,42 @@ class SweepWorker(QtCore.QRunnable):
a, b = d.split(" ")
try:
if self.app.vna.validateInput and (
- abs(float(a)) > 9.5 or
- abs(float(b)) > 9.5):
+ abs(float(a)) > 9.5 or abs(float(b)) > 9.5
+ ):
logger.warning(
- "Got a non plausible data value: (%s)", d)
+ "Got a non plausible data value: (%s)", d
+ )
done = False
break
returndata.append((float(a), float(b)))
except ValueError as exc:
- logger.exception("An exception occurred reading %s: %s",
- data, exc)
+ logger.exception(
+ "An exception occurred reading %s: %s", data, exc
+ )
done = False
if not done:
logger.debug("Re-reading %s", data)
sleep(0.2)
count += 1
if count == 5:
- logger.error("Tried and failed to read %s %d times.",
- data, count)
+ logger.error(
+ "Tried and failed to read %s %d times.", data, count
+ )
logger.debug("trying to reconnect")
self.app.vna.reconnect()
if count >= 10:
logger.critical(
"Tried and failed to read %s %d times. Giving up.",
- data, count)
+ data,
+ count,
+ )
raise IOError(
f"Failed reading {data} {count} times.\n"
f"Data outside expected valid ranges,"
f" or in an unexpected format.\n\n"
f"You can disable data validation on the"
- f"device settings screen.")
+ f"device settings screen."
+ )
return returndata
def gui_error(self, message: str):
diff --git a/src/NanoVNASaver/Touchstone.py b/src/NanoVNASaver/Touchstone.py
index eba4d3c..2a9a7f9 100644
--- a/src/NanoVNASaver/Touchstone.py
+++ b/src/NanoVNASaver/Touchstone.py
@@ -35,20 +35,22 @@ 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"
VALID_FORMATS = ("ma", "db", "ri")
- def __init__(self,
- unit: str = "GHZ",
- parameter: str = "S",
- t_format: str = "ma",
- resistance: int = 50):
+ def __init__(
+ self,
+ unit: str = "GHZ",
+ parameter: str = "S",
+ t_format: str = "ma",
+ resistance: int = 50,
+ ):
# set defaults
assert unit.lower() in Options.VALID_UNITS
assert parameter.lower() in Options.VALID_PARAMETERS
@@ -145,9 +147,11 @@ class Touchstone:
return self.sdata[Touchstone.FIELD_ORDER.index(name)]
def s_freq(self, name: str, freq: int) -> Datapoint:
- return Datapoint(freq,
- float(self._interp[name]["real"](freq)),
- float(self._interp[name]["imag"](freq)))
+ return Datapoint(
+ freq,
+ float(self._interp[name]["real"](freq)),
+ float(self._interp[name]["imag"](freq)),
+ )
def swap(self):
self.sdata = [self.s22, self.s12, self.s21, self.s11]
@@ -170,12 +174,20 @@ class Touchstone:
imag.append(dp.im)
self._interp[i] = {
- "real": interp1d(freq, real,
- kind="slinear", bounds_error=False,
- fill_value=(real[0], real[-1])),
- "imag": interp1d(freq, imag,
- kind="slinear", bounds_error=False,
- fill_value=(imag[0], imag[-1])),
+ "real": interp1d(
+ freq,
+ real,
+ kind="slinear",
+ bounds_error=False,
+ fill_value=(real[0], real[-1]),
+ ),
+ "imag": interp1d(
+ freq,
+ imag,
+ kind="slinear",
+ bounds_error=False,
+ fill_value=(imag[0], imag[-1]),
+ ),
}
def _parse_comments(self, fp) -> str:
@@ -192,27 +204,29 @@ class Touchstone:
vals = iter(data)
for v in vals:
if self.opts.format == "ri":
- next(data_list).append(Datapoint(freq, float(v),
- float(next(vals))))
+ next(data_list).append(
+ Datapoint(freq, float(v), float(next(vals)))
+ )
if self.opts.format == "ma":
z = cmath.rect(float(v), math.radians(float(next(vals))))
next(data_list).append(Datapoint(freq, z.real, z.imag))
if self.opts.format == "db":
- z = cmath.rect(10 ** (float(v) / 20),
- math.radians(float(next(vals))))
+ z = cmath.rect(
+ 10 ** (float(v) / 20), math.radians(float(next(vals)))
+ )
next(data_list).append(Datapoint(freq, z.real, z.imag))
def load(self):
logger.info("Attempting to open file %s", self.filename)
try:
- with open(self.filename, encoding='utf-8') as infile:
+ with open(self.filename, encoding="utf-8") as infile:
self.loads(infile.read())
except IOError as e:
logger.exception("Failed to open %s: %s", self.filename, e)
def loads(self, s: str):
"""Parse touchstone 1.1 string input
- appends to existing sdata if Touchstone object exists
+ appends to existing sdata if Touchstone object exists
"""
try:
self._loads(s)
@@ -239,7 +253,7 @@ class Touchstone:
continue
# ignore comments at data end
- data = line.split('!')[0]
+ data = line.split("!")[0]
data = data.split()
freq, data = round(float(data[0]) * self.opts.factor), data[1:]
data_len = len(data)
@@ -270,8 +284,7 @@ class Touchstone:
nr_params: Number of s-parameters. 2 for s1p, 4 for s2p
"""
- logger.info("Attempting to open file %s for writing",
- self.filename)
+ logger.info("Attempting to open file %s for writing", self.filename)
with open(self.filename, "w", encoding="utf-8") as outfile:
outfile.write(self.saves(nr_params))
diff --git a/src/NanoVNASaver/Version.py b/src/NanoVNASaver/Version.py
index 84b4c37..f6bf3e2 100644
--- a/src/NanoVNASaver/Version.py
+++ b/src/NanoVNASaver/Version.py
@@ -22,13 +22,16 @@ logger = logging.getLogger(__name__)
class Version:
- RXP = re.compile(r"""^
+ RXP = re.compile(
+ r"""^
\D*
(?P\d+)\.
(?P\d+)\.?
(?P\d+)?
(?P.*)
- $""", re.VERBOSE)
+ $""",
+ re.VERBOSE,
+ )
def __init__(self, vstring: str = "0.0.0"):
self.data = {
@@ -68,8 +71,10 @@ class Version:
return self.data == other.data
def __str__(self) -> str:
- return (f'{self.data["major"]}.{self.data["minor"]}'
- f'.{self.data["revision"]}{self.data["note"]}')
+ return (
+ f'{self.data["major"]}.{self.data["minor"]}'
+ f'.{self.data["revision"]}{self.data["note"]}'
+ )
@property
def major(self) -> int:
diff --git a/src/NanoVNASaver/Windows/About.py b/src/NanoVNASaver/Windows/About.py
index 1b1d8bc..e65bedd 100644
--- a/src/NanoVNASaver/Windows/About.py
+++ b/src/NanoVNASaver/Windows/About.py
@@ -53,28 +53,36 @@ class AboutWindow(QtWidgets.QWidget):
layout = QtWidgets.QVBoxLayout()
top_layout.addLayout(layout)
- layout.addWidget(QtWidgets.QLabel(
- f"NanoVNASaver version {self.app.version}"))
+ layout.addWidget(
+ QtWidgets.QLabel(f"NanoVNASaver version {self.app.version}")
+ )
layout.addWidget(QtWidgets.QLabel(""))
- layout.addWidget(QtWidgets.QLabel(
- "\N{COPYRIGHT SIGN} Copyright 2019, 2020 Rune B. Broberg\n"
- "\N{COPYRIGHT SIGN} Copyright 2020ff NanoVNA-Saver Authors"
- ))
- layout.addWidget(QtWidgets.QLabel(
- "This program comes with ABSOLUTELY NO WARRANTY"))
- layout.addWidget(QtWidgets.QLabel(
- "This program is licensed under the"
- " GNU General Public License version 3"))
+ layout.addWidget(
+ QtWidgets.QLabel(
+ "\N{COPYRIGHT SIGN} Copyright 2019, 2020 Rune B. Broberg\n"
+ "\N{COPYRIGHT SIGN} Copyright 2020ff NanoVNA-Saver Authors"
+ )
+ )
+ layout.addWidget(
+ QtWidgets.QLabel("This program comes with ABSOLUTELY NO WARRANTY")
+ )
+ layout.addWidget(
+ QtWidgets.QLabel(
+ "This program is licensed under the"
+ " GNU General Public License version 3"
+ )
+ )
layout.addWidget(QtWidgets.QLabel(""))
link_label = QtWidgets.QLabel(
- f'For further details, see: '
- f"{INFO_URL}")
+ f'For further details, see: ' f"{INFO_URL}"
+ )
link_label.setOpenExternalLinks(True)
layout.addWidget(link_label)
layout.addWidget(QtWidgets.QLabel(""))
self.versionLabel = QtWidgets.QLabel(
- "NanoVNA Firmware Version: Not connected.")
+ "NanoVNA Firmware Version: Not connected."
+ )
layout.addWidget(self.versionLabel)
layout.addStretch()
@@ -106,14 +114,15 @@ class AboutWindow(QtWidgets.QWidget):
with contextlib.suppress(IOError, AttributeError):
self.versionLabel.setText(
f"NanoVNA Firmware Version: {self.app.vna.name} "
- f"v{self.app.vna.version}")
+ f"v{self.app.vna.version}"
+ )
def findUpdates(self, automatic=False):
latest_version = Version()
latest_url = ""
try:
req = request.Request(VERSION_URL)
- req.add_header('User-Agent', f'NanoVNA-Saver/{self.app.version}')
+ req.add_header("User-Agent", f"NanoVNA-Saver/{self.app.version}")
for line in request.urlopen(req, timeout=3):
line = line.decode("utf-8")
if line.startswith("VERSION ="):
@@ -122,17 +131,20 @@ class AboutWindow(QtWidgets.QWidget):
latest_url = line[13:].strip(" \"'")
except error.HTTPError as e:
logger.exception(
- "Checking for updates produced an HTTP exception: %s", e)
+ "Checking for updates produced an HTTP exception: %s", e
+ )
self.updateLabel.setText("Connection error.")
return
except TypeError as e:
logger.exception(
- "Checking for updates provided an unparseable file: %s", e)
+ "Checking for updates provided an unparseable file: %s", e
+ )
self.updateLabel.setText("Data error reading versions.")
return
except error.URLError as e:
logger.exception(
- "Checking for updates produced a URL exception: %s", e)
+ "Checking for updates produced a URL exception: %s", e
+ )
self.updateLabel.setText("Connection error.")
return
@@ -147,13 +159,17 @@ class AboutWindow(QtWidgets.QWidget):
"Updates available",
f"There is a new update for NanoVNA-Saver available!\n"
f"Version {latest_version}\n\n"
- f'Press "About" to find the update.')
+ f'Press "About" to find the update.',
+ )
else:
QtWidgets.QMessageBox.information(
- self, "Updates available",
- "There is a new update for NanoVNA-Saver available!")
+ self,
+ "Updates available",
+ "There is a new update for NanoVNA-Saver available!",
+ )
self.updateLabel.setText(
- f'New version available.')
+ f'New version available.'
+ )
self.updateLabel.setOpenExternalLinks(True)
else:
# Probably don't show a message box, just update the screen?
@@ -161,5 +177,6 @@ class AboutWindow(QtWidgets.QWidget):
#
self.updateLabel.setText(
f"Last checked: "
- f"{strftime('%Y-%m-%d %H:%M:%S', localtime())}")
+ f"{strftime('%Y-%m-%d %H:%M:%S', localtime())}"
+ )
return
diff --git a/src/NanoVNASaver/Windows/AnalysisWindow.py b/src/NanoVNASaver/Windows/AnalysisWindow.py
index 906dc47..b467a0a 100644
--- a/src/NanoVNASaver/Windows/AnalysisWindow.py
+++ b/src/NanoVNASaver/Windows/AnalysisWindow.py
@@ -29,7 +29,9 @@ from NanoVNASaver.Analysis.HighPassAnalysis import HighPassAnalysis
from NanoVNASaver.Analysis.LowPassAnalysis import LowPassAnalysis
from NanoVNASaver.Analysis.PeakSearchAnalysis import PeakSearchAnalysis
from NanoVNASaver.Analysis.ResonanceAnalysis import ResonanceAnalysis
-from NanoVNASaver.Analysis.SimplePeakSearchAnalysis import SimplePeakSearchAnalysis
+from NanoVNASaver.Analysis.SimplePeakSearchAnalysis import (
+ SimplePeakSearchAnalysis,
+)
from NanoVNASaver.Analysis.VSWRAnalysis import VSWRAnalysis
from NanoVNASaver.Windows.Defaults import make_scrollable
@@ -55,25 +57,28 @@ class AnalysisWindow(QtWidgets.QWidget):
select_analysis_box = QtWidgets.QGroupBox("Select analysis")
select_analysis_layout = QtWidgets.QFormLayout(select_analysis_box)
self.analysis_list = QtWidgets.QComboBox()
+ self.analysis_list.addItem("Low-pass filter", LowPassAnalysis(self.app))
self.analysis_list.addItem(
- "Low-pass filter", LowPassAnalysis(self.app))
+ "Band-pass filter", BandPassAnalysis(self.app)
+ )
self.analysis_list.addItem(
- "Band-pass filter", BandPassAnalysis(self.app))
+ "High-pass filter", HighPassAnalysis(self.app)
+ )
self.analysis_list.addItem(
- "High-pass filter", HighPassAnalysis(self.app))
+ "Band-stop filter", BandStopAnalysis(self.app)
+ )
self.analysis_list.addItem(
- "Band-stop filter", BandStopAnalysis(self.app))
- self.analysis_list.addItem(
- "Simple Peak search", SimplePeakSearchAnalysis(self.app))
- self.analysis_list.addItem(
- "Peak search", PeakSearchAnalysis(self.app))
+ "Simple Peak search", SimplePeakSearchAnalysis(self.app)
+ )
+ self.analysis_list.addItem("Peak search", PeakSearchAnalysis(self.app))
self.analysis_list.addItem("VSWR analysis", VSWRAnalysis(self.app))
self.analysis_list.addItem(
- "Resonance analysis", ResonanceAnalysis(self.app))
+ "Resonance analysis", ResonanceAnalysis(self.app)
+ )
+ self.analysis_list.addItem("HWEF analysis", EFHWAnalysis(self.app))
self.analysis_list.addItem(
- "HWEF analysis", EFHWAnalysis(self.app))
- self.analysis_list.addItem(
- "MagLoop analysis", MagLoopAnalysis(self.app))
+ "MagLoop analysis", MagLoopAnalysis(self.app)
+ )
select_analysis_layout.addRow("Analysis type", self.analysis_list)
self.analysis_list.currentIndexChanged.connect(self.updateSelection)
@@ -82,15 +87,18 @@ class AnalysisWindow(QtWidgets.QWidget):
select_analysis_layout.addRow(btn_run_analysis)
self.checkbox_run_automatically = QtWidgets.QCheckBox(
- "Run automatically")
+ "Run automatically"
+ )
self.checkbox_run_automatically.stateChanged.connect(
- self.toggleAutomaticRun)
+ self.toggleAutomaticRun
+ )
select_analysis_layout.addRow(self.checkbox_run_automatically)
analysis_box = QtWidgets.QGroupBox("Analysis")
analysis_box.setSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding,
- QtWidgets.QSizePolicy.MinimumExpanding)
+ QtWidgets.QSizePolicy.MinimumExpanding,
+ )
self.analysis_layout = QtWidgets.QVBoxLayout(analysis_box)
self.analysis_layout.setContentsMargins(0, 0, 0, 0)
@@ -110,7 +118,8 @@ class AnalysisWindow(QtWidgets.QWidget):
if old_item is not None:
old_widget = self.analysis_layout.itemAt(0).widget()
self.analysis_layout.replaceWidget(
- old_widget, self.analysis.widget())
+ old_widget, self.analysis.widget()
+ )
old_widget.hide()
else:
self.analysis_layout.addWidget(self.analysis.widget())
diff --git a/src/NanoVNASaver/Windows/Bands.py b/src/NanoVNASaver/Windows/Bands.py
index c878842..fb4ded1 100644
--- a/src/NanoVNASaver/Windows/Bands.py
+++ b/src/NanoVNASaver/Windows/Bands.py
@@ -66,6 +66,7 @@ class BandsWindow(QtWidgets.QWidget):
QtWidgets.QMessageBox.Warning,
"Confirm reset",
"Are you sure you want to reset the bands to default?",
- QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Cancel).exec()
+ QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Cancel,
+ ).exec()
if confirm == QtWidgets.QMessageBox.Yes:
self.app.bands.resetBands()
diff --git a/src/NanoVNASaver/Windows/CalibrationSettings.py b/src/NanoVNASaver/Windows/CalibrationSettings.py
index bcde4ab..431b923 100644
--- a/src/NanoVNASaver/Windows/CalibrationSettings.py
+++ b/src/NanoVNASaver/Windows/CalibrationSettings.py
@@ -50,8 +50,10 @@ class CalibrationWindow(QtWidgets.QWidget):
self.setMinimumWidth(450)
self.setWindowTitle("Calibration")
self.setWindowIcon(self.app.icon)
- self.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding,
- QtWidgets.QSizePolicy.MinimumExpanding)
+ self.setSizePolicy(
+ QtWidgets.QSizePolicy.MinimumExpanding,
+ QtWidgets.QSizePolicy.MinimumExpanding,
+ )
QtWidgets.QShortcut(QtCore.Qt.Key_Escape, self, self.hide)
@@ -67,28 +69,38 @@ 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_group
+ )
cal_btn = {}
self.cal_label = {}
- for label_name in ("short", "open", "load",
- "through", "thrurefl", "isolation"):
+ for label_name in (
+ "short",
+ "open",
+ "load",
+ "through",
+ "thrurefl",
+ "isolation",
+ ):
self.cal_label[label_name] = QtWidgets.QLabel("Uncalibrated")
- cal_btn[label_name] = QtWidgets.QPushButton(
- label_name.capitalize())
+ 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))
+ partial(self.manual_save, label_name)
+ )
calibration_control_layout.addRow(
- cal_btn[label_name], self.cal_label[label_name])
+ cal_btn[label_name], self.cal_label[label_name]
+ )
self.input_offset_delay = QtWidgets.QDoubleSpinBox()
self.input_offset_delay.setMinimumHeight(20)
@@ -100,7 +112,8 @@ class CalibrationWindow(QtWidgets.QWidget):
calibration_control_layout.addRow(QtWidgets.QLabel(""))
calibration_control_layout.addRow(
- "Offset delay", self.input_offset_delay)
+ "Offset delay", self.input_offset_delay
+ )
self.btn_automatic = QtWidgets.QPushButton("Calibration assistant")
self.btn_automatic.setMinimumHeight(20)
@@ -126,7 +139,8 @@ class CalibrationWindow(QtWidgets.QWidget):
calibration_notes_group = QtWidgets.QGroupBox("Notes")
calibration_notes_layout = QtWidgets.QVBoxLayout(
- calibration_notes_group)
+ calibration_notes_group
+ )
self.notes_textedit = QtWidgets.QPlainTextEdit()
calibration_notes_layout.addWidget(self.notes_textedit)
@@ -225,7 +239,8 @@ class CalibrationWindow(QtWidgets.QWidget):
self.cal_standard_save_box = QtWidgets.QGroupBox("Saved settings")
cal_standard_save_layout = QtWidgets.QVBoxLayout(
- self.cal_standard_save_box)
+ self.cal_standard_save_box
+ )
self.cal_standard_save_box.setDisabled(True)
self.cal_standard_save_selector = QtWidgets.QComboBox()
@@ -253,7 +268,8 @@ class CalibrationWindow(QtWidgets.QWidget):
def checkExpertUser(self):
if not self.app.settings.value("ExpertCalibrationUser", False, bool):
response = QtWidgets.QMessageBox.question(
- self, "Are you sure?",
+ self,
+ "Are you sure?",
(
"Use of the manual calibration buttons is non-intuitive,"
" and primarily suited for users with very specialized"
@@ -267,7 +283,8 @@ class CalibrationWindow(QtWidgets.QWidget):
" Yes."
),
QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Cancel,
- QtWidgets.QMessageBox.Cancel)
+ QtWidgets.QMessageBox.Cancel,
+ )
if response == QtWidgets.QMessageBox.Yes:
self.app.settings.setValue("ExpertCalibrationUser", True)
@@ -280,8 +297,7 @@ class CalibrationWindow(QtWidgets.QWidget):
self.app.calibration.insert(name, self.app.data.s21)
else:
self.app.calibration.insert(name, self.app.data.s11)
- self.cal_label[name].setText(
- _format_cal_label(len(self.app.data.s11)))
+ self.cal_label[name].setText(_format_cal_label(len(self.app.data.s11)))
def manual_save(self, name: str):
if self.checkExpertUser():
@@ -289,8 +305,7 @@ 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")
@@ -300,15 +315,15 @@ 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:
# New cal standard
# Get a name
name, selected = QtWidgets.QInputDialog.getText(
- self, "Calibration standard name", "Enter name to save as")
+ self, "Calibration standard name", "Enter name to save as"
+ )
if not selected or not name:
return
write_num = num_standards
@@ -317,8 +332,7 @@ 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)
@@ -361,8 +375,7 @@ 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)))
@@ -376,7 +389,8 @@ class CalibrationWindow(QtWidgets.QWidget):
self.load_length.setText(str(self.app.settings.value("LoadDelay", 0)))
self.through_length.setText(
- str(self.app.settings.value("ThroughDelay", 0)))
+ str(self.app.settings.value("ThroughDelay", 0))
+ )
self.app.settings.endArray()
@@ -385,8 +399,7 @@ 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)
@@ -449,7 +462,8 @@ class CalibrationWindow(QtWidgets.QWidget):
self.app.settings.endArray()
self.app.settings.beginWriteArray(
- "CalibrationStandards", len(names))
+ "CalibrationStandards", len(names)
+ )
for i, name in enumerate(names):
self.app.settings.setArrayIndex(i)
self.app.settings.setValue("Name", name)
@@ -488,8 +502,11 @@ class CalibrationWindow(QtWidgets.QWidget):
if len(self.app.worker.rawData11) > 0:
# There's raw data, so we can get corrected data
logger.debug("Saving and displaying raw data.")
- self.app.saveData(self.app.worker.rawData11,
- self.app.worker.rawData21, self.app.sweepSource)
+ self.app.saveData(
+ self.app.worker.rawData11,
+ self.app.worker.rawData21,
+ self.app.sweepSource,
+ )
self.app.worker.signals.updated.emit()
def setOffsetDelay(self, value: float):
@@ -498,12 +515,18 @@ class CalibrationWindow(QtWidgets.QWidget):
if len(self.app.worker.rawData11) > 0:
# There's raw data, so we can get corrected data
logger.debug("Applying new offset to existing sweep data.")
- 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.saveData(
+ self.app.worker.data11,
+ self.app.worker.data21,
+ self.app.sweepSource,
+ )
self.app.worker.signals.updated.emit()
def calculate(self):
@@ -511,7 +534,8 @@ class CalibrationWindow(QtWidgets.QWidget):
if self.app.sweep_control.btn_stop.isEnabled():
self.app.showError(
"Unable to apply calibration while a sweep is running."
- " Please stop the sweep and try again.")
+ " Please stop the sweep and try again."
+ )
return
cal_element.short_is_ideal = True
@@ -528,63 +552,85 @@ class CalibrationWindow(QtWidgets.QWidget):
# We are using custom calibration standards
- cal_element.short_l0 = getFloatValue(
- self.short_l0_input.text()) / 1.0e12
- cal_element.short_l1 = getFloatValue(
- self.short_l1_input.text()) / 1.0e24
- cal_element.short_l2 = getFloatValue(
- self.short_l2_input.text()) / 1.0e33
- cal_element.short_l3 = getFloatValue(
- self.short_l3_input.text()) / 1.0e42
- cal_element.short_length = getFloatValue(
- self.short_length.text()) / 1.0e12
+ cal_element.short_l0 = (
+ getFloatValue(self.short_l0_input.text()) / 1.0e12
+ )
+ cal_element.short_l1 = (
+ getFloatValue(self.short_l1_input.text()) / 1.0e24
+ )
+ cal_element.short_l2 = (
+ getFloatValue(self.short_l2_input.text()) / 1.0e33
+ )
+ cal_element.short_l3 = (
+ getFloatValue(self.short_l3_input.text()) / 1.0e42
+ )
+ cal_element.short_length = (
+ getFloatValue(self.short_length.text()) / 1.0e12
+ )
- cal_element.open_c0 = getFloatValue(
- self.open_c0_input.text()) / 1.e15
- cal_element.open_c1 = getFloatValue(
- self.open_c1_input.text()) / 1.e27
- cal_element.open_c2 = getFloatValue(
- self.open_c2_input.text()) / 1.0e36
- cal_element.open_c3 = getFloatValue(
- self.open_c3_input.text()) / 1.0e45
- cal_element.openLength = getFloatValue(
- self.open_length.text()) / 1.0e12
+ cal_element.open_c0 = (
+ getFloatValue(self.open_c0_input.text()) / 1.0e15
+ )
+ cal_element.open_c1 = (
+ getFloatValue(self.open_c1_input.text()) / 1.0e27
+ )
+ cal_element.open_c2 = (
+ getFloatValue(self.open_c2_input.text()) / 1.0e36
+ )
+ cal_element.open_c3 = (
+ getFloatValue(self.open_c3_input.text()) / 1.0e45
+ )
+ cal_element.openLength = (
+ getFloatValue(self.open_length.text()) / 1.0e12
+ )
- cal_element.load_r = getFloatValue(
- self.load_resistance.text())
- cal_element.load_l = getFloatValue(
- self.load_inductance.text()) / 1.0e12
- cal_element.load_c = getFloatValue(
- self.load_capacitance.text()) / 1.0e15
- cal_element.load_length = getFloatValue(
- self.load_length.text()) / 1.0e12
+ cal_element.load_r = getFloatValue(self.load_resistance.text())
+ cal_element.load_l = (
+ getFloatValue(self.load_inductance.text()) / 1.0e12
+ )
+ cal_element.load_c = (
+ getFloatValue(self.load_capacitance.text()) / 1.0e15
+ )
+ cal_element.load_length = (
+ getFloatValue(self.load_length.text()) / 1.0e12
+ )
- cal_element.through_length = getFloatValue(
- self.through_length.text()) / 1.0e12
+ cal_element.through_length = (
+ getFloatValue(self.through_length.text()) / 1.0e12
+ )
logger.debug("Attempting calibration calculation.")
try:
self.app.calibration.calc_corrections()
self.calibration_status_label.setText(
- _format_cal_label(self.app.calibration.size(),
- "Application calibration"))
+ _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.app.calibration.source
+ )
else:
self.calibration_source_label.setText(
- f"{self.app.calibration.source} (Standards: Custom)")
+ f"{self.app.calibration.source} (Standards: Custom)"
+ )
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.saveData(
+ self.app.worker.data11,
+ self.app.worker.data21,
+ self.app.sweepSource,
+ )
self.app.worker.signals.updated.emit()
except ValueError as e:
if logger.isEnabledFor(logging.DEBUG):
@@ -592,23 +638,29 @@ class CalibrationWindow(QtWidgets.QWidget):
# showError here hides the calibration window,
# so we need to pop up our own
QtWidgets.QMessageBox.warning(
- self, "Error applying calibration", str(e))
+ self, "Error applying calibration", str(e)
+ )
self.calibration_status_label.setText(
- "Applying calibration failed.")
+ "Applying calibration failed."
+ )
self.calibration_source_label.setText(self.app.calibration.source)
def loadCalibration(self):
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
- filter="Calibration Files (*.cal);;All files (*.*)")
+ filter="Calibration Files (*.cal);;All files (*.*)"
+ )
if filename:
self.app.calibration.load(filename)
if not self.app.calibration.isValid1Port():
return
for i, name in enumerate(
- ("short", "open", "load", "through", "isolation", "thrurefl")):
+ ("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()
@@ -633,8 +685,9 @@ class CalibrationWindow(QtWidgets.QWidget):
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)
@@ -648,7 +701,8 @@ class CalibrationWindow(QtWidgets.QWidget):
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.use_ideal_values.isChecked()
+ )
def automaticCalibration(self):
self.btn_automatic.setDisabled(True)
@@ -662,14 +716,15 @@ class CalibrationWindow(QtWidgets.QWidget):
"Before starting, ensure you have Open, Short and Load"
" standards available, and the cables you wish to have"
" calibrated with the device connected.
"
- "If you want a 2-port calibration, also have a \"through\""
+ 'If you want a 2-port calibration, also have a "through"'
" connector to hand.
"
"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.
"
"Once you are ready to proceed, press Ok."
),
- QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
+ QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel,
+ )
response = introduction.exec()
if response != QtWidgets.QMessageBox.Ok:
self.btn_automatic.setDisabled(False)
@@ -679,8 +734,10 @@ 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
@@ -689,8 +746,10 @@ 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
@@ -699,11 +758,12 @@ class CalibrationWindow(QtWidgets.QWidget):
QtWidgets.QMessageBox.Information,
"Calibrate short",
(
- "Please connect the \"short\" standard to port 0 of the"
+ '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)
+ QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel,
+ )
response = short_step.exec()
if response != QtWidgets.QMessageBox.Ok:
@@ -719,7 +779,8 @@ class CalibrationWindow(QtWidgets.QWidget):
def automaticCalibrationStep(self):
if self.nextStep == -1:
self.app.worker.signals.finished.disconnect(
- self.automaticCalibrationStep)
+ self.automaticCalibrationStep
+ )
return
if self.nextStep == 0:
@@ -731,20 +792,22 @@ class CalibrationWindow(QtWidgets.QWidget):
QtWidgets.QMessageBox.Information,
"Calibrate open",
(
- "Please connect the \"open\" standard to port 0 of the"
+ '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)
+ QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel,
+ )
response = open_step.exec()
if response != QtWidgets.QMessageBox.Ok:
self.nextStep = -1
self.btn_automatic.setDisabled(False)
self.app.worker.signals.finished.disconnect(
- self.automaticCalibrationStep)
+ self.automaticCalibrationStep
+ )
return
self.app.sweep_start()
return
@@ -757,18 +820,20 @@ class CalibrationWindow(QtWidgets.QWidget):
QtWidgets.QMessageBox.Information,
"Calibrate load",
(
- "Please connect the \"load\" standard to port 0 of the"
+ '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)
+ QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel,
+ )
response = load_step.exec()
if response != QtWidgets.QMessageBox.Ok:
self.btn_automatic.setDisabled(False)
self.nextStep = -1
self.app.worker.signals.finished.disconnect(
- self.automaticCalibrationStep)
+ self.automaticCalibrationStep
+ )
return
self.app.sweep_start()
return
@@ -784,45 +849,51 @@ class CalibrationWindow(QtWidgets.QWidget):
"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\""
+ ' press "Yes". To apply the 1-port calibration and stop,'
+ ' press "Apply"'
),
- QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Apply |
- QtWidgets.QMessageBox.Cancel)
+ QtWidgets.QMessageBox.Yes
+ | QtWidgets.QMessageBox.Apply
+ | QtWidgets.QMessageBox.Cancel,
+ )
response = continue_step.exec()
if response == QtWidgets.QMessageBox.Apply:
self.calculate()
self.nextStep = -1
self.app.worker.signals.finished.disconnect(
- self.automaticCalibrationStep)
+ 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.automaticCalibrationStep
+ )
return
isolation_step = QtWidgets.QMessageBox(
QtWidgets.QMessageBox.Information,
"Calibrate isolation",
(
- "Please connect the \"load\" standard to port 1 of the"
+ '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)
+ QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel,
+ )
response = isolation_step.exec()
if response != QtWidgets.QMessageBox.Ok:
self.btn_automatic.setDisabled(False)
self.nextStep = -1
self.app.worker.signals.finished.disconnect(
- self.automaticCalibrationStep)
+ self.automaticCalibrationStep
+ )
return
self.app.sweep_start()
return
@@ -835,18 +906,20 @@ class CalibrationWindow(QtWidgets.QWidget):
QtWidgets.QMessageBox.Information,
"Calibrate through",
(
- "Please connect the \"through\" standard between"
+ '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)
+ QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel,
+ )
response = through_step.exec()
if response != QtWidgets.QMessageBox.Ok:
self.btn_automatic.setDisabled(False)
self.nextStep = -1
self.app.worker.signals.finished.disconnect(
- self.automaticCalibrationStep)
+ self.automaticCalibrationStep
+ )
return
self.app.sweep_start()
return
@@ -860,21 +933,24 @@ class CalibrationWindow(QtWidgets.QWidget):
"Calibrate complete",
(
"The calibration process is now complete. Press"
- " \"Apply\" to apply the calibration parameters."
+ ' "Apply" to apply the calibration parameters.'
),
- QtWidgets.QMessageBox.Apply | QtWidgets.QMessageBox.Cancel)
+ QtWidgets.QMessageBox.Apply | QtWidgets.QMessageBox.Cancel,
+ )
response = apply_step.exec()
if response != QtWidgets.QMessageBox.Apply:
self.btn_automatic.setDisabled(False)
self.nextStep = -1
self.app.worker.signals.finished.disconnect(
- self.automaticCalibrationStep)
+ self.automaticCalibrationStep
+ )
return
self.calculate()
self.btn_automatic.setDisabled(False)
self.nextStep = -1
self.app.worker.signals.finished.disconnect(
- self.automaticCalibrationStep)
+ self.automaticCalibrationStep
+ )
return
diff --git a/src/NanoVNASaver/Windows/Defaults.py b/src/NanoVNASaver/Windows/Defaults.py
index 9528a96..2862f00 100644
--- a/src/NanoVNASaver/Windows/Defaults.py
+++ b/src/NanoVNASaver/Windows/Defaults.py
@@ -23,7 +23,9 @@ from PyQt5 import QtWidgets
logger = logging.getLogger(__name__)
-def make_scrollable(window: QtWidgets.QWidget, layout: QtWidgets.QLayout) -> None:
+def make_scrollable(
+ window: QtWidgets.QWidget, layout: QtWidgets.QLayout
+) -> None:
area = QtWidgets.QScrollArea()
area.setWidgetResizable(True)
outer = QtWidgets.QVBoxLayout()
diff --git a/src/NanoVNASaver/Windows/DeviceSettings.py b/src/NanoVNASaver/Windows/DeviceSettings.py
index cd20df6..4b0b126 100644
--- a/src/NanoVNASaver/Windows/DeviceSettings.py
+++ b/src/NanoVNASaver/Windows/DeviceSettings.py
@@ -65,9 +65,11 @@ class DeviceSettingsWindow(QtWidgets.QWidget):
settings_layout = QtWidgets.QFormLayout(settings_box)
self.chkValidateInputData = QtWidgets.QCheckBox(
- "Validate received data")
+ "Validate received data"
+ )
validate_input = self.app.settings.value(
- "SerialInputValidation", False, bool)
+ "SerialInputValidation", False, bool
+ )
self.chkValidateInputData.setChecked(validate_input)
self.chkValidateInputData.stateChanged.connect(self.updateValidation)
settings_layout.addRow("Validation", self.chkValidateInputData)
@@ -100,12 +102,10 @@ class DeviceSettingsWindow(QtWidgets.QWidget):
settings_layout.addRow(form_layout)
def _set_datapoint_index(self, dpoints: int):
- self.datapoints.setCurrentIndex(
- self.datapoints.findText(str(dpoints)))
+ self.datapoints.setCurrentIndex(self.datapoints.findText(str(dpoints)))
def _set_bandwidth_index(self, bw: int):
- self.bandwidth.setCurrentIndex(
- self.bandwidth.findText(str(bw)))
+ self.bandwidth.setCurrentIndex(self.bandwidth.findText(str(bw)))
def show(self):
super().show()
@@ -120,10 +120,10 @@ class DeviceSettingsWindow(QtWidgets.QWidget):
self.btnCaptureScreenshot.setDisabled(True)
return
- self.label["status"].setText(
- f"Connected to {self.app.vna.name}.")
+ self.label["status"].setText(f"Connected to {self.app.vna.name}.")
self.label["firmware"].setText(
- f"{self.app.vna.name} v{self.app.vna.version}")
+ f"{self.app.vna.name} v{self.app.vna.version}"
+ )
if self.app.worker.running:
self.label["calibration"].setText("(Sweep running)")
else:
diff --git a/src/NanoVNASaver/Windows/DisplaySettings.py b/src/NanoVNASaver/Windows/DisplaySettings.py
index 36c1daf..fdfd1c9 100644
--- a/src/NanoVNASaver/Windows/DisplaySettings.py
+++ b/src/NanoVNASaver/Windows/DisplaySettings.py
@@ -22,8 +22,7 @@ from typing import List
from PyQt5 import QtWidgets, QtCore, QtGui
from NanoVNASaver import Defaults
-from NanoVNASaver.Charts.Chart import (
- Chart, ChartColors)
+from NanoVNASaver.Charts.Chart import Chart, ChartColors
from NanoVNASaver.Windows.Bands import BandsWindow
from NanoVNASaver.Windows.Defaults import make_scrollable
from NanoVNASaver.Windows.MarkerSettings import MarkerSettingsWindow
@@ -60,20 +59,24 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
self.returnloss_group.addButton(self.returnloss_is_negative)
display_options_layout.addRow(
- "Return loss is:", self.returnloss_is_negative)
+ "Return loss is:", self.returnloss_is_negative
+ )
display_options_layout.addRow("", self.returnloss_is_positive)
self.returnloss_is_positive.setChecked(
- Defaults.cfg.chart.returnloss_is_positive)
+ Defaults.cfg.chart.returnloss_is_positive
+ )
self.returnloss_is_negative.setChecked(
- not Defaults.cfg.chart.returnloss_is_positive)
+ not Defaults.cfg.chart.returnloss_is_positive
+ )
self.returnloss_is_positive.toggled.connect(self.changeReturnLoss)
self.changeReturnLoss()
self.show_lines_option = QtWidgets.QCheckBox("Show lines")
show_lines_label = QtWidgets.QLabel(
- "Displays a thin line between data points")
+ "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)
@@ -106,8 +109,7 @@ 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)
@@ -122,25 +124,31 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
display_options_layout.addRow("Marker size", self.markerSizeInput)
self.show_marker_number_option = QtWidgets.QCheckBox(
- "Show marker numbers")
+ "Show marker numbers"
+ )
show_marker_number_label = QtWidgets.QLabel(
- "Displays the marker number next to the marker")
+ "Displays the marker number next to the marker"
+ )
self.show_marker_number_option.stateChanged.connect(
- self.changeShowMarkerNumber)
+ self.changeShowMarkerNumber
+ )
display_options_layout.addRow(
- self.show_marker_number_option, show_marker_number_label)
+ 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)
+ "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.filled_marker_option, filled_marker_label
+ )
self.marker_tip_group = QtWidgets.QButtonGroup()
self.marker_at_center = QtWidgets.QRadioButton(
- "At the center of the marker")
+ "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)
@@ -183,11 +191,12 @@ 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()))
+ lambda: self.setShowBands(self.show_bands.isChecked())
+ )
bands_layout.addRow(self.show_bands)
bands_layout.addRow(
- "Chart bands",
- self.color_picker("BandsColor", "bands"))
+ "Chart bands", self.color_picker("BandsColor", "bands")
+ )
self.btn_manage_bands = QtWidgets.QPushButton("Manage bands")
self.btn_manage_bands.setMinimumHeight(20)
@@ -201,16 +210,19 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
vswr_marker_layout = QtWidgets.QFormLayout(vswr_marker_box)
self.vswrMarkers: List[float] = self.app.settings.value(
- "VSWRMarkers", [], float)
+ "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])
+ 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)
@@ -281,7 +293,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
else:
chart00_selection.setCurrentText("S11 Smith Chart")
chart00_selection.currentTextChanged.connect(
- lambda: self.changeChart(0, 0, chart00_selection.currentText()))
+ lambda: self.changeChart(0, 0, chart00_selection.currentText())
+ )
charts_layout.addWidget(chart00_selection, 0, 0)
chart01_selection = QtWidgets.QComboBox()
@@ -293,7 +306,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
else:
chart01_selection.setCurrentText("S11 Return Loss")
chart01_selection.currentTextChanged.connect(
- lambda: self.changeChart(0, 1, chart01_selection.currentText()))
+ lambda: self.changeChart(0, 1, chart01_selection.currentText())
+ )
charts_layout.addWidget(chart01_selection, 0, 1)
chart02_selection = QtWidgets.QComboBox()
@@ -305,7 +319,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
else:
chart02_selection.setCurrentText("None")
chart02_selection.currentTextChanged.connect(
- lambda: self.changeChart(0, 2, chart02_selection.currentText()))
+ lambda: self.changeChart(0, 2, chart02_selection.currentText())
+ )
charts_layout.addWidget(chart02_selection, 0, 2)
chart10_selection = QtWidgets.QComboBox()
@@ -317,7 +332,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
else:
chart10_selection.setCurrentText("S21 Polar Plot")
chart10_selection.currentTextChanged.connect(
- lambda: self.changeChart(1, 0, chart10_selection.currentText()))
+ lambda: self.changeChart(1, 0, chart10_selection.currentText())
+ )
charts_layout.addWidget(chart10_selection, 1, 0)
chart11_selection = QtWidgets.QComboBox()
@@ -329,7 +345,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
else:
chart11_selection.setCurrentText("S21 Gain")
chart11_selection.currentTextChanged.connect(
- lambda: self.changeChart(1, 1, chart11_selection.currentText()))
+ lambda: self.changeChart(1, 1, chart11_selection.currentText())
+ )
charts_layout.addWidget(chart11_selection, 1, 1)
chart12_selection = QtWidgets.QComboBox()
@@ -341,7 +358,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
else:
chart12_selection.setCurrentText("None")
chart12_selection.currentTextChanged.connect(
- lambda: self.changeChart(1, 2, chart12_selection.currentText()))
+ lambda: self.changeChart(1, 2, chart12_selection.currentText())
+ )
charts_layout.addWidget(chart12_selection, 1, 2)
self.changeChart(0, 0, chart00_selection.currentText())
@@ -353,30 +371,36 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
chart_colors = ChartColors()
Chart.color.background = self.app.settings.value(
- "BackgroundColor", defaultValue=chart_colors.background,
- type=QtGui.QColor)
+ "BackgroundColor",
+ defaultValue=chart_colors.background,
+ type=QtGui.QColor,
+ )
Chart.color.foreground = self.app.settings.value(
- "ForegroundColor", defaultValue=chart_colors.foreground,
- type=QtGui.QColor)
+ "ForegroundColor",
+ defaultValue=chart_colors.foreground,
+ type=QtGui.QColor,
+ )
Chart.color.text = self.app.settings.value(
- "TextColor", defaultValue=chart_colors.text,
- type=QtGui.QColor)
+ "TextColor", defaultValue=chart_colors.text, type=QtGui.QColor
+ )
self.bandsColor = self.app.settings.value(
- "BandsColor", defaultValue=chart_colors.bands,
- type=QtGui.QColor)
+ "BandsColor", defaultValue=chart_colors.bands, type=QtGui.QColor
+ )
self.app.bands.color = Chart.color.bands
Chart.color.swr = self.app.settings.value(
- "VSWRColor", defaultValue=chart_colors.swr,
- type=QtGui.QColor)
+ "VSWRColor", defaultValue=chart_colors.swr, type=QtGui.QColor
+ )
self.dark_mode_option.setChecked(Defaults.cfg.gui.dark_mode)
self.show_lines_option.setChecked(Defaults.cfg.chart.show_lines)
self.show_marker_number_option.setChecked(
- Defaults.cfg.chart.marker_label)
+ Defaults.cfg.chart.marker_label
+ )
self.filled_marker_option.setChecked(Defaults.cfg.chart.marker_filled)
- if self.app.settings.value("UseCustomColors",
- defaultValue=False, type=bool):
+ if self.app.settings.value(
+ "UseCustomColors", defaultValue=False, type=bool
+ ):
self.dark_mode_option.setDisabled(True)
self.dark_mode_option.setChecked(False)
self.use_custom_colors.setChecked(True)
@@ -395,20 +419,23 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
def trace_colors(self, layout: QtWidgets.QLayout):
for setting, name, attr in (
- ('SweepColor', 'Sweep color', 'sweep'),
- ('SecondarySweepColor', 'Second sweep color', 'sweep_secondary'),
- ('ReferenceColor', 'Reference color', 'reference'),
- ('SecondaryReferenceColor',
- 'Second reference color', 'reference_secondary'),
+ ("SweepColor", "Sweep color", "sweep"),
+ ("SecondarySweepColor", "Second sweep color", "sweep_secondary"),
+ ("ReferenceColor", "Reference color", "reference"),
+ (
+ "SecondaryReferenceColor",
+ "Second reference color",
+ "reference_secondary",
+ ),
):
cp = self.color_picker(setting, attr)
layout.addRow(name, cp)
def custom_colors(self, layout: QtWidgets.QLayout):
for setting, name, attr in (
- ('BackgroundColor', 'Chart background', 'background'),
- ('ForegroundColor', 'Chart foreground', 'foreground'),
- ('TextColor', 'Chart text', 'text'),
+ ("BackgroundColor", "Chart background", "background"),
+ ("ForegroundColor", "Chart foreground", "foreground"),
+ ("TextColor", "Chart text", "text"),
):
cp = self.color_picker(setting, attr)
layout.addRow(name, cp)
@@ -419,7 +446,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
cp.setMinimumHeight(20)
default = getattr(Chart.color, attr)
color = self.app.settings.value(
- setting, defaultValue=default, type=QtGui.QColor)
+ setting, defaultValue=default, type=QtGui.QColor
+ )
setattr(Chart.color, attr, color)
self.callback_params[cp] = (setting, attr)
cp.clicked.connect(self.setColor)
@@ -466,17 +494,18 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
def changeShowMarkerNumber(self):
Defaults.cfg.chart.marker_label = bool(
- self.show_marker_number_option.isChecked())
+ self.show_marker_number_option.isChecked()
+ )
self.updateCharts()
def changeFilledMarkers(self):
Defaults.cfg.chart.marker_filled = bool(
- self.filled_marker_option.isChecked())
+ self.filled_marker_option.isChecked()
+ )
self.updateCharts()
def changeMarkerAtTip(self):
- Defaults.cfg.chart.marker_at_tip = bool(
- self.marker_at_tip.isChecked())
+ Defaults.cfg.chart.marker_at_tip = bool(self.marker_at_tip.isChecked())
self.updateCharts()
def changePointSize(self, size: int):
@@ -521,7 +550,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
color = getattr(Chart.color, attr)
color = QtWidgets.QColorDialog.getColor(
- color, options=QtWidgets.QColorDialog.ShowAlphaChannel)
+ color, options=QtWidgets.QColorDialog.ShowAlphaChannel
+ )
if not color.isValid():
logger.info("Invalid color")
@@ -566,7 +596,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)
+ Marker.count() - 1, label, layout
+ )
self.btn_remove_marker.setDisabled(False)
if Marker.count() >= 2:
@@ -594,8 +625,12 @@ 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":
@@ -612,7 +647,8 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
value = float(value_str)
self.vswrMarkers.remove(value)
self.vswr_marker_dropdown.removeItem(
- self.vswr_marker_dropdown.currentIndex())
+ self.vswr_marker_dropdown.currentIndex()
+ )
if self.vswr_marker_dropdown.count() == 0:
self.vswr_marker_dropdown.addItem("None")
self.app.settings.remove("VSWRMarkers")
diff --git a/src/NanoVNASaver/Windows/Files.py b/src/NanoVNASaver/Windows/Files.py
index 8586796..9a0627b 100644
--- a/src/NanoVNASaver/Windows/Files.py
+++ b/src/NanoVNASaver/Windows/Files.py
@@ -68,27 +68,32 @@ class FilesWindow(QtWidgets.QWidget):
btn_open_file_window = QtWidgets.QPushButton("Files ...")
btn_open_file_window.clicked.connect(
- lambda: self.app.display_window("file"))
+ lambda: self.app.display_window("file")
+ )
def exportFile(self, nr_params: int = 1):
if len(self.app.data.s11) == 0:
QtWidgets.QMessageBox.warning(
- self, "No data to save", "There is no data to save.")
+ self, "No data to save", "There is no data to save."
+ )
return
if nr_params > 2 and len(self.app.data.s21) == 0:
QtWidgets.QMessageBox.warning(
- self, "No S21 data to save", "There is no S21 data to save.")
+ self, "No S21 data to save", "There is no S21 data to save."
+ )
return
filedialog = QtWidgets.QFileDialog(self)
if nr_params == 1:
filedialog.setDefaultSuffix("s1p")
filedialog.setNameFilter(
- "Touchstone 1-Port Files (*.s1p);;All files (*.*)")
+ "Touchstone 1-Port Files (*.s1p);;All files (*.*)"
+ )
else:
filedialog.setDefaultSuffix("s2p")
filedialog.setNameFilter(
- "Touchstone 2-Port Files (*.s2p);;All files (*.*)")
+ "Touchstone 2-Port Files (*.s2p);;All files (*.*)"
+ )
filedialog.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
selected = filedialog.exec()
if not selected:
@@ -113,7 +118,8 @@ class FilesWindow(QtWidgets.QWidget):
def loadReferenceFile(self):
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
- filter="Touchstone Files (*.s1p *.s2p);;All files (*.*)")
+ filter="Touchstone Files (*.s1p *.s2p);;All files (*.*)"
+ )
if filename != "":
self.app.resetReference()
t = Touchstone(filename)
@@ -122,7 +128,8 @@ class FilesWindow(QtWidgets.QWidget):
def loadSweepFile(self):
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
- filter="Touchstone Files (*.s1p *.s2p);;All files (*.*)")
+ filter="Touchstone Files (*.s1p *.s2p);;All files (*.*)"
+ )
if filename != "":
self.app.data.s11 = []
self.app.data.s21 = []
diff --git a/src/NanoVNASaver/Windows/MarkerSettings.py b/src/NanoVNASaver/Windows/MarkerSettings.py
index 2912a7f..ff6bcd4 100644
--- a/src/NanoVNASaver/Windows/MarkerSettings.py
+++ b/src/NanoVNASaver/Windows/MarkerSettings.py
@@ -28,12 +28,16 @@ logger = logging.getLogger(__name__)
class MarkerSettingsWindow(QtWidgets.QWidget):
- exampleData11 = [Datapoint(123000000, 0.89, -0.11),
- Datapoint(123500000, 0.9, -0.1),
- Datapoint(124000000, 0.91, -0.95)]
- exampleData21 = [Datapoint(123000000, -0.25, 0.49),
- Datapoint(123456000, -0.3, 0.5),
- Datapoint(124000000, -0.2, 0.5)]
+ exampleData11 = [
+ Datapoint(123000000, 0.89, -0.11),
+ Datapoint(123500000, 0.9, -0.1),
+ Datapoint(124000000, 0.91, -0.95),
+ ]
+ exampleData21 = [
+ Datapoint(123000000, -0.25, 0.49),
+ Datapoint(123456000, -0.3, 0.5),
+ Datapoint(124000000, -0.2, 0.5),
+ ]
def __init__(self, app: QtWidgets.QWidget):
super().__init__()
@@ -50,10 +54,10 @@ class MarkerSettingsWindow(QtWidgets.QWidget):
settings_group_box = QtWidgets.QGroupBox("Settings")
settings_group_box_layout = QtWidgets.QFormLayout(settings_group_box)
- self.checkboxColouredMarker = QtWidgets.QCheckBox(
- "Colored marker name")
+ self.checkboxColouredMarker = QtWidgets.QCheckBox("Colored marker name")
self.checkboxColouredMarker.setChecked(
- self.app.settings.value("ColoredMarkerNames", True, bool))
+ self.app.settings.value("ColoredMarkerNames", True, bool)
+ )
self.checkboxColouredMarker.stateChanged.connect(self.updateMarker)
settings_group_box_layout.addRow(self.checkboxColouredMarker)
@@ -103,7 +107,8 @@ class MarkerSettingsWindow(QtWidgets.QWidget):
def updateMarker(self):
self.exampleMarker.setFrequency(123456000)
self.exampleMarker.setColoredText(
- self.checkboxColouredMarker.isChecked())
+ self.checkboxColouredMarker.isChecked()
+ )
self.exampleMarker.setFieldSelection(self.currentFieldSelection)
self.exampleMarker.findLocation(self.exampleData11)
self.exampleMarker.resetLabels()
@@ -125,8 +130,11 @@ class MarkerSettingsWindow(QtWidgets.QWidget):
self.savedFieldSelection = self.currentFieldSelection[:]
self.app.settings.setValue("MarkerFields", self.savedFieldSelection)
self.app.settings.setValue(
- "ColoredMarkerNames", self.checkboxColouredMarker.isChecked())
- for m in self.app.markers + [self.app.delta_marker, ]:
+ "ColoredMarkerNames", self.checkboxColouredMarker.isChecked()
+ )
+ for m in self.app.markers + [
+ self.app.delta_marker,
+ ]:
m.setFieldSelection(self.savedFieldSelection)
m.setColoredText(self.checkboxColouredMarker.isChecked())
diff --git a/src/NanoVNASaver/Windows/Screenshot.py b/src/NanoVNASaver/Windows/Screenshot.py
index c967250..1ae20a2 100644
--- a/src/NanoVNASaver/Windows/Screenshot.py
+++ b/src/NanoVNASaver/Windows/Screenshot.py
@@ -61,25 +61,34 @@ class ScreenshotWindow(QtWidgets.QLabel):
self.pix.scaled(
self.size(),
QtCore.Qt.KeepAspectRatio,
- QtCore.Qt.FastTransformation))
+ QtCore.Qt.FastTransformation,
+ )
+ )
w, h = pixmap.width(), pixmap.height()
self.action_original_size.setText(
- "Original size (" + str(w) + "x" + str(h) + ")")
+ "Original size (" + str(w) + "x" + str(h) + ")"
+ )
self.action_2x_size.setText(
- "2x size (" + str(w * 2) + "x" + str(h * 2) + ")")
+ "2x size (" + str(w * 2) + "x" + str(h * 2) + ")"
+ )
self.action_3x_size.setText(
- "3x size (" + str(w * 3) + "x" + str(h * 3) + ")")
+ "3x size (" + str(w * 3) + "x" + str(h * 3) + ")"
+ )
self.action_4x_size.setText(
- "4x size (" + str(w * 4) + "x" + str(h * 4) + ")")
+ "4x size (" + str(w * 4) + "x" + str(h * 4) + ")"
+ )
self.action_5x_size.setText(
- "5x size (" + str(w * 5) + "x" + str(h * 5) + ")")
+ "5x size (" + str(w * 5) + "x" + str(h * 5) + ")"
+ )
def saveScreenshot(self):
if self.pix is not None:
logger.info("Saving screenshot to file...")
filename, _ = QtWidgets.QFileDialog.getSaveFileName(
- parent=self, caption="Save image",
- filter="PNG (*.png);;All files (*.*)")
+ parent=self,
+ caption="Save image",
+ filter="PNG (*.png);;All files (*.*)",
+ )
logger.debug("Filename: %s", filename)
if filename != "":
@@ -94,9 +103,13 @@ class ScreenshotWindow(QtWidgets.QLabel):
self.pix.scaled(
self.size(),
QtCore.Qt.KeepAspectRatio,
- QtCore.Qt.FastTransformation))
+ QtCore.Qt.FastTransformation,
+ )
+ )
def setScale(self, scale):
- width, height = (self.pix.size().width() * scale,
- self.pix.size().height() * scale)
+ width, height = (
+ self.pix.size().width() * scale,
+ self.pix.size().height() * scale,
+ )
self.resize(width, height)
diff --git a/src/NanoVNASaver/Windows/SweepSettings.py b/src/NanoVNASaver/Windows/SweepSettings.py
index 699a408..32a611e 100644
--- a/src/NanoVNASaver/Windows/SweepSettings.py
+++ b/src/NanoVNASaver/Windows/SweepSettings.py
@@ -21,7 +21,8 @@ from functools import partial
from PyQt5 import QtWidgets, QtCore
from NanoVNASaver.Formatting import (
- format_frequency_short, format_frequency_sweep,
+ format_frequency_short,
+ format_frequency_sweep,
)
from NanoVNASaver.Settings.Sweep import SweepMode
from NanoVNASaver.Windows.Defaults import make_scrollable
@@ -59,11 +60,12 @@ class SweepSettingsWindow(QtWidgets.QWidget):
input_title = QtWidgets.QLineEdit(self.app.sweep.properties.name)
input_title.setMinimumHeight(20)
input_title.editingFinished.connect(
- lambda: self.update_title(input_title.text()))
+ lambda: self.update_title(input_title.text())
+ )
layout.addRow(input_title)
return box
- def settings_box(self) -> 'QtWidgets.QWidget':
+ def settings_box(self) -> "QtWidgets.QWidget":
box = QtWidgets.QGroupBox("Settings")
layout = QtWidgets.QFormLayout(box)
@@ -73,25 +75,29 @@ class SweepSettingsWindow(QtWidgets.QWidget):
radio_button = QtWidgets.QRadioButton("Single sweep")
radio_button.setMinimumHeight(20)
radio_button.setChecked(
- self.app.sweep.properties.mode == SweepMode.SINGLE)
- radio_button.clicked.connect(
- lambda: self.update_mode(SweepMode.SINGLE))
+ self.app.sweep.properties.mode == SweepMode.SINGLE
+ )
+ radio_button.clicked.connect(lambda: self.update_mode(SweepMode.SINGLE))
sweep_btn_layout.addWidget(radio_button)
radio_button = QtWidgets.QRadioButton("Continous sweep")
radio_button.setMinimumHeight(20)
radio_button.setChecked(
- self.app.sweep.properties.mode == SweepMode.CONTINOUS)
+ self.app.sweep.properties.mode == SweepMode.CONTINOUS
+ )
radio_button.clicked.connect(
- lambda: self.update_mode(SweepMode.CONTINOUS))
+ lambda: self.update_mode(SweepMode.CONTINOUS)
+ )
sweep_btn_layout.addWidget(radio_button)
radio_button = QtWidgets.QRadioButton("Averaged sweep")
radio_button.setMinimumHeight(20)
radio_button.setChecked(
- self.app.sweep.properties.mode == SweepMode.AVERAGE)
+ self.app.sweep.properties.mode == SweepMode.AVERAGE
+ )
radio_button.clicked.connect(
- lambda: self.update_mode(SweepMode.AVERAGE))
+ lambda: self.update_mode(SweepMode.AVERAGE)
+ )
sweep_btn_layout.addWidget(radio_button)
layout.addRow(sweep_btn_layout)
@@ -101,7 +107,8 @@ class SweepSettingsWindow(QtWidgets.QWidget):
"Logarithmic sweeping changes the step width in each segment"
" in logarithmical manner. Useful in conjunction with small"
" amount of datapoints and many segments. Step display in"
- " SweepControl cannot reflect this currently.")
+ " SweepControl cannot reflect this currently."
+ )
label.setWordWrap(True)
label.setMinimumSize(600, 70)
layout.addRow(label)
@@ -109,26 +116,32 @@ class SweepSettingsWindow(QtWidgets.QWidget):
checkbox.setMinimumHeight(20)
checkbox.setCheckState(self.app.sweep.properties.logarithmic)
checkbox.toggled.connect(
- lambda: self.update_logarithmic(checkbox.isChecked()))
+ lambda: self.update_logarithmic(checkbox.isChecked())
+ )
layout.addRow(checkbox)
# Averaging
label = QtWidgets.QLabel(
"Averaging allows discarding outlying samples to get better"
- " averages. Common values are 3/0, 5/2, 9/4 and 25/6.")
+ " averages. Common values are 3/0, 5/2, 9/4 and 25/6."
+ )
label.setWordWrap(True)
label.setMinimumHeight(50)
layout.addRow(label)
averages = QtWidgets.QLineEdit(
- str(self.app.sweep.properties.averages[0]))
+ str(self.app.sweep.properties.averages[0])
+ )
averages.setMinimumHeight(20)
truncates = QtWidgets.QLineEdit(
- str(self.app.sweep.properties.averages[1]))
+ str(self.app.sweep.properties.averages[1])
+ )
truncates.setMinimumHeight(20)
averages.editingFinished.connect(
- lambda: self.update_averaging(averages, truncates))
+ lambda: self.update_averaging(averages, truncates)
+ )
truncates.editingFinished.connect(
- lambda: self.update_averaging(averages, truncates))
+ lambda: self.update_averaging(averages, truncates)
+ )
layout.addRow("Number of measurements to average", averages)
layout.addRow("Number to discard", truncates)
@@ -136,7 +149,8 @@ class SweepSettingsWindow(QtWidgets.QWidget):
label = QtWidgets.QLabel(
"Some times when you measure amplifiers you need to use an"
" attenuator in line with the S21 input (CH1) here you can"
- " specify it.")
+ " specify it."
+ )
label.setWordWrap(True)
label.setMinimumHeight(50)
layout.addRow(label)
@@ -144,11 +158,12 @@ class SweepSettingsWindow(QtWidgets.QWidget):
input_att = QtWidgets.QLineEdit(str(self.app.s21att))
input_att.setMinimumHeight(20)
input_att.editingFinished.connect(
- lambda: self.update_attenuator(input_att))
+ lambda: self.update_attenuator(input_att)
+ )
layout.addRow("Attenuator in port CH1 (s21) in dB", input_att)
return box
- def sweep_box(self) -> 'QtWidgets.QWidget':
+ def sweep_box(self) -> "QtWidgets.QWidget":
box = QtWidgets.QGroupBox("Sweep band")
layout = QtWidgets.QFormLayout(box)
sweep_pad_layout = QtWidgets.QHBoxLayout()
@@ -162,7 +177,11 @@ class SweepSettingsWindow(QtWidgets.QWidget):
sweep_pad_layout.addWidget(QtWidgets.QLabel("Pad band limits:"))
for btn_label, value in (
- ("None", 0), ("10%", 10), ("25%", 25), ("100%", 100),):
+ ("None", 0),
+ ("10%", 10),
+ ("25%", 25),
+ ("100%", 100),
+ ):
radio_button = QtWidgets.QRadioButton(btn_label)
radio_button.setMinimumHeight(20)
radio_button.setChecked(self.padding == value)
@@ -186,20 +205,33 @@ class SweepSettingsWindow(QtWidgets.QWidget):
power_sel = QtWidgets.QComboBox()
power_sel.addItems(power_descs)
power_sel.currentTextChanged.connect(
- partial(self.update_tx_power, freq_range))
- self._power_layout.addRow("TX power {}..{}".format(
- *map(format_frequency_short, freq_range)), power_sel)
+ partial(self.update_tx_power, freq_range)
+ )
+ self._power_layout.addRow(
+ "TX power {}..{}".format(
+ *map(format_frequency_short, freq_range)
+ ),
+ power_sel,
+ )
def update_band(self, apply: bool = False):
logger.debug("update_band(%s)", apply)
index_start = self.band_list.model().index(
- self.band_list.currentIndex(), 1)
+ self.band_list.currentIndex(), 1
+ )
index_stop = self.band_list.model().index(
- self.band_list.currentIndex(), 2)
- start = int(self.band_list.model().data(
- index_start, QtCore.Qt.ItemDataRole).value())
- stop = int(self.band_list.model().data(
- index_stop, QtCore.Qt.ItemDataRole).value())
+ self.band_list.currentIndex(), 2
+ )
+ start = int(
+ self.band_list.model()
+ .data(index_start, QtCore.Qt.ItemDataRole)
+ .value()
+ )
+ stop = int(
+ self.band_list.model()
+ .data(index_stop, QtCore.Qt.ItemDataRole)
+ .value()
+ )
if self.padding > 0:
span = stop - start
@@ -209,33 +241,37 @@ class SweepSettingsWindow(QtWidgets.QWidget):
self.band_label.setText(
f"Sweep span: {format_frequency_short(start)}"
- f" to {format_frequency_short(stop)}")
+ f" to {format_frequency_short(stop)}"
+ )
if not apply:
return
self.app.sweep_control.input_start.setText(
- format_frequency_sweep(start))
- self.app.sweep_control.input_end.setText(
- format_frequency_sweep(stop))
+ format_frequency_sweep(start)
+ )
+ self.app.sweep_control.input_end.setText(format_frequency_sweep(stop))
self.app.sweep_control.input_end.textEdited.emit(
- self.app.sweep_control.input_end.text())
+ self.app.sweep_control.input_end.text()
+ )
- def update_attenuator(self, value: 'QtWidgets.QLineEdit'):
+ def update_attenuator(self, value: "QtWidgets.QLineEdit"):
try:
att = float(value.text())
assert att >= 0
except (ValueError, AssertionError):
- logger.warning("Values for attenuator are absolute and with no"
- " minus sign, resetting.")
+ logger.warning(
+ "Values for attenuator are absolute and with no"
+ " minus sign, resetting."
+ )
att = 0
logger.debug("Attenuator %sdB inline with S21 input", att)
value.setText(str(att))
self.app.s21att = att
- def update_averaging(self,
- averages: 'QtWidgets.QLineEdit',
- truncs: 'QtWidgets.QLineEdit'):
+ def update_averaging(
+ self, averages: "QtWidgets.QLineEdit", truncs: "QtWidgets.QLineEdit"
+ ):
try:
amount = int(averages.text())
truncates = int(truncs.text())
@@ -257,7 +293,7 @@ class SweepSettingsWindow(QtWidgets.QWidget):
with self.app.sweep.lock:
self.app.sweep.properties.logarithmic = logarithmic
- def update_mode(self, mode: 'SweepMode'):
+ def update_mode(self, mode: "SweepMode"):
logger.debug("update_mode(%s)", mode)
with self.app.sweep.lock:
self.app.sweep.properties.mode = mode
diff --git a/src/NanoVNASaver/Windows/TDR.py b/src/NanoVNASaver/Windows/TDR.py
index 84bd052..f94a746 100644
--- a/src/NanoVNASaver/Windows/TDR.py
+++ b/src/NanoVNASaver/Windows/TDR.py
@@ -20,6 +20,7 @@ import logging
import math
import numpy as np
+
# pylint: disable=import-error, no-name-in-module
from scipy.signal import convolve
from scipy.constants import speed_of_light
@@ -48,9 +49,9 @@ CABLE_PARAMETERS = (
("RG-8/U (Shireen RFC®400 Low Loss) (0.86)", 0.86),
("RG-8X (Belden 9258) (0.82)", 0.82),
# Next three added by EKZ, KC3KZ, from measurement of actual cable
- ("RG-8X (Wireman \"Super 8\" CQ106) (0.81)", 0.81),
- ("RG-8X (Wireman \"MINI-8 Lo-Loss\" CQ118) (0.82)", 0.82),
- ("RG-58 (Wireman \"CQ 58 Lo-Loss Flex\" CQ129FF) (0.79)", 0.79),
+ ('RG-8X (Wireman "Super 8" CQ106) (0.81)', 0.81),
+ ('RG-8X (Wireman "MINI-8 Lo-Loss" CQ118) (0.82)', 0.82),
+ ('RG-58 (Wireman "CQ 58 Lo-Loss Flex" CQ129FF) (0.79)', 0.79),
("RG-11/U 75\N{OHM SIGN} Foam HDPE (Belden 9292) (0.84)", 0.84),
("RG-58/U 52\N{OHM SIGN} PE (Belden 9201) (0.66)", 0.66),
("RG-58A/U 54\N{OHM SIGN} Foam (Belden 8219) (0.73)", 0.73),
@@ -92,7 +93,8 @@ class TDRWindow(QtWidgets.QWidget):
for cable_name, velocity in CABLE_PARAMETERS:
self.tdr_velocity_dropdown.addItem(cable_name, velocity)
self.tdr_velocity_dropdown.insertSeparator(
- self.tdr_velocity_dropdown.count())
+ self.tdr_velocity_dropdown.count()
+ )
self.tdr_velocity_dropdown.addItem("Custom", -1)
self.tdr_velocity_dropdown.setCurrentIndex(1) # Default to PE (0.66)
self.tdr_velocity_dropdown.currentIndexChanged.connect(self.updateTDR)
@@ -121,7 +123,8 @@ class TDRWindow(QtWidgets.QWidget):
else:
self.tdr_velocity_input.setDisabled(True)
self.tdr_velocity_input.setText(
- str(self.tdr_velocity_dropdown.currentData()))
+ str(self.tdr_velocity_dropdown.currentData())
+ )
try:
v = float(self.tdr_velocity_input.text())
@@ -142,8 +145,7 @@ class TDRWindow(QtWidgets.QWidget):
step = np.ones(FFT_POINTS)
step_response = convolve(td, step)
- self.step_response_Z = 50 * (
- 1 + step_response) / (1 - step_response)
+ self.step_response_Z = 50 * (1 + step_response) / (1 - step_response)
time_axis = np.linspace(0, 1 / step_size, FFT_POINTS)
self.distance_axis = time_axis * v * speed_of_light
diff --git a/src/NanoVNASaver/Windows/__init__.py b/src/NanoVNASaver/Windows/__init__.py
index 24b6db6..5af38b8 100644
--- a/src/NanoVNASaver/Windows/__init__.py
+++ b/src/NanoVNASaver/Windows/__init__.py
@@ -9,16 +9,17 @@ from .MarkerSettings import MarkerSettingsWindow
from .Screenshot import ScreenshotWindow
from .SweepSettings import SweepSettingsWindow
from .TDR import TDRWindow
+
__all__ = [
- 'AboutWindow',
- 'AnalysisWindow',
- 'BandsWindow',
- 'CalibrationWindow',
- 'DeviceSettingsWindow',
- 'DisplaySettingsWindow',
- 'FilesWindow',
- 'MarkerSettingsWindow',
- 'ScreenshotWindow',
- 'SweepSettingsWindow',
- 'TDRWindow',
+ "AboutWindow",
+ "AnalysisWindow",
+ "BandsWindow",
+ "CalibrationWindow",
+ "DeviceSettingsWindow",
+ "DisplaySettingsWindow",
+ "FilesWindow",
+ "MarkerSettingsWindow",
+ "ScreenshotWindow",
+ "SweepSettingsWindow",
+ "TDRWindow",
]
diff --git a/src/NanoVNASaver/__init__.py b/src/NanoVNASaver/__init__.py
index 5ad22a2..73f2a09 100644
--- a/src/NanoVNASaver/__init__.py
+++ b/src/NanoVNASaver/__init__.py
@@ -2,9 +2,15 @@ import sys
if sys.version_info[:2] >= (3, 8):
# TODO: Import directly (no need for conditional) when `python_requires = >= 3.8`
- from importlib.metadata import PackageNotFoundError, version # pragma: no cover
+ from importlib.metadata import (
+ PackageNotFoundError,
+ version,
+ ) # pragma: no cover
else:
- from importlib_metadata import PackageNotFoundError, version # pragma: no cover
+ from importlib_metadata import (
+ PackageNotFoundError,
+ version,
+ ) # pragma: no cover
try:
# Change here if project is renamed and does not equal the package name
diff --git a/src/NanoVNASaver/__main__.py b/src/NanoVNASaver/__main__.py
index 944837c..a45022f 100644
--- a/src/NanoVNASaver/__main__.py
+++ b/src/NanoVNASaver/__main__.py
@@ -40,19 +40,27 @@ from NanoVNASaver.Touchstone import Touchstone
def main():
parser = argparse.ArgumentParser(
description=__doc__,
- formatter_class=argparse.RawDescriptionHelpFormatter)
- parser.add_argument("-d", "--debug", action="store_true",
- help="Set loglevel to debug")
- parser.add_argument("-D", "--debug-file",
- help="File to write debug logging output to")
- parser.add_argument("-f", "--file",
- help="Touchstone file to load as sweep for off"
- " device usage")
- parser.add_argument("-r", "--ref-file",
- help="Touchstone file to load as reference for off"
- " device usage")
- parser.add_argument("--version", action="version",
- version=f"NanoVNASaver {VERSION}")
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ )
+ parser.add_argument(
+ "-d", "--debug", action="store_true", help="Set loglevel to debug"
+ )
+ parser.add_argument(
+ "-D", "--debug-file", help="File to write debug logging output to"
+ )
+ parser.add_argument(
+ "-f",
+ "--file",
+ help="Touchstone file to load as sweep for off" " device usage",
+ )
+ parser.add_argument(
+ "-r",
+ "--ref-file",
+ help="Touchstone file to load as reference for off" " device usage",
+ )
+ parser.add_argument(
+ "--version", action="version", version=f"NanoVNASaver {VERSION}"
+ )
args = parser.parse_args()
console_log_level = logging.WARNING
@@ -69,7 +77,8 @@ def main():
ch = logging.StreamHandler()
ch.setLevel(console_log_level)
formatter = logging.Formatter(
- '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
+ )
ch.setFormatter(formatter)
logger.addHandler(ch)
@@ -81,8 +90,7 @@ def main():
logger.info("Startup...")
- QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling,
- True)
+ QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
app = QtWidgets.QApplication(sys.argv)
window = NanoVNASaver()
window.show()
@@ -104,5 +112,5 @@ def main():
raise exc
-if __name__ == '__main__':
+if __name__ == "__main__":
main()