Entschlüsseln eines ganz komischen Datenformates

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

@BlackJack
Mmm... ja da hast du recht...
Ich habe mir gedacht, dass wäre schön, wenn das Format einheitlich wäre. Allerdings müsste man dann entweder wieder mit 0-en auffüllen, was viel Speicher verbracht, oder wieder eine "Entschlüsselungstabelle" einführen...

Man könnte auch für jeden Kanal die Samples hintereinander abspeichern. Das ist vielleicht das beste.


Also das mit den Verschiedenen Programmiersprachen ist furchtbar... Da war es schöner nur in C oder nur in Python zu Programieren. Da waren die Fronten noch klar... Aber dieses Mischmasch ist furchtbar (Oder meine Unkenntnis). :-| Ich glaub ich habe für heute die Nase voll ...
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

ich glaube das bringt mich weiter

Damit packe ich die vier Bytes in eine 64Bit Variable -Reihenfolge wählbar durch umstellen der test-variablen

Code: Alles auswählen

L = (c_uint64)()
pack_into('BBBB',L,0,test[0],test[1],test[2],test[3])
BlackJack

@Torsten2000: Du hast ja immer noch nicht gesagt wie das Ergebnis überhaupt aussehen soll, aber Dir ist klar, dass sie Reihenfolge der Bytes zumindest auf Intel-Systemen (Little-Endian) zum Beispiel "richtig" ist? Wenn Du jeden Frame in eine ganze 64-Bit-Zahl umwandeln willst, bei der Bit 0, 9, 18, und 27 gesetzt sind, dann liegen die Bytes schon in der richtigen Reihenfolge vor. Da musst Du überhaupt nichts machen.

Vielleicht wäre auch `numpy` einen Blick Wert, bevor Du anfängst `struct` und `ctypes` zu mischen. `numpy`-Arrays haben zum Beispiel eine `byteswap()`-Methode.
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

So. Jetzt habe ich 8 Bytes in ein c_uint64 gepackt.

Code: Alles auswählen

      L = (c_uint64)()
      pack_into('BBBBBBBB',L,0,Wave[i+0], Wave[i+1], Wave[i+2], Wave[i+3], Wave[i+4], Wave[i+5], Wave[i+6], Wave[i+7])
dann erstelle ich eine Maske

Code: Alles auswählen

   Channel = 0
   Maske = 1 << Channel
und möchte die beiden miteinander verUNDen

Code: Alles auswählen

   print L & Maske
Jedoch geht das nicht
print L & Maske
TypeError: unsupported operand type(s) for &: 'c_ulonglong' and 'int'
wie kann ich denn jetzt wieder das c_uint64 in eine normale Python-Zahl umwandeln?
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Ich habe jetzt noch eine andere Möglichkeit gefunden

ich glaube langsam komm ich hinter.
Entschluldigt immer meine Fragerei

Code: Alles auswählen

      temp = Wave[i+0]<<(0*8) | Wave[i+1]<<(1*8) | Wave[i+2]<<(2*8) | Wave[i+3]<<(3*8) | Wave[i+4]<<(4*8) | Wave[i+5]<<(5*8) | Wave[i+6]<<(6*8) | Wave[i+7]<<(7*8) 

BlackJack

@Torsten2000: Das ist Unsinn mit dem `struct.pack_into()`. Du kopierst damit nur die Bytes in den Speicherbereich von einem `c_uint64`-Exemplar. Das kannst Du mit `c_uint64.from_buffer_copy()` einfacher haben. Da könntest Du auch gleich ein `c_uint64`-Array erstellen und das auf einen Schlag mit der `from_buffer_copy()`-Methode auf diesem Array befüllen. Umwandlung in Python-`int` gibt es dann über den Indexzugriff. Ansonsten bekommt man bei `ctypes`-Skalaren ein Python-Objekt über das `value`-Attribut.

Erwähnte ich schon `numpy`? ;-)
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Hallo BlackJack,
numpy hast du noch nicht erwähnt :-) klingt gut.
Aber das werde ich im Rahmen der Diplomarbeit wohl nicht mehr schaffen.
Bin froh, wenn ich noch das "Entschlüsseln" hin bekomme.

Ich habe jetzt folgendes Programmiert:

Code: Alles auswählen

def _get_Frame(x):
   global Wave
   i=x*8
   return = Wave[i+0]<<(0*8) | Wave[i+1]<<(1*8) | Wave[i+2]<<(2*8) | Wave[i+3]<<(3*8) | Wave[i+4]<<(4*8) | Wave[i+5]<<(5*8) | Wave[i+6]<<(6*8) | Wave[i+7]<<(7*8)
   #return c_int64.from_buffer_copy(Wave, i)

def get_Sample_from_channel(Sample, Channel, Mode = -1):
   #liefert das Ergebnis von der Abtastung der Kanal
   global Wave
   global _Mode
   if Mode == -1:
         Mode = _Mode
   P1 = HARDWARE_MODE_TABELLE[Mode].P1
   P2 = HARDWARE_MODE_TABELLE[Mode].P2
   P3 = HARDWARE_MODE_TABELLE[Mode].P3

   SamplesPerFrame = P2/P3
   FrameX = Sample / SamplesPerFrame
   SampleInFrame = Sample % SamplesPerFrame

   Frame = _get_Frame(FrameX)
   return Frame>>(SampleInFrame*P3 + Channel) & 1
   
So scheint die Funktion zu funktionieren.
Wenn ich jetzt die Variante

Code: Alles auswählen

return c_int64.from_buffer_copy(Wave, i)
aktiviere, bekomme ich eine Fehlermeldung
return Frame>>(SampleInFrame*P3 + Channel) & 1
TypeError: unsupported operand type(s) for >>: 'c_longlong' and 'int'
Wie Wandel ich denn jetzt die c_int64 denn jetzt wieder in eine Python-Zahl um?

Ich habe .value gefunden.
er Zeigt mir allerdings immer dann noch ein "L" hinter den Ergebnissen...
Hat das ihrgend einen Einfluss? Ich nehme an, das hat was mit dem ctypes zu tun und mit dem Variablen-Typ
Wie bekomme ich denn das weg?
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

ah mit "int( )"

Code: Alles auswählen

def _get_Frame(x):
   global Wave
   i=x*8
   return int(c_int64.from_buffer_copy(Wave, i).value)
Sorry für meinen blöden Fragen

Danke schön
BlackJack

@Torsten2000: Das 'L' musst Du nicht wegbekommen, insbesondere kann es sein, dass Du es gar nicht weg bekommen kannst, dann liefert `int()` genau das selbe `long`-Objekt. Der Aufruf verbraucht einfach nur unnötig Zeit ohne wirklichen Vorteil.

``global`` solltest Du loswerden. Globale Daten machen Programme nur unflexibel und das neu binden von globalen Daten macht sie zusätzlich schwerer zu durchschauen und fehleranfälliger. Zumal Du keine der ``global``-Deklarationen i den gezeigten Quelltext-Abschnitten brauchst.

Stattdessen solltest Du `Wave` und die Funktionen die darauf operieren in einer Klasse verpacken. Da ein `Wave`-Wert ja wahrscheinlich auch nur Daten "in einem `Mode`" enthält, könnte man dann auch ein paar der Sachen, die Du immer wieder aufs neue berechnest, *einmal* für alle Samplezugriffe im Voraus berechnen. Und vielleicht Indexzugriffe auf einzelne Samples ermöglichen, eine `__len__()`-Methode implementieren und so weiter.

Und statt jeden Frame einzeln durch ein `c_int64` zu jagen, könntest Du das komplette `Wave`-Objekt über ein `c_uint64`-Array ansprechen.
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Hallo BlackJack,

Wie geht denn das mit "c_uint64`-Array ansprechen"?

Danke nochmal für deine Wertvollen Tips :-)
Die sind echt spizte.
Alle anderen Module habe ich schön mit einer Klasse eingebunden (Timer-Funktionen)
Da habe ich das erste mal mit Klassen gearbeitet und den riesen Vorteil gesehen, da man ganz oft Instanzen von denen anlegen kann und die sich nicht beeinflussen (globale Variablen). Das ist echt super.
Leider hatte ich bisher nicht den Sinn bei meinem Hauptmodul gesehen - fälschlicher weise.. :(
Im Nachhinein ist man immer klüger.
ich werd jetzt erst mal die Diplomarbeit schreiben müssen und wenn ich noch Zeit habe, ändere ich das ja vielleicht noch ab (was wohl recht unwahrscheinlich ist :-( )
Aber ich habe viel durch deine Hilfe gelernt und Python echt schätzen gelernt.

Ich bin dir dafür sehr dankbar - und sorry nochmal für die eine oder andere Frage, die ich gestellt habe.
Manchmal ist es eben schneller, wenn man einen Tipp bekommt (gerade wenn man unter Zeitdruck ist). Und mit den ctypes und den einbinden der DLLs war ja schon ein bisschen spezieller, glaube ich?

Viele Grüße
Torsten

PS: wenn ich nochmal was umsetzte, dann werden ich bestimmt nochmal die eine oder andere Frage haben.
BlackJack

@Torsten2000: Na Du müsstest halt ein Array definieren was gross genug ist um die Daten aufzunehmen, davon dann die `from_buffer_copy()`-Methode benutzen um ein Array aus `Wave` zu machen, und kannst dann per Indexzugriff auf die einzelnen Werte zugreifen.
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

@BlackJack

Mmm...
Und statt jeden Frame einzeln durch ein `c_int64` zu jagen, könntest Du das komplette `Wave`-Objekt über ein `c_uint64`-Array ansprechen.
@Torsten2000: Na Du müsstest halt ein Array definieren was gross genug ist um die Daten aufzunehmen, davon dann die `from_buffer_copy()`-Methode benutzen um ein Array aus `Wave` zu machen, und kannst dann per Indexzugriff auf die einzelnen Werte zugreifen.

Ich weiß nicht genau ob ich das richtig verstanden habe

Sowas in der Richtung?

Code: Alles auswählen

def transform_Wave_from_8_to_64():
   global Wave
   temp = (c_int64 * (len(Wave)/8)) ()
   for i in range(len(w)):
      temp[i] = c_int64.from_buffer_copy(Wave, i*8)
   Wave = temp
Aber da ist doch kein Unterschied zu meiner vorigen Version - außer, dass ich das Array nur einmal anlege, oder?

Stimmt schon. mit meiner vorigen Version habe ich für jedes Sample unter Umständen immer das gleiche Frame geholt.

Schön wäre es jetzt - wie du schon gesagt hast - wenn das alles in einer Klasse wäre.
BlackJack

@Torsten2000: Du immer mit Deinem ``global``. Du weisst das man Funktionen Werte als Argumente ünbergeben kann und kennst die ``return``-Anweisung!?

Die `from_buffer_copy()`-Methode hat jeder `ctypes`-Datentyp, auch zusammengesetzte wie Arrays oder Strukturen. Du musst das nicht in einer Schleife machen sondern kannst ein Array mit einem Aufruf dieser Methode auf dem Array-Typ-Objekt erstellen. Ungetestet:

Code: Alles auswählen

def frames2array(frames_data):
    return (c_uint64 * (len(frames_data) // 8)).from_buffer_copy(frames_data)
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

@BlackJack
Ja ich weiß... kein guter Programmierstiel. Beim nächsten Projekt mache ich es besser (oder wie gesagt, wenn ich noch Zeit habe)
wie säh das denn aus wenn das in einer Klasse ist?
mit self.Wave ist das ja ähnlich wie global im Modul oder? Auch schlechte Programmierstiehl?

Auch innerhalb einer Klasse mit Parametern?
BlackJack

@Torsten2000: `self.wave` wäre ähnlich einem ``global`` aber nicht das selbe. Es ist nicht mehr automatisch für alle Funktionen im Modul sichtbar, man muss explizit über `self` darauf zugreifen. Man macht damit klar, dass hauptsächlich die Methoden darauf zugreifen. Ausserdem gibt es das nicht nur einmal, sondern man kann mehrere solcher Objekte mit verschiedenen Sampledaten erzeugen. Der Speicher kann auch automatisch wieder freigegeben werden, wenn das Objekt nicht mehr erreichbar ist.
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Ja da hast du absolut recht.
eine Klasse wäre da sehr sinnvoll.
Antworten