Merge pull request #536 from zarath/bugfix/535_msspad

Made changes on suggestions of #535 by @msspad
pull/537/head
Holger Müller 2022-09-08 09:00:00 +02:00 zatwierdzone przez GitHub
commit b2b64ab9cd
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
7 zmienionych plików z 123 dodań i 108 usunięć

Wyświetl plik

@ -23,9 +23,9 @@ jobs:
run: |
python3.9 -m venv build
. build/bin/activate
python -m pip install pip==22.1.2 setuptools==62.6.0
python -m pip install pip==22.2.2 setuptools==65.3.0
pip install -r requirements.txt
pip install PyInstaller==5.1
pip install PyInstaller==5.3
- name: Build binary
run: |
. build/bin/activate

Wyświetl plik

@ -18,9 +18,9 @@ jobs:
python-version: 3.9
- name: Install dependencies and pyinstall
run: |
python -m pip install pip==22.1.2 setuptools==62.6.0
python -m pip install pip==22.2.2 setuptools==65.3.0
pip install -r requirements.txt
pip install PyInstaller=5.1
pip install PyInstaller=5.3
- name: Build binary
run: |
pyinstaller --onefile -n nanovna-saver nanovna-saver.py

Wyświetl plik

@ -22,9 +22,9 @@ jobs:
architecture: ${{ matrix.arch }}
- name: Install dependencies and pyinstall
run: |
python -m pip install pip==22.1.2 setuptools==62.6.0
python -m pip install pip==22.2.2 setuptools==65.3.0
pip install -r requirements.txt
pip install PyInstaller==5.1
pip install PyInstaller==5.3
- name: Build binary
run: |
pyinstaller --onefile -n nanovna-saver.exe nanovna-saver.py

Wyświetl plik

@ -109,11 +109,13 @@ class TDRChart(Chart):
self.y_action_set_fixed_maximum = QtWidgets.QAction(
f"Maximum ({self.maxImpedance})")
self.y_action_set_fixed_maximum.triggered.connect(self.setMaximumImpedance)
self.y_action_set_fixed_maximum.triggered.connect(
self.setMaximumImpedance)
self.y_action_set_fixed_minimum = QtWidgets.QAction(
f"Minimum ({self.minImpedance})")
self.y_action_set_fixed_minimum.triggered.connect(self.setMinimumImpedance)
self.y_action_set_fixed_minimum.triggered.connect(
self.setMinimumImpedance)
self.y_menu.addAction(self.y_action_set_fixed_maximum)
self.y_menu.addAction(self.y_action_set_fixed_minimum)
@ -143,7 +145,7 @@ class TDRChart(Chart):
def isPlotable(self, x, y):
return self.leftMargin <= x <= self.width() - self.rightMargin and \
self.topMargin <= y <= self.height() - self.bottomMargin
self.topMargin <= y <= self.height() - self.bottomMargin
def resetDisplayLimits(self):
self.fixedSpan = False
@ -256,10 +258,12 @@ class TDRChart(Chart):
return
a0.accept()
width = self.width() - self.leftMargin - self.rightMargin
if len(self.tdrWindow.td) > 0:
if self.tdrWindow.td.size:
if self.fixedSpan:
max_index = np.searchsorted(self.tdrWindow.distance_axis, self.maxDisplayLength * 2)
min_index = np.searchsorted(self.tdrWindow.distance_axis, self.minDisplayLength * 2)
max_index = np.searchsorted(
self.tdrWindow.distance_axis, self.maxDisplayLength * 2)
min_index = np.searchsorted(
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)
@ -290,11 +294,13 @@ class TDRChart(Chart):
ticks = math.floor((self.width() - self.leftMargin) / 100)
self.drawTitle(qp)
if self.tdrWindow.td:
if self.tdrWindow.td.size:
if self.fixedSpan:
max_length = max(0.1, self.maxDisplayLength)
max_index = np.searchsorted(self.tdrWindow.distance_axis, max_length * 2)
min_index = np.searchsorted(self.tdrWindow.distance_axis, self.minDisplayLength * 2)
max_index = np.searchsorted(
self.tdrWindow.distance_axis, max_length * 2)
min_index = np.searchsorted(
self.tdrWindow.distance_axis, self.minDisplayLength * 2)
if max_index == min_index:
if max_index < len(self.tdrWindow.distance_axis) - 1:
max_index += 1
@ -343,7 +349,7 @@ class TDRChart(Chart):
1)) + "m")
y_ticks = math.floor(height / 60)
y_tick_step = height/y_ticks
y_tick_step = height / y_ticks
for i in range(y_ticks):
y = self.bottomMargin + int(i * y_tick_step)
@ -353,7 +359,8 @@ class TDRChart(Chart):
qp.setPen(Chart.color.text)
qp.drawText(3, y + 3, str(round(y_val, 1)))
qp.drawText(3, self.topMargin + height + 3, str(round(min_impedance, 1)))
qp.drawText(3, self.topMargin + height + 3,
str(round(min_impedance, 1)))
pen = QtGui.QPen(Chart.color.sweep)
pen.setWidth(self.dim.point)
@ -363,15 +370,17 @@ class TDRChart(Chart):
continue
x = self.leftMargin + int((i - min_index) / x_step)
y = (self.topMargin + height) - int(self.tdrWindow.td[i] / y_step)
y = (self.topMargin + height) - \
int(self.tdrWindow.td[i] / y_step)
if self.isPlotable(x, y):
pen.setColor(Chart.color.sweep)
qp.setPen(pen)
qp.drawPoint(x, y)
x = self.leftMargin + int((i - min_index) / x_step)
y = (self.topMargin + height) -\
int((self.tdrWindow.step_response_Z[i]-min_impedance) / y_impedance_step)
y = (self.topMargin + height) - int(
(self.tdrWindow.step_response_Z[i] - min_impedance) /
y_impedance_step)
if self.isPlotable(x, y):
pen.setColor(Chart.color.sweep_secondary)
qp.setPen(pen)
@ -403,7 +412,8 @@ class TDRChart(Chart):
2)) + "m")
if self.dragbox.state and self.dragbox.pos[0] != -1:
dashed_pen = QtGui.QPen(Chart.color.foreground, 1, QtCore.Qt.DashLine)
dashed_pen = QtGui.QPen(
Chart.color.foreground, 1, QtCore.Qt.DashLine)
qp.setPen(dashed_pen)
qp.drawRect(
QtCore.QRect(
@ -415,7 +425,7 @@ class TDRChart(Chart):
qp.end()
def valueAtPosition(self, y):
if len(self.tdrWindow.td) > 0:
if self.tdrWindow.td.size:
height = self.height() - self.topMargin - self.bottomMargin
absy = (self.height() - y) - self.bottomMargin
if self.fixedValues:
@ -433,27 +443,24 @@ class TDRChart(Chart):
return 0
def lengthAtPosition(self, x, limit=True):
if not self.tdrWindow.td:
if not self.tdrWindow.td.size:
return 0
width = self.width() - self.leftMargin - self.rightMargin
absx = x - self.leftMargin
if self.fixedSpan:
max_length = self.maxDisplayLength
min_length = self.minDisplayLength
x_step = (max_length - min_length) / width
else:
min_length = 0
max_length = self.tdrWindow.distance_axis[
math.ceil(len(self.tdrWindow.distance_axis) / 2)] / 2
x_step = max_length / width
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)
x_step = (max_length - min_length) / width
if limit and absx < 0:
return min_length
if limit and absx > width:
return max_length
return 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)
logger.debug(
"Zoom to (x,y) by (x,y): (%d, %d) by (%d, %d)", x1, y1, x2, y2)
val1 = self.valueAtPosition(y1)
val2 = self.valueAtPosition(y2)

Wyświetl plik

@ -128,13 +128,30 @@ class NanoVNA_V2(VNA):
def readFrequencies(self) -> List[int]:
return [
int(self.sweepStartHz + i * self.sweepStepHz)
for i in range(self.datapoints)]
for i in range(self.datapoints)
]
def _read_pointstoread(self, pointstoread, arr) -> None:
freq_index = -1
for i in range(pointstoread):
(fwd_real, fwd_imag, rev0_real, rev0_imag, rev1_real,
rev1_imag, freq_index) = unpack_from(
"<iiiiiihxxxxxx", arr, i * 32)
fwd = complex(fwd_real, fwd_imag)
refl = complex(rev0_real, rev0_imag)
thru = complex(rev1_real, rev1_imag)
if i == 0:
logger.debug("Freq index from: %i", freq_index)
self._sweepdata[freq_index] = (refl / fwd, thru / fwd)
logger.debug("Freq index to: %i", freq_index)
def readValues(self, value) -> List[str]:
# Actually grab the data only when requesting channel 0.
# The hardware will return all channels which we will store.
if value == "data 0":
s21hack = "S21 hack" in self.features
s21hack = 1 if "S21 hack" in self.features else 0
# reset protocol to known state
timeout = self.serial.timeout
with self.serial.lock:
@ -146,7 +163,7 @@ class NanoVNA_V2(VNA):
sleep(WRITE_SLEEP)
# clear sweepdata
self._sweepdata = [(complex(), complex())] * (
self.datapoints + s21hack)
self.datapoints + s21hack)
pointstodo = self.datapoints + s21hack
# we read at most 255 values at a time and the time required empirically is
# just over 3 seconds for 101 points or 7 seconds for 255 points
@ -175,18 +192,7 @@ class NanoVNA_V2(VNA):
if nBytes != len(arr):
return []
freq_index = -1
for i in range(pointstoread):
(fwd_real, fwd_imag, rev0_real, rev0_imag, rev1_real,
rev1_imag, freq_index) = unpack_from(
"<iiiiiihxxxxxx", arr, i * 32)
fwd = complex(fwd_real, fwd_imag)
refl = complex(rev0_real, rev0_imag)
thru = complex(rev1_real, rev1_imag)
if i == 0:
logger.debug("Freq index from: %i", freq_index)
self._sweepdata[freq_index] = (refl / fwd, thru / fwd)
logger.debug("Freq index to: %i", freq_index)
self._read_pointstoread(pointstoread, arr)
pointstodo = pointstodo - pointstoread
self.serial.timeout = timeout
@ -194,24 +200,17 @@ class NanoVNA_V2(VNA):
if s21hack:
self._sweepdata = self._sweepdata[1:]
ret = [x[0] for x in self._sweepdata]
ret = [str(x.real) + ' ' + str(x.imag) for x in ret]
return ret
if value == "data 1":
ret = [x[1] for x in self._sweepdata]
ret = [str(x.real) + ' ' + str(x.imag) for x in ret]
return ret
return []
idx = 1 if value == "data 1" else 0
return [
f'{str(x[idx].real)} {str(x[idx].imag)}'
for x in self._sweepdata
]
def resetSweep(self, start: int, stop: int):
self.setSweep(start, stop)
def readVersion(self) -> 'Version':
cmd = pack("<BBBB",
_CMD_READ, _ADDR_FW_MAJOR,
_CMD_READ, _ADDR_FW_MINOR)
def _read_version(self, cmd_0: int, cmd_1: int):
cmd = pack("<BBBB", _CMD_READ, cmd_0, _CMD_READ, cmd_1)
with self.serial.lock:
self.serial.write(cmd)
sleep(WRITE_SLEEP)
@ -219,22 +218,17 @@ class NanoVNA_V2(VNA):
if len(resp) != 2:
logger.error("Timeout reading version registers. Got: %s", resp)
raise IOError("Timeout reading version registers")
result = Version(f"{resp[0]}.0.{resp[1]}")
return Version(f"{resp[0]}.0.{resp[1]}")
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':
cmd = pack("<BBBB",
_CMD_READ, _ADDR_DEVICE_VARIANT,
_CMD_READ, _ADDR_HARDWARE_REVISION)
with self.serial.lock:
self.serial.write(cmd)
sleep(WRITE_SLEEP)
resp = self.serial.read(2)
if len(resp) != 2:
logger.error("Timeout reading version registers")
return None
result = Version(f"{resp[0]}.0.{resp[1]}")
result = self._read_version(_ADDR_DEVICE_VARIANT,
_ADDR_HARDWARE_REVISION)
logger.debug("read_board_revision: %s", result)
return result

Wyświetl plik

@ -20,9 +20,9 @@ import logging
import math
import numpy as np
import scipy.signal as signal
from PyQt5 import QtWidgets, QtCore
from scipy import signal
from PyQt5 import QtWidgets, QtCore
logger = logging.getLogger(__name__)
@ -34,7 +34,7 @@ class TDRWindow(QtWidgets.QWidget):
super().__init__()
self.app = app
self.td = []
self.td = np.array([])
self.distance_axis = []
self.step_response = []
self.step_response_Z = []
@ -54,33 +54,47 @@ class TDRWindow(QtWidgets.QWidget):
self.tdr_velocity_dropdown.addItem("Pulp Insulation (0.72)", 0.72)
self.tdr_velocity_dropdown.addItem("Foam or Cellular PE (0.78)", 0.78)
self.tdr_velocity_dropdown.addItem("Semi-solid PE (SSPE) (0.84)", 0.84)
self.tdr_velocity_dropdown.addItem("Air (Helical spacers) (0.94)", 0.94)
self.tdr_velocity_dropdown.insertSeparator(self.tdr_velocity_dropdown.count())
self.tdr_velocity_dropdown.addItem(
"Air (Helical spacers) (0.94)", 0.94)
self.tdr_velocity_dropdown.insertSeparator(
self.tdr_velocity_dropdown.count())
# Lots of cable types added by Larry Goga, AE5CZ
self.tdr_velocity_dropdown.addItem("RG-6/U PE 75\N{OHM SIGN} (Belden 8215) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem("RG-6/U Foam 75\N{OHM SIGN} (Belden 9290) (0.81)", 0.81)
self.tdr_velocity_dropdown.addItem("RG-8/U PE 50\N{OHM SIGN} (Belden 8237) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem("RG-8/U Foam (Belden 8214) (0.78)", 0.78)
self.tdr_velocity_dropdown.addItem(
"RG-6/U PE 75\N{OHM SIGN} (Belden 8215) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem(
"RG-6/U Foam 75\N{OHM SIGN} (Belden 9290) (0.81)", 0.81)
self.tdr_velocity_dropdown.addItem(
"RG-8/U PE 50\N{OHM SIGN} (Belden 8237) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem(
"RG-8/U Foam (Belden 8214) (0.78)", 0.78)
self.tdr_velocity_dropdown.addItem("RG-8/U (Belden 9913) (0.84)", 0.84)
# Next one added by EKZ, KC3KZ, from measurement of actual cable
self.tdr_velocity_dropdown.addItem("RG-8/U (Shireen RFC®400 Low Loss) (0.86)", 0.86)
self.tdr_velocity_dropdown.addItem(
"RG-8/U (Shireen RFC®400 Low Loss) (0.86)", 0.86)
self.tdr_velocity_dropdown.addItem("RG-8X (Belden 9258) (0.82)", 0.82)
# Next three added by EKZ, KC3KZ, from measurement of actual cable
self.tdr_velocity_dropdown.addItem("RG-8X (Wireman \"Super 8\" CQ106) (0.81)", 0.81)
self.tdr_velocity_dropdown.addItem("RG-8X (Wireman \"MINI-8 Lo-Loss\" CQ118) (0.82)", 0.82)
self.tdr_velocity_dropdown.addItem(
"RG-8X (Wireman \"Super 8\" CQ106) (0.81)", 0.81)
self.tdr_velocity_dropdown.addItem(
"RG-8X (Wireman \"MINI-8 Lo-Loss\" CQ118) (0.82)", 0.82)
self.tdr_velocity_dropdown.addItem(
"RG-58 (Wireman \"CQ 58 Lo-Loss Flex\" CQ129FF) (0.79)", 0.79)
self.tdr_velocity_dropdown.addItem(
"RG-11/U 75\N{OHM SIGN} Foam HDPE (Belden 9292) (0.84)", 0.84)
self.tdr_velocity_dropdown.addItem("RG-58/U 52\N{OHM SIGN} PE (Belden 9201) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem(
"RG-58/U 52\N{OHM SIGN} PE (Belden 9201) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem(
"RG-58A/U 54\N{OHM SIGN} Foam (Belden 8219) (0.73)", 0.73)
self.tdr_velocity_dropdown.addItem("RG-59A/U PE 75\N{OHM SIGN} (Belden 8241) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem(
"RG-59A/U PE 75\N{OHM SIGN} (Belden 8241) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem(
"RG-59A/U Foam 75\N{OHM SIGN} (Belden 8241F) (0.78)", 0.78)
self.tdr_velocity_dropdown.addItem("RG-174 PE (Belden 8216)(0.66)", 0.66)
self.tdr_velocity_dropdown.addItem("RG-174 Foam (Belden 7805R) (0.735)", 0.735)
self.tdr_velocity_dropdown.addItem("RG-213/U PE (Belden 8267) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem(
"RG-174 PE (Belden 8216)(0.66)", 0.66)
self.tdr_velocity_dropdown.addItem(
"RG-174 Foam (Belden 7805R) (0.735)", 0.735)
self.tdr_velocity_dropdown.addItem(
"RG-213/U PE (Belden 8267) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem("RG316 (0.695)", 0.695)
self.tdr_velocity_dropdown.addItem("RG402 (0.695)", 0.695)
self.tdr_velocity_dropdown.addItem("LMR-240 (0.84)", 0.84)
@ -88,7 +102,8 @@ class TDRWindow(QtWidgets.QWidget):
self.tdr_velocity_dropdown.addItem("LMR-400 (0.85)", 0.85)
self.tdr_velocity_dropdown.addItem("LMR400UF (0.83)", 0.83)
self.tdr_velocity_dropdown.addItem("Davis Bury-FLEX (0.82)", 0.82)
self.tdr_velocity_dropdown.insertSeparator(self.tdr_velocity_dropdown.count())
self.tdr_velocity_dropdown.insertSeparator(
self.tdr_velocity_dropdown.count())
self.tdr_velocity_dropdown.addItem("Custom", -1)
self.tdr_velocity_dropdown.setCurrentIndex(1) # Default to PE (0.66)
@ -121,7 +136,8 @@ class TDRWindow(QtWidgets.QWidget):
self.tdr_velocity_input.setDisabled(False)
else:
self.tdr_velocity_input.setDisabled(True)
self.tdr_velocity_input.setText(str(self.tdr_velocity_dropdown.currentData()))
self.tdr_velocity_input.setText(
str(self.tdr_velocity_dropdown.currentData()))
try:
v = float(self.tdr_velocity_input.text())
@ -134,10 +150,7 @@ class TDRWindow(QtWidgets.QWidget):
logger.info("Cannot compute cable length at 0 span")
return
s11 = []
for d in self.app.data.s11:
s11.append(np.complex(d.re, d.im))
s11 = [np.complex(d.re, d.im) for d in self.app.data.s11]
window = np.blackman(len(self.app.data.s11))
windowed_s11 = window * s11
@ -145,18 +158,19 @@ class TDRWindow(QtWidgets.QWidget):
step = np.ones(FFT_POINTS)
self.step_response = signal.convolve(self.td, step)
self.step_response_Z = 50 * (1 + self.step_response) / (1 - self.step_response)
self.step_response_Z = 50 * (
1 + self.step_response) / (1 - self.step_response)
time_axis = np.linspace(0, 1/step_size, FFT_POINTS)
time_axis = np.linspace(0, 1 / step_size, FFT_POINTS)
self.distance_axis = time_axis * v * c
# peak = np.max(td)
# We should check that this is an actual *peak*, and not just a vague maximum
index_peak = np.argmax(self.td)
cable_len = round(self.distance_axis[index_peak]/2, 3)
cable_len = round(self.distance_axis[index_peak] / 2, 3)
feet = math.floor(cable_len / 0.3048)
inches = round(((cable_len / 0.3048) - feet)*12, 1)
inches = round(((cable_len / 0.3048) - feet) * 12, 1)
self.tdr_result_label.setText(f"{cable_len}m ({feet}ft {inches}in)")
self.app.tdr_result_label.setText(str(cable_len) + " m")
self.app.tdr_result_label.setText(f"{cable_len}m")
self.updated.emit()

Wyświetl plik

@ -1,5 +1,5 @@
pyserial==3.5
PyQt5==5.15.7
numpy==1.23.0
scipy==1.8.1
Cython==0.29.30
numpy==1.23.2
scipy==1.9.1
Cython==0.29.32