如何使用 python 从 LTspice 解码压缩的二进制 .RAW 文件

How to Decode Compressed Binary .RAW Files from LTspice with python

我正在尝试读取 .raw LTSPice 文件。在 LTSPice 的控制面板中,可以在 ASCII 和二进制压缩之间切换。 ASCII 是可读的,没有问题,但它在大小和性能上有缺点,这就是我想使用二进制压缩的原因。有可能 select 二阶压缩,这就是目标。 LTSpice 输出 .raw 文件,ASCII 文件有电压和电流值,但在二进制文件中,有一些我无法解码的符号。

首先我尝试用notepad++打开.raw文件。当我打开 ASCII .raw 文件时,Notpad++ 在左下角显示 UTF-8,而在打开二进制解压缩的 .raw 文件时,Notpad++ 显示在左下角的 UTF-8 和 UCS-2 Little Endian。 我尝试了不同的编码,例如 UTF-16le、ISO-8859-1...实际上我打印了所有编解码器并尝试使用它们:

import codecs
print(dir(codecs))

另外,我试过没有BOM。我找到了这个,但它没有给我任何结果:

import codecs
encoded_text = open('Circuit_binary_Transient.raw', 'rb').read()    #should read in binary mode to get the BOM correctly
bom= codecs.BOM_UTF16_LE                                      #print dir(codecs) for other encodings
assert encoded_text.startswith(bom)                           
encoded_text= encoded_text[len(bom):]                         #strip away 
decoded_text= encoded_text.decode('utf-16le')
print(decoded_text)

我发现 Zlib 是常见的压缩,我试图找出我的文件中的哪些位置有压缩,但没有结果。 我用过:

import zlib
from glob import glob

def zipstreams(filename):
    """Return all zip streams and their positions in file."""
    with open(filename, 'rb') as fh:
        data = fh.read()
    i = 0
    while i < len(data):
        try:
            zo = zlib.decompressobj()
            yield i, zo.decompress(data[i:])
            i += len(data[i:]) - len(zo.unused_data)
        except zlib.error:
            i += 1

for i, data in zipstreams("Circuit_binary_Transient.raw.raw"):
    print (i, len(data))

我总是得到 0 的 len(data)。

我找到了这个脚本,但没有执行二进制 .raw 文件解码: http://www2.ee.unsw.edu.au/~tlehmann/ltspy.py
此外,我找到了 Matlab 的解决方案,Paul Wagner 的 LTSpice2Matlab(Matlab 的 ltspice reader),但我需要它 python,并且从那个特定的脚本中我找不到使用哪种编码。我发现,对于二进制解压文件,Paul Wagner 使用插值来获得更多的点,然后转换为可读格式。

实际上,我使用这段代码来读取 .raw 文件:

data = fo.read() # Binary data read
fo.close()
line = str(data, encoding='utf-16le')
print(line)

当我使用 ASCII .raw 文件和 UTF8 时,我在末尾有文本,但是当我使用二进制压缩的 .raw 文件时,我找不到如何以可读格式解码文件。

这是我目前在 LTSpice 的 .raw 文件中的内容(文本 "Binary:" 之后):

栋㲚朎㲚鸞㕼鸞㕼鸞땼䕘퇠≄뻕襾㷨⁄㷨⡜㚾⡜㚾⡜뚾䕘퇠≄㻥䏨㹔ᙘ㹓㜬㜬뜬岓逇Ⳡ㻵◲㻇㯋㻃㞟㞟랟ጟ箽㼄籼㼯덌㼩Ӏ㠋Ӏ㠋Ӏ렋괄蝄㼎ڕ㽦럍㽢먵㠹먵㠹먵령귴脍侧㼑з㽴鍰㽲럜㡆럜㡆럜롆쵺튆㼒㽺땺㽹迀㡌迀㡌迀롌偵姏䰦㼔㽾枎㽽雈㡏雈㡏雈롏䰼ᬇⅤ㼖쵅㽿ᦊ㽾⢖㡐⢖㡐⢖롐暾좳죯㼗챭㽼錒㽺䕈㡍䕈㡍䕈롍얳✀礦㼚嘻㽰㽫㿃㡁㿃㡁㿃롁먬쬥㼞㽉뙵㽁낁㠞낁㠞낁렞袨�봜㼢睿㻔瘵㻄㞠㞠랠嘈䆬흞㼦㷧븥譻븠蒱뜃蒱뜃蒱㜃빝袏噥㼪뼝뼙㼆럼㼆럼㼆㟼玵嬆㼬ﵠ뽐】뽏멬렩멬렩멬㠩떋Ҕ덭㼭葔뽩뽨챢렾챢렾챢㠾넼ꧼ㼮쏐뽵뼃뽵傴롉傴롉傴㡉뮷惵㼯툡뽻뽻婇롎婇롎婇㡎�ﶻሣ㼰姢뽿ᚶ뽿롐롐㡐誔

我希望解码并阅读它,我想我应该得到与 ASCII .raw 文件相同的结果,例如:

0       0.000000000000000e+000  
    1.884843971540818e-002  
    1.884796850054908e-002  
    9.423984250366810e-007  
    9.423984250274539e-007  
    -9.423984250328532e-007  
1       3.951925877448456e-008  
    1.959322256186405e-002  
    1.959271263253092e-002  
    9.796356316741367e-007  
    9.796356316265457e-007  
    -9.796356317259836e-007  
2       1.185577763234539e-007  
    2.108275522427772e-002  
    2.108216492289399e-002  
    1.054108246213077e-006  
    1.054108246144700e-006  
    -1.054108246245633e-006

如有任何帮助,我将不胜感激。目标是读取压缩的二进制 .raw LTSpice 文件。

Notpad++ shows in the bottom left UTF-8 when I open ASCII .raw files and UCS-2 Little Endian when open binary decompressed .raw files."

这是正常的,UTF-8是一种文本编码,它只是将一个字节序列与某个字符相关联。原始二进制文件没有固定的结构或编码,因为它们包含二进制数据:例如,考虑字符串 "3.1415926535"(在 UTF-8 中为 12 个字节)和原始浮点二进制文件之间的区别该值的表示(适合 4 个字节)。如果您将浮点数的 "raw" 4 个字节解释为文本,您将得到一些垃圾文本输出或 unicode 解码错误。对于原始文件,具体的数据格式和每个字节的含义由生成它们的软件指定。

通常,您应该查阅 LTSpice 原始文件规范,了解数据的排列方式并为此自己编写一个解析器。但由于这是 python、someone already did that for you and made a package you can install via pip,请查看该包及其示例,使用起来应该非常简单。


更新

this link 他们声明原始二进制格式没有被正式公开并且可能随时更改(尽管过去 15 年没有更改)。

格式本身是 UTF-16 header,后跟原始二进制数据。 当你说:

This is what I have currently in .raw file from LTSpice (After text "Binary:"): [...]

这是原始数据(以 UTF-16 解码,如您所见,在文本中是无意义的)。该原始数据是变量值 的打包列表,按照 header 中定义的顺序,重复数据中的任意多个时间点。时间编码为 double(即 8 个字节),其他任何内容 - 除非你强制它也加倍 - 在 float(4 个字节)中. 那么你应该做的是:

1) 解析变量列表并计算一条记录的长度(例如,8 + 4*num_of_variables)

2) 从"Binary"字符串中取出字节数据,直到文件结束, 并将它分成你在第 1 步得到的长度的块

3) 相应地解释记录中的字节

来自 LTSpice 的 .RAW 二进制文件的 header 可以用 UTF-16 解码。如果尝试转换整个二进制 RAW 文件,则只有 header 会转换为文本。使用 UTF-16 成功转换为文本的最后一个字符是 "Binary:"。在此之后,应该得到 "Chinese symbols" 或其他不可读的内容。

我使用了十六进制编辑器并比较了同一电路的 RAW ASCII 文件和 RAW 二进制文件。在 ASCII 文件中,可以找到 "Values:" 而不是 "Binary:",然后是十进制值。因此,可以在十六进制编辑器的帮助下比较二进制代码和 RAW ASCII 文件中的实际值。

经过对比,我成功解码了一个RAW二进制文件。下面写的所有内容都是十六进制的。我有 6 个变量。这对域有效:DC 扫描、DC op、瞬态和 DC 传输(对于 AC 分析和噪声始终为 2 x 8 字节双精度解码)。

  1. "Binary:"后总有3个字节:00 0A 00(0A-换行);
  2. 然后有 8 个字节,如果将其转换为 Double (float64) 精度,则给出正确的值;
  3. 然后我有 4 个字节,如果将其转换为 Single(float32) 精度,它会给出正确的值
  4. 给出一个值的 4 个字节重复 5 次(我有 6 个变量 - header "No. Variables:")
  5. 重复第 2.、3. 和 4. 点,直到 header 满足 "No. Points:" 的数字。

我使用了 LTSpice XVII。 另外,我使用了 HxD 十六进制编辑器 https://mh-nexus.de/en/hxd/

编辑:非常重要:字节顺序是 Little endian!
这意味着对于十六进制的字节顺序 - AA 77 B8 A2,它应该以相反的顺序转换 - A2 B8 77 AA。 因此,AA 77 B8 A2 的单精度 (float32) 转换为十进制为 -2.2e-13,而 A2 B8 77 AA 的单精度 (float32) 转换为十进制为 -5e-18。