- TDR window with a chart of the TDR response

pull/17/head
Rune B. Broberg 2019-09-13 17:08:20 +02:00
rodzic eafb042bff
commit a5a4e0385a
2 zmienionych plików z 183 dodań i 89 usunięć

Wyświetl plik

@ -16,6 +16,7 @@
import collections
import math
from typing import List
import numpy as np
from PyQt5 import QtWidgets, QtGui, QtCore
@ -1103,3 +1104,58 @@ class QualityFactorChart(Chart):
re = d.re
im = d.im
return -math.degrees(math.atan2(im, re))
class TDRChart(Chart):
def __init__(self, name):
super().__init__()
self.name = name
self.tdrWindow = None
self.leftMargin = 20
self.rightMargin = 20
self.lowerMargin = 35
self.setMinimumSize(400, 400)
self.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding))
pal = QtGui.QPalette()
pal.setColor(QtGui.QPalette.Background, self.backgroundColor)
self.setPalette(pal)
self.setAutoFillBackground(True)
def paintEvent(self, a0: QtGui.QPaintEvent) -> None:
qp = QtGui.QPainter(self)
qp.setPen(QtGui.QPen(self.textColor))
qp.drawText(3, 15, self.name)
width = self.width() - self.leftMargin - self.rightMargin
height = self.height() - self.lowerMargin
qp.setPen(QtCore.Qt.lightGray)
qp.drawLine(self.leftMargin - 5, self.height() - self.lowerMargin, self.width() - self.rightMargin,
self.height() - self.lowerMargin)
qp.drawLine(self.leftMargin, 20, self.leftMargin, self.height() - self.lowerMargin + 5)
ticks = math.floor((self.width() - self.leftMargin)/100) # Number of ticks does not include the origin
if len(self.tdrWindow.td) > 0:
x_step = len(self.tdrWindow.distance_axis) / width
y_step = np.max(self.tdrWindow.td)*1.1 / height
for i in range(ticks):
x = self.leftMargin + round((i + 1) * width / ticks)
qp.setPen(QtGui.QPen(QtGui.QColor("lightgray")))
qp.drawLine(x, 20, x, height)
qp.setPen(QtGui.QPen(self.textColor))
qp.drawText(x - 20, 20 + height,
str(round(self.tdrWindow.distance_axis[int((x - self.leftMargin) * x_step) - 1]/2, 1)) + "m")
qp.setPen(self.tdrWindow.app.sweepColor)
for i in range(len(self.tdrWindow.distance_axis)):
qp.drawPoint(self.leftMargin + int(i / x_step), height - int(self.tdrWindow.td[i] / y_step))
id_max = np.argmax(self.tdrWindow.td)
max_point = QtCore.QPoint(self.leftMargin + int(id_max / x_step),
height - int(self.tdrWindow.td[id_max] / y_step))
qp.setPen(self.markers[0].color)
qp.drawEllipse(max_point, 2, 2)
qp.setPen(self.textColor)
qp.drawText(max_point.x() - 10, max_point.y() - 5, str(round(self.tdrWindow.distance_axis[id_max]/2, 2)) + "m")
qp.end()

Wyświetl plik

@ -24,7 +24,7 @@ import serial
from PyQt5 import QtWidgets, QtCore, QtGui
from serial.tools import list_ports
from .Chart import Chart, PhaseChart, VSWRChart, PolarChart, SmithChart, LogMagChart, QualityFactorChart
from .Chart import Chart, PhaseChart, VSWRChart, PolarChart, SmithChart, LogMagChart, QualityFactorChart, TDRChart
from .Calibration import CalibrationWindow, Calibration
from .Marker import Marker
from .SweepWorker import SweepWorker
@ -114,6 +114,9 @@ class NanoVNASaver(QtWidgets.QWidget):
self.charts = self.s11charts + self.s21charts
self.tdr_chart = TDRChart("TDR")
self.charts.append(self.tdr_chart)
self.charts_layout = QtWidgets.QGridLayout()
left_column = QtWidgets.QVBoxLayout()
@ -299,62 +302,23 @@ class NanoVNASaver(QtWidgets.QWidget):
# TDR
################################################################################################################
self.tdr_window = TDRWindow(self)
self.tdr_chart.tdrWindow = self.tdr_window
tdr_control_box = QtWidgets.QGroupBox()
tdr_control_box.setTitle("TDR")
tdr_control_layout = QtWidgets.QFormLayout()
tdr_control_box.setLayout(tdr_control_layout)
tdr_control_box.setMaximumWidth(250)
self.tdr_velocity_dropdown = QtWidgets.QComboBox()
self.tdr_velocity_dropdown.addItem("Jelly filled (0.64)", 0.64)
self.tdr_velocity_dropdown.addItem("Polyethylene (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem("PTFE (Teflon) (0.70)", 0.70)
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())
# Lots of table types added by Larry Goga, AE5CZ
self.tdr_velocity_dropdown.addItem("RG-6/U PE 75ohm (Belden 8215) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem("RG-6/U Foam 75 ohm (Belden 9290) (0.81)", 0.81)
self.tdr_velocity_dropdown.addItem("RG-8/U PE 75 ohm (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)
self.tdr_velocity_dropdown.addItem("RG-8X (Belden9258) (0.82)", 0.82)
self.tdr_velocity_dropdown.addItem("RG-11/U 75 ohm Foam HDPE (Belden 9292) (0.84)", 0.84)
self.tdr_velocity_dropdown.addItem("RG-58/U PE (Belden 9201) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem("RG-58A/U Foam (Belden 8219) (0.73)", 0.73)
self.tdr_velocity_dropdown.addItem("RG-59A/U PE 75 ohm (Belden 8241) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem("RG-59A/U Foam 75 ohm (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("RG316 (0.69)", 0.69)
self.tdr_velocity_dropdown.addItem("RG402 (0.695)", 0.695)
self.tdr_velocity_dropdown.addItem("LMR-240 (0.84)", 0.84)
self.tdr_velocity_dropdown.addItem("LMR-240UF (0.80)", 0.80)
self.tdr_velocity_dropdown.addItem("LMR-400 (0.85)", 0.85)
self.tdr_velocity_dropdown.addItem("LMR400UF (0.85)", 0.85)
self.tdr_velocity_dropdown.addItem("Davis BuryFlex (0.82)", 0.82)
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)
self.tdr_velocity_dropdown.currentIndexChanged.connect(self.updateTDR)
tdr_control_layout.addRow(self.tdr_velocity_dropdown)
self.tdr_velocity_input = QtWidgets.QLineEdit()
self.tdr_velocity_input.setDisabled(True)
self.tdr_velocity_input.setText("0.66")
self.tdr_velocity_input.textChanged.connect(self.updateTDR)
tdr_control_layout.addRow("Velocity factor", self.tdr_velocity_input)
self.tdr_result_label = QtWidgets.QLabel()
tdr_control_layout.addRow("Estimated cable length:", self.tdr_result_label)
self.tdr_button = QtWidgets.QPushButton("Time Domain Reflectometry ...")
self.tdr_button.clicked.connect(self.displayTDRWindow)
tdr_control_layout.addRow(self.tdr_button)
left_column.addWidget(tdr_control_box)
################################################################################################################
@ -745,8 +709,10 @@ class NanoVNASaver(QtWidgets.QWidget):
for c in self.s21charts:
c.setData(self.data21)
self.sweepProgressBar.setValue(self.worker.percentage)
self.updateTDR()
self.tdr_window.updateTDR()
# Find the minimum S11 VSWR:
minVSWR = 100
minVSWRfreq = -1
@ -842,46 +808,6 @@ class NanoVNASaver(QtWidgets.QWidget):
self.btnSweep.setDisabled(False)
self.btnStopSweep.setDisabled(True)
def updateTDR(self):
c = 299792458
if len(self.data) < 2:
return
if self.tdr_velocity_dropdown.currentData() == -1:
self.tdr_velocity_input.setDisabled(False)
else:
self.tdr_velocity_input.setDisabled(True)
self.tdr_velocity_input.setText(str(self.tdr_velocity_dropdown.currentData()))
try:
v = float(self.tdr_velocity_input.text())
except ValueError:
return
step_size = self.data[1].freq - self.data[0].freq
if step_size == 0:
self.tdr_result_label.setText("")
self.lister.appendPlainText("Cannot compute cable length at 0 span")
return
s11 = []
for d in self.data:
s11.append(np.complex(d.re, d.im))
window = np.blackman(len(self.data))
windowed_s11 = window * s11
td = np.abs(np.fft.ifft(windowed_s11, 2**14))
time_axis = np.linspace(0, 1/step_size, 2**14)
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(td)
self.tdr_result_label.setText(str(round(distance_axis[index_peak]/2, 3)) + " m")
def updateCenterSpan(self):
fstart = self.parseFrequency(self.sweepStartInput.text())
fstop = self.parseFrequency(self.sweepEndInput.text())
@ -1049,6 +975,10 @@ class NanoVNASaver(QtWidgets.QWidget):
self.fileWindow.show()
QtWidgets.QApplication.setActiveWindow(self.fileWindow)
def displayTDRWindow(self):
self.tdr_window.show()
QtWidgets.QApplication.setActiveWindow(self.tdr_window)
def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
self.worker.stopped = True
self.settings.setValue("Marker1Color", self.markers[0].color)
@ -1189,3 +1119,111 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
for c in self.app.charts:
c.setBackgroundColor(QtGui.QColor(QtCore.Qt.white))
c.setTextColor(QtGui.QColor(QtCore.Qt.black))
class TDRWindow(QtWidgets.QWidget):
def __init__(self, app: NanoVNASaver):
super().__init__()
self.app = app
self.td = []
self.distance_axis = []
self.setWindowTitle("TDR")
layout = QtWidgets.QFormLayout()
self.setLayout(layout)
self.tdr_velocity_dropdown = QtWidgets.QComboBox()
self.tdr_velocity_dropdown.addItem("Jelly filled (0.64)", 0.64)
self.tdr_velocity_dropdown.addItem("Polyethylene (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem("PTFE (Teflon) (0.70)", 0.70)
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())
# Lots of table types added by Larry Goga, AE5CZ
self.tdr_velocity_dropdown.addItem("RG-6/U PE 75ohm (Belden 8215) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem("RG-6/U Foam 75 ohm (Belden 9290) (0.81)", 0.81)
self.tdr_velocity_dropdown.addItem("RG-8/U PE 75 ohm (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)
self.tdr_velocity_dropdown.addItem("RG-8X (Belden9258) (0.82)", 0.82)
self.tdr_velocity_dropdown.addItem("RG-11/U 75 ohm Foam HDPE (Belden 9292) (0.84)", 0.84)
self.tdr_velocity_dropdown.addItem("RG-58/U PE (Belden 9201) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem("RG-58A/U Foam (Belden 8219) (0.73)", 0.73)
self.tdr_velocity_dropdown.addItem("RG-59A/U PE 75 ohm (Belden 8241) (0.66)", 0.66)
self.tdr_velocity_dropdown.addItem("RG-59A/U Foam 75 ohm (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("RG316 (0.69)", 0.69)
self.tdr_velocity_dropdown.addItem("RG402 (0.695)", 0.695)
self.tdr_velocity_dropdown.addItem("LMR-240 (0.84)", 0.84)
self.tdr_velocity_dropdown.addItem("LMR-240UF (0.80)", 0.80)
self.tdr_velocity_dropdown.addItem("LMR-400 (0.85)", 0.85)
self.tdr_velocity_dropdown.addItem("LMR400UF (0.85)", 0.85)
self.tdr_velocity_dropdown.addItem("Davis BuryFlex (0.82)", 0.82)
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)
self.tdr_velocity_dropdown.currentIndexChanged.connect(self.updateTDR)
layout.addRow(self.tdr_velocity_dropdown)
self.tdr_velocity_input = QtWidgets.QLineEdit()
self.tdr_velocity_input.setDisabled(True)
self.tdr_velocity_input.setText("0.66")
self.tdr_velocity_input.textChanged.connect(self.app.dataUpdated)
layout.addRow("Velocity factor", self.tdr_velocity_input)
self.tdr_result_label = QtWidgets.QLabel()
layout.addRow("Estimated cable length:", self.tdr_result_label)
layout.addRow(self.app.tdr_chart)
def updateTDR(self):
c = 299792458
if len(self.app.data) < 2:
return
if self.tdr_velocity_dropdown.currentData() == -1:
self.tdr_velocity_input.setDisabled(False)
else:
self.tdr_velocity_input.setDisabled(True)
self.tdr_velocity_input.setText(str(self.tdr_velocity_dropdown.currentData()))
try:
v = float(self.tdr_velocity_input.text())
except ValueError:
return
step_size = self.app.data[1].freq - self.app.data[0].freq
if step_size == 0:
self.tdr_result_label.setText("")
self.lister.appendPlainText("Cannot compute cable length at 0 span")
return
s11 = []
for d in self.app.data:
s11.append(np.complex(d.re, d.im))
window = np.blackman(len(self.app.data))
windowed_s11 = window * s11
self.td = np.abs(np.fft.ifft(windowed_s11, 2**14))
time_axis = np.linspace(0, 1/step_size, 2**14)
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)
self.tdr_result_label.setText(str(round(self.distance_axis[index_peak]/2, 3)) + " m")
self.app.tdr_result_label.setText(str(round(self.distance_axis[index_peak] / 2, 3)) + " m")
self.app.tdr_chart.update()