I am trying to develop a gui to receive data over udp with rate of 72Mbit/s. I am using the pyqtgraph to plot the data of 10 channels. but after receiving some packets, the widow freezes and it seems like some packets are lost.
I am using this code:
import sys
import collections
import pyqtgraph as pg
from PyQt5.QtCore import QThread, pyqtSignal, QTimer, QCoreApplication, QObject
from PyQt5.QtWidgets import QMainWindow, QApplication, QVBoxLayout, QWidget, QLabel
import socket
def convert_hex_to_bin(hex_string):
return bin(int(hex_string, 16))[2:].zfill(len(hex_string) * 4)
class UdpThread(QThread):
raw_data_received = pyqtSignal(bytes)
def __init__(self, parent=None, port=8080):
super().__init__(parent)
self.port = port
self.running = True
def run(self):
UDP_IP = "0.0.0.0"
MAX_UDP_PAYLOAD = 1035
try:
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.bind((UDP_IP, self.port))
while self.running:
data, _ = udp_socket.recvfrom(MAX_UDP_PAYLOAD)
if data:
self.raw_data_received.emit(data)
self.msleep(10)
except socket.error as e:
print(f"Socket error: {e}")
finally:
if 'udp_socket' in locals():
udp_socket.close()
def stop(self):
self.running = False
try:
dummy_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
dummy_socket.sendto(b'stop', ('127.0.0.1', self.port))
dummy_socket.close()
except socket.error:
pass
self.wait()
class DataProcessor(QObject):
data_parsed = pyqtSignal(int, list)
def process_data(self, datagram_data):
try:
data_pack = datagram_data.hex()
data_online = data_pack[16:-6]
# --- Process Block 1 ---
block1 = data_online[:1024]
metadata_data1 = block1[:14]
metadata_bin1 = convert_hex_to_bin(metadata_data1)
channel1 = int(metadata_bin1[-7:], 2)
block1_data = block1[14:-2]
result_list1 = [int(block1_data[j:j+6], 16) for j in range(0, len(block1_data), 6)]
self.data_parsed.emit(channel1, result_list1)
# --- Process Block 2 ---
block2 = data_online[1024:]
metadata_data2 = block2[:14]
metadata_bin2 = convert_hex_to_bin(metadata_data2)
channel2 = int(metadata_bin2[-7:], 2)
block2_data = block2[14:-2]
result_list2 = [int(block2_data[j:j+6], 16) for j in range(0, len(block2_data), 6)]
self.data_parsed.emit(channel2, result_list2)
except (ValueError, IndexError) as e:
print(f"Error parsing data: {e}")
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Data Logger")
self.setGeometry(100, 100, 1200, 800)
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
self.plot_widget = pg.PlotWidget()
main_layout.addWidget(self.plot_widget)
self.plot_widget.addLegend()
self.plot_widget.showGrid(x=True, y=True, alpha=0.5)
self.num_channels = 10
self.channel_colors = ['#00BFFF', '#FF4500', '#32CD32', '#FFD700', '#9370DB', '#808080', '#00AAFF', '#FF8000', '#32AA32', '#FFA700']
self.data_buffers = {i: collections.deque() for i in range(1, self.num_channels + 1)}
self.curves = {i: self.plot_widget.plot(pen=pg.mkPen(self.channel_colors[i-1], width=2, style = pg.QtCore.Qt.DashLine), name=f"Channel {i}")
for i in range(1, self.num_channels + 1)}
self.udp_thread = UdpThread()
self.processor_thread = QThread()
self.data_processor = DataProcessor()
self.data_processor.moveToThread(self.processor_thread)
self.processor_thread.start()
self.udp_thread.raw_data_received.connect(self.data_processor.process_data)
self.data_processor.data_parsed.connect(self.update_plot)
self.udp_thread.start()
def update_plot_view(self):
max_len = max(len(buf) for buf in self.data_buffers.values())
if max_len == 0:
max_len = 1000
view_window_size = 1000
x_offset_val = (self.x_offset_slider.value() - 50) / 100.0 * view_window_size
x_div_val = (100 - self.x_div_slider.value()) / 100.0 * view_window_size + 100
x_max = max_len
x_min = max(0, x_max - x_div_val)
self.plot_widget.setXRange(x_min + x_offset_val, x_max + x_offset_val, padding=0)
def update_plot(self, channel, data):
if channel in self.data_buffers:
self.data_buffers[channel].extend(data)
self.curves[channel].setData(list(self.data_buffers[channel]))
self.update_plot_view()
def closeEvent(self, event):
print("Stopping UDP listener thread...")
self.udp_thread.stop()
self.processor_thread.quit()
self.processor_thread.wait()
super().closeEvent(event)
if __name__ == '__main__':
app = QCoreApplication.instance()
if app is None:
app = QApplication(sys.argv)
main_win = MainWindow()
main_win.show()
sys.exit(app.exec_())
but this code leads to packet losses after a short time, that is, the first 60-70 packets are received correctly without any losses, but the following packets may be lost. Can anyone help me to troubleshoot this issue? Or is there any better options to develop a gui for high rate data? Thank you