Seite 1 von 3

In Python Array auslesen und interpretieren?

Verfasst: Freitag 15. Mai 2009, 19:21
von gooogle
Hallo

ich habe einen Array bzw Puffer, welches über eine schnittstelle mit daten gefüllt wird.
nun ist es so, dass eine bestimmte anzahl an Bytes eine Bedeutung haben, wie z.B. hier -> Rx: http://www.google.de

Sowas würdich gerne in Python umsetzen aber weiss nicht wie ich da rangehen will. möchte nur den array in textform interpretieren und irgendwohin speichern.

habt ihr tipps wie man sowas machen. vielleicht ibt es schon was?

danke und gruss

Verfasst: Freitag 15. Mai 2009, 19:51
von BlackJack
@gooogle: Sorry, aber ich verstehe nicht was Du willst. Was genau ist das Problem?

Verfasst: Freitag 15. Mai 2009, 20:02
von gooogle
Hallo

sorry, hab mich vlt unverständlich ausgedrückt.



Nun ist es so dass "34, 00, 78, 89, 01, 11, 88" " Relais wurde aktiviert" bedeutet.
Ich möchte nun in Phyton den Puffer auslesen und dann wenn eine bestimmte Bytefolge auftritt, dann soll der entsprechende String bzw Text wie im obigen beispiel ausgegeben werden.

Ganz trivial:

if("999,34, 00, 78, 89, 01, 11, 88")
{

print (" Relais wurde aktiviert" )

}


usw...

die "999" ist ein kennzeichen dafür dass die Bytes zwischen den "999" zusammengehören (Frame) und eine Bedeutung haben.
Hoffe jetzt klappts mit dem verständnis...

Verfasst: Freitag 15. Mai 2009, 20:51
von CM
So was?

Code: Alles auswählen

In [1]: p = [ 999, 34, 00, 78, 89, 01, 11, 88,999,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

In [2]: p = ''.join((str(x) for x in p))

In [3]: p.split('999')
Out[3]: ['', '340788911188', '00000000000000']
Über diese veränderte Darstellung könntest Du ja iterieren und Bedingungen abfragen:

Code: Alles auswählen

In [4]: relais_msg = '340788911188'

In [5]: relais_msg in p
Out[5]: True
HTH
Christian

Verfasst: Freitag 15. Mai 2009, 21:38
von BlackJack
@CM: Und wenn in den Daten 99, 9 oder 9, 99 oder 9, 9, 9 vorkommt!?

@gooogle: Wo kommt denn die 999 her? Wie bekommst Du die Daten? In welcher Form genau?

Verfasst: Freitag 15. Mai 2009, 21:58
von numerix
Was spricht denn dagegen, ein dictionary zu nehmen, dessen Schlüssel die entsprechend auszuwertenden Byte-Folgen sind (als Tupel) und den Klartext als Wert; und dann aus der Liste mit den Bytefolgen jeweils die Teile zwischen zweimal 999 herauszunehmen und (nach Umwandlung in Tupel) den Klartext aus dem dict abzurufen?

Oder übersehe ich irgendetwas?

Verfasst: Freitag 15. Mai 2009, 22:10
von gooogle
hallo

danke für die tipps.



wie gesagt, es ist eine einfache serielle schnittstelle, (9600 Buad,1 stop/startbit, 8 Datenbits...)
insgesamt gibt es ca. 100 sequenzen, also 100 Strings die von den frames abhängig sind.

deshalb ist es so schwierig. ich muss den puffer, nachdem dieser gefült wurde, analysieren bzw die frames rausfiltern und schauen welcher text zu welchem frame gehört ..
numerix, hast du da ein beispiel. das klingt sehr interessant und eventuell für meine anwendung sehr geeignet?

Verfasst: Freitag 15. Mai 2009, 22:29
von numerix
Ich meine so etwas (kein optimaler Code, zeigt aber die Grundidee):

Code: Alles auswählen

from random import randrange

puffer = [randrange(7) or 999 for k in xrange(50000)]+[999] # zufällige Zahlensequenz anlegen zur Simulation
events = {(3,4,6):"Relais aktiviert", (5,2,1):"Relais deaktiviert"} # Dictionary mit den zu identifizierenden Teilsequenzen
while 999 in puffer: # solange wie noch eine 999 drin steht: weiter auswerten
    p = puffer.index(999) # erstes Vorkommen in der Sequenz suchen
    seq = tuple(puffer[:p]) # Teilsequenz bis dahin separieren
    del puffer[:p+1] # Sequenz bis dahin abschnippeln
    if seq in events: # Falls die Teilsequenz als Schlüssel im dict vorkommt
        print events[seq] # Wert zum Schlüssel ausgeben


Edit: Kommentare ergänzt.

Falls du es nicht ausprobiert hast: Der Code ist so lauffähig. Experimentiere doch ein wenig damit.

Statt den Puffer scheibchenweise abzuschneiden wäre es vermutlich performanter, einen Zeiger mitzuführen und die index-Methode dann mit dem start-Parameter zu verwenden.

Verfasst: Freitag 15. Mai 2009, 23:15
von gooogle
hallo

danke dir numerix. leider bin ich relativ neu auf diesem gebiet und brauche immer kommentare zu den jeweiligen zeilen (um es zu verstehen). wäre super wenn du es kurz mit kommentaren versehst ;)

eine andere frage: ich habe die möglichkeit dictionaries anzulgene. würde sowas auch mit dictionarys gehen? falls ja wie könnte man das machen.
so in der art?:

'Relai aktiviert': ' 34, 00, 78, 89, 01, 11, 88'...

würde sowas gehen bzw gibt es beispiel codes? :)

Verfasst: Freitag 15. Mai 2009, 23:25
von yipyip
Hier auch noch ein Ansatz, der von Numerix gar nicht
so weit entfernt ist.

Code: Alles auswählen

class ChunkDispatcher(object):

  def __init__(self, marker=999):

    self.marker = marker
    self.state = 0
    self.buf = []
    self.dispatching = {(1,2,3): self.on,
                        (11,22,33): self.off}
    
  def check(self, c):
    
    if c == self.marker:
      self.state ^= 1
      if not self.state:
        self.dispatch()
        self.state ^= 1
    else:
      if self.state:
        self.buf.append(c)


  def dispatch(self):

    self.dispatching.get(tuple(self.buf), lambda: None)()
    self.buf = []

        
  def on(self):

    print 'Relais on'


  def off(self):

    print 'Relais off'


def main():

  output = (1,2, 999,
            2,999,
            1, 2, 3, 999,
            1, 2, 3, 4, 999,
            11, 22, 33, 999,
            1, 2, 3,999,
            0, 0, 999,
            11, 22, 33,999)

  disp = ChunkDispatcher()

  for c in output:
    print c
    disp.check(c)


if __name__ == '__main__':

  main()
:wink:
yipyip

Verfasst: Samstag 16. Mai 2009, 08:11
von BlackJack
@gooogle: Also ich würde noch einmal bei der 999 einhaken wollen. Wo kommt die in den Puffer? Warum kannst Du an *der* Stelle nicht etwas sinnvolleres machen, zum Beispiel eine weitere Liste einführen, so dass sich das Problem was Du hier lösen möchtest so gar nicht erst ergibt. Der Puffer, den Du analysieren müsstest, würde dann so aussehen:

[[34, 00, 78, 89, 01, 11, 88], [77, 56, 89, 89, 78], ...]

Eine IMHO sehr viel sinnvollere Datenstruktur für das Problem. Wenn Du aus den inneren Listen Tupel machst, dann kannst Du auch ganz einfach den Vorlschlag mit dem Nachschlagen der Nachrichtentexte in einem Dictionary umsetzen.

Verfasst: Samstag 16. Mai 2009, 20:25
von gooogle
hallo

danke numerix für die kommentare :)

hallo yipyip. Könntest du dein Programm vielleicht auch kommentieren :) wäre super für mich anfänger ;)


blackjack: die 999 kommt dann immer in den puffer wenn ein neuer frame erkannt wird..das passiert zeitgesteuert über ein separates programm und hat mit python nichts zu tun ;) man sollte einfach davon ausgehen dass ein derartiger puffer einfach zu verfügung steht.




So ein Array soll einfach als gegeben angesehen werden, welcher dann analysiiert wird und entsprechend auf die Bedeutungen in textform referenziert werden ;).

deine idee ist gut aber in meinem fall nicht möglich da das puffern nicht über python geschieht. lediglich as auswerten soll über python gehen weil es einfacher gehen soll :)
es ist wirklich nur so, dass man den array durchgeht und die Bytes zwischen 999 hheruasfiltert und zu den dazugehörigen Texten in Listen oder Dictionaries referenziert um so nicht die Bytes zu sehen sondern den dazugehörigen text.
ich will einfach später in einer datei oder was auch immer einen Text sehen in der Form:

15:30:45 Relais wurde aktiviert
15:31:56 Relais wurde deaktiviert
15:33:57 Spannung weg geschaltet
15:36:12 Spannung eingeschaltet
15:55:14 Relais wurde aktiviert
....
usw

Ich hoffe ihr habt mein anliegen verstanden :)

Verfasst: Samstag 16. Mai 2009, 22:24
von gooogle
Hallo

noch ein ekurze Frage:

in dem codebeispiel von numerix kommt folgendes vor:

Code: Alles auswählen

events = {(3,4,6):"Relais aktiviert", (5,2,1):"Relais deaktiviert"}
Was ist wenn z.B das zweite element der ersten 3 bytes nicht wichtig ist, also in der form:

Code: Alles auswählen

events = {(3,' ',6):"Relais aktiviert", (5,2,1):"Relais deaktiviert"}
habe die stelle einfach durch hochkomme gekennzeichnet. soll heissen dass das zweite byte eigentlich jeden wert haben könnte und für die referenzierung des texts nicht notwendig ist, sondern nur die anderen beiden? wie würd man sowas in python ergänzen?kann man das mit hochkomme machen oder "None" ? :)

Verfasst: Samstag 16. Mai 2009, 22:45
von BlackJack
Wenn so etwas vorkommen kann, dann kannst Du nicht mehr so einfach Dictionaries verwenden.

Verfasst: Samstag 16. Mai 2009, 22:47
von yipyip
So, jetzt habe ich es Dir (hoffentlich nicht zu unverständlich,
aber eine Python Doku kann es natürlich nicht ersetzen)
kommentiert:
http://paste.pocoo.org/show/117642/

Zu Deiner letzten Frage:
Dann nimm einfach ein Dictionary mit den 2erTupeln.
Zuvor musst Du die Sequenz entprechend
Deinen Anforderungen transformieren.

z.B.:

Code: Alles auswählen

a, b, c = [1, 2, 3]
lookup_seq = a, c
mydict.get(lookup_seq, ....
:wink:
yipyip

Verfasst: Samstag 16. Mai 2009, 22:49
von gooogle
hallo

coole sache yipyip...danke dir. werd ich ausprobieren :)

grüsse

Verfasst: Sonntag 17. Mai 2009, 16:30
von str1442
@yipyip:

self.state ^= 1 solltest du besser mit Wahrheitswerten und self.state = not self.state umsetzen.

Verfasst: Sonntag 17. Mai 2009, 16:55
von yipyip
Klar, bei nur 2 Zuständen reichen boolsche Werte aus.
Ich denke bei diesen Problemstellungen immer an
endliche Automaten, deshalb habe ich mir die Anzahl der Zustände
zunächst offengelassen und deshalb Integer-Werte verwendet.

:wink:
yipyip

Verfasst: Sonntag 17. Mai 2009, 19:24
von Dill
warum ist denn der code für "relais aktiviert" so lang?
sicher dass da nicht noch einiges an balast bei ist? (ack, seq, crc, ...)

Verfasst: Sonntag 17. Mai 2009, 20:56
von gooogle
Hallo Dill

ja, da ist auch balast dabei aber dieser ist für meine anwendung uninteressant ;) ich möchte einfach später nur den kurzen Text "Relais wurde aktiviert" sehen.