读取文件信息
import re, os.path
import numpy as np
import pandas as pd
'''
[HZ/KHZ/MHZ/GHZ] [S/Y/Z/G/H] [MA/DB/RI] [R n]
'''
class ReadSNP():
__UNIT = {"HZ": 1, "KHZ": 1e3, "MHZ": 1e6, "GHZ": 1e9, "THZ": 1e12}
def __init__(self,filename:str):
self.file = filename
self.VNA = ""
self.VNA_SN = ""
self.testDate = ""
self.FormatInfo = ""
self.Date_info = ""
self.VNA_info = ""
self.result = re.match(r".+\.s(\d{1,2})p$", os.path.basename(self.file),re.IGNORECASE)
if self.result:
self.PORTS = int(self.result.group(1))
else:
raise "文件不是合法的snp文件"
self.ValidRowNo = 0
try:
with open(self.file, "r") as f:
content = f.readline()
while content:
re_VAN = re.match(r"^!\s?[a-zA-Z]{4,}.+,(.+),(.+),.+", content)
if re_VAN:
self.VNA_info = content
self.VNA = re_VAN.group(1)
self.VNA_SN = re_VAN.group(2)
re_date = re.match(r"^! Created:(.+)$|^!Date:(.+)$", content)
if re_date:
s = re_date.group(1) if re_date.group(1) else re_date.group(2)
s = s.strip()
from datetime import datetime
try:
datestr = datetime.strptime(s, '%A, %B %d, %Y %H:%M:%S')
self.Date_info = content
self.testDate = datestr
except:
pass
try:
datestr = datetime.strptime(s, '%a %B %d %H:%M:%S %Y')
self.Date_info = content
self.testDate = datestr
except:
pass
try:
datestr = datetime.strptime(s, "UTC %m/%d/%Y, %I:%M:%S %p")
self.Date_info = content
self.testDate = datestr
except:
pass
if not self.testDate:
print("日期<{}>格式匹配错误".format(s))
if content.startswith("!"):
self.ValidRowNo += 1
elif content.startswith("#"):
self.ValidRowNo += 1
self.FormatInfo = content
_,self.fre_unit, _, self.datamode,*a = self.FormatInfo.split()
else:
break
content = f.readline()
except:
raise "snp读取失败!"
with open(self.file, "r") as f:
data = f.readlines()[self.ValidRowNo:]
data = [float(x) for i in range(len(data)) for x in data[i].split()]
data = np.array(data).reshape(len(data) // (2 * self.PORTS * self.PORTS + 1), 2 * self.PORTS * self.PORTS + 1)
self.freq = data[...,0]*self.__UNIT.get(self.fre_unit.upper(),1)
self.oddData = data[..., 1::2]
self.evenData = data[..., 2::2]
self.data = self.oddData + self.evenData * 1j
if self.datamode.upper() == "DB":
print("将数据格式由DB转化为RI")
self.data = self.transDataFromDB2RI(self.data)
elif self.datamode.upper() == "MA":
self.data = self.transDataFromMA2RI(self.data)
self.oddData = self.data.real
self.evenData = self.data.imag
def transDataFromDB2RI(self,data):
assert self.datamode.upper() == "DB","数据不是DB格式"
r = np.power(10, data.real / 20)
i = data.imag / 180 * np.pi
data = r * np.cos(i) + r * np.sin(i) * 1j
return data
def transDataFromMA2RI(self,data):
assert self.datamode.upper() == "MA", "数据不是MA格式"
data = data.real*np.cos(data.imag) + data.real*np.sin(data.imag) * 1j
return data
def getSparameters(self,a:int=None,b:int=None,mode="RL")->np.array:
assert isinstance(a, int) or a == None, "端口号必须是整数"
assert isinstance(b, int) or b == None, "端口号必须是整数"
if a == None and b == None:
s = np.abs(self.data)
elif (a == None) ^ (b == None):
raise "S参数不完整,"
else:
index = (a-1)*self.PORTS+(b-1)
s = np.abs(self.data)[...,index]
if mode.upper() in ["VSWR"]:
if isinstance(a,int) and isinstance(b,int):
return (1+s)/(1-s)
for i in range(self.PORTS):
for j in range(self.PORTS):
if i == j:
s[..., i * self.PORTS + j] = (1+s[...,i*self.PORTS+j])/(1-s[...,i*self.PORTS+j])
else:
s[..., i * self.PORTS + j] = 20*np.log10(s[..., i * self.PORTS + j])
return s
else :
return 20 * np.log10(s)
def getTrace(self,S,mode = "RL"):
a = S[1:len(S) // 2 + 1]
b = S[len(S) // 2 + 1:]
return self.getSparameters(int(a),int(b),mode=mode)
def _to_excel(self,mode="RL")->"excel":
columns = ["S%d%d" % (a + 1, b + 1) if a < 9 and b < 9
else "S%02d%02d" % (a + 1, b + 1) for a in range(self.PORTS) for b in range(self.PORTS)]
filename = os.path.basename(self.file)
excel_file = os.path.splitext(filename)[0] + ".xls"
df = pd.DataFrame(self.getSparameters(mode=mode),columns=columns,index=self.freq)
date = self.testDate.strftime("%Y%m%d %H:%M:%S") if self.testDate else ""
df.index.name = "频率 仪器型号:{} 仪器序列号:{} 测试日期:{}".format(self.VNA,self.VNA_SN,date)
try:
df.to_excel(excel_file,sheet_name="{} {}".format(self.VNA,self.testDate),encoding="utf_8_sig")
print(">>> {}文件已经生成".format(excel_file))
except:
excel_file = os.path.splitext(filename)[0] + ".csv"
df.to_csv(excel_file, encoding="utf_8_sig")
print(">>> 由于excel文件格式限制,使用{}文件代替输出".format(excel_file))
def _to_csv(self,filepath = None,mode="RL",ports = None)->"csv":
columns = ["S%d_%d" % (a + 1, b + 1) for a in range(self.PORTS) for b in range(self.PORTS)]
filename = os.path.basename(self.file)
csv_file = os.path.splitext(filename)[0]
df = pd.DataFrame(self.getSparameters(mode=mode), columns=columns, index=self.freq)
if not ports:
date = self.testDate.strftime("%Y%m%d %H:%M:%S") if self.testDate else ""
df.index.name = "频率 仪器型号:{} 仪器序列号:{} 测试日期:{}".format(self.VNA,self.VNA_SN,date)
if filepath:
csv_file = os.path.join(filepath,csv_file+".csv")
else:
csv_file += ".csv"
df.to_csv(csv_file,encoding="utf_8_sig")
print(">>> {}文件已经生成".format(csv_file))
else:
column_index = ["S%d_%d" % (a, b) for a in ports for b in ports]
date = self.testDate.strftime("%Y%m%d %H:%M:%S") if self.testDate else ""
df = df[column_index]
df.index.name = "频率 仪器型号:{} 仪器序列号:{} 测试日期:{}".format(self.VNA, self.VNA_SN, date)
if filepath:
str_ports = [str(x) for x in ports]
csv_file = os.path.join(filepath,csv_file+'_' +"_".join(str_ports)+ ".csv")
else:
csv_file = csv_file +'_'+"_".join([str(x) for x in ports])+ ".csv"
df.to_csv(csv_file, encoding="utf_8_sig")
print(">>> {}文件已经生成".format(csv_file))
def _to_snp(self,filepath = None,ports=None,quickMode = False):
'''ports为空时,表示整个都复制'''
if not ports:
HeadList = []
with open(self.file, "r") as f:
for i in range(self.ValidRowNo):
content = f.readline()
HeadList.append(content)
row, col = self.oddData.shape
datas = np.zeros(shape=(row, 2 * col + 1), dtype=float)
datas[..., 0] = self.freq
for i in range(col):
datas[..., 2 * i + 1] = self.data[...,i].real
datas[..., 2 * i + 2] = self.data[...,i].imag
bigContent = ""
if quickMode:
for index_ in range(row):
temparray = datas[index_, ...]
fre_str = "{:.10e}".format(temparray[0])
bigContent += fre_str + " "
i = 0
for item in temparray[1:]:
i += 1
bigContent += "{:.7e}".format(item) + " "
if i % 8 == 0:
bigContent += "\n"
bigContent += "\n"
else:
justSize = 17
for index_ in range(row):
temparray = datas[index_,...]
fre_str = "{:.10e}".format(temparray[0]).ljust(justSize)
bigContent += fre_str + " "
i = 0
for item in temparray[1:]:
i += 1
bigContent += "{:.7e}".format(item).rjust(justSize) + " "
if i % 8 == 0:
bigContent += "\n" + "".rjust(len(fre_str)) + " "
bigContent += "\n"
if filepath:
raw_file = os.path.basename(self.file).split('.')
raw_file.pop()
ports = [str(x) for x in ports]
file_out = '.'.join(raw_file) + '_' + '_'.join(ports) + '.s{}p'.format(len(ports))
file_out = os.path.join(filepath, file_out)
else:
raw_file = self.file.split('.')
raw_file.pop()
ports = [str(x) for x in ports]
file_out = '.'.join(raw_file) + '_' + '_'.join(ports) + '.s{}p'.format(len(ports))
with open(file_out,"w") as w:
for line in HeadList:
w.write(line)
w.write(bigContent)
else :
column_index = ["S%d_%d" % (a, b) for a in ports for b in ports]
assert isinstance(ports,list),"必须是端口列表参数!"
HeadList = []
HeadList.append(self.VNA_info)
HeadList.append(self.Date_info)
v = len(ports)
first_start = f"!S{v}P File: Measurements: "
start = "!"
for i in range(v):
if i == 0:
begin = first_start
else:
begin = start
t = ["S%d%d" % (i + 1, b + 1) if i + 1 < 9 and b + 1 < 9
else "S%02d%02d" % (i + 1, b + 1) for b in range(v)]
HeadList.append(begin + "<" + ", ".join(t) + '>\n')
HeadList.append(self.FormatInfo)
columns = ["S%d_%d" % (a + 1, b + 1) for a in range(self.PORTS) for b in range(self.PORTS)]
column_index_list = [columns.index(i) for i in column_index]
tempData = self.data[...,column_index_list]
row,col = tempData.shape
datas = np.zeros(shape=(row, 2 * col + 1), dtype=float)
datas[..., 0] = self.freq
for i in range(col):
datas[..., 2 * i + 1] = tempData[..., i].real
datas[..., 2 * i + 2] = tempData[..., i].imag
bigContent = ""
justSize = 17
for index_ in range(row):
temparray = datas[index_, ...]
fre_str = "{:.10e}".format(temparray[0]).ljust(justSize)
bigContent += fre_str + " "
i = 0
for item in temparray[1:]:
i += 1
bigContent += "{:.7e}".format(item).rjust(justSize) + " "
if i % 8 == 0:
bigContent += "\n" + "".rjust(len(fre_str)) + " "
bigContent += "\n"
if filepath:
raw_file = os.path.basename(self.file).split('.')
raw_file.pop()
ports = [str(x) for x in ports]
file_out = '.'.join(raw_file) + '_' + '_'.join(ports) + '.s{}p'.format(len(ports))
file_out = os.path.join(filepath,file_out)
else:
raw_file = self.file.split('.')
raw_file.pop()
ports = [str(x) for x in ports]
file_out = '.'.join(raw_file) + '_' + '_'.join(ports) + '.s{}p'.format(len(ports))
with open(file_out, "w") as w:
for line in HeadList:
w.write(line)
w.write(bigContent)
定义获取数据格式