Versuchen Sie, mit Binärdaten in Python zu arbeiten

Ich hatte die Möglichkeit, die Binärdaten mit Python zu verarbeiten, aber da ich die Binärdaten zum ersten Mal berührt hatte und verschiedene Dinge untersuchen musste, möchte ich sie als Memorandum behalten!

Dieses Mal haben wir uns mit den Daten der Erweiterungsdatei "**. Sl2 **" befasst, also werden wir die .sl2-Daten als Beispiel schreiben!

Über Binärdaten

Die Datenstruktur von Binärdaten wird durch jedes Format bestimmt. Dieses Mal hatte ich es mit einer Datei namens .sl2 zu tun, die ich zum ersten Mal gesehen habe, aber in diesem Fall muss ich zuerst "die Struktur der .sl2-Datei" in irgendeiner Weise kennen. Wenn Sie das nicht wissen, können Sie nicht damit umgehen!

In meinem Fall habe ich auf die folgende Seite verwiesen, daher werde ich dies anhand dieser Referenzseite erläutern. (** Infolgedessen war diese Seite falsch ... **) https://wiki.openstreetmap.org/wiki/SL2

Header

Es scheint, dass die meisten Binärdaten einen Header haben. Dies ist ein fester Wert in den ersten Bytes und enthält eine Beschreibung des Datenformats, z. B. Versionsinformationen.

In diesem Fall werden die folgende Tabelle und Erläuterung in der Spalte "** Grundstruktur **" der Referenzseite beschrieben. Es scheint mehrere Typen in der SL2-Datei zu geben, aber vorerst scheint der Header 10 Bytes zu sein.

The files show up with a 10 byte header. First 2 bytes describe the format version (01=SLG, 02=SL2). Bytes 5,4 provide the block size. It varies depending on the sensor: 0x07b2 for HDI=Primary/Secondary+DSI and 0x0c80 for Sidescan). Seen values are image.png

Bytereihenfolge

Sehr grob gesagt ist es die "Anordnung" oder "Anordnungsreihenfolge" der Daten, die die Reihenfolge definiert, in der die Daten gespeichert werden, wenn sie in den Speicher geschrieben werden.

Soweit ich das beurteilen kann, gehört die Bytereihenfolge meistens zu "Big Endian" oder "Little Endian". Sie müssen also herausfinden, welche.

In diesem Fall habe ich herausgefunden, dass es ein wenig tolandisch ist, da die folgende Beschreibung in der Spalte "** Grundstruktur **" der Referenzseite enthalten ist.

The file is a binary file with little endian format. Float values are stored as IEEE 754 floating-point "single format".

Byteblock

Schließlich werden wir die Daten nach dem Header lesen. Auf der Referenzseite werden der Datentyp und die Länge jedes Blocks wie in der folgenden Tabelle gezeigt definiert (Teilauszug).

image.png

Sehen Sie sich zunächst die Datenbeschreibungsspalte ganz rechts an und wählen Sie die Daten aus, die Sie extrahieren möchten. Überprüfen Sie nach der Entscheidung, welche Daten extrahiert werden sollen, den Datentyp (Variablentyp) und den Versatzwert.

Der Versatz ist die Information der Position relativ zum Referenzpunkt und repräsentiert die Adresse der Daten. Da diesmal ein Datensatz 144 Bytes enthält, bedeutet dies, dass die Anzahl der Bytes angezeigt wird, in die die Daten geschrieben werden.

This should close the 144 byte frame.

Python-Strukturmodul

Ich habe oben viel über Binärdaten organisiert. Wir verwenden ein Modul namens ** struct **, um diese Binärdaten zu verarbeiten. Offizielles Dokument

Über die Bytereihenfolge

Das offizielle Dokument enthält die folgende Tabelle, in der die Zeichen festgelegt sind, die die Bytereihenfolge darstellen. image.png

Informationen zum Datenformat

Wie im Kapitel [Byte Block](#Byte Block) bestätigt, haben alle Daten ihren eigenen Datentyp (valiable type). Es ist notwendig, die Verarbeitungsmethode abhängig vom Datentyp zu ändern, jedoch in struct, solange Sie die Datentypinformationen übergeben Danach fühlt es sich so an, als würde es alles tun, um der Form zu entsprechen.

Das Format kann jedoch vom offiziellen Dokument abweichen, daher müssen Sie es entsprechend lesen. In diesem Fall ist es wie folgt.

short int → unsigned short(H)
int       → unsigned long(L)
byte(int) → unsigned char(B)

image.png

Binärdaten lesen

Sie kann gelesen werden, indem Sie die Option beim Öffnen der Datei auf "rb (read binary)" setzen.

with open(file_name, 'br') as f:
   data = f.read()

Interpretation von Binärdaten

Sie können die gelesenen Binärdaten mit der Funktion struct.unpack_from () konvertieren. Das Grundformat ist "struct.unpack_from (Datentyp, Daten, Offset)". Ich kenne den Datentyp und den Offset bereits, also muss ich ihn nur angeben!

Unten ist das große Bild. Es sieht länger aus als ich erwartet hatte, aber im Grunde passe ich zuerst den Header an und wiederhole dann die Arbeit des Auspackens, indem ich den Versatz um die Anzahl der Elemente verschiebe.

import sys
import struct

OLAR_EARTH_RADIUS = 6356752.3142
# PI = Math: : PI
MAX_UINT4 = 4294967295
FT2M = 1/3.2808399  # factor for feet to meter conversions
KN2KM = 1/1.852     # factor for knots to km conversions

args = sys.argv

if args[1] == '':
    print('Usage:  python sl2decoder.py your_file.sl2')

block_offset = 0

#Shift um 10 Bytes Header
block_offset += 10   

# Datatypes:
# ===================================================================================================
# Type    Definition                                          Directive for Python's String#unpack
# ---------------------------------------------------------------------------------------------------
# byte 	  UInt8                                               B
# short   UInt16LE                                            H
# int 	  UInt32LE                                            L
# float   FloatLE (32 bits IEEE 754 floating point number)    f
# flags   UInt16LE                                            H
# ---------------------------------------------------------------------------------------------------

#Definieren Sie Offset und Datentyp für jedes Element
block_def = {
    'blockSize'         : {'offset': 26, 'type': '<H'},
    #  'lastBlockSize': {'offset': 28, 'type': '<H'},
    'channel'           : {'offset': 30, 'type': '<H'},
    'packetSize'        : {'offset': 32, 'type': '<H'},
    'frameIndex'        : {'offset': 34, 'type': '<L'},
    'upperLimit'        : {'offset': 38, 'type': '<f'},
    'lowerLimit'        : {'offset': 42, 'type': '<f'},
    'frequency'         : {'offset': 51, 'type': '<B'},
    #  'time1': {'offset': 58, 'type': '<H'}          # unknown resolution, unknown epoche
    'waterDepthFt'      : {'offset': 62, 'type': '<f'},  # in feet
    'keelDepthFt'       : {'offset': 66, 'type': '<f'},  # in feet
    'speedGpsKnots'     : {'offset': 98, 'type': '<f'},  # in knots
    'temperature'       : {'offset': 102, 'type': '<f'}, # in °C
    'lowrance_longitude': {'offset': 106, 'type': '<L'}, # Lowrance encoding (easting)
    'lowrance_latitude' : {'offset': 110, 'type': '<L'}, # Lowrance encoding (northing)
    'speedWaterKnots'   : {'offset': 114, 'type': '<f'}, # from "water wheel sensor" if present, else GPS value(?)
    'courseOverGround'  : {'offset': 118, 'type': '<f'}, # ourseOverGround in radians
    'altitudeFt'        : {'offset': 122, 'type': '<f'}, # in feet
    'heading'           : {'offset': 126, 'type': '<f'}, # in radians
    'flags'             : {'offset': 130, 'type': '<H'},
    #  'time': {'offset': 138, 'type': '<H', 'len': 4}          # unknown resolution, unknown epoche
}

with open('%s_output_py.csv' % args[0], 'w') as f_raw:
    title = ','.join(['Channel', 'Frequency', 'UpperLimit[ft]', 'LowerLimit[ft]', 'Depth[ft]', 'WaterTemp[C]', 'WaterSpeed[kn]',
 'PositionX', 'PositionY', 'Speed[kn]', 'Track[rad]','Altitude[ft]', 'Heading[rad]']) + '\n'
    f_raw.write(title)

    alive_counter = 0

    with open(args[1], 'br') as f:
        data = f.read()
        sl2_file_size = len(data)

        while block_offset < sl2_file_size:
            h = {}
            if alive_counter % 100 == 0:
                print('%d done...' % round(100.0*block_offset/sl2_file_size))

            for k, v in block_def.items():
                t_offset = block_offset + v['offset']
                h[k] = struct.unpack_from(v['type'], data, t_offset)

            print(h['blockSize'])
            block_offset += h['blockSize'][0]

            #In einer Datenzeile kombinieren
            csv_line = ','.join([str(h['channel'][0]), str(h['frequency'][0]), 
                                 str(h['upperLimit'][0]), str(h['lowerLimit'][0]), 
                                 str(h['waterDepthFt'][0]), str(h['temperature'][0]), 
                                 str(h['speedWaterKnots'][0]), str(h['lowrance_longitude'][0]), 
                                 str(h['lowrance_latitude'][0]), str(h['speedGpsKnots'][0]), 
                                 str(h['courseOverGround'][0]), str(h['altitudeFt'][0]), 
                                 str(h['heading'][0])]) + '\n'

            f_raw.write(csv_line)

print('Read up to block_offset %d' % block_offset)


Recommended Posts

Versuchen Sie, mit Binärdaten in Python zu arbeiten
Betreiben Sie LibreOffice mit Python
Umgang mit Sounds in Python
Versuchen Sie, mit Mongo in Python auf dem Mac zu arbeiten
Arbeiten mit LibreOffice in Python: Importieren
Arbeiten mit DICOM-Bildern in Python
Versuchen Sie, COVID-19 Tokyo-Daten mit Python zu kratzen
Holen Sie sich mit Python zusätzliche Daten zu LDAP
Versuchen Sie, sich mit Python bei qiita anzumelden
Behandeln Sie 3D-Datenstrukturen mit Pandas
Datenanalyse mit Python 2
Versuchen Sie es mit Python.
Dichotomie mit Python
Versuchen Sie gRPC in Python
Dichotomie mit Python
Dichotomie mit Python 3
Probieren Sie 9 Slices in Python aus
Binäre Suche in Python
Datenanalyse mit Python
Lesen Sie Tabellendaten in einer PDF-Datei mit Python
Eine Geschichte über den Umgang mit Binärdaten in Python
[Einführung für Anfänger] Umgang mit MySQL mit Python
Mit Python erstellte Beispieldaten
Behandeln Sie Umgebungsdaten in Python
Schaben mit Selen in Python
Schaben mit Chromedriver in Python
Spezifischer Beispielcode für die Arbeit mit SQLite3 in Python
Zeigen Sie UTM-30LX-Daten in Python an
Debuggen mit pdb in Python
Probieren Sie die Python-Ausgabe mit Haxe 3.2 aus
Holen Sie sich Youtube-Daten mit Python
Versuchen Sie, assoziativen Speicher durch Hop-Field-Netzwerk in Python zu implementieren
Python: Arbeiten mit Firefox mit Selen
Versuchen Sie, Python mit pybind11 in ein C ++ - Programm einzubetten
Scraping mit Selen in Python
Versuchen Sie LINE Notify mit Python
Binäre Suche in Python / C ++
Algorithmus in Python (Dichotomie)
Scraping mit Tor in Python
Tweet mit Bild in Python
Kombiniert mit Ordnungszahl in Python
Anzeige von Positionsinformationsdaten in Python - Versuchen Sie, mit der Kartenanzeigebibliothek (Folium) zu zeichnen -
Versuchen Sie, Python mit Try Jupyter auszuführen
Lassen Sie uns Yuma in Python 3 implementieren
Versuchen Sie die Gesichtserkennung mit Python
Lesen von JSON-Daten mit Python
Versuchen Sie, Python in der mit pipenv erstellten Django-Umgebung auszuführen
Versuchen Sie, Ihre eigenen Objekte mit Prioritätswarteschlangen in Python zu sortieren
[Homologie] Zählen Sie mit Python die Anzahl der Löcher in den Daten
Holen Sie sich LeapMotion-Daten in Python.
Zahlenerkennung in Bildern mit Python
Schreiben Sie eine Dichotomie in Python
Versuchen Sie es mit Python + Beautiful Soup
Testen mit Zufallszahlen in Python
GOTO in Python mit erhabenem Text 3
Lesen Sie die Protokollpufferdaten mit Python3
Speichern Sie die Binärdatei in Python
Scraping mit Selen in Python (Basic)
CSS-Analyse mit cssutils in Python