kopia lustrzana https://github.com/NanoVNA-Saver/nanovna-saver
Rewrite of touchstone parser
- keeped compatible with previous version - add test examples of touchstone files - commented out writing to loaded file to fix bug #99pull/100/head
rodzic
d12cdd4b24
commit
c3639b2557
|
@ -905,7 +905,8 @@ class NanoVNASaver(QtWidgets.QWidget):
|
||||||
self.data21 = []
|
self.data21 = []
|
||||||
t = Touchstone(filename)
|
t = Touchstone(filename)
|
||||||
t.load()
|
t.load()
|
||||||
self.saveData(t.s11data, t.s21data, filename)
|
# shouldn't modify read file. even destroys it if read fails
|
||||||
|
# self.saveData(t.s11data, t.s21data, filename)
|
||||||
self.dataUpdated()
|
self.dataUpdated()
|
||||||
|
|
||||||
def sizeHint(self) -> QtCore.QSize:
|
def sizeHint(self) -> QtCore.QSize:
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
import logging
|
import logging
|
||||||
import cmath
|
import cmath
|
||||||
|
import io
|
||||||
from NanoVNASaver.RFTools import Datapoint
|
from NanoVNASaver.RFTools import Datapoint
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -61,30 +62,73 @@ class Options:
|
||||||
|
|
||||||
class Touchstone:
|
class Touchstone:
|
||||||
|
|
||||||
def __init__(self, filename):
|
def __init__(self, filename: str):
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
self.s11data = []
|
self.sdata = [[], [], [], []] # at max 4 data pairs
|
||||||
self.s21data = []
|
|
||||||
self.s12data = []
|
|
||||||
self.s22data = []
|
|
||||||
self.comments = []
|
self.comments = []
|
||||||
self.opts = Options()
|
self.opts = Options()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def s11data(self) -> list:
|
||||||
|
return self.sdata[0]
|
||||||
|
|
||||||
|
@s11data.setter
|
||||||
|
def s11data(self, data: list):
|
||||||
|
self.sdata[0] = data[:]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def s21data(self) -> list:
|
||||||
|
return self.sdata[1]
|
||||||
|
|
||||||
|
@s21data.setter
|
||||||
|
def s21data(self, data: list):
|
||||||
|
self.sdata[1] = data[:]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def s12data(self) -> list:
|
||||||
|
return self.sdata[2]
|
||||||
|
|
||||||
|
@s12data.setter
|
||||||
|
def s12data(self, data: list):
|
||||||
|
self.sdata[2] = data[:]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def s22data(self) -> list:
|
||||||
|
return self.sdata[3]
|
||||||
|
|
||||||
|
@s22data.setter
|
||||||
|
def s22data(self, data: list):
|
||||||
|
self.sdata[3] = data[:]
|
||||||
|
|
||||||
|
def _parse_comments(self, fp) -> str:
|
||||||
|
for line in fp:
|
||||||
|
line = line.strip()
|
||||||
|
if line.startswith("!"):
|
||||||
|
logger.info(line)
|
||||||
|
self.comments.append(line)
|
||||||
|
else:
|
||||||
|
return line
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
logger.info("Attempting to open file %s", self.filename)
|
logger.info("Attempting to open file %s", self.filename)
|
||||||
sdata = [[], [], [], []] # at max 4 data pairs
|
try:
|
||||||
|
with open(self.filename) as infile:
|
||||||
|
self.loads(infile.read())
|
||||||
|
except TypeError as e:
|
||||||
|
logger.exception("Failed to parse %s: %s", self.filename, e)
|
||||||
|
except IOError as e:
|
||||||
|
logger.exception("Failed to open %s: %s", self.filename, e)
|
||||||
|
|
||||||
with open(self.filename, "r") as file:
|
def loads(self, s: str):
|
||||||
for line in file:
|
"""Parse touchstone 1.1 string input
|
||||||
line = line.strip()
|
appends to existing sdata if Touchstone object exists
|
||||||
if line.startswith("!"):
|
"""
|
||||||
logger.info(line)
|
with io.StringIO(s) as file:
|
||||||
self.comments.append(line)
|
opts_line = self._parse_comments(file)
|
||||||
continue
|
self.opts.parse(opts_line)
|
||||||
break
|
|
||||||
self.opts.parse(line)
|
|
||||||
|
|
||||||
prev_freq = prev_len = 0
|
prev_freq = 0.0
|
||||||
|
prev_len = 0
|
||||||
for line in file:
|
for line in file:
|
||||||
# ignore empty lines (even if not specified)
|
# ignore empty lines (even if not specified)
|
||||||
if not line.strip():
|
if not line.strip():
|
||||||
|
@ -108,7 +152,7 @@ class Touchstone:
|
||||||
elif data_len != prev_len:
|
elif data_len != prev_len:
|
||||||
raise TypeError("Inconsistent number of pairs: " + line)
|
raise TypeError("Inconsistent number of pairs: " + line)
|
||||||
|
|
||||||
data_list = iter(sdata)
|
data_list = iter(self.sdata)
|
||||||
vals = iter(data)
|
vals = iter(data)
|
||||||
for v in vals:
|
for v in vals:
|
||||||
if self.opts.format == "ri":
|
if self.opts.format == "ri":
|
||||||
|
@ -118,7 +162,5 @@ class Touchstone:
|
||||||
z = cmath.polar(float(v), float(next(vals)))
|
z = cmath.polar(float(v), float(next(vals)))
|
||||||
next(data_list).append(Datapoint(freq, z.real, z.imag))
|
next(data_list).append(Datapoint(freq, z.real, z.imag))
|
||||||
|
|
||||||
self.s11data, self.s21data, self.s12data, self.s22data = sdata[:]
|
|
||||||
|
|
||||||
def setFilename(self, filename):
|
def setFilename(self, filename):
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Hz S RI R 50
|
||||||
|
140000000 -0.720544874 -0.074467673
|
||||||
|
140307234 -0.707615315 -0.045678697
|
||||||
|
140614468 -0.694235622 -0.017205553
|
||||||
|
140921702 -0.679476678 0.011064857
|
||||||
|
141228936 0.037949264
|
||||||
|
141536169 -0.645231842 0.06495472
|
||||||
|
141843404 -0.625548779 0.090901531
|
||||||
|
142150638 -0.605278372 0.116493001
|
|
@ -0,0 +1,16 @@
|
||||||
|
! Vector Network Analyzer VNA R2
|
||||||
|
! Tucson Amateur Packet Radio
|
||||||
|
! Saturday, 9 November, 2019 17:48:47
|
||||||
|
! Frequency S11 S21 S12 S22
|
||||||
|
! ListType=Lin
|
||||||
|
# HZ S RI R 50
|
||||||
|
000500000 -3.33238E-001 1.80018E-004 6.74780E-001 -8.19510E-007 6.75290E-001 -8.20129E-007 -3.33238E-001 3.08078E-004
|
||||||
|
001382728 -3.33017E-001 6.89580E-004 6.74251E-001 -3.70855E-004 6.74761E-001 -5.04361E-004 -3.33016E-001 9.45694E-004
|
||||||
|
002265456 -3.33136E-001 1.06095E-003 6.74766E-001 -1.00228E-003 6.75276E-001 -1.00304E-003 -3.33136E-001 1.06095E-003
|
||||||
|
003148184 -3.33120E-001 1.97467E-003 6.74773E-001 -1.65230E-003 6.74773E-001 -1.65230E-003 -3.33121E-001 1.91064E-003
|
||||||
|
004030912 -3.32847E-001 2.45743E-003 6.74777E-001 -2.28839E-003 6.75288E-001 -2.15679E-003
|
||||||
|
004913640 -3.32746E-001 2.93382E-003 6.75260E-001 -2.94645E-003 6.75261E-001 -2.81312E-003 -3.32990E-001 3.06364E-003
|
||||||
|
005796368 -3.33479E-001 3.06528E-003 6.75798E-001 -2.32365E-003 6.76309E-001 -2.32540E-003 -3.33479E-001 3.06528E-003
|
||||||
|
006679097 -3.32609E-001 3.80377E-003 6.74764E-001 -4.08250E-003 6.74764E-001 -4.08250E-003 -3.32854E-001 3.80608E-003
|
||||||
|
007561825 -3.32448E-001 4.35906E-003 6.75247E-001 -4.96650E-003 6.75249E-001 -4.69986E-003 -3.32692E-001 4.36169E-003
|
||||||
|
008444553 -3.32510E-001 4.94361E-003 6.74737E-001 -5.33508E-003 6.75248E-001 -5.20579E-003 -3.32508E-001 5.13540E-003
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Hz S RI R 50
|
||||||
|
140000000 -0.720544874 -0.074467673
|
||||||
|
140307234 -0.707615315 -0.045678697
|
||||||
|
140921702 -0.679476678 0.011064857
|
||||||
|
140614468 -0.694235622 -0.017205553
|
||||||
|
141536169 -0.645231842 0.06495472
|
||||||
|
141843404 -0.625548779 0.090901531
|
||||||
|
142150638 -0.605278372 0.116493001
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Hz S RI R 50
|
||||||
|
140000000 -0.720544874 -0.074467673
|
||||||
|
140307234 -0.707615315 -0.045678697
|
||||||
|
140614468 -0.694235622 -0.017205553
|
||||||
|
140921702 -0.679476678 0.011064857
|
||||||
|
141228936 -0.662805676 0.037949264
|
||||||
|
141536169 -0.645231842 0.06495472 ! just a test comment
|
||||||
|
141843404 -0.625548779 0.090901531
|
||||||
|
142150638 -0.605278372 0.116493001
|
||||||
|
142457872 -0.583680212 0.140287563
|
||||||
|
142765106 -0.560637235 0.16401714
|
||||||
|
143072339 -0.536502182 0.186390563
|
Ładowanie…
Reference in New Issue