kopia lustrzana https://github.com/NanoVNA-Saver/nanovna-saver
Trivial style changes (#625)
* Style: update type annotations * Style: simplify extraction of version from metadata * Style: replace some handwritten classes with namedtuples or dataclasses * RIZ.py: remove unused import * Style: remove some redundant lambda constructs * Marker/Values: remove __init__ parameters Mutable default values imply some complexity. In this case, the constructor is always called without arguments.pull/629/head
rodzic
d89c9f9d94
commit
6eb24f2315
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
import math
|
||||
from typing import Dict, List
|
||||
|
||||
from PyQt6 import QtWidgets
|
||||
|
||||
|
@ -158,13 +157,13 @@ class BandPassAnalysis(Analysis):
|
|||
self.set_result(f"Analysis complete ({len(s21)} points)")
|
||||
|
||||
def derive_60dB(
|
||||
self, cutoff_pos: Dict[str, int], cutoff_freq: Dict[str, float]
|
||||
self, cutoff_pos: dict[str, int], cutoff_freq: dict[str, float]
|
||||
):
|
||||
"""derive 60dB cutoff if needed an possible
|
||||
|
||||
Args:
|
||||
cutoff_pos (Dict[str, int])
|
||||
cutoff_freq (Dict[str, float])
|
||||
cutoff_pos (dict[str, int])
|
||||
cutoff_freq (dict[str, float])
|
||||
"""
|
||||
if (
|
||||
math.isnan(cutoff_freq["60.0dB_l"])
|
||||
|
@ -191,7 +190,7 @@ class BandPassAnalysis(Analysis):
|
|||
)
|
||||
)
|
||||
|
||||
def find_center(self, gains: List[float]) -> int:
|
||||
def find_center(self, gains: list[float]) -> int:
|
||||
marker = self.app.markers[0]
|
||||
if marker.location <= 0 or marker.location >= len(gains) - 1:
|
||||
logger.debug(
|
||||
|
@ -207,8 +206,8 @@ class BandPassAnalysis(Analysis):
|
|||
return peak
|
||||
|
||||
def find_bounderies(
|
||||
self, gains: List[float], peak: int, peak_db: float
|
||||
) -> Dict[str, int]:
|
||||
self, gains: list[float], peak: int, peak_db: float
|
||||
) -> dict[str, int]:
|
||||
cutoff_pos = {}
|
||||
for attn in CUTOFF_VALS:
|
||||
cutoff_pos[f"{attn:.1f}dB_l"] = at.cut_off_left(
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
from typing import Dict, List
|
||||
|
||||
import NanoVNASaver.AnalyticTools as at
|
||||
from NanoVNASaver.Analysis.Base import CUTOFF_VALS
|
||||
|
@ -31,12 +30,12 @@ class BandStopAnalysis(BandPassAnalysis):
|
|||
super().__init__(app)
|
||||
self.set_titel("Band stop filter analysis")
|
||||
|
||||
def find_center(self, gains: List[float]) -> int:
|
||||
def find_center(self, gains: list[float]) -> int:
|
||||
return max(enumerate(gains), key=lambda i: i[1])[0]
|
||||
|
||||
def find_bounderies(
|
||||
self, gains: List[float], _: int, peak_db: float
|
||||
) -> Dict[str, int]:
|
||||
self, gains: list[float], _: int, peak_db: float
|
||||
) -> dict[str, int]:
|
||||
cutoff_pos = {}
|
||||
for attn in CUTOFF_VALS:
|
||||
(
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
from typing import Dict
|
||||
from PyQt6 import QtWidgets
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -34,7 +33,7 @@ class QHLine(QtWidgets.QFrame):
|
|||
class Analysis:
|
||||
def __init__(self, app: QtWidgets.QWidget):
|
||||
self.app = app
|
||||
self.label: Dict[str, QtWidgets.QLabel] = {
|
||||
self.label: dict[str, QtWidgets.QLabel] = {
|
||||
"titel": QtWidgets.QLabel(),
|
||||
"result": QtWidgets.QLabel(),
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
import math
|
||||
from typing import Dict, List
|
||||
|
||||
from PyQt6 import QtWidgets
|
||||
|
||||
|
@ -109,7 +108,7 @@ class HighPassAnalysis(Analysis):
|
|||
|
||||
self.set_result(f"Analysis complete ({len(s21)}) points)")
|
||||
|
||||
def find_level(self, gains: List[float]) -> int:
|
||||
def find_level(self, gains: list[float]) -> int:
|
||||
marker = self.app.markers[0]
|
||||
logger.debug("Pass band location: %d", marker.location)
|
||||
if marker.location < 0:
|
||||
|
@ -118,8 +117,8 @@ class HighPassAnalysis(Analysis):
|
|||
return at.center_from_idx(gains, marker.location)
|
||||
|
||||
def find_cutoffs(
|
||||
self, gains: List[float], peak: int, peak_db: float
|
||||
) -> Dict[str, int]:
|
||||
self, gains: list[float], peak: int, peak_db: float
|
||||
) -> dict[str, int]:
|
||||
return {
|
||||
f"{attn:.1f}dB": at.cut_off_left(gains, peak, peak_db, attn)
|
||||
for attn in CUTOFF_VALS
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
from typing import Dict, List
|
||||
|
||||
import NanoVNASaver.AnalyticTools as at
|
||||
from NanoVNASaver.Analysis.Base import CUTOFF_VALS
|
||||
|
@ -33,8 +32,8 @@ class LowPassAnalysis(HighPassAnalysis):
|
|||
self.set_titel("Lowpass filter analysis")
|
||||
|
||||
def find_cutoffs(
|
||||
self, gains: List[float], peak: int, peak_db: float
|
||||
) -> Dict[str, int]:
|
||||
self, gains: list[float], peak: int, peak_db: float
|
||||
) -> dict[str, int]:
|
||||
return {
|
||||
f"{attn:.1f}dB": at.cut_off_right(gains, peak, peak_db, attn)
|
||||
for attn in CUTOFF_VALS
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
import os
|
||||
import csv
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from PyQt6 import QtWidgets
|
||||
|
||||
|
@ -44,7 +43,7 @@ def vswr_transformed(z, ratio=49) -> float:
|
|||
class ResonanceAnalysis(Analysis):
|
||||
def __init__(self, app):
|
||||
super().__init__(app)
|
||||
self.crossings: List[int] = []
|
||||
self.crossings: list[int] = []
|
||||
self.filename = ""
|
||||
self._widget = QtWidgets.QWidget()
|
||||
self.layout = QtWidgets.QFormLayout()
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
from typing import Callable, List, Tuple
|
||||
from typing import Callable
|
||||
|
||||
from PyQt6 import QtWidgets
|
||||
import numpy as np
|
||||
|
@ -102,7 +102,7 @@ class SimplePeakSearchAnalysis(Analysis):
|
|||
if self.button["move_marker"].isChecked() and self.app.markers:
|
||||
self.app.markers[0].setFrequency(f"{s11[idx_peak].freq}")
|
||||
|
||||
def data_and_format(self) -> Tuple[List[float], Callable]:
|
||||
def data_and_format(self) -> tuple[list[float], Callable]:
|
||||
s11 = self.app.data.s11
|
||||
s21 = self.app.data.s21
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from PyQt6 import QtWidgets
|
||||
|
||||
|
@ -54,7 +53,7 @@ class VSWRAnalysis(Analysis):
|
|||
self.results_label = QtWidgets.QLabel("<b>Results</b>")
|
||||
self.layout.addRow(self.results_label)
|
||||
|
||||
self.minimums: List[int] = []
|
||||
self.minimums: list[int] = []
|
||||
|
||||
def runAnalysis(self):
|
||||
if not self.app.data.s11:
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import itertools as it
|
||||
import math
|
||||
from typing import Callable, List, Tuple
|
||||
from typing import Callable
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
@ -28,14 +28,14 @@ from scipy.signal import find_peaks
|
|||
from NanoVNASaver.RFTools import Datapoint
|
||||
|
||||
|
||||
def zero_crossings(data: List[float]) -> List[int]:
|
||||
def zero_crossings(data: list[float]) -> list[int]:
|
||||
"""find zero crossings
|
||||
|
||||
Args:
|
||||
data (List[float]): data list execute
|
||||
data (list[float]): data list execute
|
||||
|
||||
Returns:
|
||||
List[int]: sorted indices of zero crossing points
|
||||
list[int]: sorted indices of zero crossing points
|
||||
"""
|
||||
if not data:
|
||||
return []
|
||||
|
@ -54,27 +54,27 @@ def zero_crossings(data: List[float]) -> List[int]:
|
|||
return sorted(real_zeros + crossings)
|
||||
|
||||
|
||||
def maxima(data: List[float], threshold: float = 0.0) -> List[int]:
|
||||
def maxima(data: list[float], threshold: float = 0.0) -> list[int]:
|
||||
"""maxima
|
||||
|
||||
Args:
|
||||
data (List[float]): data list to execute
|
||||
data (list[float]): data list to execute
|
||||
|
||||
Returns:
|
||||
List[int]: indices of maxima
|
||||
list[int]: indices of maxima
|
||||
"""
|
||||
peaks = find_peaks(data, width=2, distance=3, prominence=1)[0].tolist()
|
||||
return [i for i in peaks if data[i] > threshold] if threshold else peaks
|
||||
|
||||
|
||||
def minima(data: List[float], threshold: float = 0.0) -> List[int]:
|
||||
def minima(data: list[float], threshold: float = 0.0) -> list[int]:
|
||||
"""minima
|
||||
|
||||
Args:
|
||||
data (List[float]): data list to execute
|
||||
data (list[float]): data list to execute
|
||||
|
||||
Returns:
|
||||
List[int]: indices of minima
|
||||
list[int]: indices of minima
|
||||
"""
|
||||
bottoms = find_peaks(-np.array(data), width=2, distance=3, prominence=1)[
|
||||
0
|
||||
|
@ -83,18 +83,18 @@ def minima(data: List[float], threshold: float = 0.0) -> List[int]:
|
|||
|
||||
|
||||
def take_from_idx(
|
||||
data: List[float], idx: int, predicate: Callable
|
||||
) -> List[int]:
|
||||
data: list[float], idx: int, predicate: Callable
|
||||
) -> list[int]:
|
||||
"""take_from_center
|
||||
|
||||
Args:
|
||||
data (List[float]): data list to execute
|
||||
data (list[float]): data list to execute
|
||||
idx (int): index of a start position
|
||||
predicate (Callable): predicate on which elements to take
|
||||
from center. (e.g. lambda i: i[1] < threshold)
|
||||
|
||||
Returns:
|
||||
List[int]: indices of element matching predicate left
|
||||
list[int]: indices of element matching predicate left
|
||||
and right from index
|
||||
"""
|
||||
lower = list(
|
||||
|
@ -111,11 +111,11 @@ def take_from_idx(
|
|||
return lower + upper
|
||||
|
||||
|
||||
def center_from_idx(gains: List[float], idx: int, delta: float = 3.0) -> int:
|
||||
def center_from_idx(gains: list[float], idx: int, delta: float = 3.0) -> int:
|
||||
"""find maximum from index postion of gains in a attn dB gain span
|
||||
|
||||
Args:
|
||||
gains (List[float]): gain values
|
||||
gains (list[float]): gain values
|
||||
idx (int): start position to search from
|
||||
delta (float, optional): max gain delta from start. Defaults to 3.0.
|
||||
|
||||
|
@ -128,13 +128,13 @@ def center_from_idx(gains: List[float], idx: int, delta: float = 3.0) -> int:
|
|||
|
||||
|
||||
def cut_off_left(
|
||||
gains: List[float], idx: int, peak_gain: float, attn: float = 3.0
|
||||
gains: list[float], idx: int, peak_gain: float, attn: float = 3.0
|
||||
) -> int:
|
||||
"""find first position in list where gain in attn lower then peak
|
||||
left from index
|
||||
|
||||
Args:
|
||||
gains (List[float]): gain values
|
||||
gains (list[float]): gain values
|
||||
idx (int): start position to search from
|
||||
peak_gain (float): reference gain value
|
||||
attn (float, optional): attenuation to search position for.
|
||||
|
@ -149,13 +149,13 @@ def cut_off_left(
|
|||
|
||||
|
||||
def cut_off_right(
|
||||
gains: List[float], idx: int, peak_gain: float, attn: float = 3.0
|
||||
gains: list[float], idx: int, peak_gain: float, attn: float = 3.0
|
||||
) -> int:
|
||||
"""find first position in list where gain in attn lower then peak
|
||||
right from index
|
||||
|
||||
Args:
|
||||
gains (List[float]): gain values
|
||||
gains (list[float]): gain values
|
||||
idx (int): start position to search from
|
||||
peak_gain (float): reference gain value
|
||||
attn (float, optional): attenuation to search position for.
|
||||
|
@ -171,15 +171,15 @@ def cut_off_right(
|
|||
|
||||
|
||||
def dip_cut_offs(
|
||||
gains: List[float], peak_gain: float, attn: float = 3.0
|
||||
) -> Tuple[int, int]:
|
||||
gains: list[float], peak_gain: float, attn: float = 3.0
|
||||
) -> tuple[int, int]:
|
||||
rng = np.where(np.array(gains) < (peak_gain - attn))[0].tolist()
|
||||
return (rng[0], rng[-1]) if rng else (math.nan, math.nan)
|
||||
|
||||
|
||||
def calculate_rolloff(
|
||||
s21: List[Datapoint], idx_1: int, idx_2: int
|
||||
) -> Tuple[float, float]:
|
||||
s21: list[Datapoint], idx_1: int, idx_2: int
|
||||
) -> tuple[float, float]:
|
||||
if idx_1 == idx_2:
|
||||
return (math.nan, math.nan)
|
||||
freq_1, freq_2 = s21[idx_1].freq, s21[idx_2].freq
|
||||
|
|
|
@ -23,7 +23,6 @@ import os
|
|||
import re
|
||||
from collections import defaultdict, UserDict
|
||||
from dataclasses import dataclass
|
||||
from typing import List
|
||||
|
||||
from scipy.interpolate import interp1d
|
||||
|
||||
|
@ -235,7 +234,7 @@ class CalDataSet(UserDict):
|
|||
setattr(self.data[freq], name, (dp.z))
|
||||
self.data[freq].freq = freq
|
||||
|
||||
def frequencies(self) -> List[int]:
|
||||
def frequencies(self) -> list[int]:
|
||||
return sorted(self.data.keys())
|
||||
|
||||
def get(self, key: int, default: CalData = None) -> CalData:
|
||||
|
@ -276,7 +275,7 @@ class Calibration:
|
|||
|
||||
self.source = "Manual"
|
||||
|
||||
def insert(self, name: str, data: List[Datapoint]):
|
||||
def insert(self, name: str, data: list[Datapoint]):
|
||||
for dp in data:
|
||||
self.dataset.insert(name, dp)
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import math
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from PyQt6 import QtGui
|
||||
|
||||
|
@ -33,11 +32,11 @@ class CombinedLogMagChart(LogMagChart):
|
|||
def __init__(self, name=""):
|
||||
super().__init__(name)
|
||||
|
||||
self.data11: List[Datapoint] = []
|
||||
self.data21: List[Datapoint] = []
|
||||
self.data11: list[Datapoint] = []
|
||||
self.data21: list[Datapoint] = []
|
||||
|
||||
self.reference11: List[Datapoint] = []
|
||||
self.reference21: List[Datapoint] = []
|
||||
self.reference11: list[Datapoint] = []
|
||||
self.reference21: list[Datapoint] = []
|
||||
|
||||
def setCombinedData(self, data11, data21):
|
||||
self.data11 = data11
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
import logging
|
||||
|
||||
from dataclasses import dataclass, field, replace
|
||||
from typing import List, Set, Tuple, ClassVar, Any, Optional
|
||||
from typing import ClassVar, Any
|
||||
|
||||
from PyQt6 import QtWidgets, QtGui, QtCore
|
||||
from PyQt6.QtCore import pyqtSignal, Qt
|
||||
|
@ -67,8 +67,8 @@ class ChartDimensions:
|
|||
|
||||
@dataclass
|
||||
class ChartDragBox:
|
||||
pos: Tuple[int] = (-1, -1)
|
||||
pos_start: Tuple[int] = (0, 0)
|
||||
pos: tuple[int] = (-1, -1)
|
||||
pos_start: tuple[int] = (0, 0)
|
||||
state: bool = False
|
||||
move_x: int = -1
|
||||
move_y: int = -1
|
||||
|
@ -128,11 +128,11 @@ class Chart(QtWidgets.QWidget):
|
|||
|
||||
self.draggedMarker = None
|
||||
|
||||
self.data: List[Datapoint] = []
|
||||
self.reference: List[Datapoint] = []
|
||||
self.data: list[Datapoint] = []
|
||||
self.reference: list[Datapoint] = []
|
||||
|
||||
self.markers: List[Marker] = []
|
||||
self.swrMarkers: Set[float] = set()
|
||||
self.markers: list[Marker] = []
|
||||
self.swrMarkers: set[float] = set()
|
||||
|
||||
self.action_popout = QAction("Popout chart")
|
||||
self.action_popout.triggered.connect(
|
||||
|
@ -192,7 +192,7 @@ class Chart(QtWidgets.QWidget):
|
|||
None,
|
||||
)
|
||||
|
||||
def getNearestMarker(self, x, y) -> Optional[Marker]:
|
||||
def getNearestMarker(self, x, y) -> Marker | None:
|
||||
if not self.data:
|
||||
return None
|
||||
shortest = 10**6
|
||||
|
@ -205,7 +205,7 @@ class Chart(QtWidgets.QWidget):
|
|||
nearest = m
|
||||
return nearest
|
||||
|
||||
def getPosition(self, d: Datapoint) -> Tuple[int, int]:
|
||||
def getPosition(self, d: Datapoint) -> tuple[int, int]:
|
||||
return self.getXPosition(d), self.getYPosition(d)
|
||||
|
||||
def setDrawLines(self, draw_lines):
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import math
|
||||
import logging
|
||||
from typing import List, Tuple
|
||||
|
||||
import numpy as np
|
||||
from PyQt6 import QtWidgets, QtGui, QtCore
|
||||
|
@ -405,7 +404,7 @@ class FrequencyChart(Chart):
|
|||
step = span / self.dim.width
|
||||
return round(self.fstart + absx * step)
|
||||
|
||||
def valueAtPosition(self, y) -> List[float]:
|
||||
def valueAtPosition(self, y) -> list[float]:
|
||||
"""
|
||||
Returns the chart-specific value(s) at the specified Y-position
|
||||
:param y: The Y position to calculate for.
|
||||
|
@ -493,7 +492,7 @@ class FrequencyChart(Chart):
|
|||
self.drawDragbog(qp)
|
||||
qp.end()
|
||||
|
||||
def _data_oob(self, data: List[Datapoint]) -> bool:
|
||||
def _data_oob(self, data: list[Datapoint]) -> bool:
|
||||
return data[0].freq > self.fstop or self.data[-1].freq < self.fstart
|
||||
|
||||
def _check_frequency_boundaries(self, qp: QtGui.QPainter):
|
||||
|
@ -605,7 +604,7 @@ class FrequencyChart(Chart):
|
|||
self.drawData(qp, self.reference, Chart.color.reference)
|
||||
self.drawMarkers(qp)
|
||||
|
||||
def _find_scaling(self) -> Tuple[float, float]:
|
||||
def _find_scaling(self) -> tuple[float, float]:
|
||||
min_value = self.minDisplayValue / 10e11
|
||||
max_value = self.maxDisplayValue / 10e11
|
||||
if self.fixedValues:
|
||||
|
@ -686,7 +685,7 @@ class FrequencyChart(Chart):
|
|||
def drawData(
|
||||
self,
|
||||
qp: QtGui.QPainter,
|
||||
data: List[Datapoint],
|
||||
data: list[Datapoint],
|
||||
color: QtGui.QColor,
|
||||
y_function=None,
|
||||
):
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import math
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
@ -74,7 +73,7 @@ class GroupDelayChart(FrequencyChart):
|
|||
self.groupDelayReference = self.calc_data(self.reference)
|
||||
self.update()
|
||||
|
||||
def calc_data(self, data: List[Datapoint]):
|
||||
def calc_data(self, data: list[Datapoint]):
|
||||
data_len = len(data)
|
||||
if data_len <= 1:
|
||||
return []
|
||||
|
@ -172,8 +171,8 @@ class GroupDelayChart(FrequencyChart):
|
|||
self,
|
||||
qp: QtGui.QPainter,
|
||||
color: QtGui.QColor,
|
||||
data: List[Datapoint],
|
||||
delay: List[Datapoint],
|
||||
data: list[Datapoint],
|
||||
delay: list[Datapoint],
|
||||
):
|
||||
pen = QtGui.QPen(color)
|
||||
pen.setWidth(self.dim.point)
|
||||
|
@ -216,7 +215,7 @@ class GroupDelayChart(FrequencyChart):
|
|||
(self.maxDelay - delay) / self.span * self.dim.height
|
||||
)
|
||||
|
||||
def valueAtPosition(self, y) -> List[float]:
|
||||
def valueAtPosition(self, y) -> list[float]:
|
||||
absy = y - self.topMargin
|
||||
val = -1 * ((absy / self.dim.height * self.span) - self.maxDelay)
|
||||
return [val]
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
from dataclasses import dataclass
|
||||
import math
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from PyQt6 import QtGui
|
||||
|
||||
|
@ -165,7 +164,7 @@ class LogMagChart(FrequencyChart):
|
|||
(self.maxValue - logMag) / self.span * self.dim.height
|
||||
)
|
||||
|
||||
def valueAtPosition(self, y) -> List[float]:
|
||||
def valueAtPosition(self, y) -> list[float]:
|
||||
absy = y - self.topMargin
|
||||
val = -1 * ((absy / self.dim.height * self.span) - self.maxValue)
|
||||
return [val]
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import math
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from PyQt6 import QtGui
|
||||
|
||||
|
@ -127,7 +126,7 @@ class MagnitudeChart(FrequencyChart):
|
|||
(self.maxValue - mag) / self.span * self.dim.height
|
||||
)
|
||||
|
||||
def valueAtPosition(self, y) -> List[float]:
|
||||
def valueAtPosition(self, y) -> list[float]:
|
||||
absy = y - self.topMargin
|
||||
val = -1 * ((absy / self.dim.height * self.span) - self.maxValue)
|
||||
return [val]
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import math
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from PyQt6 import QtGui
|
||||
|
||||
|
@ -129,7 +128,7 @@ class MagnitudeZChart(FrequencyChart):
|
|||
)
|
||||
return self.topMargin
|
||||
|
||||
def valueAtPosition(self, y) -> List[float]:
|
||||
def valueAtPosition(self, y) -> list[float]:
|
||||
absy = y - self.topMargin
|
||||
if self.logarithmicY:
|
||||
span = math.log(self.maxValue) - math.log(self.minValue)
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import math
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from PyQt6 import QtGui
|
||||
|
||||
|
@ -325,7 +324,7 @@ class PermeabilityChart(FrequencyChart):
|
|||
self.topMargin + (self.max - re) / self.span * self.dim.height
|
||||
)
|
||||
|
||||
def valueAtPosition(self, y) -> List[float]:
|
||||
def valueAtPosition(self, y) -> list[float]:
|
||||
absy = y - self.topMargin
|
||||
if self.logarithmicY:
|
||||
min_val = self.max - self.span
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
import math
|
||||
import logging
|
||||
|
||||
from typing import List
|
||||
import numpy as np
|
||||
|
||||
from PyQt6.QtGui import QAction, QPainter, QPen
|
||||
|
@ -151,7 +150,7 @@ class PhaseChart(FrequencyChart):
|
|||
(self.maxAngle - angle) / self.span * self.dim.height
|
||||
)
|
||||
|
||||
def valueAtPosition(self, y) -> List[float]:
|
||||
def valueAtPosition(self, y) -> list[float]:
|
||||
absy = y - self.topMargin
|
||||
val = -1 * ((absy / self.dim.height * self.span) - self.maxAngle)
|
||||
return [val]
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import math
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from PyQt6 import QtGui
|
||||
|
||||
|
@ -127,7 +126,7 @@ class QualityFactorChart(FrequencyChart):
|
|||
(self.maxQ - Q) / self.span * self.dim.height
|
||||
)
|
||||
|
||||
def valueAtPosition(self, y) -> List[float]:
|
||||
def valueAtPosition(self, y) -> list[float]:
|
||||
absy = y - self.topMargin
|
||||
val = -1 * ((absy / self.dim.height * self.span) - self.maxQ)
|
||||
return [val]
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import math
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
|
||||
from PyQt6 import QtWidgets, QtGui
|
||||
|
||||
|
@ -381,7 +380,7 @@ class RealImaginaryChart(FrequencyChart):
|
|||
else self.topMargin
|
||||
)
|
||||
|
||||
def valueAtPosition(self, y) -> List[float]:
|
||||
def valueAtPosition(self, y) -> list[float]:
|
||||
absy = y - self.topMargin
|
||||
valRe = -1 * ((absy / self.dim.height * self.span_real) - self.max_real)
|
||||
valIm = -1 * ((absy / self.dim.height * self.span_imag) - self.max_imag)
|
||||
|
@ -408,7 +407,7 @@ class RealImaginaryChart(FrequencyChart):
|
|||
|
||||
self.update()
|
||||
|
||||
def getNearestMarker(self, x, y) -> Optional[Marker]:
|
||||
def getNearestMarker(self, x, y) -> Marker | None:
|
||||
if not self.data:
|
||||
return None
|
||||
shortest = 10e6
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
|
||||
from PyQt6 import QtWidgets, QtGui
|
||||
from PyQt6 import QtGui
|
||||
|
||||
from NanoVNASaver.Formatting import format_frequency_chart
|
||||
from NanoVNASaver.RFTools import Datapoint
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from PyQt6 import QtGui
|
||||
|
||||
|
@ -142,7 +141,7 @@ class SParameterChart(FrequencyChart):
|
|||
+ (self.maxValue - d.im) / self.span * self.dim.height
|
||||
)
|
||||
|
||||
def valueAtPosition(self, y) -> List[float]:
|
||||
def valueAtPosition(self, y) -> list[float]:
|
||||
absy = y - self.topMargin
|
||||
val = -1 * ((absy / self.dim.height * self.span) - self.maxValue)
|
||||
return [val]
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
import math
|
||||
from typing import List
|
||||
|
||||
from PyQt6 import QtGui, QtCore, QtWidgets
|
||||
|
||||
|
@ -58,7 +57,7 @@ class SquareChart(Chart):
|
|||
self,
|
||||
qp: QtGui.QPainter,
|
||||
color: QtGui.QColor,
|
||||
data: List[Datapoint],
|
||||
data: list[Datapoint],
|
||||
fstart: int = 0,
|
||||
fstop: int = 0,
|
||||
):
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import math
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from PyQt6 import QtGui
|
||||
|
||||
|
@ -166,7 +165,7 @@ class VSWRChart(FrequencyChart):
|
|||
def getYPosition(self, d: Datapoint) -> int:
|
||||
return self.getYPositionFromValue(d.vswr)
|
||||
|
||||
def valueAtPosition(self, y) -> List[float]:
|
||||
def valueAtPosition(self, y) -> list[float]:
|
||||
absy = y - self.topMargin
|
||||
if self.logarithmicY:
|
||||
min_val = self.maxVSWR - self.span
|
||||
|
|
|
@ -62,7 +62,7 @@ class Chart:
|
|||
marker_size: int = 8
|
||||
returnloss_is_positive: bool = False
|
||||
show_bands: bool = False
|
||||
vswr_lines: list = DC.field(default_factory=lambda: [])
|
||||
vswr_lines: list = DC.field(default_factory=list)
|
||||
|
||||
|
||||
@DC.dataclass
|
||||
|
@ -126,11 +126,11 @@ class Markers:
|
|||
|
||||
@DC.dataclass
|
||||
class CFG:
|
||||
gui: object = DC.field(default_factory=lambda: GUI())
|
||||
charts_selected: object = DC.field(default_factory=lambda: ChartsSelected())
|
||||
chart: object = DC.field(default_factory=lambda: Chart())
|
||||
chart_colors: object = DC.field(default_factory=lambda: ChartColors())
|
||||
markers: object = DC.field(default_factory=lambda: Markers())
|
||||
gui: object = DC.field(default_factory=GUI)
|
||||
charts_selected: object = DC.field(default_factory=ChartsSelected)
|
||||
chart: object = DC.field(default_factory=Chart)
|
||||
chart_colors: object = DC.field(default_factory=ChartColors)
|
||||
markers: object = DC.field(default_factory=Markers)
|
||||
|
||||
|
||||
cfg = CFG()
|
||||
|
@ -159,9 +159,9 @@ def store(settings: "AppSettings", data: CFG = None) -> None:
|
|||
|
||||
def from_type(data) -> str:
|
||||
type_map = {
|
||||
bytearray: lambda x: x.hex(),
|
||||
QColor: lambda x: x.getRgb(),
|
||||
QByteArray: lambda x: x.toHex(),
|
||||
bytearray: bytearray.hex,
|
||||
QColor: QColor.getRgb,
|
||||
QByteArray: QByteArray.toHex,
|
||||
}
|
||||
return (
|
||||
f"{type_map[type(data)](data)}" if type(data) in type_map else f"{data}"
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import math
|
||||
from numbers import Number
|
||||
from typing import Union
|
||||
|
||||
from NanoVNASaver import SITools
|
||||
|
||||
|
@ -55,7 +54,7 @@ def format_frequency(freq: Number) -> str:
|
|||
return str(SITools.Value(freq, "Hz", FMT_FREQ))
|
||||
|
||||
|
||||
def format_frequency_inputs(freq: Union[Number, str]) -> str:
|
||||
def format_frequency_inputs(freq: Number | str) -> str:
|
||||
return str(SITools.Value(freq, "Hz", FMT_FREQ_INPUTS))
|
||||
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ import logging
|
|||
import platform
|
||||
from collections import namedtuple
|
||||
from time import sleep
|
||||
from typing import List
|
||||
|
||||
import serial
|
||||
from serial.tools import list_ports
|
||||
|
@ -91,7 +90,7 @@ def usb_typename(device: ListPortInfo) -> str:
|
|||
# Get list of interfaces with VNAs connected
|
||||
|
||||
|
||||
def get_interfaces() -> List[Interface]:
|
||||
def get_interfaces() -> list[Interface]:
|
||||
interfaces = []
|
||||
# serial like usb interfaces
|
||||
for d in list_ports.comports():
|
||||
|
@ -117,7 +116,7 @@ def get_interfaces() -> List[Interface]:
|
|||
return interfaces
|
||||
|
||||
|
||||
def get_portinfos() -> List[str]:
|
||||
def get_portinfos() -> list[str]:
|
||||
portinfos = []
|
||||
# serial like usb interfaces
|
||||
for d in list_ports.comports():
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
import struct
|
||||
from typing import List
|
||||
|
||||
import serial
|
||||
import numpy as np
|
||||
|
@ -123,7 +122,7 @@ class NanoVNA(VNA):
|
|||
self.features.add("Scan command")
|
||||
self.sweep_method = "scan"
|
||||
|
||||
def readFrequencies(self) -> List[int]:
|
||||
def readFrequencies(self) -> list[int]:
|
||||
logger.debug("readFrequencies: %s", self.sweep_method)
|
||||
if self.sweep_method != "scan_mask":
|
||||
return super().readFrequencies()
|
||||
|
@ -134,7 +133,7 @@ class NanoVNA(VNA):
|
|||
)
|
||||
]
|
||||
|
||||
def readValues(self, value) -> List[str]:
|
||||
def readValues(self, value) -> list[str]:
|
||||
if self.sweep_method != "scan_mask":
|
||||
return super().readValues(value)
|
||||
logger.debug("readValue with scan mask (%s)", value)
|
||||
|
|
|
@ -20,7 +20,6 @@ import logging
|
|||
import platform
|
||||
from struct import pack, unpack_from
|
||||
from time import sleep
|
||||
from typing import List
|
||||
|
||||
from NanoVNASaver.Hardware.Serial import Interface
|
||||
from NanoVNASaver.Hardware.VNA import VNA
|
||||
|
@ -131,7 +130,7 @@ class NanoVNA_V2(VNA):
|
|||
logger.debug("readFirmware: %s", result)
|
||||
return result
|
||||
|
||||
def readFrequencies(self) -> List[int]:
|
||||
def readFrequencies(self) -> list[int]:
|
||||
return [
|
||||
int(self.sweepStartHz + i * self.sweepStepHz)
|
||||
for i in range(self.datapoints)
|
||||
|
@ -159,7 +158,7 @@ class NanoVNA_V2(VNA):
|
|||
|
||||
logger.debug("Freq index to: %i", freq_index)
|
||||
|
||||
def readValues(self, value) -> List[str]:
|
||||
def readValues(self, value) -> list[str]:
|
||||
# Actually grab the data only when requesting channel 0.
|
||||
# The hardware will return all channels which we will store.
|
||||
if value == "data 0":
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
import struct
|
||||
from typing import List
|
||||
|
||||
import serial
|
||||
import numpy as np
|
||||
|
@ -109,11 +108,11 @@ class TinySA(VNA):
|
|||
list(self.exec_command(f"sweep {start} {stop} {self.datapoints}"))
|
||||
list(self.exec_command("trigger auto"))
|
||||
|
||||
def readFrequencies(self) -> List[int]:
|
||||
def readFrequencies(self) -> list[int]:
|
||||
logger.debug("readFrequencies")
|
||||
return [int(line) for line in self.exec_command("frequencies")]
|
||||
|
||||
def readValues(self, value) -> List[str]:
|
||||
def readValues(self, value) -> list[str]:
|
||||
def conv2float(data: str) -> float:
|
||||
try:
|
||||
return 10 ** (float(data.strip()) / 20)
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
from time import sleep
|
||||
from typing import List, Iterator, Set
|
||||
from typing import Iterator
|
||||
|
||||
from PyQt6 import QtGui
|
||||
|
||||
|
@ -131,7 +131,7 @@ class VNA:
|
|||
if len(self.valid_datapoints) > 1:
|
||||
self.features.add("Customizable data points")
|
||||
|
||||
def get_bandwidths(self) -> List[int]:
|
||||
def get_bandwidths(self) -> list[int]:
|
||||
logger.debug("get bandwidths")
|
||||
if self.bw_method == "dislord":
|
||||
return list(DISLORD_BW.keys())
|
||||
|
@ -153,7 +153,7 @@ class VNA:
|
|||
raise IOError(f"set_bandwith({bandwidth}: {result}")
|
||||
self.bandwidth = bandwidth
|
||||
|
||||
def readFrequencies(self) -> List[int]:
|
||||
def readFrequencies(self) -> list[int]:
|
||||
return [int(f) for f in self.readValues("frequencies")]
|
||||
|
||||
def resetSweep(self, start: int, stop: int):
|
||||
|
@ -170,7 +170,7 @@ class VNA:
|
|||
def connected(self) -> bool:
|
||||
return self.serial.is_open
|
||||
|
||||
def getFeatures(self) -> Set[str]:
|
||||
def getFeatures(self) -> set[str]:
|
||||
return self.features
|
||||
|
||||
def getCalibration(self) -> str:
|
||||
|
@ -194,7 +194,7 @@ class VNA:
|
|||
logger.debug("result:\n%s", result)
|
||||
return result
|
||||
|
||||
def readValues(self, value) -> List[str]:
|
||||
def readValues(self, value) -> list[str]:
|
||||
logger.debug("VNA reading %s", value)
|
||||
result = list(self.exec_command(value))
|
||||
logger.debug("VNA done reading %s (%d values)", value, len(result))
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import List, NamedTuple
|
||||
from typing import NamedTuple
|
||||
from NanoVNASaver.RFTools import Datapoint
|
||||
|
||||
|
||||
|
@ -72,15 +72,12 @@ class Value:
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
freq: int = 0,
|
||||
s11: List[Datapoint] = None,
|
||||
s21: List[Datapoint] = None,
|
||||
):
|
||||
self.freq = freq
|
||||
self.s11 = [] if s11 is None else s11[:]
|
||||
self.s21 = [] if s21 is None else s21[:]
|
||||
self.freq: int = 0
|
||||
self.s11: list[Datapoint] = []
|
||||
self.s21: list[Datapoint] = []
|
||||
|
||||
def store(self, index: int, s11: List[Datapoint], s21: List[Datapoint]):
|
||||
def store(self, index: int, s11: list[Datapoint], s21: list[Datapoint]):
|
||||
# handle boundaries
|
||||
if index == 0:
|
||||
index = 1
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import math
|
||||
from typing import List
|
||||
|
||||
from PyQt6 import QtGui, QtWidgets, QtCore
|
||||
from PyQt6.QtCore import pyqtSignal
|
||||
|
@ -253,7 +252,7 @@ class Marker(QtCore.QObject, Value):
|
|||
def getRow(self):
|
||||
return QtWidgets.QLabel(self.name), self.layout
|
||||
|
||||
def findLocation(self, data: List[RFTools.Datapoint]):
|
||||
def findLocation(self, data: list[RFTools.Datapoint]):
|
||||
self.location = -1
|
||||
self.frequencyInput.nextFrequency = -1
|
||||
self.frequencyInput.previousFrequency = -1
|
||||
|
@ -298,7 +297,7 @@ class Marker(QtCore.QObject, Value):
|
|||
v.setText("")
|
||||
|
||||
def updateLabels(
|
||||
self, s11: List[RFTools.Datapoint], s21: List[RFTools.Datapoint]
|
||||
self, s11: list[RFTools.Datapoint], s21: list[RFTools.Datapoint]
|
||||
):
|
||||
if not s11:
|
||||
return
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import math
|
||||
import cmath
|
||||
from typing import List, NamedTuple
|
||||
from typing import NamedTuple
|
||||
|
||||
from NanoVNASaver.SITools import Format, clamp_value
|
||||
|
||||
|
@ -92,7 +92,7 @@ def gamma_to_impedance(gamma: complex, ref_impedance: float = 50) -> complex:
|
|||
return math.inf
|
||||
|
||||
|
||||
def groupDelay(data: List[Datapoint], index: int) -> float:
|
||||
def groupDelay(data: list[Datapoint], index: int) -> float:
|
||||
idx0 = clamp_value(index - 1, 0, len(data) - 1)
|
||||
idx1 = clamp_value(index + 1, 0, len(data) - 1)
|
||||
delta_angle = data[idx1].phase - data[idx0].phase
|
||||
|
@ -147,7 +147,7 @@ def serial_to_parallel(z: complex) -> complex:
|
|||
return complex(z_sq_sum / z.real, z_sq_sum / z.imag)
|
||||
|
||||
|
||||
def corr_att_data(data: List[Datapoint], att: float) -> List[Datapoint]:
|
||||
def corr_att_data(data: list[Datapoint], att: float) -> list[Datapoint]:
|
||||
"""Correct the ratio for a given attenuation on s21 input"""
|
||||
if att <= 0:
|
||||
return data
|
||||
|
|
|
@ -17,10 +17,11 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
from dataclasses import dataclass, replace
|
||||
from enum import Enum
|
||||
from math import log
|
||||
from threading import Lock
|
||||
from typing import Iterator, Tuple
|
||||
from typing import Iterator, NamedTuple
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -31,63 +32,28 @@ class SweepMode(Enum):
|
|||
AVERAGE = 2
|
||||
|
||||
|
||||
class Properties:
|
||||
def __init__(
|
||||
self,
|
||||
name: str = "",
|
||||
mode: "SweepMode" = SweepMode.SINGLE,
|
||||
averages: Tuple[int, int] = (3, 0),
|
||||
logarithmic: bool = False,
|
||||
):
|
||||
self.name = name
|
||||
self.mode = mode
|
||||
self.averages = averages
|
||||
self.logarithmic = logarithmic
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
f"Properties('{self.name}', {self.mode}, {self.averages},"
|
||||
f" {self.logarithmic})"
|
||||
)
|
||||
class Properties(NamedTuple):
|
||||
name: str = ""
|
||||
mode: "SweepMode" = SweepMode.SINGLE
|
||||
averages: tuple[int, int] = (3, 0)
|
||||
logarithmic: bool = False
|
||||
|
||||
|
||||
@dataclass
|
||||
class Sweep:
|
||||
def __init__(
|
||||
self,
|
||||
start: int = 3600000,
|
||||
end: int = 30000000,
|
||||
points: int = 101,
|
||||
segments: int = 1,
|
||||
properties: "Properties" = Properties(),
|
||||
):
|
||||
self.start = start
|
||||
self.end = end
|
||||
self.points = points
|
||||
self.segments = segments
|
||||
self.properties = properties
|
||||
start: int = 3600000
|
||||
end: int = 30000000
|
||||
points: int = 101
|
||||
segments: int = 1
|
||||
properties: "Properties" = Properties()
|
||||
|
||||
def __post_init__(self):
|
||||
self.lock = Lock()
|
||||
self.check()
|
||||
logger.debug("%s", self)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"Sweep({self.start}, {self.end}, {self.points}, {self.segments},"
|
||||
f" {self.properties})"
|
||||
)
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
return (
|
||||
self.start == other.start
|
||||
and self.end == other.end
|
||||
and self.points == other.points
|
||||
and self.segments == other.segments
|
||||
and self.properties == other.properties
|
||||
)
|
||||
|
||||
def copy(self) -> "Sweep":
|
||||
return Sweep(
|
||||
self.start, self.end, self.points, self.segments, self.properties
|
||||
)
|
||||
return replace(self)
|
||||
|
||||
@property
|
||||
def span(self) -> int:
|
||||
|
@ -110,7 +76,7 @@ class Sweep:
|
|||
def _exp_factor(self, index: int) -> float:
|
||||
return 1 - log(self.segments + 1 - index) / log(self.segments + 1)
|
||||
|
||||
def get_index_range(self, index: int) -> Tuple[int, int]:
|
||||
def get_index_range(self, index: int) -> tuple[int, int]:
|
||||
if not self.properties.logarithmic:
|
||||
start = self.start + index * self.points * self.stepsize
|
||||
end = start + (self.points - 1) * self.stepsize
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
from time import sleep
|
||||
from typing import List, Tuple
|
||||
|
||||
import numpy as np
|
||||
from PyQt6 import QtCore, QtWidgets
|
||||
|
@ -31,7 +30,7 @@ from NanoVNASaver.Settings.Sweep import Sweep, SweepMode
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def truncate(values: List[List[Tuple]], count: int) -> List[List[Tuple]]:
|
||||
def truncate(values: list[list[tuple]], count: int) -> list[list[tuple]]:
|
||||
"""truncate drops extrema from data list if averaging is active"""
|
||||
keep = len(values) - count
|
||||
logger.debug("Truncating from %d values to %d", len(values), keep)
|
||||
|
@ -62,10 +61,10 @@ class SweepWorker(QtCore.QRunnable):
|
|||
self.sweep = Sweep()
|
||||
self.setAutoDelete(False)
|
||||
self.percentage = 0
|
||||
self.data11: List[Datapoint] = []
|
||||
self.data21: List[Datapoint] = []
|
||||
self.rawData11: List[Datapoint] = []
|
||||
self.rawData21: List[Datapoint] = []
|
||||
self.data11: list[Datapoint] = []
|
||||
self.data21: list[Datapoint] = []
|
||||
self.rawData11: list[Datapoint] = []
|
||||
self.rawData21: list[Datapoint] = []
|
||||
self.init_data()
|
||||
self.stopped = False
|
||||
self.running = False
|
||||
|
@ -187,10 +186,10 @@ class SweepWorker(QtCore.QRunnable):
|
|||
self.signals.updated.emit()
|
||||
|
||||
def applyCalibration(
|
||||
self, raw_data11: List[Datapoint], raw_data21: List[Datapoint]
|
||||
) -> Tuple[List[Datapoint], List[Datapoint]]:
|
||||
data11: List[Datapoint] = []
|
||||
data21: List[Datapoint] = []
|
||||
self, raw_data11: list[Datapoint], raw_data21: list[Datapoint]
|
||||
) -> tuple[list[Datapoint], list[Datapoint]]:
|
||||
data11: list[Datapoint] = []
|
||||
data21: list[Datapoint] = []
|
||||
|
||||
if not self.app.calibration.isCalculated:
|
||||
data11 = raw_data11.copy()
|
||||
|
|
|
@ -22,8 +22,6 @@ import cmath
|
|||
import io
|
||||
from operator import attrgetter
|
||||
|
||||
from typing import List
|
||||
|
||||
from scipy.interpolate import interp1d
|
||||
|
||||
from NanoVNASaver.RFTools import Datapoint
|
||||
|
@ -108,42 +106,42 @@ class Touchstone:
|
|||
self._interp = {}
|
||||
|
||||
@property
|
||||
def s11(self) -> List[Datapoint]:
|
||||
def s11(self) -> list[Datapoint]:
|
||||
return self.s("11")
|
||||
|
||||
@s11.setter
|
||||
def s11(self, value: List[Datapoint]):
|
||||
def s11(self, value: list[Datapoint]):
|
||||
self.sdata[0] = value
|
||||
|
||||
@property
|
||||
def s12(self) -> List[Datapoint]:
|
||||
def s12(self) -> list[Datapoint]:
|
||||
return self.s("12")
|
||||
|
||||
@s12.setter
|
||||
def s12(self, value: List[Datapoint]):
|
||||
def s12(self, value: list[Datapoint]):
|
||||
self.sdata[2] = value
|
||||
|
||||
@property
|
||||
def s21(self) -> List[Datapoint]:
|
||||
def s21(self) -> list[Datapoint]:
|
||||
return self.s("21")
|
||||
|
||||
@s21.setter
|
||||
def s21(self, value: List[Datapoint]):
|
||||
def s21(self, value: list[Datapoint]):
|
||||
self.sdata[1] = value
|
||||
|
||||
@property
|
||||
def s22(self) -> List[Datapoint]:
|
||||
def s22(self) -> list[Datapoint]:
|
||||
return self.s("22")
|
||||
|
||||
@s22.setter
|
||||
def s22(self, value: List[Datapoint]):
|
||||
def s22(self, value: list[Datapoint]):
|
||||
self.sdata[3] = value
|
||||
|
||||
@property
|
||||
def r(self) -> int:
|
||||
return self.opts.resistance
|
||||
|
||||
def s(self, name: str) -> List[Datapoint]:
|
||||
def s(self, name: str) -> list[Datapoint]:
|
||||
return self.sdata[Touchstone.FIELD_ORDER.index(name)]
|
||||
|
||||
def s_freq(self, name: str, freq: int) -> Datapoint:
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
import re
|
||||
import typing
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Version:
|
||||
RXP = re.compile(
|
||||
_RXP = re.compile(
|
||||
r"""^
|
||||
\D*
|
||||
(?P<major>\d+)\.
|
||||
|
@ -33,61 +33,26 @@ class Version:
|
|||
re.VERBOSE,
|
||||
)
|
||||
|
||||
def __init__(self, vstring: str = "0.0.0"):
|
||||
self.data = {
|
||||
"major": 0,
|
||||
"minor": 0,
|
||||
"revision": 0,
|
||||
"note": "",
|
||||
}
|
||||
try:
|
||||
self.data = Version.RXP.search(vstring).groupdict()
|
||||
for name in ("major", "minor", "revision"):
|
||||
self.data[name] = int(self.data[name])
|
||||
except TypeError:
|
||||
self.data["revision"] = 0
|
||||
except AttributeError:
|
||||
logger.error("Unable to parse version: %s", vstring)
|
||||
|
||||
def __gt__(self, other: "Version") -> bool:
|
||||
left, right = self.data, other.data
|
||||
for name in ("major", "minor", "revision"):
|
||||
if left[name] > right[name]:
|
||||
return True
|
||||
if left[name] < right[name]:
|
||||
return False
|
||||
return False
|
||||
|
||||
def __lt__(self, other: "Version") -> bool:
|
||||
return other.__gt__(self)
|
||||
|
||||
def __ge__(self, other: "Version") -> bool:
|
||||
return self.__gt__(other) or self.__eq__(other)
|
||||
|
||||
def __le__(self, other: "Version") -> bool:
|
||||
return other.__gt__(self) or self.__eq__(other)
|
||||
|
||||
def __eq__(self, other: "Version") -> bool:
|
||||
return self.data == other.data
|
||||
class _Version(typing.NamedTuple):
|
||||
major: int
|
||||
minor: int
|
||||
revision: int
|
||||
note: str
|
||||
|
||||
def __str__(self) -> str:
|
||||
return (
|
||||
f'{self.data["major"]}.{self.data["minor"]}'
|
||||
f'.{self.data["revision"]}{self.data["note"]}'
|
||||
f'{self.major}.{self.minor}'
|
||||
f'.{self.revision}{self.note}'
|
||||
)
|
||||
|
||||
@property
|
||||
def major(self) -> int:
|
||||
return self.data["major"]
|
||||
|
||||
@property
|
||||
def minor(self) -> int:
|
||||
return self.data["minor"]
|
||||
def Version(vstring: str = "0.0.0") -> '_Version':
|
||||
if (match := _RXP.search(vstring)) is None:
|
||||
logger.error("Unable to parse version: %s", vstring)
|
||||
return _Version(0, 0, 0, '')
|
||||
|
||||
@property
|
||||
def revision(self) -> int:
|
||||
return self.data["revision"]
|
||||
|
||||
@property
|
||||
def note(self) -> str:
|
||||
return self.data["note"]
|
||||
return _Version(int(match.group('major')),
|
||||
int(match.group('minor')),
|
||||
int(match.group('revision') or '0'),
|
||||
match.group('note'))
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from PyQt6 import QtWidgets, QtCore
|
||||
from PyQt6.QtGui import QColor, QColorConstants, QPalette, QShortcut
|
||||
|
@ -210,7 +209,7 @@ class DisplaySettingsWindow(QtWidgets.QWidget):
|
|||
vswr_marker_box = QtWidgets.QGroupBox("VSWR Markers")
|
||||
vswr_marker_layout = QtWidgets.QFormLayout(vswr_marker_box)
|
||||
|
||||
self.vswrMarkers: List[float] = self.app.settings.value(
|
||||
self.vswrMarkers: list[float] = self.app.settings.value(
|
||||
"VSWRMarkers", [], float
|
||||
)
|
||||
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
from importlib.metadata import (
|
||||
PackageNotFoundError,
|
||||
version,
|
||||
)
|
||||
import importlib.metadata
|
||||
|
||||
try:
|
||||
# Change here if project is renamed and does not equal the package name
|
||||
dist_name = "nanovna-saver"
|
||||
__version__ = version(dist_name)
|
||||
except PackageNotFoundError: # pragma: no cover
|
||||
__version__ = importlib.metadata.version(distribution_name="nanovna-saver")
|
||||
except importlib.metadata.PackageNotFoundError: # pragma: no cover
|
||||
__version__ = "unknown"
|
||||
finally:
|
||||
del version, PackageNotFoundError
|
||||
|
|
|
@ -27,8 +27,10 @@ class TestCases(unittest.TestCase):
|
|||
def test_sweep(self):
|
||||
sweep = Sweep()
|
||||
self.assertEqual(str(sweep),
|
||||
"Sweep(3600000, 30000000, 101, 1, Properties('',"
|
||||
" SweepMode.SINGLE, (3, 0), False))")
|
||||
"Sweep(start=3600000, end=30000000, points=101,"
|
||||
" segments=1, properties=Properties(name='',"
|
||||
" mode=<SweepMode.SINGLE: 0>, averages=(3, 0),"
|
||||
" logarithmic=False))")
|
||||
self.assertTrue(Sweep(3600000) == sweep)
|
||||
self.assertFalse(Sweep(3600001) == sweep)
|
||||
self.assertRaises(ValueError, Sweep, -1)
|
||||
|
|
Ładowanie…
Reference in New Issue