2017-10-20 20 views
3

j'ai un fichier binaire dans laquelle les données sont organisées en blocs entiers de 16 bits comme ceci:lecture des données binaires au niveau des bits

  • bit 15: bit numérique 1
  • bit 14: bit numérique 2
  • bits 13 à 0: 14 bits entier signé

La seule façon que je trouve comment extraire les données du fichier à 3 rangées est la suivante:

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) 

Maintenant, je sais que je pourrais faire la même chose avec la boucle for sur les données d'origine et remplir 3 tableaux séparés, mais ce serait encore moche. Ce que je voudrais savoir est comment faire ceci plus efficacement dans le style de dtype=[('db', [('1', bit), ('2', bit)]), ('temp', 14bit-signed-int)]) de sorte qu'il soit facile d'accéder comme data['db']['1'] = array of ones and zeros.

+0

Jamais entendu parler de 'pack'. Je ne vois pas vraiment ce que numpy a à voir avec les fichiers binaires. –

+0

Pourriez-vous formuler votre commentaire d'une manière plus aidante? Peut-être que cela n'a pas grand chose à voir avec les fichiers binaires, mais avec leur contenu, c'est vraiment utile. Au moins dans mon cas. – TheoryX

Répondre

2

Voici une méthode qui est plus efficace que votre code car Numpy fait la boucle à la vitesse compilée, ce qui est beaucoup plus rapide que l'utilisation de boucles Python. Et nous pouvons utiliser l'arithmétique au niveau du bit au lieu de ces tests if.

Vous n'avez fourni aucune donnée d'exemple, j'ai donc écrit du code Python 3 pour créer de fausses données. J'enregistre ces données dans un fichier au format endian, mais cela est assez facile à changer si vos données sont stockées en little-endian. Je n'utilise pas numpy.fromfile pour lire ces données, car il est plus rapide de lire le fichier en Python ordinaire, puis de convertir les octets lus en utilisant numpy.frombuffer.

La seule partie délicate est de gérer ces entiers signés de 14 bits. Je suppose que vous utilisez la représentation 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) 

sortie

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] 

Si vous avez besoin d'utiliser la commande de little-endian, il suffit de changer le DTYPE à '<u2' dans l'appel np.frombuffer. Et pour le tester, changez 'grand' en 'petit' dans l'appel n.to_bytes dans la fausse section de création de données.

+0

Merci pour votre réponse vraiment sympa. C'est exactement ce que je voulais. Selon la documentation numpy 'fromfile' fonction supporte dtype et sur votre exemple et mes données, ils fonctionnent tous les deux. Peut-être vaut-il la peine d'ajouter que 'open' avec' frombuffer' est plus rapide d'environ 25% que 'fromfile'. – TheoryX

+0

@TheoryX Pas de soucis. J'ai mal interprété la section _Notes_ des docs 'fromfile'. Je vais ajuster ma réponse sous peu. –