kopia lustrzana https://github.com/NanoVNA-Saver/nanovna-saver
rodzic
5dd8c1d20d
commit
c0e1cfb310
|
@ -1,6 +1,7 @@
|
|||
[run]
|
||||
# ignore GUI code atm.
|
||||
omit =
|
||||
NanoVNASaver/About.py
|
||||
NanoVNASaver/Analysis/*.py
|
||||
NanoVNASaver/Calibration.py
|
||||
NanoVNASaver/Charts/*.py
|
||||
|
|
|
@ -36,7 +36,7 @@ from .Formatting import (
|
|||
parse_frequency,
|
||||
)
|
||||
from .Hardware import get_interfaces, get_VNA, InvalidVNA
|
||||
from .RFTools import Datapoint, corrAttData
|
||||
from .RFTools import Datapoint, corr_att_data
|
||||
from .Charts.Chart import Chart
|
||||
from .Charts import (
|
||||
CapacitanceChart,
|
||||
|
@ -696,8 +696,7 @@ class NanoVNASaver(QtWidgets.QWidget):
|
|||
if self.dataLock.acquire(blocking=True):
|
||||
self.data = data
|
||||
if self.s21att > 0:
|
||||
corData12 = corrAttData(data12, self.s21att)
|
||||
self.data21 = corData12
|
||||
self.data21 = corr_att_data(data12, self.s21att)
|
||||
else:
|
||||
self.data21 = data12
|
||||
else:
|
||||
|
|
|
@ -26,26 +26,43 @@ FMT_SHORT = Format(max_nr_digits=4)
|
|||
FMT_SWEEP = Format(max_nr_digits=9, allow_strip=True)
|
||||
|
||||
|
||||
def parallel_to_serial(z: complex) -> complex:
|
||||
"""Convert parallel impedance to serial impedance equivalent"""
|
||||
z_sq_sum = z.real ** 2 + z.imag ** 2
|
||||
# TODO: Fix divide by zero
|
||||
return complex(z.real * z.imag ** 2 / z_sq_sum,
|
||||
z.real ** 2 * z.imag / z_sq_sum)
|
||||
def corr_att_data(data: List[Datapoint], att: float):
|
||||
"""Correct the ratio for a given attenuation on s21 input"""
|
||||
if att <= 0:
|
||||
return data
|
||||
else:
|
||||
att = 10**(att/20)
|
||||
ndata = []
|
||||
for dp in data:
|
||||
freq, re, im = dp
|
||||
orig = complex(re, im)
|
||||
corrected = orig * att
|
||||
ndata.append(Datapoint(freq, corrected.real, corrected.imag))
|
||||
return ndata
|
||||
|
||||
|
||||
def serial_to_parallel(z: complex) -> complex:
|
||||
"""Convert serial impedance to parallel impedance equivalent"""
|
||||
z_sq_sum = z.real ** 2 + z.imag ** 2
|
||||
if z.real == 0 and z.imag == 0:
|
||||
return complex(math.inf, math.inf)
|
||||
if z_sq_sum == 0:
|
||||
return complex(0, 0)
|
||||
if z.imag == 0:
|
||||
return complex(z_sq_sum / z.real, math.copysign(math.inf, z_sq_sum))
|
||||
if z.real == 0:
|
||||
return complex(math.copysign(math.inf, z_sq_sum), z_sq_sum / z.real)
|
||||
return complex(z_sq_sum / z.real, z_sq_sum / z.imag)
|
||||
def gamma_to_impedance(gamma: complex, ref_impedance: float = 50) -> complex:
|
||||
"""Calculate impedance from gamma"""
|
||||
try:
|
||||
return ((-gamma - 1) / (gamma - 1)) * ref_impedance
|
||||
except ZeroDivisionError:
|
||||
return math.inf
|
||||
|
||||
|
||||
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
|
||||
delta_freq = data[idx1].freq - data[idx0].freq
|
||||
if delta_freq == 0:
|
||||
return 0
|
||||
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 / delta_freq
|
||||
return val
|
||||
|
||||
|
||||
def impedance_to_capacitance(z: complex, freq: float) -> float:
|
||||
|
@ -74,17 +91,32 @@ def norm_to_impedance(z: complex, ref_impedance: float = 50) -> complex:
|
|||
return z * ref_impedance
|
||||
|
||||
|
||||
def parallel_to_serial(z: complex) -> complex:
|
||||
"""Convert parallel impedance to serial impedance equivalent"""
|
||||
z_sq_sum = z.real ** 2 + z.imag ** 2
|
||||
# TODO: Fix divide by zero
|
||||
return complex(z.real * z.imag ** 2 / z_sq_sum,
|
||||
z.real ** 2 * z.imag / z_sq_sum)
|
||||
|
||||
|
||||
def reflection_coefficient(z: complex, ref_impedance: float = 50) -> complex:
|
||||
"""Calculate reflection coefficient for z"""
|
||||
return (z - ref_impedance) / (z + ref_impedance)
|
||||
|
||||
|
||||
def gamma_to_impedance(gamma: complex, ref_impedance: float = 50) -> complex:
|
||||
"""Calculate impedance from gamma"""
|
||||
try:
|
||||
return ((-gamma - 1) / (gamma - 1)) * ref_impedance
|
||||
except ZeroDivisionError:
|
||||
return math.inf
|
||||
def serial_to_parallel(z: complex) -> complex:
|
||||
"""Convert serial impedance to parallel impedance equivalent"""
|
||||
z_sq_sum = z.real ** 2 + z.imag ** 2
|
||||
if z.real == 0 and z.imag == 0:
|
||||
return complex(math.inf, math.inf)
|
||||
# only possible if real and imag == 0, therefor commented out
|
||||
# if z_sq_sum == 0:
|
||||
# return complex(0, 0)
|
||||
if z.imag == 0:
|
||||
return complex(z_sq_sum / z.real, math.copysign(math.inf, z_sq_sum))
|
||||
if z.real == 0:
|
||||
return complex(math.copysign(math.inf, z_sq_sum), z_sq_sum / z.imag)
|
||||
return complex(z_sq_sum / z.real, z_sq_sum / z.imag)
|
||||
|
||||
|
||||
class Datapoint(NamedTuple):
|
||||
|
@ -131,36 +163,3 @@ class Datapoint(NamedTuple):
|
|||
def inductiveEquivalent(self, ref_impedance: float = 50) -> float:
|
||||
return impedance_to_inductance(self.impedance(ref_impedance), self.freq)
|
||||
|
||||
|
||||
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
|
||||
delta_freq = data[idx1].freq - data[idx0].freq
|
||||
if delta_freq == 0:
|
||||
return 0
|
||||
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 / delta_freq
|
||||
return val
|
||||
|
||||
|
||||
def corrAttData(data: Datapoint, att: float):
|
||||
"""Correct the ratio for a given attenuation on s21 input"""
|
||||
|
||||
if att <= 0:
|
||||
return data
|
||||
else:
|
||||
att = 10**(att/20)
|
||||
|
||||
ndata = []
|
||||
for i in range(len(data)):
|
||||
freq, re, im = data[i]
|
||||
orig = complex(re, im)
|
||||
corrected = orig * att
|
||||
ndata.append(Datapoint(freq, corrected.real, corrected.imag))
|
||||
|
||||
return ndata
|
||||
|
|
|
@ -81,6 +81,15 @@ class TestRFTools(unittest.TestCase):
|
|||
complex(50, 10))
|
||||
|
||||
def test_serial_to_parallel(self):
|
||||
self.assertEqual(
|
||||
serial_to_parallel(complex(0, 0)),
|
||||
complex(math.inf, math.inf))
|
||||
self.assertEqual(
|
||||
serial_to_parallel(complex(50, 0)),
|
||||
complex(50, math.inf))
|
||||
self.assertEqual(
|
||||
serial_to_parallel(complex(0, 50)),
|
||||
complex(math.inf, 50))
|
||||
self.assertAlmostEqual(
|
||||
serial_to_parallel(complex(50, 10)),
|
||||
complex(52, 260))
|
||||
|
@ -105,9 +114,9 @@ class TestRFTools(unittest.TestCase):
|
|||
Datapoint(100002, 0.1091, 0.3130),
|
||||
]
|
||||
dpoints0 = [
|
||||
Datapoint(100000, 0.1091, 0.3118),
|
||||
Datapoint(100000, 0.1091, 0.3124),
|
||||
Datapoint(100000, 0.1091, 0.3130),
|
||||
Datapoint(100000, 0.1091, 0.3124),
|
||||
Datapoint(100000, 0.1091, 0.3124),
|
||||
]
|
||||
self.assertAlmostEqual(groupDelay(dpoints, 1), -9.514e-5)
|
||||
self.assertEqual(groupDelay(dpoints0, 1), 0.0)
|
||||
|
@ -120,6 +129,7 @@ class TestRFToolsDatapoint(unittest.TestCase):
|
|||
self.dp0 = Datapoint(100000, 0, 0)
|
||||
self.dp50 = Datapoint(100000, 1, 0)
|
||||
self.dp75 = Datapoint(100000, 0.2, 0)
|
||||
self.dp_im50 = Datapoint(100000, 0, 1)
|
||||
|
||||
def test_properties(self):
|
||||
self.assertEqual(self.dp.z, complex(0.1091, 0.3118))
|
||||
|
@ -134,6 +144,7 @@ class TestRFToolsDatapoint(unittest.TestCase):
|
|||
complex(74.99628755, 52.49617517))
|
||||
self.assertEqual(self.dp0.qFactor(), 0.0)
|
||||
self.assertEqual(self.dp75.qFactor(), 0.0)
|
||||
self.assertEqual(self.dp_im50.qFactor(), -1.0)
|
||||
self.assertAlmostEqual(self.dp.qFactor(), 0.6999837)
|
||||
self.assertAlmostEqual(self.dp.capacitiveEquivalent(), -4.54761539e-08)
|
||||
self.assertAlmostEqual(self.dp.inductiveEquivalent(), 5.57001e-05)
|
||||
|
|
Ładowanie…
Reference in New Issue