Live Plot mit PyQwt

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.
Antworten
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

Hallo allerseits,

dies ist nicht wirklich eine python spezifische Frage, aber da ich es in python implementiere schreib ich es mal hier rein. Das Ganze orientiert sich an diesem Beispiel Skript http://pyqwt.sourceforge.net/examples/DataDemo.py.html.

In meinem Programmierszenario hab ich zwei Prozesse gegeben: Der eine Prozess (Quelle) sendet kontinuierlich über eine Queue Samples an den zweiten Prozess, der diese wiederum in der GUI anzeigen soll.
Mein Problem ist, dass ich nur eine begrenzte Auflösung auf der x-Achse hab. Das Ganze soll so aussehen, dass nachdem das Ende der Zeitleiste erreicht hat, das Array wieder von vorne gefüllt werden soll.

Bisher hab ich das so implementiert, dass der Plot die rohe Daten erstmal zwischenspeichert, ob das wirklich notwendig ist, weiß ich nicht.

Code: Alles auswählen

    def add_data(self, incoming_data):
        self.data = concatenate((self.data, incoming_data))
add_data wird aufgerufen, sobald Daten aus der Queue zu holen sind, incoming_data ist einfach eine array aus samples

So jetzt kommt der interessante Teil, bisher hab ich nur das Beispiel von oben übernommen. timerEvent wird momentan alle 20 ms aufgerufen.

Code: Alles auswählen

    def timerEvent(self, e):
        if len(self.data):
            self.y = concatenate((self.y[:1], self.y[:-1]))
            self.y[0] = self.data[0]
            self.data = self.data[1:]
        self.curveR.setData(self.x, self.y)
        self.replot()
Offenbar wird lediglich immer nur eine Sample von dem data sample abgespalten und angezeigt. Im Grunde genommen müsste ich 20 ms an Samples abspalten, was bei eine Rate von 44100 882 Samples ergeben müsste. Das Problem ist, dass meine x-Achse nur eine begrenzte Auslösung hat. Irgendwo oben im Konstruktor steht sowas

Code: Alles auswählen

self.x = arange(0, self.resolution)
Ich muss die Samples also wahrscheinlich irgendwie runterrechnen. Die Frage ist nur wie?

Ich will natürlich das meine Daten in Echtzeit angezeigt werden, sprich: nicht schneller aber auch nicht langsamer. Ich hab mir auch weiter oben definiert wie Lange in Sekunden die ganze Zeitspanne ist. Ich weiß also wie lange ein runtergerechnetes Sample auf der x-Achse sein soll. Wenn ich eine Zeitspanne von 5 Sekunden wähle und eine Auflösung von 1000, dann umfast ein Sample 5 ms des original Signals. Dies entspricht 220.5 Samples die ich oben zusammenfassen müsste. Mittelwert berechnen? Vielleicht denk ich auch zu kompliziert :) Es wäre nett, wenn ihr mir helfen könntet.

Edit: Die Zahlen oben sind beliebig aber fest in meinem Programm. Sie sind da um das Problem zu illustrieren.

Grüße,
anogayales
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

Hab das Ganze mit diesem netten Snippet hinbekommen:

Code: Alles auswählen

from itertools import islice
def downsample_to_proportion(rows, proportion=1):
    return list(islice(rows, 0, len(rows), int(1/proportion)))
# taken from http://stackoverflow.com/questions/3012 ... erpolation
BlackJack

@anogayales: Ich bin ja der totale Fan von Iteratoren, aber hier ist das unnötig umständlich. `islice()` + `list()` ist fast das selbe als wenn man gleich die Slice-Syntax auf die Sequenz anwendet. Mit dem Unterschied, dass bei Slice-Syntax nicht unbedingt eine Liste heraus kommen muss, sondern bei Numpy-Arrays beispielsweise wieder ein Numpy-Array. Das sich in diesem Fall die Daten mit dem ursprünglichen Array teilt, also völlig unabhängig von der Grösse des Arrays in konstanter Zeit läuft und mit konstantem zusätzlichen Speicher auskommt.

Code: Alles auswählen

def downsample_to_proportion(rows, proportion):
    return rows[::int(1 / proportion)]
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

Vielen Dank, hab total vergessen, dass das auch so geht!

Grüße,
anogayales
Antworten