2020-06-25 17:52:30 +00:00
|
|
|
# NanoVNASaver
|
|
|
|
#
|
|
|
|
# A python program to view and export Touchstone data from a NanoVNA
|
|
|
|
# Copyright (C) 2019, 2020 Rune B. Broberg
|
2021-06-30 05:21:14 +00:00
|
|
|
# Copyright (C) 2020,2021 NanoVNA-Saver Authors
|
2019-09-01 21:13:21 +00:00
|
|
|
#
|
|
|
|
# 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
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2019-09-05 12:56:40 +00:00
|
|
|
import math
|
2019-09-22 11:42:05 +00:00
|
|
|
import logging
|
2019-09-01 21:13:21 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
import numpy as np
|
2019-09-01 21:13:21 +00:00
|
|
|
from PyQt5 import QtWidgets, QtGui, QtCore
|
2019-09-05 12:56:40 +00:00
|
|
|
|
2021-07-06 15:01:20 +00:00
|
|
|
from NanoVNASaver.Charts.Chart import Chart
|
2019-09-24 21:29:26 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
2019-09-24 21:29:26 +00:00
|
|
|
|
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
class TDRChart(Chart):
|
|
|
|
maxDisplayLength = 50
|
|
|
|
minDisplayLength = 0
|
2019-09-24 21:29:26 +00:00
|
|
|
fixedSpan = False
|
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
minImpedance = 0
|
|
|
|
maxImpedance = 1000
|
|
|
|
fixedValues = False
|
2019-09-24 21:29:26 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
markerLocation = -1
|
2019-09-29 14:34:50 +00:00
|
|
|
|
2019-09-24 21:29:26 +00:00
|
|
|
def __init__(self, name):
|
|
|
|
super().__init__(name)
|
2020-05-18 18:58:18 +00:00
|
|
|
self.tdrWindow = None
|
2022-05-28 20:50:07 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
self.bottomMargin = 25
|
|
|
|
self.topMargin = 20
|
2022-05-28 20:50:07 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
self.setMinimumSize(300, 300)
|
2020-06-15 11:27:00 +00:00
|
|
|
self.setSizePolicy(
|
|
|
|
QtWidgets.QSizePolicy(
|
|
|
|
QtWidgets.QSizePolicy.MinimumExpanding,
|
|
|
|
QtWidgets.QSizePolicy.MinimumExpanding))
|
2020-05-18 18:58:18 +00:00
|
|
|
pal = QtGui.QPalette()
|
2021-07-06 15:01:20 +00:00
|
|
|
pal.setColor(QtGui.QPalette.Background, Chart.color.background)
|
2020-05-18 18:58:18 +00:00
|
|
|
self.setPalette(pal)
|
|
|
|
self.setAutoFillBackground(True)
|
2019-09-24 21:29:26 +00:00
|
|
|
|
2019-09-29 18:30:25 +00:00
|
|
|
self.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu)
|
2019-09-24 21:29:26 +00:00
|
|
|
self.menu = QtWidgets.QMenu()
|
2019-09-25 10:25:50 +00:00
|
|
|
|
|
|
|
self.reset = QtWidgets.QAction("Reset")
|
|
|
|
self.reset.triggered.connect(self.resetDisplayLimits)
|
|
|
|
self.menu.addAction(self.reset)
|
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
self.x_menu = QtWidgets.QMenu("Length axis")
|
|
|
|
self.mode_group = QtWidgets.QActionGroup(self.x_menu)
|
2019-09-24 21:29:26 +00:00
|
|
|
self.action_automatic = QtWidgets.QAction("Automatic")
|
|
|
|
self.action_automatic.setCheckable(True)
|
|
|
|
self.action_automatic.setChecked(True)
|
2020-06-15 11:27:00 +00:00
|
|
|
self.action_automatic.changed.connect(
|
|
|
|
lambda: self.setFixedSpan(self.action_fixed_span.isChecked()))
|
2019-09-24 21:29:26 +00:00
|
|
|
self.action_fixed_span = QtWidgets.QAction("Fixed span")
|
|
|
|
self.action_fixed_span.setCheckable(True)
|
2020-06-15 11:27:00 +00:00
|
|
|
self.action_fixed_span.changed.connect(
|
|
|
|
lambda: self.setFixedSpan(self.action_fixed_span.isChecked()))
|
2020-05-18 18:58:18 +00:00
|
|
|
self.mode_group.addAction(self.action_automatic)
|
|
|
|
self.mode_group.addAction(self.action_fixed_span)
|
2019-09-24 21:29:26 +00:00
|
|
|
self.x_menu.addAction(self.action_automatic)
|
|
|
|
self.x_menu.addAction(self.action_fixed_span)
|
|
|
|
self.x_menu.addSeparator()
|
|
|
|
|
2020-06-15 11:27:00 +00:00
|
|
|
self.action_set_fixed_start = QtWidgets.QAction(
|
|
|
|
f"Start ({self.minDisplayLength})")
|
2020-05-18 18:58:18 +00:00
|
|
|
self.action_set_fixed_start.triggered.connect(self.setMinimumLength)
|
2019-09-24 21:29:26 +00:00
|
|
|
|
2020-06-15 11:27:00 +00:00
|
|
|
self.action_set_fixed_stop = QtWidgets.QAction(
|
|
|
|
f"Stop ({self.maxDisplayLength})")
|
2020-05-18 18:58:18 +00:00
|
|
|
self.action_set_fixed_stop.triggered.connect(self.setMaximumLength)
|
2019-09-24 21:29:26 +00:00
|
|
|
|
|
|
|
self.x_menu.addAction(self.action_set_fixed_start)
|
|
|
|
self.x_menu.addAction(self.action_set_fixed_stop)
|
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
self.y_menu = QtWidgets.QMenu("Impedance axis")
|
|
|
|
self.y_mode_group = QtWidgets.QActionGroup(self.y_menu)
|
2019-09-24 21:29:26 +00:00
|
|
|
self.y_action_automatic = QtWidgets.QAction("Automatic")
|
|
|
|
self.y_action_automatic.setCheckable(True)
|
|
|
|
self.y_action_automatic.setChecked(True)
|
2020-06-15 11:27:00 +00:00
|
|
|
self.y_action_automatic.changed.connect(
|
|
|
|
lambda: self.setFixedValues(self.y_action_fixed.isChecked()))
|
2020-05-18 18:58:18 +00:00
|
|
|
self.y_action_fixed = QtWidgets.QAction("Fixed")
|
|
|
|
self.y_action_fixed.setCheckable(True)
|
2020-06-15 11:27:00 +00:00
|
|
|
self.y_action_fixed.changed.connect(
|
|
|
|
lambda: self.setFixedValues(self.y_action_fixed.isChecked()))
|
2020-05-18 18:58:18 +00:00
|
|
|
self.y_mode_group.addAction(self.y_action_automatic)
|
|
|
|
self.y_mode_group.addAction(self.y_action_fixed)
|
2019-09-24 21:29:26 +00:00
|
|
|
self.y_menu.addAction(self.y_action_automatic)
|
2020-05-18 18:58:18 +00:00
|
|
|
self.y_menu.addAction(self.y_action_fixed)
|
2019-09-24 21:29:26 +00:00
|
|
|
self.y_menu.addSeparator()
|
|
|
|
|
2020-06-15 11:27:00 +00:00
|
|
|
self.y_action_set_fixed_maximum = QtWidgets.QAction(
|
|
|
|
f"Maximum ({self.maxImpedance})")
|
2020-05-18 18:58:18 +00:00
|
|
|
self.y_action_set_fixed_maximum.triggered.connect(self.setMaximumImpedance)
|
2019-09-24 21:29:26 +00:00
|
|
|
|
2020-06-15 11:27:00 +00:00
|
|
|
self.y_action_set_fixed_minimum = QtWidgets.QAction(
|
|
|
|
f"Minimum ({self.minImpedance})")
|
2020-05-18 18:58:18 +00:00
|
|
|
self.y_action_set_fixed_minimum.triggered.connect(self.setMinimumImpedance)
|
2019-09-24 21:29:26 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
self.y_menu.addAction(self.y_action_set_fixed_maximum)
|
|
|
|
self.y_menu.addAction(self.y_action_set_fixed_minimum)
|
2019-09-24 21:29:26 +00:00
|
|
|
|
|
|
|
self.menu.addMenu(self.x_menu)
|
|
|
|
self.menu.addMenu(self.y_menu)
|
2019-09-29 18:30:25 +00:00
|
|
|
self.menu.addSeparator()
|
|
|
|
self.menu.addAction(self.action_save_screenshot)
|
2019-10-13 08:37:14 +00:00
|
|
|
self.action_popout = QtWidgets.QAction("Popout chart")
|
2020-06-15 11:27:00 +00:00
|
|
|
self.action_popout.triggered.connect(
|
|
|
|
lambda: self.popoutRequested.emit(self))
|
2019-10-13 08:37:14 +00:00
|
|
|
self.menu.addAction(self.action_popout)
|
2019-11-22 13:07:38 +00:00
|
|
|
|
2021-06-26 22:55:43 +00:00
|
|
|
self.dim.width = self.width() - self.leftMargin - self.rightMargin
|
|
|
|
self.dim.height = self.height() - self.bottomMargin - self.topMargin
|
2019-11-22 13:07:38 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
def contextMenuEvent(self, event):
|
2020-06-15 11:27:00 +00:00
|
|
|
self.action_set_fixed_start.setText(
|
|
|
|
f"Start ({self.minDisplayLength})")
|
|
|
|
self.action_set_fixed_stop.setText(
|
|
|
|
f"Stop ({self.maxDisplayLength})")
|
|
|
|
self.y_action_set_fixed_minimum.setText(
|
|
|
|
f"Minimum ({self.minImpedance})")
|
|
|
|
self.y_action_set_fixed_maximum.setText(
|
|
|
|
f"Maximum ({self.maxImpedance})")
|
2019-09-24 21:29:26 +00:00
|
|
|
self.menu.exec_(event.globalPos())
|
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
def isPlotable(self, x, y):
|
|
|
|
return self.leftMargin <= x <= self.width() - self.rightMargin and \
|
|
|
|
self.topMargin <= y <= self.height() - self.bottomMargin
|
2019-09-24 21:29:26 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
def resetDisplayLimits(self):
|
|
|
|
self.fixedSpan = False
|
|
|
|
self.minDisplayLength = 0
|
|
|
|
self.maxDisplayLength = 100
|
|
|
|
self.fixedValues = False
|
|
|
|
self.minImpedance = 0
|
|
|
|
self.maxImpedance = 1000
|
2019-09-24 21:29:26 +00:00
|
|
|
self.update()
|
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
def setFixedSpan(self, fixed_span):
|
|
|
|
self.fixedSpan = fixed_span
|
2019-10-12 20:33:45 +00:00
|
|
|
self.update()
|
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
def setMinimumLength(self):
|
2020-06-15 11:27:00 +00:00
|
|
|
min_val, selected = QtWidgets.QInputDialog.getDouble(
|
|
|
|
self, "Start length (m)",
|
|
|
|
"Set start length (m)", value=self.minDisplayLength,
|
|
|
|
min=0, decimals=1)
|
2019-09-24 21:29:26 +00:00
|
|
|
if not selected:
|
|
|
|
return
|
2020-05-18 18:58:18 +00:00
|
|
|
if not (self.fixedSpan and min_val >= self.maxDisplayLength):
|
|
|
|
self.minDisplayLength = min_val
|
2019-09-24 21:29:26 +00:00
|
|
|
if self.fixedSpan:
|
|
|
|
self.update()
|
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
def setMaximumLength(self):
|
2020-06-15 11:27:00 +00:00
|
|
|
max_val, selected = QtWidgets.QInputDialog.getDouble(
|
|
|
|
self, "Stop length (m)",
|
|
|
|
"Set stop length (m)", value=self.minDisplayLength,
|
|
|
|
min=0.1, decimals=1)
|
2019-09-24 21:29:26 +00:00
|
|
|
if not selected:
|
|
|
|
return
|
2020-05-18 18:58:18 +00:00
|
|
|
if not (self.fixedSpan and max_val <= self.minDisplayLength):
|
|
|
|
self.maxDisplayLength = max_val
|
2019-09-24 21:29:26 +00:00
|
|
|
if self.fixedSpan:
|
|
|
|
self.update()
|
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
def setFixedValues(self, fixed_values):
|
|
|
|
self.fixedValues = fixed_values
|
|
|
|
self.update()
|
|
|
|
|
|
|
|
def setMinimumImpedance(self):
|
2020-06-15 11:27:00 +00:00
|
|
|
min_val, selected = QtWidgets.QInputDialog.getDouble(
|
|
|
|
self, "Minimum impedance (\N{OHM SIGN})",
|
|
|
|
"Set minimum impedance (\N{OHM SIGN})",
|
|
|
|
value=self.minDisplayLength,
|
|
|
|
min=0, decimals=1)
|
2019-09-24 21:29:26 +00:00
|
|
|
if not selected:
|
|
|
|
return
|
2020-05-18 18:58:18 +00:00
|
|
|
if not (self.fixedValues and min_val >= self.maxImpedance):
|
|
|
|
self.minImpedance = min_val
|
2019-09-24 21:29:26 +00:00
|
|
|
if self.fixedValues:
|
|
|
|
self.update()
|
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
def setMaximumImpedance(self):
|
2020-06-15 11:27:00 +00:00
|
|
|
max_val, selected = QtWidgets.QInputDialog.getDouble(
|
|
|
|
self, "Maximum impedance (\N{OHM SIGN})",
|
|
|
|
"Set maximum impedance (\N{OHM SIGN})",
|
|
|
|
value=self.minDisplayLength,
|
|
|
|
min=0.1, decimals=1)
|
2019-09-24 21:29:26 +00:00
|
|
|
if not selected:
|
|
|
|
return
|
2020-05-18 18:58:18 +00:00
|
|
|
if not (self.fixedValues and max_val <= self.minImpedance):
|
|
|
|
self.maxImpedance = max_val
|
2019-09-24 21:29:26 +00:00
|
|
|
if self.fixedValues:
|
|
|
|
self.update()
|
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
def copy(self):
|
|
|
|
new_chart: TDRChart = super().copy()
|
|
|
|
new_chart.tdrWindow = self.tdrWindow
|
|
|
|
new_chart.minDisplayLength = self.minDisplayLength
|
|
|
|
new_chart.maxDisplayLength = self.maxDisplayLength
|
|
|
|
new_chart.fixedSpan = self.fixedSpan
|
|
|
|
new_chart.minImpedance = self.minImpedance
|
|
|
|
new_chart.maxImpedance = self.maxImpedance
|
|
|
|
new_chart.fixedValues = self.fixedValues
|
|
|
|
self.tdrWindow.updated.connect(new_chart.update)
|
|
|
|
return new_chart
|
2019-11-08 09:17:58 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
def mouseMoveEvent(self, a0: QtGui.QMouseEvent) -> None:
|
|
|
|
if a0.buttons() == QtCore.Qt.RightButton:
|
2019-11-11 22:55:05 +00:00
|
|
|
a0.ignore()
|
|
|
|
return
|
2020-05-18 18:58:18 +00:00
|
|
|
if a0.buttons() == QtCore.Qt.MiddleButton:
|
|
|
|
# Drag the display
|
|
|
|
a0.accept()
|
2021-06-27 08:59:07 +00:00
|
|
|
if self.dragbox.move_x != -1 and self.dragbox.move_y != -1:
|
|
|
|
dx = self.dragbox.move_x - a0.x()
|
|
|
|
dy = self.dragbox.move_y - a0.y()
|
2020-05-18 18:58:18 +00:00
|
|
|
self.zoomTo(self.leftMargin + dx, self.topMargin + dy,
|
2021-06-26 22:55:43 +00:00
|
|
|
self.leftMargin + self.dim.width + dx,
|
|
|
|
self.topMargin + self.dim.height + dy)
|
2021-06-27 08:59:07 +00:00
|
|
|
self.dragbox.move_x = a0.x()
|
|
|
|
self.dragbox.move_y = a0.y()
|
2020-05-18 18:58:18 +00:00
|
|
|
return
|
2019-11-22 13:13:39 +00:00
|
|
|
if a0.modifiers() == QtCore.Qt.ControlModifier:
|
2020-05-18 18:58:18 +00:00
|
|
|
# Dragging a box
|
2021-06-27 08:59:07 +00:00
|
|
|
if not self.dragbox.state:
|
|
|
|
self.dragbox.pos_start = (a0.x(), a0.y())
|
|
|
|
self.dragbox.pos = (a0.x(), a0.y())
|
2020-05-18 18:58:18 +00:00
|
|
|
self.update()
|
2019-11-10 21:59:16 +00:00
|
|
|
a0.accept()
|
2019-09-25 10:25:50 +00:00
|
|
|
return
|
2019-11-16 11:07:32 +00:00
|
|
|
|
2019-09-25 10:25:50 +00:00
|
|
|
x = a0.x()
|
2020-05-18 18:58:18 +00:00
|
|
|
absx = x - self.leftMargin
|
|
|
|
if absx < 0 or absx > self.width() - self.rightMargin:
|
2019-09-25 10:25:50 +00:00
|
|
|
a0.ignore()
|
|
|
|
return
|
2020-05-18 18:58:18 +00:00
|
|
|
a0.accept()
|
|
|
|
width = self.width() - self.leftMargin - self.rightMargin
|
2022-09-07 08:37:37 +00:00
|
|
|
if self.tdrWindow.td:
|
2020-05-18 18:58:18 +00:00
|
|
|
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)
|
|
|
|
x_step = (max_index - min_index) / width
|
|
|
|
else:
|
|
|
|
max_index = math.ceil(len(self.tdrWindow.distance_axis) / 2)
|
|
|
|
x_step = max_index / width
|
2019-09-25 10:25:50 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
self.markerLocation = int(round(absx * x_step))
|
|
|
|
self.update()
|
|
|
|
return
|
2019-09-29 14:34:50 +00:00
|
|
|
|
2021-06-26 22:23:54 +00:00
|
|
|
def paintEvent(self, _: QtGui.QPaintEvent) -> None:
|
2019-09-29 16:56:53 +00:00
|
|
|
qp = QtGui.QPainter(self)
|
2021-07-06 15:01:20 +00:00
|
|
|
qp.setPen(QtGui.QPen(Chart.color.text))
|
2019-12-12 14:16:37 +00:00
|
|
|
qp.drawText(3, 15, self.name)
|
2020-05-18 18:58:18 +00:00
|
|
|
|
|
|
|
width = self.width() - self.leftMargin - self.rightMargin
|
|
|
|
height = self.height() - self.bottomMargin - self.topMargin
|
|
|
|
|
2021-07-06 15:01:20 +00:00
|
|
|
qp.setPen(QtGui.QPen(Chart.color.foreground))
|
2020-06-15 11:27:00 +00:00
|
|
|
qp.drawLine(self.leftMargin - 5,
|
|
|
|
self.height() - self.bottomMargin,
|
|
|
|
self.width() - self.rightMargin,
|
2020-05-18 18:58:18 +00:00
|
|
|
self.height() - self.bottomMargin)
|
2020-06-15 11:27:00 +00:00
|
|
|
qp.drawLine(self.leftMargin,
|
|
|
|
self.topMargin - 5,
|
|
|
|
self.leftMargin,
|
|
|
|
self.height() - self.bottomMargin + 5)
|
|
|
|
# Number of ticks does not include the origin
|
|
|
|
ticks = math.floor((self.width() - self.leftMargin) / 100)
|
2019-12-12 14:16:37 +00:00
|
|
|
self.drawTitle(qp)
|
|
|
|
|
2022-05-28 19:48:13 +00:00
|
|
|
if self.tdrWindow.td:
|
2020-05-18 18:58:18 +00:00
|
|
|
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)
|
|
|
|
if max_index == min_index:
|
|
|
|
if max_index < len(self.tdrWindow.distance_axis) - 1:
|
|
|
|
max_index += 1
|
|
|
|
else:
|
|
|
|
min_index -= 1
|
|
|
|
x_step = (max_index - min_index) / width
|
2019-10-12 20:33:45 +00:00
|
|
|
else:
|
2020-05-18 18:58:18 +00:00
|
|
|
min_index = 0
|
|
|
|
max_index = math.ceil(len(self.tdrWindow.distance_axis) / 2)
|
|
|
|
x_step = max_index / width
|
2019-10-12 20:33:45 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
if self.fixedValues:
|
|
|
|
min_impedance = max(0, self.minImpedance)
|
|
|
|
max_impedance = max(0.1, self.maxImpedance)
|
|
|
|
else:
|
|
|
|
# TODO: Limit the search to the selected span?
|
2020-06-15 11:27:00 +00:00
|
|
|
min_impedance = max(
|
|
|
|
0,
|
|
|
|
np.min(self.tdrWindow.step_response_Z) / 1.05)
|
|
|
|
max_impedance = min(
|
|
|
|
1000,
|
|
|
|
np.max(self.tdrWindow.step_response_Z) * 1.05)
|
2019-09-26 20:57:34 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
y_step = np.max(self.tdrWindow.td) * 1.1 / height
|
|
|
|
y_impedance_step = (max_impedance - min_impedance) / height
|
2019-09-29 16:56:53 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
for i in range(ticks):
|
|
|
|
x = self.leftMargin + round((i + 1) * width / ticks)
|
2021-07-06 15:01:20 +00:00
|
|
|
qp.setPen(QtGui.QPen(Chart.color.foreground))
|
2020-05-18 18:58:18 +00:00
|
|
|
qp.drawLine(x, self.topMargin, x, self.topMargin + height)
|
2021-07-06 15:01:20 +00:00
|
|
|
qp.setPen(QtGui.QPen(Chart.color.text))
|
2020-06-15 11:27:00 +00:00
|
|
|
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")
|
2019-09-29 16:56:53 +00:00
|
|
|
|
2021-07-06 15:01:20 +00:00
|
|
|
qp.setPen(QtGui.QPen(Chart.color.text))
|
2020-06-15 11:27:00 +00:00
|
|
|
qp.drawText(
|
|
|
|
self.leftMargin - 10,
|
|
|
|
self.topMargin + height + 15,
|
|
|
|
str(round(self.tdrWindow.distance_axis[min_index] / 2,
|
|
|
|
1)) + "m")
|
2019-09-29 14:34:50 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
y_ticks = math.floor(height / 60)
|
|
|
|
y_tick_step = height/y_ticks
|
2019-09-29 16:56:53 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
for i in range(y_ticks):
|
|
|
|
y = self.bottomMargin + int(i * y_tick_step)
|
2021-07-06 15:01:20 +00:00
|
|
|
qp.setPen(Chart.color.foreground)
|
2020-05-18 18:58:18 +00:00
|
|
|
qp.drawLine(self.leftMargin, y, self.leftMargin + width, y)
|
|
|
|
y_val = max_impedance - y_impedance_step * i * y_tick_step
|
2021-07-06 15:01:20 +00:00
|
|
|
qp.setPen(Chart.color.text)
|
2020-05-18 18:58:18 +00:00
|
|
|
qp.drawText(3, y + 3, str(round(y_val, 1)))
|
2019-10-13 21:10:01 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
qp.drawText(3, self.topMargin + height + 3, str(round(min_impedance, 1)))
|
2019-10-13 21:10:01 +00:00
|
|
|
|
2021-07-06 15:01:20 +00:00
|
|
|
pen = QtGui.QPen(Chart.color.sweep)
|
2021-06-26 22:55:43 +00:00
|
|
|
pen.setWidth(self.dim.point)
|
2020-05-18 18:58:18 +00:00
|
|
|
qp.setPen(pen)
|
|
|
|
for i in range(min_index, max_index):
|
|
|
|
if i < min_index or i > max_index:
|
|
|
|
continue
|
2019-10-13 21:10:01 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
x = self.leftMargin + int((i - min_index) / x_step)
|
|
|
|
y = (self.topMargin + height) - int(self.tdrWindow.td[i] / y_step)
|
|
|
|
if self.isPlotable(x, y):
|
2021-07-06 15:01:20 +00:00
|
|
|
pen.setColor(Chart.color.sweep)
|
2020-05-18 18:58:18 +00:00
|
|
|
qp.setPen(pen)
|
|
|
|
qp.drawPoint(x, y)
|
2019-10-13 21:10:01 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
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)
|
|
|
|
if self.isPlotable(x, y):
|
2021-07-06 15:01:20 +00:00
|
|
|
pen.setColor(Chart.color.sweep_secondary)
|
2020-05-18 18:58:18 +00:00
|
|
|
qp.setPen(pen)
|
|
|
|
qp.drawPoint(x, y)
|
2019-11-17 21:26:00 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
id_max = np.argmax(self.tdrWindow.td)
|
2020-06-15 11:27:00 +00:00
|
|
|
max_point = QtCore.QPoint(
|
|
|
|
self.leftMargin + int((id_max - min_index) / x_step),
|
|
|
|
(self.topMargin + height) - int(self.tdrWindow.td[id_max] / y_step))
|
2020-05-18 18:58:18 +00:00
|
|
|
qp.setPen(self.markers[0].color)
|
|
|
|
qp.drawEllipse(max_point, 2, 2)
|
2021-07-06 15:01:20 +00:00
|
|
|
qp.setPen(Chart.color.text)
|
2020-05-18 18:58:18 +00:00
|
|
|
qp.drawText(max_point.x() - 10, max_point.y() - 5,
|
2020-06-15 11:27:00 +00:00
|
|
|
str(round(self.tdrWindow.distance_axis[id_max] / 2,
|
|
|
|
2)) + "m")
|
2019-09-24 21:29:26 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
if self.markerLocation != -1:
|
2020-06-15 11:27:00 +00:00
|
|
|
marker_point = QtCore.QPoint(
|
|
|
|
self.leftMargin +
|
|
|
|
int((self.markerLocation - min_index) / x_step),
|
|
|
|
(self.topMargin + height) -
|
|
|
|
int(self.tdrWindow.td[self.markerLocation] / y_step))
|
2021-07-06 15:01:20 +00:00
|
|
|
qp.setPen(Chart.color.text)
|
2020-05-18 18:58:18 +00:00
|
|
|
qp.drawEllipse(marker_point, 2, 2)
|
2020-06-15 11:27:00 +00:00
|
|
|
qp.drawText(
|
|
|
|
marker_point.x() - 10,
|
|
|
|
marker_point.y() - 5,
|
|
|
|
str(round(self.tdrWindow.distance_axis[self.markerLocation] / 2,
|
|
|
|
2)) + "m")
|
2019-09-19 12:15:47 +00:00
|
|
|
|
2021-06-27 08:59:07 +00:00
|
|
|
if self.dragbox.state and self.dragbox.pos[0] != -1:
|
2021-07-06 15:01:20 +00:00
|
|
|
dashed_pen = QtGui.QPen(Chart.color.foreground, 1, QtCore.Qt.DashLine)
|
2020-05-18 18:58:18 +00:00
|
|
|
qp.setPen(dashed_pen)
|
2022-05-28 19:48:13 +00:00
|
|
|
qp.drawRect(
|
|
|
|
QtCore.QRect(
|
|
|
|
QtCore.QPoint(*self.dragbox.pos_start),
|
|
|
|
QtCore.QPoint(*self.dragbox.pos)
|
|
|
|
)
|
|
|
|
)
|
2019-09-19 12:15:47 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
qp.end()
|
2019-09-19 12:15:47 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
def valueAtPosition(self, y):
|
2022-09-07 08:37:37 +00:00
|
|
|
if self.tdrWindow.td:
|
2020-05-18 18:58:18 +00:00
|
|
|
height = self.height() - self.topMargin - self.bottomMargin
|
|
|
|
absy = (self.height() - y) - self.bottomMargin
|
|
|
|
if self.fixedValues:
|
|
|
|
min_impedance = self.minImpedance
|
|
|
|
max_impedance = self.maxImpedance
|
|
|
|
else:
|
2020-06-15 11:27:00 +00:00
|
|
|
min_impedance = max(
|
|
|
|
0,
|
|
|
|
np.min(self.tdrWindow.step_response_Z) / 1.05)
|
|
|
|
max_impedance = min(
|
|
|
|
1000,
|
|
|
|
np.max(self.tdrWindow.step_response_Z) * 1.05)
|
2020-05-18 18:58:18 +00:00
|
|
|
y_step = (max_impedance - min_impedance) / height
|
|
|
|
return y_step * absy + min_impedance
|
2020-06-15 11:27:00 +00:00
|
|
|
return 0
|
2019-10-03 12:17:04 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
def lengthAtPosition(self, x, limit=True):
|
2022-05-28 19:48:13 +00:00
|
|
|
if not self.tdrWindow.td:
|
|
|
|
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
|
|
|
|
if limit and absx < 0:
|
|
|
|
return min_length
|
|
|
|
if limit and absx > width:
|
|
|
|
return max_length
|
|
|
|
return absx * x_step + min_length
|
2019-09-05 12:56:40 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
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)
|
|
|
|
val1 = self.valueAtPosition(y1)
|
|
|
|
val2 = self.valueAtPosition(y2)
|
2019-09-25 10:25:50 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
if val1 != val2:
|
|
|
|
self.minImpedance = round(min(val1, val2), 3)
|
|
|
|
self.maxImpedance = round(max(val1, val2), 3)
|
|
|
|
self.setFixedValues(True)
|
2019-09-05 12:56:40 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
len1 = max(0, self.lengthAtPosition(x1, limit=False))
|
|
|
|
len2 = max(0, self.lengthAtPosition(x2, limit=False))
|
2019-10-03 12:17:04 +00:00
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
if len1 >= 0 and len2 >= 0 and len1 != len2:
|
|
|
|
self.minDisplayLength = min(len1, len2)
|
|
|
|
self.maxDisplayLength = max(len1, len2)
|
|
|
|
self.setFixedSpan(True)
|
2019-10-13 21:10:01 +00:00
|
|
|
|
2019-10-03 12:17:04 +00:00
|
|
|
self.update()
|
|
|
|
|
2020-05-18 18:58:18 +00:00
|
|
|
def resizeEvent(self, a0: QtGui.QResizeEvent) -> None:
|
|
|
|
super().resizeEvent(a0)
|
2021-06-26 22:55:43 +00:00
|
|
|
self.dim.width = self.width() - self.leftMargin - self.rightMargin
|
|
|
|
self.dim.height = self.height() - self.bottomMargin - self.topMargin
|