我有一个二进制文件,其中数据以16位整数块组织,如下所示:
我发现如何从文件中提取数据到3个数组的唯一方法是:
data = np.fromfile("test1.bin", dtype=np.uint16)
digbit1 = data >= 2**15
data = np.array([x - 2**15 if x >= 2**15 else x for x in data], dtype=np.uint16)
digbit2 = data >= 2**14
data = np.array([x-2**14 if x >= 2**14 else x for x in data])
data = np.array([x-2**14 if x >= 2**13 else x for x in data], dtype=np.int16)
现在我知道我可以使用for循环覆盖原始数据并填写3个单独的数组,但这仍然是丑陋的。我想知道的是如何以dtype=[('db', [('1', bit), ('2', bit)]), ('temp', 14bit-signed-int)])
的方式更有效地执行此操作,以便像data['db']['1'] = array of ones and zeros
一样轻松访问。
答案 0 :(得分:2)
这是一种比你的代码更有效的方法,因为Numpy以编译速度进行循环,这比使用Python循环要快得多。我们可以使用按位算术代替那些if
测试。
你没有提供任何样本数据,所以我写了一些简单的Python 3代码来创建一些假数据。我将这些数据以大endian格式保存到文件中,但如果您的数据实际存储在little-endian中,则很容易更改。我没有使用numpy.fromfile
来读取数据,因为用普通的Python读取文件然后使用numpy.frombuffer
转换读取的字节会更快。
唯一棘手的部分是处理那些14位有符号整数。我假设你正在使用two's complement代表。
import numpy as np
# Make some fake data
bdata = []
bitlen = 14
mask = (1 << bitlen) - 1
for i in range(12):
# Two initial bits
a = i % 4
# A signed number
b = i - 6
# Combine initial bits with the signed number,
# using 14 bit two's complement.
n = (a << bitlen) | (b & mask)
# Convert to bytes, using 16 bit big-endian
nbytes = n.to_bytes(2, 'big')
bdata.append(nbytes)
print('{} {:2} {:016b} {} {:>5}'.format(a, b, n, nbytes.hex(), n))
print()
# Save the data to a file
fname = 'test1.bin'
with open(fname, 'wb') as f:
f.write(b''.join(bdata))
# And read it back in
with open(fname, 'rb') as f:
data = np.frombuffer(f.read(), dtype='>u2')
print(data)
# Get the leading bits
digbit1 = data >> 15
print(digbit1)
# Get the second bits
digbit2 = (data >> 14) & 1
print(digbit2)
# Get the 14 bit signed integers
data = ((data & mask) << 2).astype(np.int16) >> 2
print(data)
<强>输出强>
0 -6 0011111111111010 3ffa 16378
1 -5 0111111111111011 7ffb 32763
2 -4 1011111111111100 bffc 49148
3 -3 1111111111111101 fffd 65533
0 -2 0011111111111110 3ffe 16382
1 -1 0111111111111111 7fff 32767
2 0 1000000000000000 8000 32768
3 1 1100000000000001 c001 49153
0 2 0000000000000010 0002 2
1 3 0100000000000011 4003 16387
2 4 1000000000000100 8004 32772
3 5 1100000000000101 c005 49157
[16378 32763 49148 65533 16382 32767 32768 49153 2 16387 32772 49157]
[0 0 1 1 0 0 1 1 0 0 1 1]
[0 1 0 1 0 1 0 1 0 1 0 1]
[-6 -5 -4 -3 -2 -1 0 1 2 3 4 5]
如果您确实需要使用little-endian字节排序,只需在'<u2'
调用中将dtype更改为np.frombuffer
即可。并测试它,改变&#39;大&#39;小小的&#39;在假数据制作部分的n.to_bytes
电话中。