4. 可视化基础:用 Matplotlib 绘制单变量时序图
做飞控调优,说白了就是跟数据打交道。
你想想看,飞机在天上飞了十分钟,日志文件里攒了几十万行数据。Roll 角、Pitch 角、Yaw 角、电机转速、GPS 经纬度……全是数字。光盯着数字看,眼睛看花了也看不出门道。
这时候就需要可视化。把数字变成曲线图,一眼就能看出问题在哪。
我个人习惯,拿到一份新日志,第一件事就是画 Roll 角的时序图。为什么?因为 Roll 角最能反映飞控的横滚响应好不好,有没有超调,有没有震荡。画出来一看,心里就有底了。
4.1 横纵坐标到底在说什么?
很多初学者觉得坐标轴很简单,不就是 X 轴和 Y 轴吗?嗯,确实简单,但理解不到位,后面分析就容易跑偏。
- 横轴(X 轴):时间。单位通常是秒(s)或者毫秒(ms)。注意,飞控日志里的时间戳有两种——系统启动后的相对时间,和 GPS 的绝对时间。我一般用相对时间,方便看飞行阶段。
- 纵轴(Y 轴):变量值。比如 Roll 角,单位是度(°)。正负号代表方向——正的是右倾,负的是左倾。
举个例子。你画出来的 Roll 角曲线,如果横轴是 0 到 300 秒,纵轴是 -30 到 +30 度。那你就知道:这架飞机在 5 分钟里,最大横滚角度没超过 30 度,说明飞得还算平稳。
一个小技巧:画图之前,先看一眼数据的范围。如果 Roll 角突然跳到 180 度,那大概率是传感器数据异常,不是飞机真的翻了。我在项目里遇到过这种情况,当时吓一跳,后来发现是 IMU 的 SPI 通信丢了一帧。
4.2 第一张图:Roll 角时序图
好,我们直接上代码。用 Matplotlib 画一张 Roll 角随时间变化的图。
import matplotlib.pyplot as plt
import pandas as pd
# 假设你已经把日志解析成了 DataFrame
# df 里有 'timestamp' 和 'roll' 两列
df = pd.read_csv('flight_log.csv')
plt.figure(figsize=(12, 5))
plt.plot(df['timestamp'], df['roll'], color='#3498db', linewidth=1.5)
plt.xlabel('Time (s)')
plt.ylabel('Roll Angle (deg)')
plt.title('Roll Angle vs Time - Flight Log Analysis')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
这段代码很简单。但有几个细节我想强调一下:
figsize=(12, 5):宽高比。飞控时序图我习惯用宽屏,因为时间跨度长,窄了看不清细节。linewidth=1.5:线宽。太细了看不清,太粗了遮挡数据点。1.5 刚刚好。grid(True, alpha=0.3):网格线。透明度调低一点,别喧宾夺主。
注意:如果你的日志里时间戳是毫秒级的,记得先转成秒。不然横轴数字会很大,看着别扭。我曾经犯过这个错,画出来的图横轴从 0 到 600000,完全没法看。
4.3 图形标注:让图表会说话
光画一条线不够。你得告诉看图的人——这里发生了什么。
我常用的标注方式有三种:
| 标注类型 | 用途 | 代码示例 |
|---|---|---|
| 垂直参考线 | 标记关键时间点,比如起飞、降落、切模式 | plt.axvline(x=120, color='red', linestyle='--') |
| 水平参考线 | 标记目标值或阈值,比如期望 Roll 角 0 度 | plt.axhline(y=0, color='gray', linestyle=':') |
| 文本注释 | 在图上直接写说明,比如“此处有超调” | plt.text(125, 15, 'Overshoot', fontsize=10) |
举个例子。假设你在 120 秒时切了增稳模式,Roll 角出现了一个小尖峰。你可以这样标注:
plt.axvline(x=120, color='#e74c3c', linestyle='--', linewidth=1, label='Mode Switch')
plt.text(122, 10, 'Mode switch to Stabilize', fontsize=9, color='#e74c3c')
plt.legend()
这样一看图,就知道那个尖峰是因为切模式引起的,不是飞控参数有问题。
核心原则:标注是为了让看图的人一眼就能抓住重点。不要标太多,否则图会变成花脸。我一般一张图不超过 5 个标注。
4.4 保存图片:别让分析成果白费
画完图,你得保存下来。不然下次还得重新跑代码。
保存图片用 plt.savefig()。我建议用 PNG 格式,兼顾清晰度和文件大小。
plt.savefig('roll_angle_analysis.png', dpi=200, bbox_inches='tight')
几个参数说明:
dpi=200:分辨率。200 够清晰,又不至于文件太大。如果你要打印或者放报告里,可以调到 300。bbox_inches='tight':自动裁剪空白边。不然保存出来的图四周会有一圈白边,看着不专业。
我的习惯:文件名里带上日期和飞行架次。比如
2024-03-15_flight03_roll.png。这样找图的时候不会乱。我曾经把所有图都存成 plot.png,结果第二天就覆盖了,后悔莫及。
4.5 本章知识体系
下面这张图帮你梳理一下本章的核心逻辑:
4.6 避坑指南
最后,分享几个我踩过的坑:
- 时间戳不连续:飞控日志有时候会丢帧。画出来的图会出现断点。解决办法是用
plt.plot()的marker参数把数据点标出来,比如marker='o', markersize=2。这样能看出哪些地方数据缺失了。 - 纵轴范围不合适:如果 Roll 角大部分时间在 -5 到 +5 度之间,但有一次跳到了 30 度,Matplotlib 会自动把纵轴拉到 -30 到 +30。这时候小波动就看不清楚了。我一般用
plt.ylim(-10, 10)手动固定范围,把异常值单独分析。 - 中文字体乱码:Matplotlib 默认不支持中文。如果你要在图上写中文标注,记得先设置字体:
plt.rcParams['font.sans-serif'] = ['SimHei']。不然出来的图全是方框。
嗯,这一章的内容就这些。画好一张 Roll 角时序图,是后面所有分析的基础。下一张图,我们会加上期望值和实际值的对比,看看飞控到底跟不跟得上指令。