Batch Plot Update Optimierung
Übersicht
Diese Dokumentation beschreibt die Optimierung der Plot-Updates für hochfrequente Datenverarbeitung in der HRNGGUI-Anwendung. Die Optimierung löst Performance-Probleme bei hohen Datenraten durch die Implementierung von Batch-Updates.
Problem
Bei der ursprünglichen Implementierung wurde der Plot für jeden einzelnen empfangenen Datenpunkt aktualisiert:
Alter Ansatz - ineffizient bei hohen Datenraten
- for data_point in received_data:
plot.update_plot(data_point) # Jeder Punkt löst komplette Neuzeichnung aus
Dies führte zu folgenden Problemen:
Performance-Einbrüche bei Datenraten > 50 Hz
GUI-Blockierung durch zu häufige Plot-Updates
Hohe CPU-Last durch redundante Neuzeichnungen
Schlechte Benutzerexperience bei hochfrequenter Datenerfassung
Lösung: Batch-Update-System
1. Neue PlotWidget-Methode
- def update_plot_batch(self, new_points: list) -> None:
„““ Aktualisiert den Plot mit mehreren Datenpunkten in einer einzigen Operation. Deutlich effizienter als mehrere einzelne update_plot() Aufrufe. „““ for x, y in new_points:
# Punkte zu internen Arrays hinzufügen # … (ohne Neuzeichnung)
# Nur EINE Neuzeichnung für alle Punkte self._adjust_limits() self.fig.canvas.draw()
2. Optimierter DataController
- def _process_queued_data(self) -> None:
„““Verarbeitet alle Daten aus der Queue und aktualisiert die GUI.“““ new_points = []
# Alle verfügbaren Punkte sammeln while not self.data_queue.empty():
new_points.append(self.data_queue.get_nowait())
# Batch-Update des Plots if new_points and hasattr(self.plot, ‚update_plot_batch‘):
self.plot.update_plot_batch(new_points)
3. Timer-basierte GUI-Updates
Datenerfassung: Läuft kontinuierlich mit hoher Frequenz
GUI-Updates: Erfolgen nur alle 100ms (einstellbar)
Queue-System: Sammelt Daten zwischen GUI-Updates
Performance-Verbesserungen
Gemessene Ergebnisse
Skalierbarkeit
Beispiel: 500 Hz Datenrate
- def high_frequency_test():
# 500 Datenpunkte/Sekunde → 50 Punkte pro 100ms GUI-Update # Plot wird nur 10x/Sekunde aktualisiert statt 500x/Sekunde # Resultat: 50x weniger Plot-Operationen bei gleicher Datenqualität
Implementierungsdetails
DataController-Queue-System
- class DataController:
- def __init__(self):
self.data_queue = queue.Queue() # Thread-safe self.gui_update_timer = QTimer() self.gui_update_timer.timeout.connect(self._process_queued_data) self.gui_update_timer.start(100) # 100ms Intervall
- def add_data_point_fast(self, index, value):
„““Schnelles Hinzufügen ohne GUI-Update“““ self.data_queue.put((index, value, time()))
- def _process_queued_data(self):
„““Verarbeitet alle Queue-Daten in einem Batch“““ # Sammle alle verfügbaren Punkte # Aktualisiere Plot nur einmal # Aktualisiere andere GUI-Elemente
PlotWidget-Optimierungen
- class PlotWidget:
- def update_plot_batch(self, new_points: list):
„““Batch-Update-Methode“““ # 1. Alle Punkte zu internen Arrays hinzufügen for x, y in new_points:
self._add_point_to_arrays(x, y)
# 2. Nur EINE Neuzeichnung am Ende self.line.set_data(self._x_data, self._y_data) self._adjust_limits() self.fig.canvas.draw()
Verwendung
Für hochfrequente Daten (Arduino/Serial)
In DataAcquisitionThread
- def process_received_data(self, data):
# Verwende die schnelle Queue-Methode self.data_controller.add_data_point_fast(index, value) # GUI wird automatisch alle 100ms aktualisiert
Direkter Batch-Update des Plots
large_dataset = [(i, measurement_i) for i in range(1000)] plot_widget.update_plot_batch(large_dataset)
Konfiguration
GUI-Update-Intervall anpassen
Für sehr hohe Datenraten: längere Intervalle
controller = DataController(gui_update_interval=200) # 200ms
Für interaktive Anwendungen: kürzere Intervalle
controller = DataController(gui_update_interval=50) # 50ms
Mehr Punkte im Speicher für längere Historie
plot = PlotWidget(max_plot_points=1000)
Weniger Punkte für bessere Performance
plot = PlotWidget(max_plot_points=100)
Tests
Die Optimierung wird durch umfassende Tests abgedeckt:
Batch-Update-Tests ausführen
python test_batch_plot_update.py
Performance-Demo
python demo_batch_optimization.py
Abwärtskompatibilität
Die alte update_plot() Methode bleibt erhalten:
Alte Methode funktioniert weiterhin
plot.update_plot((x, y))
Neue Methode für bessere Performance
plot.update_plot_batch([(x1, y1), (x2, y2), (x3, y3)])
Auswirkungen auf die Anwendung
Vorteile
✅ Deutlich bessere Performance bei hohen Datenraten
✅ Flüssige GUI auch bei 500+ Hz Datenerfassung
✅ Niedrigere CPU-Last durch weniger Plot-Updates
✅ Bessere Skalierbarkeit für zukünftige Erweiterungen
✅ Abwärtskompatibilität zu bestehenden Code
Nachteile
⚠️ Minimale Latenz (max. 100ms) zwischen Datenempfang und Anzeige
⚠️ Etwas komplexere Architektur durch Queue-System
Fazit
Die Batch-Update-Optimierung löst erfolgreich die Performance-Probleme bei hohen Datenraten. Die Anwendung kann jetzt:
Datenraten von 500+ Hz verarbeiten
Flüssige GUI-Performance beibehalten
Für zukünftige Hochgeschwindigkeits-Messungen skalieren
Bestehende Funktionalität ohne Änderungen nutzen
Die Optimierung ist produktionsreif und sollte in der Hauptanwendung aktiviert werden.