kopia lustrzana https://github.com/NanoVNA-Saver/nanovna-saver
Add group delay as a marker display option
rodzic
7b246e9bc9
commit
137715b76f
|
@ -20,6 +20,7 @@ from typing import List
|
|||
from PyQt5 import QtGui, QtWidgets, QtCore
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
|
||||
from NanoVNASaver import SITools
|
||||
from NanoVNASaver.RFTools import Datapoint, RFTools
|
||||
|
||||
|
||||
|
@ -88,6 +89,8 @@ class Marker(QtCore.QObject):
|
|||
self.gain_label = QtWidgets.QLabel("")
|
||||
self.s11_phase_label = QtWidgets.QLabel("")
|
||||
self.s21_phase_label = QtWidgets.QLabel("")
|
||||
self.s11_group_delay_label = QtWidgets.QLabel("")
|
||||
self.s21_group_delay_label = QtWidgets.QLabel("")
|
||||
self.quality_factor_label = QtWidgets.QLabel("")
|
||||
|
||||
self.fields = {"actualfreq": ("Frequency:", self.frequency_label),
|
||||
|
@ -105,8 +108,10 @@ class Marker(QtCore.QObject):
|
|||
"vswr": ("VSWR:", self.vswr_label),
|
||||
"s11q": ("Quality factor:", self.quality_factor_label),
|
||||
"s11phase": ("S11 Phase:", self.s11_phase_label),
|
||||
"s11groupdelay": ("S11 Group Delay:", self.s11_group_delay_label),
|
||||
"s21gain": ("S21 Gain:", self.gain_label),
|
||||
"s21phase": ("S21 Phase:", self.s21_phase_label),
|
||||
"s21groupdelay": ("S21 Group Delay:", self.s21_group_delay_label),
|
||||
}
|
||||
|
||||
################################################################################################################
|
||||
|
@ -383,7 +388,13 @@ class Marker(QtCore.QObject):
|
|||
self.quality_factor_label.setText(q_str)
|
||||
self.s11_phase_label.setText(
|
||||
str(round(RFTools.phaseAngle(s11data[self.location]), 2)) + "\N{DEGREE SIGN}")
|
||||
fmt = SITools.Format(max_nr_digits=5, space_str=" ")
|
||||
self.s11_group_delay_label.setText(str(SITools.Value(RFTools.groupDelay(s11data, self.location), "s", fmt)))
|
||||
|
||||
if len(s21data) == len(s11data):
|
||||
self.gain_label.setText(str(round(RFTools.gain(s21data[self.location]), 3)) + " dB")
|
||||
self.s21_phase_label.setText(
|
||||
str(round(RFTools.phaseAngle(s21data[self.location]), 2)) + "\N{DEGREE SIGN}")
|
||||
self.s21_group_delay_label.setText(str(SITools.Value(RFTools.groupDelay(s21data, self.location),
|
||||
"s", fmt)))
|
||||
|
||||
|
|
|
@ -2363,12 +2363,12 @@ class AnalysisWindow(QtWidgets.QWidget):
|
|||
|
||||
|
||||
class MarkerSettingsWindow(QtWidgets.QWidget):
|
||||
exampleData11 = [Datapoint(123000000, 0, 0),
|
||||
exampleData11 = [Datapoint(123000000, 0.89, -0.11),
|
||||
Datapoint(123500000, 0.9, -0.1),
|
||||
Datapoint(124000000, 0, 0)]
|
||||
exampleData21 = [Datapoint(123000000, 0, 0),
|
||||
Datapoint(124000000, 0.91, -0.95)]
|
||||
exampleData21 = [Datapoint(123000000, -0.25, 0.49),
|
||||
Datapoint(123456000, -0.3, 0.5),
|
||||
Datapoint(124000000, 0, 0)]
|
||||
Datapoint(124000000, -0.2, 0.5)]
|
||||
|
||||
fieldList = {"actualfreq": "Actual frequency",
|
||||
"impedance": "Impedance",
|
||||
|
@ -2385,8 +2385,10 @@ class MarkerSettingsWindow(QtWidgets.QWidget):
|
|||
"returnloss": "Return loss",
|
||||
"s11q": "S11 Quality factor",
|
||||
"s11phase": "S11 Phase",
|
||||
"s11groupdelay": "S11 Group Delay",
|
||||
"s21gain": "S21 Gain",
|
||||
"s21phase": "S21 Phase",
|
||||
"s21groupdelay": "S21 Group Delay",
|
||||
}
|
||||
|
||||
defaultValue = ["actualfreq",
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import collections
|
||||
import math
|
||||
from typing import List
|
||||
|
||||
from NanoVNASaver.SITools import Value, Format
|
||||
|
||||
PREFIXES = ("", "k", "M", "G", "T")
|
||||
|
@ -69,15 +71,15 @@ class RFTools:
|
|||
def capacitanceEquivalent(im50, freq) -> str:
|
||||
if im50 == 0 or freq == 0:
|
||||
return "- pF"
|
||||
capacitance = 10**12/(freq * 2 * math.pi * im50)
|
||||
return str(Value(-capacitance, "F", Format(max_nr_digits=5)))
|
||||
capacitance = 1 / (freq * 2 * math.pi * im50)
|
||||
return str(Value(-capacitance, "F", Format(max_nr_digits=5, space_str=" ")))
|
||||
|
||||
@staticmethod
|
||||
def inductanceEquivalent(im50, freq) -> str:
|
||||
if freq == 0:
|
||||
return "- nH"
|
||||
inductance = im50 * 1000000000 / (freq * 2 * math.pi)
|
||||
return str(Value(inductance, "H", Format(max_nr_digits=5)))
|
||||
inductance = im50 * 1 / (freq * 2 * math.pi)
|
||||
return str(Value(inductance, "H", Format(max_nr_digits=5, space_str=" ")))
|
||||
|
||||
@staticmethod
|
||||
def formatFrequency(freq):
|
||||
|
@ -141,3 +143,29 @@ class RFTools:
|
|||
re = data.re
|
||||
im = data.im
|
||||
return math.atan2(im, re)
|
||||
|
||||
@staticmethod
|
||||
def groupDelay(data: List[Datapoint], index: int) -> float:
|
||||
if index == 0:
|
||||
angle0 = RFTools.phaseAngleRadians(data[0])
|
||||
angle1 = RFTools.phaseAngleRadians(data[1])
|
||||
freq0 = data[0].freq
|
||||
freq1 = data[1].freq
|
||||
elif index == len(data) - 1:
|
||||
angle0 = RFTools.phaseAngleRadians(data[-2])
|
||||
angle1 = RFTools.phaseAngleRadians(data[-1])
|
||||
freq0 = data[-2].freq
|
||||
freq1 = data[-1].freq
|
||||
else:
|
||||
angle0 = RFTools.phaseAngleRadians(data[index-1])
|
||||
angle1 = RFTools.phaseAngleRadians(data[index+1])
|
||||
freq0 = data[index-1].freq
|
||||
freq1 = data[index+1].freq
|
||||
delta_angle = (angle1 - angle0)
|
||||
if abs(delta_angle) > math.tau:
|
||||
if delta_angle > 0:
|
||||
delta_angle = delta_angle % math.tau
|
||||
else:
|
||||
delta_angle = -1 * (delta_angle % math.tau)
|
||||
val = delta_angle / math.tau / (freq1 - freq0)
|
||||
return val
|
||||
|
|
|
@ -29,8 +29,7 @@ class Format(object):
|
|||
assume_infinity: bool = True,
|
||||
min_offset: int = -8,
|
||||
max_offset: int = 8):
|
||||
assert(min_offset >= -8 and max_offset <= 8 and
|
||||
min_offset < max_offset)
|
||||
assert(min_offset >= -8 and max_offset <= 8 and min_offset < max_offset)
|
||||
self.max_nr_digits = max_nr_digits
|
||||
self.fix_decimals = fix_decimals
|
||||
self.space_str = space_str
|
||||
|
@ -52,15 +51,12 @@ class Value(object):
|
|||
self.fmt = fmt
|
||||
|
||||
def __repr__(self):
|
||||
return (f"{self.__class__.__name__}("
|
||||
f"{self.value}, '{self._unit}', {self.fmt})")
|
||||
return f"{self.__class__.__name__}({self.value}, '{self._unit}', {self.fmt})"
|
||||
|
||||
def __str__(self):
|
||||
fmt = self.fmt
|
||||
if fmt.assume_infinity and \
|
||||
abs(self.value) >= 10 ** ((fmt.max_offset + 1) * 3):
|
||||
return (("-" if self.value < 0 else "") +
|
||||
"\N{INFINITY}" + fmt.space_str + self._unit)
|
||||
if fmt.assume_infinity and abs(self.value) >= 10 ** ((fmt.max_offset + 1) * 3):
|
||||
return ("-" if self.value < 0 else "") + "\N{INFINITY}" + fmt.space_str + self._unit
|
||||
|
||||
if self.value == 0:
|
||||
offset = 0
|
||||
|
@ -78,8 +74,8 @@ class Value(object):
|
|||
formstr = ".0f"
|
||||
else:
|
||||
max_digits = fmt.max_nr_digits + (
|
||||
(1 if not fmt.fix_decimals and real < 10 else 0) +
|
||||
(1 if not fmt.fix_decimals and real < 100 else 0))
|
||||
(1 if not fmt.fix_decimals and abs(real) < 10 else 0) +
|
||||
(1 if not fmt.fix_decimals and abs(real) < 100 else 0))
|
||||
formstr = "." + str(max_digits - 3) + "f"
|
||||
|
||||
result = format(real, formstr)
|
||||
|
|
Ładowanie…
Reference in New Issue