kopia lustrzana https://github.com/NanoVNA-Saver/nanovna-saver
Cable impedance measurement - first version.
rodzic
6acf4f532d
commit
55f7934df9
|
@ -1875,10 +1875,11 @@ class TDRChart(Chart):
|
|||
def __init__(self, name):
|
||||
super().__init__(name)
|
||||
self.tdrWindow = None
|
||||
self.leftMargin = 20
|
||||
self.leftMargin = 30
|
||||
self.rightMargin = 20
|
||||
self.bottomMargin = 35
|
||||
self.setMinimumSize(250, 250)
|
||||
self.bottomMargin = 25
|
||||
self.topMargin = 20
|
||||
self.setMinimumSize(300, 300)
|
||||
self.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding,
|
||||
QtWidgets.QSizePolicy.MinimumExpanding))
|
||||
pal = QtGui.QPalette()
|
||||
|
@ -1975,12 +1976,12 @@ class TDRChart(Chart):
|
|||
qp.drawText(3, 15, self.name)
|
||||
|
||||
width = self.width() - self.leftMargin - self.rightMargin
|
||||
height = self.height() - self.bottomMargin
|
||||
height = self.height() - self.bottomMargin - self.topMargin
|
||||
|
||||
qp.setPen(QtGui.QPen(self.foregroundColor))
|
||||
qp.drawLine(self.leftMargin - 5, self.height() - self.bottomMargin, self.width() - self.rightMargin,
|
||||
self.height() - self.bottomMargin)
|
||||
qp.drawLine(self.leftMargin, 20, self.leftMargin, self.height() - self.bottomMargin + 5)
|
||||
qp.drawLine(self.leftMargin, self.topMargin - 5, self.leftMargin, self.height() - self.bottomMargin + 5)
|
||||
|
||||
ticks = math.floor((self.width() - self.leftMargin)/100) # Number of ticks does not include the origin
|
||||
|
||||
|
@ -1991,33 +1992,58 @@ class TDRChart(Chart):
|
|||
x_step = (max_index - min_index) / width
|
||||
else:
|
||||
min_index = 0
|
||||
max_index = len(self.tdrWindow.distance_axis)
|
||||
x_step = len(self.tdrWindow.distance_axis) / (width * 2)
|
||||
max_index = math.ceil(len(self.tdrWindow.distance_axis) / 2)
|
||||
x_step = max_index / width
|
||||
|
||||
y_step = np.max(self.tdrWindow.td)*1.1 / height
|
||||
# TODO: Limit the search to the selected span?
|
||||
min_impedance = max(0, np.min(self.tdrWindow.step_response_Z) / 1.05)
|
||||
max_impedance = min(10000, np.max(self.tdrWindow.step_response_Z) * 1.05)
|
||||
|
||||
y_step = np.max(self.tdrWindow.td) * 1.1 / height
|
||||
y_impedance_step = (max_impedance - min_impedance) / height
|
||||
|
||||
for i in range(ticks):
|
||||
x = self.leftMargin + round((i + 1) * width / ticks)
|
||||
qp.setPen(QtGui.QPen(self.foregroundColor))
|
||||
qp.drawLine(x, 20, x, height)
|
||||
qp.drawLine(x, self.topMargin, x, self.topMargin + height)
|
||||
qp.setPen(QtGui.QPen(self.textColor))
|
||||
qp.drawText(x - 15, 20 + height,
|
||||
qp.drawText(x - 15, self.topMargin + height + 15,
|
||||
str(round(self.tdrWindow.distance_axis[min_index + int((x - self.leftMargin) * x_step) - 1]/2, 1)) + "m")
|
||||
|
||||
qp.setPen(QtGui.QPen(self.textColor))
|
||||
qp.drawText(self.leftMargin - 10, 20 + height,
|
||||
qp.drawText(self.leftMargin - 10, self.topMargin + height + 15,
|
||||
str(round(self.tdrWindow.distance_axis[min_index]/2, 1)) + "m")
|
||||
|
||||
y_ticks = math.floor(height / 60)
|
||||
y_tick_step = height/y_ticks
|
||||
|
||||
for i in range(y_ticks):
|
||||
y = self.bottomMargin + int(i * y_tick_step)
|
||||
qp.setPen(QtGui.QPen(self.foregroundColor))
|
||||
qp.drawLine(self.leftMargin, y, self.leftMargin + width, y)
|
||||
y_val = max_impedance - y_impedance_step * i * y_tick_step
|
||||
qp.drawText(3, y + 3, str(round(y_val, 1)))
|
||||
|
||||
qp.drawText(3, self.topMargin + height + 3, str(round(min_impedance, 1)))
|
||||
|
||||
pen = QtGui.QPen(self.sweepColor)
|
||||
pen.setWidth(self.pointSize)
|
||||
qp.setPen(pen)
|
||||
for i in range(len(self.tdrWindow.distance_axis)):
|
||||
for i in range(min_index, max_index):
|
||||
if i < min_index or i > max_index:
|
||||
continue
|
||||
qp.drawPoint(self.leftMargin + int((i - min_index) / x_step), height - int(self.tdrWindow.td[i] / y_step))
|
||||
pen.setColor(self.sweepColor)
|
||||
qp.setPen(pen)
|
||||
qp.drawPoint(self.leftMargin + int((i - min_index) / x_step),
|
||||
(self.topMargin + height) - int(self.tdrWindow.td[i] / y_step))
|
||||
pen.setColor(self.secondarySweepColor)
|
||||
qp.setPen(pen)
|
||||
qp.drawPoint(self.leftMargin + int((i - min_index) / x_step),
|
||||
(self.topMargin + height) - int((self.tdrWindow.step_response_Z[i]-min_impedance) / y_impedance_step))
|
||||
|
||||
id_max = np.argmax(self.tdrWindow.td)
|
||||
max_point = QtCore.QPoint(self.leftMargin + int((id_max - min_index) / x_step),
|
||||
height - int(self.tdrWindow.td[id_max] / y_step))
|
||||
(self.topMargin + 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)
|
||||
|
|
|
@ -22,6 +22,7 @@ from time import sleep, strftime, localtime
|
|||
from typing import List, Tuple
|
||||
|
||||
import numpy as np
|
||||
import scipy.signal as signal
|
||||
import serial
|
||||
import typing
|
||||
from PyQt5 import QtWidgets, QtCore, QtGui
|
||||
|
@ -1691,6 +1692,8 @@ class TDRWindow(QtWidgets.QWidget):
|
|||
|
||||
self.td = []
|
||||
self.distance_axis = []
|
||||
self.step_response = []
|
||||
self.step_response_Z = []
|
||||
|
||||
self.setWindowTitle("TDR")
|
||||
self.setWindowIcon(self.app.icon)
|
||||
|
@ -1754,6 +1757,9 @@ class TDRWindow(QtWidgets.QWidget):
|
|||
|
||||
def updateTDR(self):
|
||||
c = 299792458
|
||||
# TODO: Let the user select whether to use high or low resolution TDR?
|
||||
FFT_POINTS = 2**14
|
||||
|
||||
if len(self.app.data) < 2:
|
||||
return
|
||||
|
||||
|
@ -1781,12 +1787,14 @@ class TDRWindow(QtWidgets.QWidget):
|
|||
window = np.blackman(len(self.app.data))
|
||||
|
||||
windowed_s11 = window * s11
|
||||
self.td = np.abs(np.fft.ifft(windowed_s11, FFT_POINTS))
|
||||
step = np.ones(FFT_POINTS)
|
||||
self.step_response = signal.convolve(self.td, step)
|
||||
|
||||
self.td = np.abs(np.fft.ifft(windowed_s11, 2**16))
|
||||
self.step_response_Z = 50 * (1 + self.step_response) / (1 - self.step_response)
|
||||
|
||||
time_axis = np.linspace(0, 1/step_size, 2**16)
|
||||
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)
|
||||
|
||||
|
|
|
@ -14,5 +14,5 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
version = '0.1.4'
|
||||
debug = False
|
||||
version = '0.1.5alpha'
|
||||
debug = True
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
scipy
|
||||
pyqt5
|
||||
pyserial
|
||||
numpy
|
1
setup.py
1
setup.py
|
@ -52,5 +52,6 @@ setup(
|
|||
'pyserial',
|
||||
'PyQt5==5.11.2',
|
||||
'numpy',
|
||||
'scipy'
|
||||
],
|
||||
)
|
||||
|
|
Ładowanie…
Reference in New Issue