Added measurement graphs showing impedance measured via S21

Fixes #165

- Allows for both |Z| and R + jX display
- Measurements of shunt impedance (accurate for low impedance values)
  as well as series impedance (accurate for high impedance values)
pull/376/head
Roel Jordans 2021-02-18 16:57:49 +01:00
rodzic 97c7c8f3f2
commit c6878fce8f
9 zmienionych plików z 195 dodań i 8 usunięć

Wyświetl plik

@ -89,6 +89,8 @@ class MagnitudeZChart(FrequencyChart):
maxValue = 0
for d in self.data:
mag = self.magnitude(d)
if math.isinf(mag): # Avoid infinite scales
continue
if mag > maxValue:
maxValue = mag
if mag < minValue:
@ -97,6 +99,8 @@ class MagnitudeZChart(FrequencyChart):
if d.freq < self.fstart or d.freq > self.fstop:
continue
mag = self.magnitude(d)
if math.isinf(mag): # Avoid infinite scales
continue
if mag > maxValue:
maxValue = mag
if mag < minValue:
@ -142,7 +146,10 @@ class MagnitudeZChart(FrequencyChart):
def getYPosition(self, d: Datapoint) -> int:
mag = self.magnitude(d)
return self.topMargin + round((self.maxValue - mag) / self.span * self.chartHeight)
if math.isfinite(mag):
return self.topMargin + round((self.maxValue - mag) / self.span * self.chartHeight)
else:
return self.topMargin
def valueAtPosition(self, y) -> List[float]:
absy = y - self.topMargin

Wyświetl plik

@ -0,0 +1,40 @@
# NanoVNASaver
#
# A python program to view and export Touchstone data from a NanoVNA
# Copyright (C) 2019, 2020 Rune B. Broberg
# Copyright (C) 2020 NanoVNA-Saver Authors
#
# 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/>.
import math
import logging
from typing import List
from PyQt5 import QtWidgets, QtGui
from NanoVNASaver.RFTools import Datapoint
from .MagnitudeZ import MagnitudeZChart
logger = logging.getLogger(__name__)
class MagnitudeZSeriesChart(MagnitudeZChart):
def __init__(self, name=""):
super().__init__(name)
@staticmethod
def magnitude(p: Datapoint) -> float:
return abs(p.seriesImpedance())

Wyświetl plik

@ -0,0 +1,40 @@
# NanoVNASaver
#
# A python program to view and export Touchstone data from a NanoVNA
# Copyright (C) 2019, 2020 Rune B. Broberg
# Copyright (C) 2020 NanoVNA-Saver Authors
#
# 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/>.
import math
import logging
from typing import List
from PyQt5 import QtWidgets, QtGui
from NanoVNASaver.RFTools import Datapoint
from .MagnitudeZ import MagnitudeZChart
logger = logging.getLogger(__name__)
class MagnitudeZShuntChart(MagnitudeZChart):
def __init__(self, name=""):
super().__init__(name)
@staticmethod
def magnitude(p: Datapoint) -> float:
return abs(p.shuntImpedance())

Wyświetl plik

@ -178,8 +178,10 @@ class RealImaginaryChart(FrequencyChart):
max_real = 0
max_imag = -1000
for d in self.data:
imp = d.impedance()
imp = self.impedance(d)
re, im = imp.real, imp.imag
if math.isinf(re): # Avoid infinite scales
continue
if re > max_real:
max_real = re
if re < min_real:
@ -191,8 +193,10 @@ class RealImaginaryChart(FrequencyChart):
for d in self.reference: # Also check min/max for the reference sweep
if d.freq < fstart or d.freq > fstop:
continue
imp = d.impedance()
imp = self.impedance(d)
re, im = imp.real, imp.imag
if math.isinf(re): # Avoid infinite scales
continue
if re > max_real:
max_real = re
if re < min_real:
@ -397,12 +401,15 @@ class RealImaginaryChart(FrequencyChart):
self.drawMarker(x, y_im, qp, m.color, self.markers.index(m)+1)
def getImYPosition(self, d: Datapoint) -> int:
im = d.impedance().imag
im = self.impedance(d).imag
return self.topMargin + round((self.max_imag - im) / self.span_imag * self.chartHeight)
def getReYPosition(self, d: Datapoint) -> int:
re = d.impedance().real
return self.topMargin + round((self.max_real - re) / self.span_real * self.chartHeight)
re = self.impedance(d).real
if math.isfinite(re):
return self.topMargin + round((self.max_real - re) / self.span_real * self.chartHeight)
else:
return self.topMargin
def valueAtPosition(self, y) -> List[float]:
absy = y - self.topMargin
@ -520,3 +527,6 @@ class RealImaginaryChart(FrequencyChart):
self.action_set_fixed_maximum_imag.setText(
f"Maximum jX ({self.maxDisplayImag})")
self.menu.exec_(event.globalPos())
def impedance(self, p: Datapoint) -> complex:
return p.impedance()

Wyświetl plik

@ -0,0 +1,35 @@
# NanoVNASaver
#
# A python program to view and export Touchstone data from a NanoVNA
# Copyright (C) 2019, 2020 Rune B. Broberg
# Copyright (C) 2020 NanoVNA-Saver Authors
#
# 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/>.
import math
import logging
from typing import List
from NanoVNASaver.RFTools import Datapoint
from .RI import RealImaginaryChart
logger = logging.getLogger(__name__)
class RealImaginarySeriesChart(RealImaginaryChart):
def __init__(self, name=""):
super().__init__(name)
def impedance(self, p: Datapoint) -> complex:
return p.seriesImpedance()

Wyświetl plik

@ -0,0 +1,35 @@
# NanoVNASaver
#
# A python program to view and export Touchstone data from a NanoVNA
# Copyright (C) 2019, 2020 Rune B. Broberg
# Copyright (C) 2020 NanoVNA-Saver Authors
#
# 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/>.
import math
import logging
from typing import List
from NanoVNASaver.RFTools import Datapoint
from .RI import RealImaginaryChart
logger = logging.getLogger(__name__)
class RealImaginaryShuntChart(RealImaginaryChart):
def __init__(self, name=""):
super().__init__(name)
def impedance(self, p: Datapoint) -> complex:
return p.shuntImpedance()

Wyświetl plik

@ -9,10 +9,14 @@ from .LogMag import LogMagChart
from .CLogMag import CombinedLogMagChart
from .Magnitude import MagnitudeChart
from .MagnitudeZ import MagnitudeZChart
from .MagnitudeZShunt import MagnitudeZShuntChart
from .MagnitudeZSeries import MagnitudeZSeriesChart
from .Permeability import PermeabilityChart
from .Phase import PhaseChart
from .QFactor import QualityFactorChart
from .RI import RealImaginaryChart
from .RIShunt import RealImaginaryShuntChart
from .RISeries import RealImaginarySeriesChart
from .Smith import SmithChart
from .SParam import SParameterChart
from .TDR import TDRChart

Wyświetl plik

@ -40,9 +40,9 @@ from .Charts import (
CapacitanceChart,
CombinedLogMagChart, GroupDelayChart, InductanceChart,
LogMagChart, PhaseChart,
MagnitudeChart, MagnitudeZChart,
MagnitudeChart, MagnitudeZChart, MagnitudeZShuntChart, MagnitudeZSeriesChart,
QualityFactorChart, VSWRChart, PermeabilityChart, PolarChart,
RealImaginaryChart,
RealImaginaryChart, RealImaginaryShuntChart, RealImaginarySeriesChart,
SmithChart, SParameterChart, TDRChart,
)
from .Calibration import Calibration
@ -155,6 +155,10 @@ class NanoVNASaver(QtWidgets.QWidget):
reflective=False)),
("log_mag", LogMagChart("S21 Gain")),
("magnitude", MagnitudeChart("|S21|")),
("magnitude_z_shunt", MagnitudeZShuntChart("S21 |Z| shunt")),
("magnitude_z_series", MagnitudeZSeriesChart("S21 |Z| series")),
("real_imag_shunt", RealImaginaryShuntChart("S21 R+jX shunt")),
("real_imag_series", RealImaginarySeriesChart("S21 R+jX series")),
("phase", PhaseChart("S21 Phase")),
("polar", PolarChart("S21 Polar Plot")),
("s_parameter", SParameterChart("S21 Real/Imaginary")),

Wyświetl plik

@ -67,6 +67,18 @@ class Datapoint(NamedTuple):
def impedance(self, ref_impedance: float = 50) -> complex:
return gamma_to_impedance(self.z, ref_impedance)
def shuntImpedance(self, ref_impedance: float = 50) -> complex:
try:
return 0.5 * ref_impedance * self.z / (1 - self.z)
except ZeroDivisionError:
return math.inf
def seriesImpedance(self, ref_impedance: float = 50) -> complex:
try:
return 2 * ref_impedance * (1 - self.z) / self.z
except ZeroDivisionError:
return math.inf
def qFactor(self, ref_impedance: float = 50) -> float:
imp = self.impedance(ref_impedance)
if imp.real == 0.0: