pull/617/head
Holger Müller 2023-03-13 12:08:33 +01:00
rodzic 9ace7d8cd4
commit 5b21315a11
9 zmienionych plików z 80 dodań i 84 usunięć

Wyświetl plik

@ -39,7 +39,8 @@ points, and generally display and analyze the resulting data.
* Copyright 2019, 2020 Rune B. Broberg * Copyright 2019, 2020 Rune B. Broberg
* Copyright 2020ff NanoVNA-Saver Authors * Copyright 2020ff NanoVNA-Saver Authors
It's written in **Python 3** using **PyQt6** and **scipy**. It's developed in **Python 3 (>=3.8)** using **PyQt6**, **numpy** and
**scipy**.
Introduction Introduction
@ -88,8 +89,6 @@ Screenshot
Running the application Running the application
----------------------- -----------------------
The software was written in Python on Windows, using Pycharm, and the modules
PyQT5, numpy, scipy and pyserial.
Main development is currently done on Linux (Mint 21 "Vanessa" Cinnamon) Main development is currently done on Linux (Mint 21 "Vanessa" Cinnamon)
Installation Installation
@ -187,10 +186,13 @@ for the plot (right click on the plot).
Latest Changes Latest Changes
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
* Using PyQt6
* Moved to PyScaffold project structure
Changes in 0.5.5 Changes in 0.5.5
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
* Measuring inductor core permeability * Measuring inductor core permeability
* Bugfixes for calibration data loading and saving * Bugfixes for calibration data loading and saving
* Let V2 Devices more time for usb-serial setup * Let V2 Devices more time for usb-serial setup
@ -199,7 +201,6 @@ Changes in 0.5.5
Changes in 0.5.4 Changes in 0.5.4
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
* Bugfixes for Python3.11 compatability * Bugfixes for Python3.11 compatability
* Bugfix for Python3.8 compatability * Bugfix for Python3.8 compatability
* use math instead of table for log step calculation * use math instead of table for log step calculation

Wyświetl plik

@ -1,2 +1,3 @@
#!/bin/sh #!/bin/sh
export PYTHONPATH="src"
exec python -m debugpy --listen 5678 --wait-for-client $@ exec python -m debugpy --listen 5678 --wait-for-client $@

Wyświetl plik

@ -102,8 +102,6 @@ class ResonanceAnalysis(Analysis):
self.layout.addRow(QtWidgets.QLabel("No resonance found")) self.layout.addRow(QtWidgets.QLabel("No resonance found"))
return return
self
self.do_resonance_analysis() self.do_resonance_analysis()
def do_resonance_analysis(self): def do_resonance_analysis(self):

Wyświetl plik

@ -144,7 +144,7 @@ class PermeabilityChart(FrequencyChart):
primary_pen = pen primary_pen = pen
secondary_pen = QtGui.QPen(Chart.color.sweep_secondary) secondary_pen = QtGui.QPen(Chart.color.sweep_secondary)
if len(self.data) > 0: if self.data:
c = QtGui.QColor(Chart.color.sweep) c = QtGui.QColor(Chart.color.sweep)
c.setAlpha(255) c.setAlpha(255)
pen = QtGui.QPen(c) pen = QtGui.QPen(c)
@ -215,7 +215,7 @@ class PermeabilityChart(FrequencyChart):
line_pen.setColor(Chart.color.reference) line_pen.setColor(Chart.color.reference)
secondary_pen.setColor(Chart.color.reference_secondary) secondary_pen.setColor(Chart.color.reference_secondary)
qp.setPen(primary_pen) qp.setPen(primary_pen)
if len(self.reference) > 0: if self.reference:
c = QtGui.QColor(Chart.color.reference) c = QtGui.QColor(Chart.color.reference)
c.setAlpha(255) c.setAlpha(255)
pen = QtGui.QPen(c) pen = QtGui.QPen(c)

Wyświetl plik

@ -22,7 +22,7 @@ import logging
from typing import List from typing import List
import numpy as np import numpy as np
from PyQt6 import QtWidgets, QtGui from PyQt6.QtGui import QAction, QPainter, QPen
from NanoVNASaver.RFTools import Datapoint from NanoVNASaver.RFTools import Datapoint
from NanoVNASaver.Charts.Chart import Chart from NanoVNASaver.Charts.Chart import Chart
@ -47,7 +47,7 @@ class PhaseChart(FrequencyChart):
self.maxDisplayValue = 180 self.maxDisplayValue = 180
self.y_menu.addSeparator() self.y_menu.addSeparator()
self.action_unwrap = QtGui.QAction("Unwrap") self.action_unwrap = QAction("Unwrap")
self.action_unwrap.setCheckable(True) self.action_unwrap.setCheckable(True)
self.action_unwrap.triggered.connect( self.action_unwrap.triggered.connect(
lambda: self.setUnwrap(self.action_unwrap.isChecked()) lambda: self.setUnwrap(self.action_unwrap.isChecked())
@ -64,7 +64,7 @@ class PhaseChart(FrequencyChart):
self.unwrap = unwrap self.unwrap = unwrap
self.update() self.update()
def drawValues(self, qp: QtGui.QPainter): def drawValues(self, qp: QPainter):
if len(self.data) == 0 and len(self.reference) == 0: if len(self.data) == 0 and len(self.reference) == 0:
return return
@ -102,7 +102,7 @@ class PhaseChart(FrequencyChart):
(self.maxAngle - angle) / self.span * self.dim.height (self.maxAngle - angle) / self.span * self.dim.height
) )
if angle not in [minAngle, maxAngle]: if angle not in [minAngle, maxAngle]:
qp.setPen(QtGui.QPen(Chart.color.text)) qp.setPen(QPen(Chart.color.text))
if angle != 0: if angle != 0:
digits = max( digits = max(
0, min(2, math.floor(3 - math.log10(abs(angle)))) 0, min(2, math.floor(3 - math.log10(abs(angle))))
@ -115,7 +115,7 @@ class PhaseChart(FrequencyChart):
else: else:
anglestr = "0" anglestr = "0"
qp.drawText(3, y + 3, f"{anglestr}°") qp.drawText(3, y + 3, f"{anglestr}°")
qp.setPen(QtGui.QPen(Chart.color.foreground)) qp.setPen(QPen(Chart.color.foreground))
qp.drawLine( qp.drawLine(
self.leftMargin - 5, y, self.leftMargin + self.dim.width, y self.leftMargin - 5, y, self.leftMargin + self.dim.width, y
) )

Wyświetl plik

@ -20,8 +20,18 @@ import math
import logging import logging
import numpy as np import numpy as np
from PyQt6 import QtWidgets, QtGui, QtCore from PyQt6.QtCore import QPoint, QRect, Qt
from PyQt6.QtCore import Qt from PyQt6.QtGui import (
QAction,
QActionGroup,
QMouseEvent,
QPalette,
QPainter,
QPaintEvent,
QPen,
QResizeEvent,
)
from PyQt6.QtWidgets import QInputDialog, QMenu, QSizePolicy
from NanoVNASaver.Charts.Chart import Chart from NanoVNASaver.Charts.Chart import Chart
@ -48,32 +58,32 @@ class TDRChart(Chart):
self.setMinimumSize(300, 300) self.setMinimumSize(300, 300)
self.setSizePolicy( self.setSizePolicy(
QtWidgets.QSizePolicy( QSizePolicy(
QtWidgets.QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.MinimumExpanding,
QtWidgets.QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.MinimumExpanding,
) )
) )
pal = QtGui.QPalette() pal = QPalette()
pal.setColor(QtGui.QPalette.ColorRole.Window, Chart.color.background) pal.setColor(QPalette.ColorRole.Window, Chart.color.background)
self.setPalette(pal) self.setPalette(pal)
self.setAutoFillBackground(True) self.setAutoFillBackground(True)
self.setContextMenuPolicy(Qt.ContextMenuPolicy.DefaultContextMenu) self.setContextMenuPolicy(Qt.ContextMenuPolicy.DefaultContextMenu)
self.menu = QtWidgets.QMenu() self.menu = QMenu()
self.reset = QtGui.QAction("Reset") self.reset = QAction("Reset")
self.reset.triggered.connect(self.resetDisplayLimits) self.reset.triggered.connect(self.resetDisplayLimits)
self.menu.addAction(self.reset) self.menu.addAction(self.reset)
self.x_menu = QtWidgets.QMenu("Length axis") self.x_menu = QMenu("Length axis")
self.mode_group = QtGui.QActionGroup(self.x_menu) self.mode_group = QActionGroup(self.x_menu)
self.action_automatic = QtGui.QAction("Automatic") self.action_automatic = QAction("Automatic")
self.action_automatic.setCheckable(True) self.action_automatic.setCheckable(True)
self.action_automatic.setChecked(True) self.action_automatic.setChecked(True)
self.action_automatic.changed.connect( 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 = QtGui.QAction("Fixed span") self.action_fixed_span = QAction("Fixed span")
self.action_fixed_span.setCheckable(True) self.action_fixed_span.setCheckable(True)
self.action_fixed_span.changed.connect( self.action_fixed_span.changed.connect(
lambda: self.setFixedSpan(self.action_fixed_span.isChecked()) lambda: self.setFixedSpan(self.action_fixed_span.isChecked())
@ -84,28 +94,26 @@ class TDRChart(Chart):
self.x_menu.addAction(self.action_fixed_span) self.x_menu.addAction(self.action_fixed_span)
self.x_menu.addSeparator() self.x_menu.addSeparator()
self.action_set_fixed_start = QtGui.QAction( self.action_set_fixed_start = QAction(
f"Start ({self.minDisplayLength})" f"Start ({self.minDisplayLength})"
) )
self.action_set_fixed_start.triggered.connect(self.setMinimumLength) self.action_set_fixed_start.triggered.connect(self.setMinimumLength)
self.action_set_fixed_stop = QtGui.QAction( self.action_set_fixed_stop = QAction(f"Stop ({self.maxDisplayLength})")
f"Stop ({self.maxDisplayLength})"
)
self.action_set_fixed_stop.triggered.connect(self.setMaximumLength) self.action_set_fixed_stop.triggered.connect(self.setMaximumLength)
self.x_menu.addAction(self.action_set_fixed_start) self.x_menu.addAction(self.action_set_fixed_start)
self.x_menu.addAction(self.action_set_fixed_stop) self.x_menu.addAction(self.action_set_fixed_stop)
self.y_menu = QtWidgets.QMenu("Impedance axis") self.y_menu = QMenu("Impedance axis")
self.y_mode_group = QtGui.QActionGroup(self.y_menu) self.y_mode_group = QActionGroup(self.y_menu)
self.y_action_automatic = QtGui.QAction("Automatic") self.y_action_automatic = QAction("Automatic")
self.y_action_automatic.setCheckable(True) self.y_action_automatic.setCheckable(True)
self.y_action_automatic.setChecked(True) self.y_action_automatic.setChecked(True)
self.y_action_automatic.changed.connect( 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 = QtGui.QAction("Fixed") self.y_action_fixed = QAction("Fixed")
self.y_action_fixed.setCheckable(True) self.y_action_fixed.setCheckable(True)
self.y_action_fixed.changed.connect( self.y_action_fixed.changed.connect(
lambda: self.setFixedValues(self.y_action_fixed.isChecked()) lambda: self.setFixedValues(self.y_action_fixed.isChecked())
@ -116,14 +124,14 @@ class TDRChart(Chart):
self.y_menu.addAction(self.y_action_fixed) self.y_menu.addAction(self.y_action_fixed)
self.y_menu.addSeparator() self.y_menu.addSeparator()
self.y_action_set_fixed_maximum = QtGui.QAction( self.y_action_set_fixed_maximum = QAction(
f"Maximum ({self.maxImpedance})" f"Maximum ({self.maxImpedance})"
) )
self.y_action_set_fixed_maximum.triggered.connect( self.y_action_set_fixed_maximum.triggered.connect(
self.setMaximumImpedance self.setMaximumImpedance
) )
self.y_action_set_fixed_minimum = QtGui.QAction( self.y_action_set_fixed_minimum = QAction(
f"Minimum ({self.minImpedance})" f"Minimum ({self.minImpedance})"
) )
self.y_action_set_fixed_minimum.triggered.connect( self.y_action_set_fixed_minimum.triggered.connect(
@ -137,7 +145,7 @@ class TDRChart(Chart):
self.menu.addMenu(self.y_menu) self.menu.addMenu(self.y_menu)
self.menu.addSeparator() self.menu.addSeparator()
self.menu.addAction(self.action_save_screenshot) self.menu.addAction(self.action_save_screenshot)
self.action_popout = QtGui.QAction("Popout chart") self.action_popout = QAction("Popout chart")
self.action_popout.triggered.connect( self.action_popout.triggered.connect(
lambda: self.popoutRequested.emit(self) lambda: self.popoutRequested.emit(self)
) )
@ -177,7 +185,7 @@ class TDRChart(Chart):
self.update() self.update()
def setMinimumLength(self): def setMinimumLength(self):
min_val, selected = QtWidgets.QInputDialog.getDouble( min_val, selected = QInputDialog.getDouble(
self, self,
"Start length (m)", "Start length (m)",
"Set start length (m)", "Set start length (m)",
@ -193,7 +201,7 @@ class TDRChart(Chart):
self.update() self.update()
def setMaximumLength(self): def setMaximumLength(self):
max_val, selected = QtWidgets.QInputDialog.getDouble( max_val, selected = QInputDialog.getDouble(
self, self,
"Stop length (m)", "Stop length (m)",
"Set stop length (m)", "Set stop length (m)",
@ -213,7 +221,7 @@ class TDRChart(Chart):
self.update() self.update()
def setMinimumImpedance(self): def setMinimumImpedance(self):
min_val, selected = QtWidgets.QInputDialog.getDouble( min_val, selected = QInputDialog.getDouble(
self, self,
"Minimum impedance (\N{OHM SIGN})", "Minimum impedance (\N{OHM SIGN})",
"Set minimum impedance (\N{OHM SIGN})", "Set minimum impedance (\N{OHM SIGN})",
@ -229,7 +237,7 @@ class TDRChart(Chart):
self.update() self.update()
def setMaximumImpedance(self): def setMaximumImpedance(self):
max_val, selected = QtWidgets.QInputDialog.getDouble( max_val, selected = QInputDialog.getDouble(
self, self,
"Maximum impedance (\N{OHM SIGN})", "Maximum impedance (\N{OHM SIGN})",
"Set maximum impedance (\N{OHM SIGN})", "Set maximum impedance (\N{OHM SIGN})",
@ -256,7 +264,7 @@ class TDRChart(Chart):
self.tdrWindow.updated.connect(new_chart.update) self.tdrWindow.updated.connect(new_chart.update)
return new_chart return new_chart
def mouseMoveEvent(self, a0: QtGui.QMouseEvent) -> None: def mouseMoveEvent(self, a0: QMouseEvent) -> None:
if a0.buttons() == Qt.MouseButton.RightButton: if a0.buttons() == Qt.MouseButton.RightButton:
a0.ignore() a0.ignore()
return return
@ -310,12 +318,12 @@ class TDRChart(Chart):
def _draw_ticks(self, height, width, x_step, min_index): def _draw_ticks(self, height, width, x_step, min_index):
ticks = (self.width() - self.leftMargin) // 100 ticks = (self.width() - self.leftMargin) // 100
qp = QtGui.QPainter(self) qp = QPainter(self)
for i in range(ticks): for i in range(ticks):
x = self.leftMargin + round((i + 1) * width / ticks) x = self.leftMargin + round((i + 1) * width / ticks)
qp.setPen(QtGui.QPen(Chart.color.foreground)) qp.setPen(QPen(Chart.color.foreground))
qp.drawLine(x, self.topMargin, x, self.topMargin + height) qp.drawLine(x, self.topMargin, x, self.topMargin + height)
qp.setPen(QtGui.QPen(Chart.color.text)) qp.setPen(QPen(Chart.color.text))
distance = ( distance = (
self.tdrWindow.distance_axis[ self.tdrWindow.distance_axis[
min_index + int((x - self.leftMargin) * x_step) - 1 min_index + int((x - self.leftMargin) * x_step) - 1
@ -325,15 +333,15 @@ class TDRChart(Chart):
qp.drawText( qp.drawText(
x - 15, self.topMargin + height + 15, f"{round(distance, 1)}m" x - 15, self.topMargin + height + 15, f"{round(distance, 1)}m"
) )
qp.setPen(QtGui.QPen(Chart.color.text)) qp.setPen(QPen(Chart.color.text))
qp.drawText( qp.drawText(
self.leftMargin - 10, self.leftMargin - 10,
self.topMargin + height + 15, self.topMargin + height + 15,
str(round(self.tdrWindow.distance_axis[min_index] / 2, 1)) + "m", f"{str(round(self.tdrWindow.distance_axis[min_index] / 2, 1))}m",
) )
def _draw_y_ticks(self, height, width, min_impedance, max_impedance): def _draw_y_ticks(self, height, width, min_impedance, max_impedance):
qp = QtGui.QPainter(self) qp = QPainter(self)
y_step = (max_impedance - min_impedance) / height y_step = (max_impedance - min_impedance) / height
y_ticks = math.floor(height / 60) y_ticks = math.floor(height / 60)
y_tick_step = height / y_ticks y_tick_step = height / y_ticks
@ -350,10 +358,10 @@ class TDRChart(Chart):
) )
def _draw_max_point(self, height, x_step, y_step, min_index): def _draw_max_point(self, height, x_step, y_step, min_index):
qp = QtGui.QPainter(self) qp = QPainter(self)
id_max = np.argmax(self.tdrWindow.td) id_max = np.argmax(self.tdrWindow.td)
max_point = QtCore.QPoint( max_point = QPoint(
self.leftMargin + int((id_max - min_index) / x_step), 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),
) )
@ -368,8 +376,8 @@ class TDRChart(Chart):
) )
def _draw_marker(self, height, x_step, y_step, min_index): def _draw_marker(self, height, x_step, y_step, min_index):
qp = QtGui.QPainter(self) qp = QPainter(self)
marker_point = QtCore.QPoint( marker_point = QPoint(
self.leftMargin + int((self.markerLocation - min_index) / x_step), self.leftMargin + int((self.markerLocation - min_index) / x_step),
(self.topMargin + height) (self.topMargin + height)
- int(self.tdrWindow.td[self.markerLocation] / y_step), - int(self.tdrWindow.td[self.markerLocation] / y_step),
@ -415,8 +423,8 @@ class TDRChart(Chart):
self._draw_ticks(height, width, x_step, min_index) 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) qp = QPainter(self)
pen = QtGui.QPen(Chart.color.sweep) pen = QPen(Chart.color.sweep)
pen.setWidth(self.dim.point) pen.setWidth(self.dim.point)
qp.setPen(pen) qp.setPen(pen)
@ -443,15 +451,15 @@ class TDRChart(Chart):
if self.markerLocation != -1: if self.markerLocation != -1:
self._draw_marker(height, x_step, y_step, min_index) self._draw_marker(height, x_step, y_step, min_index)
def paintEvent(self, _: QtGui.QPaintEvent) -> None: def paintEvent(self, _: QPaintEvent) -> None:
qp = QtGui.QPainter(self) qp = QPainter(self)
qp.setPen(QtGui.QPen(Chart.color.text)) qp.setPen(QPen(Chart.color.text))
qp.drawText(3, 15, self.name) qp.drawText(3, 15, self.name)
width = self.width() - self.leftMargin - self.rightMargin width = self.width() - self.leftMargin - self.rightMargin
height = self.height() - self.bottomMargin - self.topMargin height = self.height() - self.bottomMargin - self.topMargin
qp.setPen(QtGui.QPen(Chart.color.foreground)) qp.setPen(QPen(Chart.color.foreground))
qp.drawLine( qp.drawLine(
self.leftMargin - 5, self.leftMargin - 5,
self.height() - self.bottomMargin, self.height() - self.bottomMargin,
@ -471,14 +479,12 @@ class TDRChart(Chart):
self._draw_graph(height, width) self._draw_graph(height, width)
if self.dragbox.state and self.dragbox.pos[0] != -1: if self.dragbox.state and self.dragbox.pos[0] != -1:
dashed_pen = QtGui.QPen( dashed_pen = QPen(Chart.color.foreground, 1, Qt.DashLine)
Chart.color.foreground, 1, QtCore.Qt.DashLine
)
qp.setPen(dashed_pen) qp.setPen(dashed_pen)
qp.drawRect( qp.drawRect(
QtCore.QRect( QRect(
QtCore.QPoint(*self.dragbox.pos_start), QPoint(*self.dragbox.pos_start),
QtCore.QPoint(*self.dragbox.pos), QPoint(*self.dragbox.pos),
) )
) )
@ -548,7 +554,7 @@ class TDRChart(Chart):
self.update() self.update()
def resizeEvent(self, a0: QtGui.QResizeEvent) -> None: def resizeEvent(self, a0: QResizeEvent) -> None:
super().resizeEvent(a0) super().resizeEvent(a0)
self.dim.width = self.width() - self.leftMargin - self.rightMargin self.dim.width = self.width() - self.leftMargin - self.rightMargin
self.dim.height = self.height() - self.bottomMargin - self.topMargin self.dim.height = self.height() - self.bottomMargin - self.topMargin

Wyświetl plik

@ -101,6 +101,6 @@ class Value:
] ]
self.freq = s11[1].freq self.freq = s11[1].freq
self.s11 = s11[index - 1 : index + 2] self.s11 = s11[index - 1: index + 2]
if s21: if s21:
self.s21 = s21[index - 1 : index + 2] self.s21 = s21[index - 1: index + 2]

Wyświetl plik

@ -232,11 +232,11 @@ class Marker(QtCore.QObject, Value):
if color.isValid(): if color.isValid():
self.color = color self.color = color
p = self.btnColorPicker.palette() p = self.btnColorPicker.palette()
# TODO: p.setColor(QtGui.QPalette.ButtonText, self.color) p.setColor(QtGui.QPalette.ColorRole.ButtonText, self.color)
self.btnColorPicker.setPalette(p) self.btnColorPicker.setPalette(p)
# TODO: fix Stylesheet
if self.coloredText: if self.coloredText:
color_string = QtCore.QVariant(color) color_string = QtCore.QVariant(color)
# TODO: color_string.convert(str)
self.group_box.setStyleSheet( self.group_box.setStyleSheet(
f"QGroupBox {{ color: {color_string.value()}; " f"QGroupBox {{ color: {color_string.value()}; "
f"font-size: {self._size_str()}}};" f"font-size: {self._size_str()}}};"
@ -377,7 +377,6 @@ class Marker(QtCore.QObject, Value):
self.label["s21polar"].setText( self.label["s21polar"].setText(
f"{str(round(abs(_s21.z), 2))}{format_phase(_s21.phase)}" f"{str(round(abs(_s21.z), 2))}{format_phase(_s21.phase)}"
) )
self.label["s21magshunt"].setText( self.label["s21magshunt"].setText(
format_magnitude(abs(_s21.shuntImpedance())) format_magnitude(abs(_s21.shuntImpedance()))
) )

Wyświetl plik

@ -1,16 +1,7 @@
import sys from importlib.metadata import (
PackageNotFoundError,
if sys.version_info[:2] >= (3, 8): version,
# TODO: Import directly (no need for conditional) when `python_requires = >= 3.8` )
from importlib.metadata import (
PackageNotFoundError,
version,
) # pragma: no cover
else:
from importlib_metadata import (
PackageNotFoundError,
version,
) # pragma: no cover
try: try:
# Change here if project is renamed and does not equal the package name # Change here if project is renamed and does not equal the package name