From e0ee24b103ab10fac2841df6285fdd1b9b72de02 Mon Sep 17 00:00:00 2001 From: "Rune B. Broberg" Date: Wed, 11 Sep 2019 20:26:57 +0200 Subject: [PATCH] New marker layout, and added Q readout. Application has a new icon! --- NanoVNASaver/Marker.py | 85 ++++++++++++++++++++++++++--------- NanoVNASaver/NanoVNASaver.py | 14 ++++-- icon_48x48.png | Bin 0 -> 17432 bytes 3 files changed, 74 insertions(+), 25 deletions(-) create mode 100644 icon_48x48.png diff --git a/NanoVNASaver/Marker.py b/NanoVNASaver/Marker.py index cab54b6..2856443 100644 --- a/NanoVNASaver/Marker.py +++ b/NanoVNASaver/Marker.py @@ -41,31 +41,66 @@ class Marker(QtCore.QObject): self.frequencyInput.setAlignment(QtCore.Qt.AlignRight) self.frequencyInput.returnPressed.connect(lambda: self.setFrequency(self.frequencyInput.text())) + ################################################################################################################ + # Data display label + ################################################################################################################ + + self.frequency_label = QtWidgets.QLabel("") + self.frequency_label.setMinimumWidth(100) + self.impedance_label = QtWidgets.QLabel("") + self.returnloss_label = QtWidgets.QLabel("") + self.returnloss_label.setMinimumWidth(80) + self.vswr_label = QtWidgets.QLabel("") + self.inductance_label = QtWidgets.QLabel("") + self.capacitance_label = QtWidgets.QLabel("") + self.gain_label = QtWidgets.QLabel("") + self.phase_label = QtWidgets.QLabel("") + self.quality_factor_label = QtWidgets.QLabel("") + + ################################################################################################################ + # Marker control layout + ################################################################################################################ + self.btnColorPicker = QtWidgets.QPushButton("█") self.btnColorPicker.setFixedWidth(20) self.setColor(initialColor) self.btnColorPicker.clicked.connect(lambda: self.setColor(QtWidgets.QColorDialog.getColor(self.color, options=QtWidgets.QColorDialog.ShowAlphaChannel))) + self.radioButton = QtWidgets.QRadioButton() self.layout = QtWidgets.QHBoxLayout() self.layout.addWidget(self.frequencyInput) self.layout.addWidget(self.btnColorPicker) + self.layout.addWidget(self.radioButton) + + ################################################################################################################ + # Data display layout + ################################################################################################################ self.group_box = QtWidgets.QGroupBox(self.name) - box_layout = QtWidgets.QFormLayout(self.group_box) - self.frequency_label = QtWidgets.QLabel("") - box_layout.addRow(QtWidgets.QLabel("Actual frequency:"), self.frequency_label) - self.impedance_label = QtWidgets.QLabel("") - box_layout.addRow(QtWidgets.QLabel("Impedance:"), self.impedance_label) - self.returnloss_label = QtWidgets.QLabel("") - box_layout.addRow(QtWidgets.QLabel("Return loss:"), self.returnloss_label) - self.vswr_label = QtWidgets.QLabel("") - box_layout.addRow(QtWidgets.QLabel("VSWR:"), self.vswr_label) - self.reactance_label = QtWidgets.QLabel("") - box_layout.addRow(QtWidgets.QLabel("C/L equivalent:"), self.reactance_label) - self.gain_label = QtWidgets.QLabel("") - box_layout.addRow(QtWidgets.QLabel("S21 Gain:"), self.gain_label) - self.phase_label = QtWidgets.QLabel("") - box_layout.addRow(QtWidgets.QLabel("S21 Phase:"), self.phase_label) + box_layout = QtWidgets.QHBoxLayout(self.group_box) + + line = QtWidgets.QFrame() + line.setFrameShape(QtWidgets.QFrame.VLine) + #line.setFrameShadow(QtWidgets.QFrame.Sunken) + + left_form = QtWidgets.QFormLayout() + right_form = QtWidgets.QFormLayout() + box_layout.addLayout(left_form) + box_layout.addWidget(line) + box_layout.addLayout(right_form) + + # Left side + left_form.addRow(QtWidgets.QLabel("Frequency:"), self.frequency_label) + left_form.addRow(QtWidgets.QLabel("Impedance:"), self.impedance_label) + left_form.addRow(QtWidgets.QLabel("L equiv.:"), self.inductance_label) + left_form.addRow(QtWidgets.QLabel("C equiv.:"), self.capacitance_label) + left_form.addRow(QtWidgets.QLabel("Q:"), self.quality_factor_label) + + # Right side + right_form.addRow(QtWidgets.QLabel("Return loss:"), self.returnloss_label) + right_form.addRow(QtWidgets.QLabel("VSWR:"), self.vswr_label) + right_form.addRow(QtWidgets.QLabel("S21 Gain:"), self.gain_label) + right_form.addRow(QtWidgets.QLabel("S21 Phase:"), self.phase_label) def setFrequency(self, frequency): from .NanoVNASaver import NanoVNASaver @@ -111,9 +146,11 @@ class Marker(QtCore.QObject): self.impedance_label.setText("") self.vswr_label.setText("") self.returnloss_label.setText("") - self.reactance_label.setText("") + self.inductance_label.setText("") + self.capacitance_label.setText("") self.gain_label.setText("") self.phase_label.setText("") + self.quality_factor_label.setText("") def updateLabels(self, s11data: List[Datapoint], s21data: List[Datapoint]): from NanoVNASaver.Chart import PhaseChart @@ -121,15 +158,21 @@ class Marker(QtCore.QObject): if self.location != -1: im50, re50, vswr = NanoVNASaver.vswr(s11data[self.location]) if im50 < 0: - im50str = " - j" + str(round(-1 * im50, 3)) + im50str = " -j" + str(round(-1 * im50, 3)) else: - im50str = " + j" + str(round(im50, 3)) + im50str = " +j" + str(round(im50, 3)) self.frequency_label.setText(NanoVNASaver.formatFrequency(s11data[self.location].freq)) self.impedance_label.setText(str(round(re50, 3)) + im50str) self.returnloss_label.setText(str(round(20 * math.log10((vswr - 1) / (vswr + 1)), 3)) + " dB") - reactance = NanoVNASaver.reactanceEquivalent(im50, s11data[self.location].freq) - self.reactance_label.setText(reactance) - self.vswr_label.setText(str(round(vswr, 3))) + capacitance = NanoVNASaver.capacitanceEquivalent(im50, s11data[self.location].freq) + inductance = NanoVNASaver.inductanceEquivalent(im50, s11data[self.location].freq) + self.inductance_label.setText(inductance) + self.capacitance_label.setText(capacitance) + vswr = round(vswr, 3) + if vswr < 0: + vswr = "-" + self.vswr_label.setText(str(vswr)) + self.quality_factor_label.setText(str(round(NanoVNASaver.qualifyFactor(s11data[self.location]), 1))) if len(s21data) == len(s11data): _, _, vswr = NanoVNASaver.vswr(s21data[self.location]) self.gain_label.setText(str(round(20 * math.log10((vswr - 1) / (vswr + 1)), 3)) + " dB") diff --git a/NanoVNASaver/NanoVNASaver.py b/NanoVNASaver/NanoVNASaver.py index 4d7c857..c7fb2a6 100644 --- a/NanoVNASaver/NanoVNASaver.py +++ b/NanoVNASaver/NanoVNASaver.py @@ -41,6 +41,8 @@ class NanoVNASaver(QtWidgets.QWidget): def __init__(self): super().__init__() + self.setWindowIcon(QtGui.QIcon("icon_48x48.png")) + self.settings = QtCore.QSettings(QtCore.QSettings.IniFormat, QtCore.QSettings.UserScope, "NanoVNASaver", "NanoVNASaver") @@ -187,7 +189,7 @@ class NanoVNASaver(QtWidgets.QWidget): marker_control_box = QtWidgets.QGroupBox() marker_control_box.setTitle("Markers") - marker_control_box.setMaximumWidth(300) + marker_control_box.setMaximumWidth(350) marker_control_layout = QtWidgets.QFormLayout(marker_control_box) mouse_marker_color = self.settings.value("MouseMarkerColor", QtGui.QColor(20, 255, 20), QtGui.QColor) @@ -466,7 +468,7 @@ class NanoVNASaver(QtWidgets.QWidget): self.lister = QtWidgets.QPlainTextEdit() self.lister.setFixedHeight(200) - self.lister.setMaximumWidth(300) + self.lister.setMaximumWidth(350) marker_column.addWidget(self.lister) self.worker.signals.updated.connect(self.dataUpdated) @@ -768,10 +770,14 @@ class NanoVNASaver(QtWidgets.QWidget): return Q @staticmethod - def reactanceEquivalent(im50, freq) -> str: + def capacitanceEquivalent(im50, freq) -> str: capacitance = 10**12/(freq * 2 * math.pi * im50) + return str(round(-capacitance, 3)) + " pF" + + @staticmethod + def inductanceEquivalent(im50, freq) -> str: inductance = im50 / (freq * 2 * math.pi) - return str(round(-capacitance, 3)) + " pF / " + str(round(inductance * 1000000000, 3)) + " nH" + return str(round(inductance * 1000000000, 3)) + " nH" @staticmethod def gain(data: Datapoint): diff --git a/icon_48x48.png b/icon_48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..20fdfa0d2328d85554d259d424b1539f4f1221da GIT binary patch literal 17432 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 bPxbr<7_3Sj=cji)00000NkvXXu0mjfw}UJD literal 0 HcmV?d00001