add interpolation for touchstone data

pull/231/head
Holger Müller 2020-07-07 14:09:58 +02:00
rodzic 948c04f154
commit 27d3f492d8
3 zmienionych plików z 118 dodań i 41 usunięć

Wyświetl plik

@ -292,42 +292,33 @@ class Calibration:
e30.append(caldata["e30"])
e10e32.append(caldata["e10e32"])
self.interp["e00"] = interp1d(freq, e00, kind="slinear")
self.interp["e11"] = interp1d(freq, e11, kind="slinear")
self.interp["delta_e"] = interp1d(freq, delta_e, kind="slinear")
self.interp["e30"] = interp1d(freq, e30, kind="slinear")
self.interp["e10e32"] = interp1d(freq, e10e32, kind="slinear")
self.interp = {
"e00": interp1d(freq, e00,
kind="slinear", bounds_error=False,
fill_value=(e00[0], e00[-1])),
"e11": interp1d(freq, e11,
kind="slinear", bounds_error=False,
fill_value=(e11[0], e11[-1])),
"delta_e": interp1d(freq, delta_e,
kind="slinear", bounds_error=False,
fill_value=(delta_e[0], delta_e[-1])),
"e30": interp1d(freq, e30,
kind="slinear", bounds_error=False,
fill_value=(e30[0], e30[-1])),
"e10e32": interp1d(freq, e10e32,
kind="slinear", bounds_error=False,
fill_value=(e10e32[0], e10e32[-1])),
}
def correct11(self, dp: Datapoint):
i = self.interp
try:
s11 = (dp.z - i["e00"](dp.freq)) / (
(dp.z * i["e11"](dp.freq)) - i["delta_e"](dp.freq))
return Datapoint(dp.freq, s11.real, s11.imag)
except ValueError:
# TODO: implement warn message in gui
logger.info("Data outside calibration")
nearest = sorted(self.dataset.frequencies(),
key=lambda k: abs(dp.freq - k))[0]
ds = self.dataset.get(nearest)
s11 = (dp.z - ds["e00"]) / (
(dp.z * ds["e11"]) - ds["delta_e"])
s11 = (dp.z - i["e00"](dp.freq)) / (
(dp.z * i["e11"](dp.freq)) - i["delta_e"](dp.freq))
return Datapoint(dp.freq, s11.real, s11.imag)
def correct21(self, dp: Datapoint):
i = self.interp
try:
s21 = (dp.z - i["e30"](dp.freq)) / i["e10e32"](dp.freq)
return Datapoint(dp.freq, s21.real, s21.imag)
except ValueError:
# TODO: implement warn message in gui
logger.info("Data outside calibration")
nearest = sorted(self.dataset.frequencies(),
key=lambda k: abs(dp.freq - k))[0]
ds = self.dataset.get(nearest)
s21 = (dp.z - ds["e30"]) / ds["e10e32"]
s21 = (dp.z - i["e30"](dp.freq)) / i["e10e32"](dp.freq)
return Datapoint(dp.freq, s21.real, s21.imag)
# TODO: implement tests

Wyświetl plik

@ -21,6 +21,11 @@ import math
import cmath
import io
from operator import attrgetter
from typing import List
from scipy.interpolate import interp1d
from NanoVNASaver.RFTools import Datapoint
logger = logging.getLogger(__name__)
@ -98,30 +103,78 @@ class Touchstone:
self.sdata = [[], [], [], []] # at max 4 data pairs
self.comments = []
self.opts = Options()
self._interp = {}
@property
def s11data(self) -> list:
def s11data(self) -> List[Datapoint]:
return self.s("11")
@s11data.setter
def s11data(self, value: List[Datapoint]):
self.sdata[0] = value
@property
def s12data(self) -> list:
def s12data(self) -> List[Datapoint]:
return self.s("12")
@property
def s21data(self) -> list:
return self.s("21")
@s12data.setter
def s12data(self, value: List[Datapoint]):
self.sdata[2] = value
@property
def s22data(self) -> list:
def s21data(self) -> List[Datapoint]:
return self.s("21")
@s21data.setter
def s21data(self, value: List[Datapoint]):
self.sdata[1] = value
@property
def s22data(self) -> List[Datapoint]:
return self.s("22")
@s22data.setter
def s22data(self, value: List[Datapoint]):
self.sdata[3] = value
@property
def r(self) -> int:
return self.opts.resistance
def s(self, name: str) -> list:
def s(self, name: str) -> List[Datapoint]:
return self.sdata[Touchstone.FIELD_ORDER.index(name)]
def s_freq(self, name: str, freq: int) -> Datapoint:
return Datapoint(freq,
float(self._interp[name]["real"](freq)),
float(self._interp[name]["imag"](freq)))
def min_freq(self) -> int:
return self.s("11")[0].freq
def max_freq(self) -> int:
return self.s("11")[-1].freq
def gen_interpolation(self):
for i in Touchstone.FIELD_ORDER:
freq = []
real = []
imag = []
for dp in self.s(i):
freq.append(dp.freq)
real.append(dp.re)
imag.append(dp.im)
self._interp[i] = {
"real": interp1d(freq, real,
kind="slinear", bounds_error=False,
fill_value=(real[0], real[-1])),
"imag": interp1d(freq, imag,
kind="slinear", bounds_error=False,
fill_value=(imag[0], imag[-1])),
}
def _parse_comments(self, fp) -> str:
for line in fp:
line = line.strip()

Wyświetl plik

@ -69,12 +69,20 @@ class TestTouchstoneTouchstone(unittest.TestCase):
ts = Touchstone("./test/data/valid.s2p")
ts.load()
ts.gen_interpolation()
self.assertEqual(str(ts.opts), "# HZ S RI R 50")
self.assertEqual(len(ts.s11data), 1020)
self.assertEqual(len(ts.s21data), 1020)
self.assertEqual(len(ts.s12data), 1020)
self.assertEqual(len(ts.s22data), 1020)
self.assertIn("! Vector Network Analyzer VNA R2", ts.comments)
self.assertEqual(ts.min_freq(), 500000)
self.assertEqual(ts.max_freq(), 900000000)
self.assertEqual(ts.s_freq("11", 1),
Datapoint(1, -3.33238E-001, 1.80018E-004))
self.assertEqual(ts.s_freq("11", 750000),
Datapoint(750000, -0.3331754099382822,
0.00032433255669243524))
ts = Touchstone("./test/data/ma.s2p")
ts.load()
@ -119,9 +127,13 @@ class TestTouchstoneTouchstone(unittest.TestCase):
with self.assertLogs(level=logging.WARNING) as cm:
ts.load()
self.assertEqual(cm.output, [
'WARNING:NanoVNASaver.Touchstone:Non integer resistance value: 50.0',
'WARNING:NanoVNASaver.Touchstone:Comment after header: !freq ReS11 ImS11 ReS21 ImS21 ReS12 ImS12 ReS22 ImS22',
'WARNING:NanoVNASaver.Touchstone:Frequency not ascending: 15000000.0 0.849810063 -0.4147357 -0.000306106 0.0041482 0.0 0.0 0.0 0.0',
'WARNING:NanoVNASaver.Touchstone:'
'Non integer resistance value: 50.0',
'WARNING:NanoVNASaver.Touchstone:Comment after header:'
' !freq ReS11 ImS11 ReS21 ImS21 ReS12 ImS12 ReS22 ImS22',
'WARNING:NanoVNASaver.Touchstone:Frequency not ascending:'
' 15000000.0 0.849810063 -0.4147357 -0.000306106 0.0041482'
' 0.0 0.0 0.0 0.0',
'WARNING:NanoVNASaver.Touchstone:Reordering data',
])
self.assertEqual(str(ts.opts), "# HZ S RI R 50")
@ -129,6 +141,23 @@ class TestTouchstoneTouchstone(unittest.TestCase):
self.assertIn("!freq ReS11 ImS11 ReS21 ImS21 ReS12 ImS12 ReS22 ImS22",
ts.comments)
def test_setter(self):
ts = Touchstone("")
dp_list = [Datapoint(1, 0.0, 0.0), Datapoint(3, 1.0, 1.0)]
ts.s11data = dp_list[:]
ts.s21data = dp_list[:]
ts.s12data = dp_list[:]
ts.s22data = dp_list[:]
self.assertEqual(ts.s11data, dp_list)
self.assertEqual(ts.s21data, dp_list)
self.assertEqual(ts.s12data, dp_list)
self.assertEqual(ts.s22data, dp_list)
self.assertEqual(ts.min_freq(), 1)
self.assertEqual(ts.max_freq(), 3)
ts.gen_interpolation()
self.assertEqual(ts.s_freq("11", 2), Datapoint(2, 0.5, 0.5))
def test_save(self):
ts = Touchstone("./test/data/valid.s2p")
self.assertEqual(ts.saves(), "# HZ S RI R 50\n")
@ -141,8 +170,12 @@ class TestTouchstoneTouchstone(unittest.TestCase):
lines = ts.saves(4).splitlines()
self.assertEqual(len(lines), 1021)
self.assertEqual(lines[0], "# HZ S RI R 50")
self.assertEqual(lines[1], '500000 -0.333238 0.000180018 0.67478 -8.1951e-07 0.67529 -8.20129e-07 -0.333238 0.000308078')
self.assertEqual(lines[-1], '900000000 -0.127646 0.31969 0.596287 -0.503453 0.599076 -0.50197 -0.122713 0.326965')
self.assertEqual(lines[1],
'500000 -0.333238 0.000180018 0.67478 -8.1951e-07'
' 0.67529 -8.20129e-07 -0.333238 0.000308078')
self.assertEqual(lines[-1],
'900000000 -0.127646 0.31969 0.596287 -0.503453'
' 0.599076 -0.50197 -0.122713 0.326965')
ts.filename = "./test/data/output.s2p"
ts.save(4)
os.remove(ts.filename)