forked from theilen/parse_tektronix
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparse_isf.py
111 lines (94 loc) · 3.47 KB
/
parse_isf.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# -*- coding: utf-8 -*-
"""
Created on Fri May 15 17:26:45 2015
@author: Sebastian Theilenberg
"""
import numpy as np
import os.path
def parse_curve(isf_file):
"""
Reads one tektronix .isf file and returns a dictionary containing
all tags as keys. The actual data is stored in the key "data".
"""
extensions = set([".isf"])
if os.path.splitext(isf_file)[-1].lower() not in extensions:
raise ValueError("File type unkown.")
with open(isf_file, 'rb') as ifile:
# read header
header = {}
while True:
name = _read_chunk(ifile, " ")
if name != ":CURVE":
value = _read_chunk(ifile, ";")
assert name not in header
header[name] = value
else:
# ":CURVE " is the last tag of the header, followed by
# '#XYYY' with X being the number of bytes of YYY.
# YYY is the length of the datastream following in bytes.
value = ifile.read(2)
y_str = ifile.read(int(value[-1]))
value += y_str
# the number of bytes might be present with or without the
# preceding header ":WFMPRE:"
nobytes = header.get("BYT_NR",
header.get(":WFMPRE:BYT_NR", "0")
)
assert int(y_str) == int(header["NR_PT"]) * int(nobytes)
header[name] = value
currentposition = ifile.tell()
break
assert header["ENCDG"] == "BINARY"
# read data as numpy array
header["data"] = _read_data(ifile, currentposition, header)
return header
def _read_chunk(headerfile, delimiter):
"""
Reads one chunk of header data. Based on delimiter, this may be a tag
(ended by " ") or the value of a tag (ended by ";").
"""
prior_delimiter = None
chunk = []
while True:
c = headerfile.read(1)
if c != delimiter:
chunk.append(c)
if c == '"':
# switch delimiter to make sure to parse the whole string
# enclosed in '"'.
delimiter, prior_delimiter = c, delimiter
elif prior_delimiter:
# switch back delimiter
chunk.append(c)
delimiter, prior_delimiter = prior_delimiter, None
else:
return "".join(chunk)
def _read_data(bfile, position, header):
"""
Reads in the binary data as numpy array.
Apparently, there are only 1d-signals stored in .isf files, so a 1d-array
is read.
"""
# determine the datatype from header tags
datatype = ">" if header["BYT_OR"] == "MSB" else "<"
if header["BN_FMT"] == "RI":
datatype += "i"
else:
datatype += "u"
# BYT_NR might be present with preceding header ":WFMPRE:BYT_NR"
nobytes = header.get("BYT_NR",
header.get(":WFMPRE:BYT_NR", "")
)
datatype += nobytes
assert len(datatype) >= 3
bfile.seek(position)
data = np.fromfile(bfile, datatype)
assert data.size == int(header["NR_PT"])
# calculate true values
# offset in digitizing levels is "YOFF"
# factor to convert digitizing levels to physical units is "YMULT"
# TODO: offset might be present in physical units in "YZERO" instead
offset = float(header["YOFF"])
factor = float(header["YMULT"])
data = (data - offset) * factor
return data