Feature/linting 220402 (#499)

* added .flatpak-builder to .gitingnore
* GroupDelay Chart simplified
* allow numpy > 1.21 fixes #456
* Added flatpak manifest
pull/504/head
Holger Müller 2022-05-14 11:00:34 +02:00 zatwierdzone przez GitHub
rodzic 140ce4906c
commit 6aa7aaa051
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
18 zmienionych plików z 278 dodań i 419 usunięć

3
.gitignore vendored
Wyświetl plik

@ -11,4 +11,5 @@
settings.json
.gitignore
.coverage
/nanovna-saver.exe.spec
.flatpak-builder
/nanovna-saver.exe.spec

Wyświetl plik

@ -70,23 +70,21 @@ class MagLoopAnalysis(VSWRAnalysis):
if len(self.minimums) == 1:
m = self.minimums[0]
start, lowest, end = m
if start != end:
if 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)
self.layout.addRow(
"Q", QtWidgets.QLabel("{}".format(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)
else:
if start == end:
new_start = self.app.data.s11[start].freq - 2 * self.bandwith
new_end = self.app.data.s11[end].freq + 2 * self.bandwith
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)
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)
if self.vswr_limit_value > self.vswr_bandwith_value:
self.vswr_limit_value = max(
self.vswr_bandwith_value, self.vswr_limit_value - 1)
@ -96,13 +94,14 @@ class MagLoopAnalysis(VSWRAnalysis):
else:
new_start = new_start - 5 * self.bandwith
new_end = new_end + 5 * self.bandwith
if all((new_start <= self.min_freq,
new_end >= self.max_freq)):
if self.vswr_limit_value < 10:
self.vswr_limit_value += 2
self.input_vswr_limit.setValue(self.vswr_limit_value)
logger.debug(
"no minimum found, looking for higher value %s", self.vswr_limit_value)
if (
all((new_start <= self.min_freq, new_end >= self.max_freq))
and self.vswr_limit_value < 10
):
self.vswr_limit_value += 2
self.input_vswr_limit.setValue(self.vswr_limit_value)
logger.debug(
"no minimum found, looking for higher value %s", 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",

Wyświetl plik

@ -109,7 +109,7 @@ class Chart(QtWidgets.QWidget):
def __init__(self, name):
super().__init__()
self.name = name
self.sweepTitle = ""
self.sweepTitle = ''
self.dim = ChartDimensions()
self.dragbox = ChartDragBox()
@ -170,10 +170,14 @@ class Chart(QtWidgets.QWidget):
def getActiveMarker(self) -> Marker:
if self.draggedMarker is not None:
return self.draggedMarker
for m in self.markers:
if m.isMouseControlledRadioButton.isChecked():
return m
return None
return next(
(
m
for m in self.markers
if m.isMouseControlledRadioButton.isChecked()
),
None,
)
def getNearestMarker(self, x, y) -> Marker:
if len(self.data) == 0:
@ -264,7 +268,6 @@ class Chart(QtWidgets.QWidget):
self.swrMarkers.remove(swr)
except KeyError:
logger.debug("KeyError from %s", self.name)
return
finally:
self.update()
@ -277,8 +280,6 @@ class Chart(QtWidgets.QWidget):
cmarker.draw(x, y, color, str(number))
def drawTitle(self, qp: QtGui.QPainter, position: QtCore.QPoint = None):
if not self.sweepTitle:
return
qp.setPen(Chart.color.text)
if position is None:
qf = QtGui.QFontMetricsF(self.font())

Wyświetl plik

@ -96,11 +96,11 @@ class FrequencyChart(Chart):
self.x_menu.addSeparator()
self.action_set_fixed_start = QtWidgets.QAction(
"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(
"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)

Wyświetl plik

@ -62,64 +62,40 @@ class GroupDelayChart(FrequencyChart):
def setReference(self, data):
self.reference = data
self.calculateGroupDelay()
def setData(self, data):
self.data = data
self.calculateGroupDelay()
def calculateGroupDelay(self):
rawData = []
for d in self.data:
rawData.append(d.phase)
rawReference = []
for d in self.reference:
rawReference.append(d.phase)
if len(self.data) > 1:
unwrappedData = np.degrees(np.unwrap(rawData))
self.groupDelay = []
for i in range(len(self.data)):
# TODO: Replace with call to RFTools.groupDelay
if i == 0:
phase_change = unwrappedData[1] - unwrappedData[0]
freq_change = self.data[1].freq - self.data[0].freq
elif i == len(self.data)-1:
idx = len(self.data)-1
phase_change = unwrappedData[idx] - unwrappedData[idx-1]
freq_change = self.data[idx].freq - self.data[idx-1].freq
else:
phase_change = unwrappedData[i+1] - unwrappedData[i-1]
freq_change = self.data[i+1].freq - self.data[i-1].freq
delay = (-phase_change / (freq_change * 360)) * 10e8
if not self.reflective:
delay /= 2
self.groupDelay.append(delay)
if len(self.reference) > 1:
unwrappedReference = np.degrees(np.unwrap(rawReference))
self.groupDelayReference = []
for i in range(len(self.reference)):
if i == 0:
phase_change = unwrappedReference[1] - unwrappedReference[0]
freq_change = self.reference[1].freq - self.reference[0].freq
elif i == len(self.reference)-1:
idx = len(self.reference)-1
phase_change = unwrappedReference[idx] - unwrappedReference[idx-1]
freq_change = self.reference[idx].freq - self.reference[idx-1].freq
else:
phase_change = unwrappedReference[i+1] - unwrappedReference[i-1]
freq_change = self.reference[i+1].freq - self.reference[i-1].freq
delay = (-phase_change / (freq_change * 360)) * 10e8
if not self.reflective:
delay /= 2
self.groupDelayReference.append(delay)
self.groupDelay = self.calc_data(self.data)
self.groupDelayReference = self.calc_data(self.reference)
self.update()
def calc_data(self, data: List[Datapoint]):
data_len = len(data)
if data_len <= 1:
return []
unwrapped = np.degrees(np.unwrap([d.phase for d in data]))
delay_data = []
for i, d in enumerate(data):
# TODO: Replace with call to RFTools.groupDelay
if i == 0:
phase_change = unwrapped[1] - unwrapped[i]
freq_change = data[1].freq - d.freq
elif i == data_len - 1:
phase_change = unwrapped[-1] - unwrapped[-2]
freq_change = d.freq - data[-2].freq
else:
phase_change = unwrapped[i+1] - unwrapped[i-1]
freq_change = data[i+1].freq - data[i-1].freq
delay = (-phase_change / (freq_change * 360)) * 10e8
if not self.reflective:
delay /= 2
delay_data.append(delay)
return delay_data
def drawValues(self, qp: QtGui.QPainter):
if len(self.data) == 0 and len(self.reference) == 0:
return
@ -146,23 +122,19 @@ class GroupDelayChart(FrequencyChart):
self.span = span
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)
if delay != min_delay and delay != max_delay:
if delay not in {min_delay, max_delay}:
qp.setPen(QtGui.QPen(Chart.color.text))
if delay != 0:
digits = max(0, min(2, math.floor(3 - math.log10(abs(delay)))))
if digits == 0:
delaystr = str(round(delay))
else:
delaystr = str(round(delay, digits))
else:
delaystr = "0"
# TODO use format class
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,
self.topMargin,
self.leftMargin + self.dim.width,
@ -179,66 +151,48 @@ class GroupDelayChart(FrequencyChart):
self.drawFrequencyTicks(qp)
color = Chart.color.sweep
pen = QtGui.QPen(color)
pen.setWidth(self.dim.point)
line_pen = QtGui.QPen(color)
line_pen.setWidth(self.dim.line)
qp.setPen(pen)
for i in range(len(self.data)):
x = self.getXPosition(self.data[i])
y = self.getYPositionFromDelay(self.groupDelay[i])
if self.isPlotable(x, y):
qp.drawPoint(int(x), int(y))
if self.flag.draw_lines and i > 0:
prevx = self.getXPosition(self.data[i - 1])
prevy = self.getYPositionFromDelay(self.groupDelay[i - 1])
qp.setPen(line_pen)
if self.isPlotable(x, y) and self.isPlotable(prevx, prevy):
qp.drawLine(x, y, prevx, prevy)
elif self.isPlotable(x, y) and not self.isPlotable(prevx, prevy):
new_x, new_y = self.getPlotable(x, y, prevx, prevy)
qp.drawLine(x, y, new_x, new_y)
elif not self.isPlotable(x, y) and self.isPlotable(prevx, prevy):
new_x, new_y = self.getPlotable(prevx, prevy, x, y)
qp.drawLine(prevx, prevy, new_x, new_y)
qp.setPen(pen)
color = Chart.color.reference
pen = QtGui.QPen(color)
pen.setWidth(self.dim.point)
line_pen = QtGui.QPen(color)
line_pen.setWidth(self.dim.line)
qp.setPen(pen)
for i in range(len(self.reference)):
x = self.getXPosition(self.reference[i])
y = self.getYPositionFromDelay(self.groupDelayReference[i])
if self.isPlotable(x, y):
qp.drawPoint(int(x), int(y))
if self.flag.draw_lines and i > 0:
prevx = self.getXPosition(self.reference[i - 1])
prevy = self.getYPositionFromDelay(self.groupDelayReference[i - 1])
qp.setPen(line_pen)
if self.isPlotable(x, y) and self.isPlotable(prevx, prevy):
qp.drawLine(x, y, prevx, prevy)
elif self.isPlotable(x, y) and not self.isPlotable(prevx, prevy):
new_x, new_y = self.getPlotable(x, y, prevx, prevy)
qp.drawLine(x, y, new_x, new_y)
elif not self.isPlotable(x, y) and self.isPlotable(prevx, prevy):
new_x, new_y = self.getPlotable(prevx, prevy, x, y)
qp.drawLine(prevx, prevy, new_x, new_y)
qp.setPen(pen)
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]):
pen = QtGui.QPen(color)
pen.setWidth(self.dim.point)
line_pen = QtGui.QPen(color)
line_pen.setWidth(self.dim.line)
qp.setPen(pen)
for i, d in enumerate(data):
x = self.getXPosition(d)
y = self.getYPositionFromDelay(delay[i])
if self.isPlotable(x, y):
qp.drawPoint(int(x), int(y))
if self.flag.draw_lines and i > 0:
prevx = self.getXPosition(data[i - 1])
prevy = self.getYPositionFromDelay(delay[i - 1])
qp.setPen(line_pen)
if self.isPlotable(x, y) and self.isPlotable(prevx, prevy):
qp.drawLine(x, y, prevx, prevy)
elif self.isPlotable(x, y) and not self.isPlotable(prevx, prevy):
new_x, new_y = self.getPlotable(x, y, prevx, prevy)
qp.drawLine(x, y, new_x, new_y)
elif not self.isPlotable(x, y) and self.isPlotable(prevx, prevy):
new_x, new_y = self.getPlotable(prevx, prevy, x, y)
qp.drawLine(prevx, prevy, new_x, new_y)
qp.setPen(pen)
def getYPosition(self, d: Datapoint) -> int:
# TODO: Find a faster way than these expensive "d in self.data" lookups
if d in self.data:
# TODO: Find a faster way than these expensive "d in data" lookups
try:
delay = self.groupDelay[self.data.index(d)]
elif d in self.reference:
delay = self.groupDelayReference[self.reference.index(d)]
else:
delay = 0
except ValueError:
try:
delay = self.groupDelayReference[self.reference.index(d)]
except ValueError:
delay = 0
return self.getYPositionFromDelay(delay)
def getYPositionFromDelay(self, delay: float):

Wyświetl plik

@ -1,8 +1,8 @@
# NanoVNASaver
#
# A python program to view and export Touchstone data from a NanoVNA
# Copyright (C) 2019, 2020 Rune B. Broberg
# Copyright (C) 2020,2021 NanoVNA-Saver Authors
# Copyright (C) 2019, 2020 Rune B. Broberg
# Copyright (C) 2020ff NanoVNA-Saver Authors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -16,12 +16,9 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import math
import logging
from PyQt5 import QtGui, QtCore
from NanoVNASaver.RFTools import Datapoint
from NanoVNASaver.Charts.Chart import Chart
from NanoVNASaver.Charts.Square import SquareChart
@ -29,129 +26,32 @@ logger = logging.getLogger(__name__)
class PolarChart(SquareChart):
def __init__(self, name=""):
super().__init__(name)
self.dim.width = 250
self.dim.height = 250
self.setMinimumSize(self.dim.width + 40, self.dim.height + 40)
pal = QtGui.QPalette()
pal.setColor(QtGui.QPalette.Background, Chart.color.background)
self.setPalette(pal)
self.setAutoFillBackground(True)
def paintEvent(self, _: QtGui.QPaintEvent) -> None:
qp = QtGui.QPainter(self)
self.drawChart(qp)
self.drawValues(qp)
qp.end()
def drawChart(self, qp: QtGui.QPainter):
centerX = int(self.width()/2)
centerY = int(self.height()/2)
center_x = int(self.width()/2)
center_y = int(self.height()/2)
width_2 = int(self.dim.width / 2)
height_2 = int(self.dim.height / 2)
width_45 = width_2 * 0.7071
height_45 = height_2 * 0.7071
qp.setPen(QtGui.QPen(Chart.color.text))
qp.drawText(3, 15, self.name)
qp.setPen(QtGui.QPen(Chart.color.foreground))
qp.drawEllipse(QtCore.QPoint(centerX, centerY),
int(self.dim.width / 2),
int(self.dim.height / 2))
qp.drawEllipse(QtCore.QPoint(centerX, centerY),
int(self.dim.width / 4),
int(self.dim.height / 4))
qp.drawLine(centerX - int(self.dim.width / 2), centerY,
centerX + int(self.dim.width / 2), centerY)
qp.drawLine(centerX, centerY - int(self.dim.height / 2),
centerX, centerY + int(self.dim.height / 2))
qp.drawLine(centerX + int(self.dim.height / 2 * math.sin(math.pi / 4)),
centerY + int(self.dim.height / 2 * math.sin(math.pi / 4)),
centerX - int(self.dim.height / 2 * math.sin(math.pi / 4)),
centerY - int(self.dim.height / 2 * math.sin(math.pi / 4)))
qp.drawLine(centerX + int(self.dim.height / 2 * math.sin(math.pi / 4)),
centerY - int(self.dim.height / 2 * math.sin(math.pi / 4)),
centerX - int(self.dim.height / 2 * math.sin(math.pi / 4)),
centerY + int(self.dim.height / 2 * math.sin(math.pi / 4)))
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.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)
def drawValues(self, qp: QtGui.QPainter):
if len(self.data) == 0 and len(self.reference) == 0:
return
pen = QtGui.QPen(Chart.color.sweep)
pen.setWidth(self.dim.point)
line_pen = QtGui.QPen(Chart.color.sweep)
line_pen.setWidth(self.dim.line)
qp.setPen(pen)
for i in range(len(self.data)):
x = self.getXPosition(self.data[i])
y = self.height()/2 + self.data[i].im * -1 * self.dim.height/2
qp.drawPoint(int(x), int(y))
if self.flag.draw_lines and i > 0:
prevx = self.getXPosition(self.data[i-1])
prevy = self.height() / 2 + self.data[i-1].im * -1 * self.dim.height / 2
qp.setPen(line_pen)
qp.drawLine(x, y, prevx, prevy)
qp.setPen(pen)
pen.setColor(Chart.color.reference)
line_pen.setColor(Chart.color.reference)
qp.setPen(pen)
if len(self.data) > 0:
fstart = self.data[0].freq
fstop = self.data[len(self.data) - 1].freq
else:
fstart = self.reference[0].freq
fstop = self.reference[len(self.reference) - 1].freq
for i in range(len(self.reference)):
data = self.reference[i]
if data.freq < fstart or data.freq > fstop:
continue
x = self.getXPosition(self.reference[i])
y = self.height()/2 + data.im * -1 * self.dim.height/2
qp.drawPoint(int(x), int(y))
if self.flag.draw_lines and i > 0:
prevx = self.getXPosition(self.reference[i-1])
prevy = self.height() / 2 + self.reference[i-1].im * -1 * self.dim.height / 2
qp.setPen(line_pen)
qp.drawLine(x, y, prevx, prevy)
qp.setPen(pen)
# Now draw the markers
for m in self.markers:
if m.location != -1 and m.location < len(self.data):
x = self.getXPosition(self.data[m.location])
y = self.height() / 2 + self.data[m.location].im * -1 * self.dim.height / 2
self.drawMarker(x, y, qp, m.color, self.markers.index(m)+1)
def getXPosition(self, d: Datapoint) -> int:
return self.width()/2 + d.re * self.dim.width/2
def getYPosition(self, d: Datapoint) -> int:
return self.height()/2 + d.im * -1 * self.dim.height/2
def mouseMoveEvent(self, a0: QtGui.QMouseEvent) -> None:
if a0.buttons() == QtCore.Qt.RightButton:
a0.ignore()
return
x = a0.x()
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 len(self.data) == len(self.reference) == 0:
a0.ignore()
return
a0.accept()
if len(self.data) > 0:
target = self.data
else:
target = self.reference
positions = []
for d in target:
thisx = self.width() / 2 + d.re * self.dim.width / 2
thisy = self.height() / 2 + d.im * -1 * self.dim.height / 2
positions.append(math.sqrt((x - thisx)**2 + (y - thisy)**2))
minimum_position = positions.index(min(positions))
m = self.getActiveMarker()
if m is not None:
m.setFrequency(str(round(target[minimum_position].freq)))
m.frequencyInput.setText(str(round(target[minimum_position].freq)))
return
def zoomTo(self, x1, y1, x2, y2):
raise NotImplementedError()

Wyświetl plik

@ -1,8 +1,8 @@
# NanoVNASaver
#
# A python program to view and export Touchstone data from a NanoVNA
# Copyright (C) 2019, 2020 Rune B. Broberg
# Copyright (C) 2020,2021 NanoVNA-Saver Authors
# Copyright (C) 2019, 2020 Rune B. Broberg
# Copyright (C) 2020ff NanoVNA-Saver Authors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -16,12 +16,9 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import math
import logging
from PyQt5 import QtGui, QtCore
from NanoVNASaver.RFTools import Datapoint
from NanoVNASaver.Charts.Chart import Chart
from NanoVNASaver.Charts.Square import SquareChart
@ -29,25 +26,7 @@ logger = logging.getLogger(__name__)
class SmithChart(SquareChart):
def __init__(self, name=""):
super().__init__(name)
self.dim.width = 250
self.dim.height = 250
self.setMinimumSize(self.dim.width + 40, self.dim.height + 40)
pal = QtGui.QPalette()
pal.setColor(QtGui.QPalette.Background, Chart.color.background)
self.setPalette(pal)
self.setAutoFillBackground(True)
def paintEvent(self, _: QtGui.QPaintEvent) -> None:
qp = QtGui.QPainter(self)
# qp.begin(self) # Apparently not needed?
self.drawSmithChart(qp)
self.drawValues(qp)
qp.end()
def drawSmithChart(self, qp: QtGui.QPainter):
def drawChart(self, qp: QtGui.QPainter) -> None:
centerX = int(self.width()/2)
centerY = int(self.height()/2)
qp.setPen(QtGui.QPen(Chart.color.text))
@ -116,91 +95,5 @@ class SmithChart(SquareChart):
QtCore.QRect(centerX - 50, centerY - 4 + r, 100, 20),
QtCore.Qt.AlignCenter, str(swr))
def drawValues(self, qp: QtGui.QPainter):
if len(self.data) == 0 and len(self.reference) == 0:
return
pen = QtGui.QPen(Chart.color.sweep)
pen.setWidth(self.dim.point)
line_pen = QtGui.QPen(Chart.color.sweep)
line_pen.setWidth(self.dim.line)
highlighter = QtGui.QPen(QtGui.QColor(20, 0, 255))
highlighter.setWidth(1)
qp.setPen(pen)
for i in range(len(self.data)):
x = self.getXPosition(self.data[i])
y = int(self.height()/2 + self.data[i].im * -1 * self.dim.height/2)
qp.drawPoint(x, y)
if self.flag.draw_lines and i > 0:
prevx = self.getXPosition(self.data[i-1])
prevy = int(self.height() / 2 + self.data[i-1].im * -1 * self.dim.height / 2)
qp.setPen(line_pen)
qp.drawLine(x, y, prevx, prevy)
qp.setPen(pen)
pen.setColor(Chart.color.reference)
line_pen.setColor(Chart.color.reference)
qp.setPen(pen)
if len(self.data) > 0:
fstart = self.data[0].freq
fstop = self.data[len(self.data)-1].freq
else:
fstart = self.reference[0].freq
fstop = self.reference[len(self.reference)-1].freq
for i in range(len(self.reference)):
data = self.reference[i]
if data.freq < fstart or data.freq > fstop:
continue
x = self.getXPosition(data)
y = int(self.height()/2 + data.im * -1 * self.dim.height/2)
qp.drawPoint(x, y)
if self.flag.draw_lines and i > 0:
prevx = self.getXPosition(self.reference[i-1])
prevy = int(self.height() / 2 + self.reference[i-1].im * -1 * self.dim.height / 2)
qp.setPen(line_pen)
qp.drawLine(x, y, prevx, prevy)
qp.setPen(pen)
# Now draw the markers
for m in self.markers:
if m.location != -1:
x = self.getXPosition(self.data[m.location])
y = self.height() / 2 + self.data[m.location].im * -1 * self.dim.height / 2
self.drawMarker(x, y, qp, m.color, self.markers.index(m)+1)
def getXPosition(self, d: Datapoint) -> int:
return int(self.width()/2 + d.re * self.dim.width/2)
def getYPosition(self, d: Datapoint) -> int:
return int(self.height()/2 + d.im * -1 * self.dim.height/2)
def heightForWidth(self, a0: int) -> int:
return a0
def mouseMoveEvent(self, a0: QtGui.QMouseEvent) -> None:
if a0.buttons() == QtCore.Qt.RightButton:
a0.ignore()
return
x = a0.x()
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 len(self.data) == len(self.reference) == 0:
a0.ignore()
return
a0.accept()
if len(self.data) > 0:
target = self.data
else:
target = self.reference
positions = []
for d in target:
thisx = self.width() / 2 + d.re * self.dim.width / 2
thisy = self.height() / 2 + d.im * -1 * self.dim.height / 2
positions.append(math.sqrt((x - thisx)**2 + (y - thisy)**2))
minimum_position = positions.index(min(positions))
m = self.getActiveMarker()
if m is not None:
m.setFrequency(str(round(target[minimum_position].freq)))
m.frequencyInput.setText(str(round(target[minimum_position].freq)))
return
def zoomTo(self, x1, y1, x2, y2):
raise NotImplementedError()

Wyświetl plik

@ -17,23 +17,81 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import logging
import math
from typing import List
from PyQt5 import QtGui, QtCore
from PyQt5 import QtWidgets, QtGui
from NanoVNASaver.Charts.Chart import Chart
from NanoVNASaver.RFTools import Datapoint
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)
self.setSizePolicy(sizepolicy)
self.dim.width = self.width()-40
self.dim.height = self.height()-40
self.dim.width = 250
self.dim.height = 250
self.setMinimumSize(self.dim.width + 40, self.dim.height + 40)
pal = QtGui.QPalette()
pal.setColor(QtGui.QPalette.Background, Chart.color.background)
self.setPalette(pal)
self.setAutoFillBackground(True)
def paintEvent(self, _: QtGui.QPaintEvent) -> None:
qp = QtGui.QPainter(self)
self.drawChart(qp)
self.drawValues(qp)
qp.end()
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):
if not data:
return
fstop = fstop or data[-1].freq
pen = QtGui.QPen(color)
pen.setWidth(self.dim.point)
line_pen = QtGui.QPen(color)
line_pen.setWidth(self.dim.line)
qp.setPen(pen)
prev_x = self.getXPosition(data[0])
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)
if d.freq > fstart and d.freq < fstop:
qp.drawPoint(x, y)
if self.flag.draw_lines and i > 0:
qp.setPen(line_pen)
qp.drawLine(x, y, prev_x, prev_y)
qp.setPen(pen)
prev_x, prev_y = x, y
def drawValues(self, qp: QtGui.QPainter):
if not (self.data or self.reference):
return
self.draw_data(qp, Chart.color.sweep, self.data)
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)
for m in self.markers:
if m.location != -1 and m.location < len(self.data):
x = self.getXPosition(self.data[m.location])
y = self.height() / 2 + self.data[m.location].im * -1 * self.dim.height / 2
self.drawMarker(x, y, qp, m.color, self.markers.index(m)+1)
def resizeEvent(self, a0: QtGui.QResizeEvent) -> None:
if not self.flag.is_popout:
@ -44,3 +102,44 @@ class SquareChart(Chart):
min_dimension = min(a0.size().height(), a0.size().width())
self.dim.width = self.dim.height = min_dimension - 40
self.update()
def mouseMoveEvent(self, a0: QtGui.QMouseEvent):
if a0.buttons() == QtCore.Qt.RightButton:
a0.ignore()
return
x = a0.x()
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 len(self.data) == len(self.reference) == 0:
a0.ignore()
return
a0.accept()
target = self.data or self.reference
positions = []
dim_x_2 = self.dim.width / 2
dim_y_2 = self.dim.height / 2
width_2 = self.width() / 2
height_2 = self.height() / 2
positions = [
math.sqrt(
(x - (width_2 + d.re * dim_x_2))**2 +
(y - (height_2 - d.im * dim_y_2))**2)
for d in target
]
minimum_position = positions.index(min(positions))
if m := self.getActiveMarker():
m.setFrequency(str(round(target[minimum_position].freq)))
m.frequencyInput.setText(str(round(target[minimum_position].freq)))
def getXPosition(self, d: Datapoint) -> int:
return int(self.width()/2 + d.re * self.dim.width/2)
def getYPosition(self, d: Datapoint) -> int:
return int(self.height()/2 + d.im * -1 * self.dim.height/2)

Wyświetl plik

@ -34,6 +34,7 @@ from NanoVNASaver.Hardware.NanoVNA_H4 import NanoVNA_H4
from NanoVNASaver.Hardware.NanoVNA_V2 import NanoVNA_V2
from NanoVNASaver.Hardware.TinySA import TinySA
from NanoVNASaver.Hardware.Serial import drain_serial, Interface
from NanoVNASaver.Hardware.VNA import VNA
logger = logging.getLogger(__name__)

Wyświetl plik

@ -41,7 +41,7 @@ def drain_serial(serial_port: serial.Serial):
class Interface(serial.Serial):
def __init__(self, interface_type: str, comment, *args, **kwargs):
super().__init__(*args, **kwargs)
assert interface_type in ('serial', 'usb', 'bt', 'network')
assert interface_type in {'serial', 'usb', 'bt', 'network'}
self.type = interface_type
self.comment = comment
self.port = None

Wyświetl plik

@ -38,7 +38,7 @@ class TinySA(VNA):
def __init__(self, iface: Interface):
super().__init__(iface)
self.features = set(('Screenshots',))
self.features = {'Screenshots'}
logger.debug("Setting initial start,stop")
self.start, self.stop = self._get_running_frequencies()
self.sweep_max_freq_Hz = 950e6

Wyświetl plik

@ -77,15 +77,8 @@ class DeltaMarker(Marker):
RFTools.impedance_to_inductance(imp_p_b, s11_b.freq)-
RFTools.impedance_to_inductance(imp_p_a, s11_a.freq))
if imp.imag < 0:
x_str = cap_str
else:
x_str = ind_str
if imp_p.imag < 0:
x_p_str = cap_p_str
else:
x_p_str = ind_p_str
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))

Wyświetl plik

@ -84,9 +84,9 @@ class Value():
if s21:
s21 = [s21[0], ] + s21
if index == len(s11):
s11 = s11 + [s11[-1], ]
s11 += [s11[-1], ]
if s21:
s21 = s21 + [s21[-1], ]
s21 += [s21[-1], ]
self.freq = s11[1].freq
self.s11 = s11[index-1:index+2]
if s21:

Wyświetl plik

@ -271,7 +271,7 @@ class Marker(QtCore.QObject, Value):
self.location = i-1
if i < datasize:
self.frequencyInput.nextFrequency = item.freq
if (i-2) >= 0:
if i >= 2:
self.frequencyInput.previousFrequency = data[i-2].freq
return
# If we still didn't find a best spot, it was the last value
@ -317,15 +317,8 @@ class Marker(QtCore.QObject, Value):
ind_p_str = format_inductance(
RFTools.impedance_to_inductance(imp_p, _s11.freq))
if imp.imag < 0:
x_str = cap_str
else:
x_str = ind_str
if imp_p.imag < 0:
x_p_str = cap_p_str
else:
x_p_str = ind_p_str
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))
@ -342,7 +335,9 @@ class Marker(QtCore.QObject, Value):
self.label['s11mag'].setText(format_magnitude(abs(_s11.z)))
self.label['s11phase'].setText(format_phase(_s11.phase))
self.label['s11polar'].setText(
str(round(abs(_s11.z), 2)) + "" + format_phase(_s11.phase))
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)
@ -359,7 +354,9 @@ class Marker(QtCore.QObject, Value):
self.label['s21mag'].setText(format_magnitude(abs(_s21.z)))
self.label['s21phase'].setText(format_phase(_s21.phase))
self.label['s21polar'].setText(
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(
format_magnitude(abs(_s21.shuntImpedance())))
self.label['s21magseries'].setText(

Wyświetl plik

@ -16,6 +16,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
import contextlib
import logging
import typing
@ -132,10 +133,8 @@ class BandsModel(QtCore.QAbstractTableModel):
orientation: QtCore.Qt.Orientation, role: int = ...):
if (role == QtCore.Qt.DisplayRole and
orientation == QtCore.Qt.Horizontal):
try:
with contextlib.suppress(IndexError):
return _HEADER_DATA[section]
except IndexError:
pass
return None
def flags(self, index: QModelIndex) -> QtCore.Qt.ItemFlags:

Wyświetl plik

@ -192,12 +192,10 @@ class SweepWorker(QtCore.QRunnable):
if not self.app.calibration.isCalculated:
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)
else:
if self.app.calibration.isValid1Port():
for dp in raw_data11:
data11.append(self.app.calibration.correct11(dp))
else:
data11 = raw_data11.copy()
data11 = raw_data11.copy()
if self.app.calibration.isValid2Port():
for counter, dp in enumerate(raw_data21):

Wyświetl plik

@ -0,0 +1,24 @@
app-id: io.github.zarath.nanovna-saver
runtime: org.kde.Platform
runtime-version: '5.15-21.08'
sdk: org.kde.Sdk
command: /app/bin/NanoVNASaver
build-options:
build-args:
- --share=network
modules:
- name: nanonva-saver
buildsystem: simple
build-commands:
- pip3 install --prefix=/app wheel
- pip3 install --prefix=/app git+https://github.com/NanoVNA-Saver/nanovna-saver.git
finish-args:
# X11 + XShm access
- --share=ipc
- --socket=x11
# Wayland access
- --socket=wayland
# Needs access to NanoVNAs
- --device=all
# Needs to save files locally
- --filesystem=xdg-documents

Wyświetl plik

@ -13,7 +13,7 @@ packages = find_namespace:
install_requires=
pyserial>=3.5
PyQt5>=5.15.0
numpy>=1.21.1,<1.22.0
numpy>=1.21.1
scipy>=1.7.1
Cython>=0.29.24
python_requires = >=3.8, <4