串口数据动态绘图延迟过高问题优化求助
实时绘图延迟优化方案
核心问题原因
你的代码延迟主要来自以下冗余设计:
- 每次收到新数据都调用
plt.cla()清空画布后重绘全量历史数据,执行耗时会随数据量增长线性上升,运行越久延迟越高 - 强制添加
plt.pause(0.05)固定50ms暂停,每秒最多只能刷新20次,延迟会持续累积 - 绘图操作和串口读取强绑定,数据刷新率高时会触发大量无效重绘
优化后实现代码
import serial import time import matplotlib.pyplot as plt # 配置参数 MAX_SHOW_POINTS = 100 # 最多显示最近100个数据点,可根据需要调整 REFRESH_INTERVAL = 0.02 # 绘图刷新间隔20ms,可根据帧率需要调整 COM_PORT = 'COM6' BAUD_RATE = 2000000 # 初始化变量 start = time.time() x = [] y = [] last_refresh_time = start # 初始化串口 ser = serial.Serial(COM_PORT, BAUD_RATE, timeout=0) time.sleep(2) # 初始化绘图对象,只创建一次曲线 plt.ion() fig, ax = plt.subplots() line, = ax.plot([], [], 'red') # 提前创建Line2D对象,后续只更新数据 ax.set_xlabel('流逝时间(s)') ax.set_ylabel('传感器数值') # 预先启动画布渲染 fig.canvas.draw() plt.show(block=False) # 缓存背景,加快刷新速度 background = fig.canvas.copy_from_bbox(ax.bbox) while True: # 优先处理串口数据读取 line_data = ser.readline() if line_data: try: num = float(line_data.decode().strip()) except (ValueError, UnicodeDecodeError): # 跳过解析失败的脏数据 continue time_elapsed = time.time() - start x.append(time_elapsed) y.append(num) # 限制数据列表长度,只保留最近MAX_SHOW_POINTS个点 if len(x) > MAX_SHOW_POINTS: x.pop(0) y.pop(0) # 按设定间隔刷新绘图,和数据读取解耦 current_time = time.time() if current_time - last_refresh_time >= REFRESH_INTERVAL: # 增量更新曲线数据,不重绘整张画布 line.set_data(x, y) # 自适应调整坐标轴范围 ax.relim() ax.autoscale_view() # 快速刷新画布 fig.canvas.restore_region(background) ax.draw_artist(line) fig.canvas.blit(ax.bbox) # 处理画布事件,避免界面无响应 fig.canvas.flush_events() last_refresh_time = current_time
关键优化点说明
- 提前创建
Line2D对象,后续仅更新曲线数据,不需要每次清空重绘,刷新效率提升数倍 - 限制显示的最大数据量,避免数据列表无限膨胀导致的性能下降;如果需要保留全量历史数据做后续分析,可额外定义列表存储所有数据,绘图仅使用裁剪后的最近N个点即可
- 绘图刷新和串口读取逻辑解耦,既保证数据不丢,也控制绘图调用频率不会过高
- 使用
blit机制增量刷新画布,仅更新曲线变动的区域,减少冗余渲染开销 - 移除了
plt.pause固定延迟,仅保留必要的界面事件处理逻辑 - 可选优化:如果传感器数值范围和观测时间窗口固定,可以预先设置
ax.set_ylim(最小值, 最大值)、ax.set_xlim(0, 观测窗口时长),去掉ax.relim()和ax.autoscale_view()调用,刷新效率会更高
内容的提问来源于stack exchange,提问作者user3643087
相关产品推荐
相关产品推荐

