2016-12-19 4 views
-1

Ich mache einen Live-Plotter, um die analogen Änderungen von einem Arduino Sensor zu zeigen. Der Arduino druckt einen Wert an den seriellen mit einer Baudrate von 9600. Die Python-Code sieht wie folgt:Arduino Live Serial Plotten mit einem MatplotlibAnimation wird langsam

import matplotlib.pyplot as plt 
import matplotlib.animation as animation 
import serial 
import time 

ser = serial.Serial("com3", 9600) 
ser.readline() 

optimal_frequency = 100 

fig = plt.figure(figsize=(6, 6)) 
ax1 = fig.add_subplot(1, 1, 1) 

# the following arrays must be initialized outside the loop 

xar = [] 
yar = [] 

print(time.ctime()) 

def animate(i): 
    global b, xar, yar # otherwise a 

    for i in range(optimal_frequency): 

     a = str(ser.readline(), 'utf-8') 
     try: 
      b = float(a) 
     except ValueError: 
      ser.readline() 
     xar.append(str(time.time())) 
     yar.append(b) 
    ax1.clear() 
    ax1.plot(xar, yar) 

ani = animation.FuncAnimation(fig, animate, interval=optimal_frequency) 
plt.show() 

A eine oke Reaktionszeit in der Handlung, aber wenn ich über 20 Minuten, um die Reaktionszeiten wurde Plotten Anstieg auf ca. 1 min. I.e. Es dauert 1 Minute, bis das Diagramm mit den neuen Werten aktualisiert wird. Ich habe es auch mit PyQtGraph versucht, aber das ist von Anfang an verzögert.

Neben der Verzögerung für Zeiten über 20 Minuten, bekomme ich einige Überschreitungen und Unterschreitungen in der Handlung.

Irgendwelche Hilfe?

+0

Ich denke, dass das Problem ist, dass _xar_ und _yar_ Variablen nach einiger Zeit riesig werden. Sie können versuchen, List-Comprehensions zu verwenden und stattdessen ein dynamisches Lesen der Liste durchzuführen. – Jalo

+0

Nach 20 Minuten können Sie mit dem Plotten aufhören, da Ihr Plot mit mehr als 10 Millionen verbundenen Punkten vollständig unlesbar geworden ist. – Goyo

+0

@Jalo danke. Ich sehe die Variablen zu groß werden. Das Problem ist, dass ich alle Werte neu plotten muss, da ich das Plot jedes Mal lösche, um seinen Speicher nicht zu überladen. Ich gehe in Sampling-Frequenz nach unten :-) – Ivy

Antwort

0

wie in den Kommentaren erwähnt, Sie zwei Dinge tun, ist falsch:

  • Sie Ihre Arrays eingehenden Daten halten anhängt, die
  • Sie klar Ihre Achsen nach einer Weile riesigen bekommen und eine neue ax.plot() bei jeder Iteration.

was wollen Sie stattdessen zu tun ist:

in einer Initialisierungsfunktion, ein leeres Line2D Objekt

def init(): 
    line, = ax.plot([], [], lw=2) 
    return line, 

dann in Ihrem Update-Funktion (animate()) Sie line.set_data() verwenden die aktualisieren Koordinaten Ihrer Punkte. Um jedoch die Leistung aufrechtzuerhalten, müssen Sie auf eine vernünftige Größe die Größe der Arrays zu halten, und so werden Sie die älteren Daten fallen müssen als neuere Daten in

def animate(i): 
    (...) 
    xar.append(str(time.time())) 
    yar.append(b) 
    line.set_data(xar, yar) 
    return line, 

prüfen kommt einige Tutorials like this one. Es gibt auch viele Fragen zu SO, die Ihre Frage bereits beantworten. Zum Beispiel enthält this answer alle Elemente, die Sie benötigen, damit Ihr Code funktioniert.

0

Wie die Kommentare beziehen, wird Lesen von den Arrays natürlich langsam aufgrund ihrer großen Größe. Mit einer Baudrate von 9600 erhalte ich ungefähr 130 serielle Ablesungen und Zeitstempel pro Sekunde in den Variablen xar und yar; welche nach 20 min eine Größe von 156000 bekommen. Das Reduzieren der Baudrate auf 2400 verringert die Länge der Variablen auf 36000, und das kann leicht neu gezeichnet werden.