Python 读取 LTspice 图导出
Python read LTspice plot export
我想用 Python 和 matplotlib 从 LTspice 中绘制一些数据,我正在寻找一个解决方案来从 Python 中导入从 LTspice 导出的绘图数据。
我发现无法使用 Pandas 执行此操作,因为数据格式如下所示:
5.00000000000000e+006\t(2.84545891331278e+001dB,8.85405282381414e+001°)
是否有可能用 Pandas 导入它(例如用自己的方言)或者有人知道一个简单的解决方法(比如逐行读取文件并提取值)?
更糟糕的是,当导出多个步骤的图时,数据被像
这样的线分隔
Step Information: L=410n (Run: 2/4)
在Java中,我可能使用了Scanner对象来读取数据。 Python 中是否有类似的功能,或者更简单的方法将绘图数据输入 Python?
我不熟悉从 LTspice 导出的绘图数据,所以我假设您提供的示例行的格式始终有效。
查看 pandas-0.18 文档 (here) 的 IO 工具部分,我没有看到任何适用于您的数据格式的现成解析器实用程序。首先想到的是在填写 pandas 数据框之前进行自己的解析和准备。
我假设你的问题的关键部分是解析数据文件,我已经有一段时间没玩过 pandas 和 matplotlib 了,所以预计会出现与这些相关的错误。
例子
这是一个快速而肮脏的 python3 脚本,用于将您的数据解析为字典列表,用它构建一个 pandas 数据框并绘制它使用 DataFrame 的 plot
方法。我试图在评论中解释这些步骤:
# ltspice.py
""" Use it as:
> python3 ltspice.py /path/to/datafile """
import pandas
import sys
data_header = "Time Gain Degree".split()
# Valid line example:
# 5.00000000000000e+006\t(2.84545891331278e+001dB,8.85405282381414e+001°)
def parse_line(linestr):
# ValueError and IndexError exceptions are used to mark the failure of
# the parse.
try:
# First we split at the '\t' character. This will raise ValueError if
# there is no \t character or there is more than 1 \t
timestr, rest = linestr.split('\t')
# Then we find the indexes of the '(' and ')' in the rest string.
parenst, parenend = (rest.find('(')+1, rest.find(')'))
if (parenst == -1) or (parenend == -1):
# find() method returns -1 if nothing is found, I raise ValueError
# to mark it as a parsing failure
raise ValueError
# rest[parenst:parenend] returns the string inside parens. split method
# splits the string into words separated by the given character (i.e.
# ',')
powstr, degstr = rest[parenst:parenend].split(',')
# converting strings into floats. Replacing units as necessary.
time = float(timestr)
power = float(powstr.replace('dB', ''))
# this will fail with python 2.x
deg = float(degstr.replace('°', ''))
# You can use dict() instead of tuple()
return tuple(zip(data_header, (time, power, deg)))
except (ValueError,IndexError) as e:
return None
def fileparser(fname):
""" A generator function to return a parsed line on each iteration """
with open(fname, mode='r') as fin:
for line in fin:
res = parse_line(line)
if res is not None:
yield res
def create_dataframe(fname):
p = fileparser(fname)
# rec is a tuple of 2-tuples that can be used to directly build a python
# dictionary
recs = [dict(rec) for rec in p]
return pandas.DataFrame.from_records(recs)
if __name__ == '__main__':
data_fname = sys.argv[1]
df = create_dataframe(data_fname)
ax = df.plot(x='Time', y='Gain')
fig = ax.get_figure()
fig.savefig('df.png')
您可以将此代码复制到文本编辑器,并在您的终端中使用 python3 ltspice.py yourdata.dat
将其另存为 ltspice.py
和 运行。
请注意,parse_line
函数实际上 returns 形式为 ('key', value) 的 2 元组的元组,其中 'key' 表示列名。然后使用此值在 create_dataframe
函数中构建字典列表。
额外
我写了另一个脚本来测试行为:
# test.py
import random
from ltspice import fileparser
def gen_data():
time = random.randint(0,100)*1e6
db = random.lognormvariate(2,0.5)
degree = random.uniform(0,360)
# this is necessary for comparing parsed values with values generated
truncate = lambda x: float('{:.15e}'.format(x))
return (truncate(time),truncate(db),truncate(degree))
def format_data_line(datatpl):
time, db, degree = datatpl[0], datatpl[1], datatpl[2]
formatted = "{0:.15e}\t({1:.15e}dB,{2:.15e}°)\n"
return formatted.format(time, db, degree)
def gen_ignore_line():
tmpl = "Step Information: L={}n (Run:{}/{})\n"
l = random.randint(100,1000)
r2 = random.randint(1,100)
r1 = random.randint(0,r2)
return tmpl.format(l,r1,r2)
def create_test_file(fname, valid_count, invalid_count):
""" Creates a test file containing data lines mixed with lines to be
ignored. Returns the data created.
valid_count: number of the actual data lines
invalid_count: number of the to-be-ignored lines
"""
header = 'Time Gain Degree'.split()
data = []
formatteddatalines = []
for i in range(valid_count):
unfmtdata = gen_data()
data.append(tuple(zip(header, unfmtdata)))
formatteddatalines.append(format_data_line(unfmtdata))
invalidlines = []
for i in range(invalid_count):
invalidlines.append(gen_ignore_line())
lines = formatteddatalines + invalidlines
random.shuffle(lines)
with open(fname, mode='w') as fout:
fout.writelines(lines)
return data
if __name__ == '__main__':
fname = 'test.data'
validcnt = 10
invalidcnt = 2
validdata = create_test_file(fname, validcnt, invalidcnt)
parseddata = [data for data in fileparser(fname)]
# Note: this check ignores duplicates.
assert(set(validdata) == set(parseddata))
我已经为 LTSpice 仿真输出文件写了 Python reader,您可以在这里找到:LTSPy. There are also some examples files on how to use the reader here: exltspy.zip。希望有用。 (我为我草率的编码做法提前道歉)。
我想用 Python 和 matplotlib 从 LTspice 中绘制一些数据,我正在寻找一个解决方案来从 Python 中导入从 LTspice 导出的绘图数据。
我发现无法使用 Pandas 执行此操作,因为数据格式如下所示:
5.00000000000000e+006\t(2.84545891331278e+001dB,8.85405282381414e+001°)
是否有可能用 Pandas 导入它(例如用自己的方言)或者有人知道一个简单的解决方法(比如逐行读取文件并提取值)?
更糟糕的是,当导出多个步骤的图时,数据被像
这样的线分隔Step Information: L=410n (Run: 2/4)
在Java中,我可能使用了Scanner对象来读取数据。 Python 中是否有类似的功能,或者更简单的方法将绘图数据输入 Python?
我不熟悉从 LTspice 导出的绘图数据,所以我假设您提供的示例行的格式始终有效。
查看 pandas-0.18 文档 (here) 的 IO 工具部分,我没有看到任何适用于您的数据格式的现成解析器实用程序。首先想到的是在填写 pandas 数据框之前进行自己的解析和准备。
我假设你的问题的关键部分是解析数据文件,我已经有一段时间没玩过 pandas 和 matplotlib 了,所以预计会出现与这些相关的错误。
例子
这是一个快速而肮脏的 python3 脚本,用于将您的数据解析为字典列表,用它构建一个 pandas 数据框并绘制它使用 DataFrame 的 plot
方法。我试图在评论中解释这些步骤:
# ltspice.py
""" Use it as:
> python3 ltspice.py /path/to/datafile """
import pandas
import sys
data_header = "Time Gain Degree".split()
# Valid line example:
# 5.00000000000000e+006\t(2.84545891331278e+001dB,8.85405282381414e+001°)
def parse_line(linestr):
# ValueError and IndexError exceptions are used to mark the failure of
# the parse.
try:
# First we split at the '\t' character. This will raise ValueError if
# there is no \t character or there is more than 1 \t
timestr, rest = linestr.split('\t')
# Then we find the indexes of the '(' and ')' in the rest string.
parenst, parenend = (rest.find('(')+1, rest.find(')'))
if (parenst == -1) or (parenend == -1):
# find() method returns -1 if nothing is found, I raise ValueError
# to mark it as a parsing failure
raise ValueError
# rest[parenst:parenend] returns the string inside parens. split method
# splits the string into words separated by the given character (i.e.
# ',')
powstr, degstr = rest[parenst:parenend].split(',')
# converting strings into floats. Replacing units as necessary.
time = float(timestr)
power = float(powstr.replace('dB', ''))
# this will fail with python 2.x
deg = float(degstr.replace('°', ''))
# You can use dict() instead of tuple()
return tuple(zip(data_header, (time, power, deg)))
except (ValueError,IndexError) as e:
return None
def fileparser(fname):
""" A generator function to return a parsed line on each iteration """
with open(fname, mode='r') as fin:
for line in fin:
res = parse_line(line)
if res is not None:
yield res
def create_dataframe(fname):
p = fileparser(fname)
# rec is a tuple of 2-tuples that can be used to directly build a python
# dictionary
recs = [dict(rec) for rec in p]
return pandas.DataFrame.from_records(recs)
if __name__ == '__main__':
data_fname = sys.argv[1]
df = create_dataframe(data_fname)
ax = df.plot(x='Time', y='Gain')
fig = ax.get_figure()
fig.savefig('df.png')
您可以将此代码复制到文本编辑器,并在您的终端中使用 python3 ltspice.py yourdata.dat
将其另存为 ltspice.py
和 运行。
请注意,parse_line
函数实际上 returns 形式为 ('key', value) 的 2 元组的元组,其中 'key' 表示列名。然后使用此值在 create_dataframe
函数中构建字典列表。
额外
我写了另一个脚本来测试行为:
# test.py
import random
from ltspice import fileparser
def gen_data():
time = random.randint(0,100)*1e6
db = random.lognormvariate(2,0.5)
degree = random.uniform(0,360)
# this is necessary for comparing parsed values with values generated
truncate = lambda x: float('{:.15e}'.format(x))
return (truncate(time),truncate(db),truncate(degree))
def format_data_line(datatpl):
time, db, degree = datatpl[0], datatpl[1], datatpl[2]
formatted = "{0:.15e}\t({1:.15e}dB,{2:.15e}°)\n"
return formatted.format(time, db, degree)
def gen_ignore_line():
tmpl = "Step Information: L={}n (Run:{}/{})\n"
l = random.randint(100,1000)
r2 = random.randint(1,100)
r1 = random.randint(0,r2)
return tmpl.format(l,r1,r2)
def create_test_file(fname, valid_count, invalid_count):
""" Creates a test file containing data lines mixed with lines to be
ignored. Returns the data created.
valid_count: number of the actual data lines
invalid_count: number of the to-be-ignored lines
"""
header = 'Time Gain Degree'.split()
data = []
formatteddatalines = []
for i in range(valid_count):
unfmtdata = gen_data()
data.append(tuple(zip(header, unfmtdata)))
formatteddatalines.append(format_data_line(unfmtdata))
invalidlines = []
for i in range(invalid_count):
invalidlines.append(gen_ignore_line())
lines = formatteddatalines + invalidlines
random.shuffle(lines)
with open(fname, mode='w') as fout:
fout.writelines(lines)
return data
if __name__ == '__main__':
fname = 'test.data'
validcnt = 10
invalidcnt = 2
validdata = create_test_file(fname, validcnt, invalidcnt)
parseddata = [data for data in fileparser(fname)]
# Note: this check ignores duplicates.
assert(set(validdata) == set(parseddata))
我已经为 LTSpice 仿真输出文件写了 Python reader,您可以在这里找到:LTSPy. There are also some examples files on how to use the reader here: exltspy.zip。希望有用。 (我为我草率的编码做法提前道歉)。