2017-10-20 2 views
3

나는 데이터과 같이 16 비트 정수 블록으로 구성되어있는 이진 파일이 있습니다읽기 이진 데이터

  • 비트 15 : 디지털 비트를 1
  • 비트 14 : 디지털 비트 2
  • 비트 13-0 : 14 비트 부호있는 정수

내가 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

'팩'에 대해 들어 본 적이 있습니다. numpy가 바이너리 파일과 관련이 있다는 것을 나는 실제로 알지 못한다. –

+0

좀 더 도움이되는 방법으로 의견을 표현해 주실 수 있습니까? 아마도 바이너리 파일 자체와는 관련이 없지만 내용이 있으면 정말 유용합니다. 적어도 내 경우에는. – TheoryX

답변

2

Numpy가 컴파일 된 속도로 루핑을하기 때문에 코드보다 효율적입니다. Python 루프를 사용하는 것보다 훨씬 빠릅니다. 그리고 if 테스트 대신 비트 연산을 사용할 수 있습니다.

당신은 샘플 데이터를 제공하지 않았으므로 일부 가짜 데이터를 생성하기 위해 간단한 Python 3 코드를 작성했습니다. 해당 데이터를 큰 파일 -형식으로 저장하지만, 실제로 데이터가 리틀 엔디안에 저장되어 있으면 쉽게 변경할 수 있습니다. 나는 평범한 파이썬으로 파일을 읽고 나서 numpy.frombuffer을 사용하여 읽은 바이트를 변환하는 것이 더 빠르기 때문에 numpy.fromfile을 사용하여 그 데이터를 읽지 않습니다.

유일한 까다로운 부분은 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] 

그냥 np.frombuffer 호출 '<u2'에 DTYPE을 변경, little endian의 바이트 순서를 사용해야하는 경우 출력. 그리고 그것을 테스트하기 위해 가짜 데이터 작성 섹션에서 n.to_bytes 콜에서 '크게'를 '약간'으로 변경하십시오.

+0

정말로 좋은 답변을 해주셔서 감사합니다. 정확히 내가 원했던 것입니다. numpy 문서에 따르면'fromfile' 함수는 dtype을 지원하고 예제와 내 데이터 모두에서 작동합니다. 아마도 'frombuffer'로 time-wise 'open'은'fromfile'보다 약 25 % 더 빠르다는 것을 추가할만한 가치가 있을지도 모른다. – TheoryX

+0

@ TheoryX 걱정할 필요가 없습니다. 나는'fromfile' 문서의 _Notes_ 섹션을 잘못 읽었습니다. 나는 곧 내 대답을 조정할 것이다. –