reordered RFTools functions alphabetically

added some test cases
pull/199/head^2
Holger Müller 2020-06-28 15:43:47 +02:00
rodzic 5dd8c1d20d
commit c0e1cfb310
4 zmienionych plików z 72 dodań i 62 usunięć

Wyświetl plik

@ -1,6 +1,7 @@
[run]
# ignore GUI code atm.
omit =
NanoVNASaver/About.py
NanoVNASaver/Analysis/*.py
NanoVNASaver/Calibration.py
NanoVNASaver/Charts/*.py

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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