Add group delay as a marker display option

pull/90/head
Rune Broberg 2019-11-11 10:51:24 +01:00
rodzic 7b246e9bc9
commit 137715b76f
4 zmienionych plików z 55 dodań i 18 usunięć

Wyświetl plik

@ -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)))

Wyświetl plik

@ -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",

Wyświetl plik

@ -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

Wyświetl plik

@ -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)