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
	
	 Rune Broberg
						Rune Broberg