Python读取LTspice图导出

标签 python python-3.x pandas import pspice

我想使用 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 文档的 IO 工具部分 ( here ),我没有看到任何适合您的数据格式的现成解析器实用程序。首先想到的是在填写 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')

您可以将此代码复制到文本编辑器并将其另存为 ltspice.py 并从终端使用 python3 ltspice.py yourdata.dat 运行它。

请注意,parse_line函数实际上以('key', value)的形式返回一个二元组,其中'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))

关于Python读取LTspice图导出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38435305/

相关文章:

python - 如何用pandas-python递归地构造一列数据框?

python - 如何像使用 R hist 函数一样使用 Python 制作直方图

python - 将我的 python 代码转换为 Windows 应用程序(右键单击菜单)

python - 将相同的操作应用于不同的数据帧

Python - 在下一个代码中使用打印

Python Pandas 将包含字符串的单元格替换为上面的单元格

python - 如何让 Blender 导出器脚本从命令行运行?

Python 3.3 for() 循环迭代处理时间呈指数增长?

python - 在同一台 PC 上管理两个版本的 Python

python - 为什么 5 != 5.0000000000000000001 为假,而 5 != 5.00000001 为真?