2. MATLAB基础速通:矩阵运算、脚本与函数、绘图基础、数据类型与结构体
各位同学,欢迎来到第二章。说实话,很多初学者一上来就啃飞控算法,结果连MATLAB的基本操作都磕磕绊绊,最后代码跑不通,心态先崩了。我个人习惯是:先把工具箱的底子打牢,后面建模才顺手。这一章,我们就用最快的速度,把MATLAB最核心的几个技能点过一遍。
2.1 矩阵运算:MATLAB的看家本领
MATLAB全名叫Matrix Laboratory,说白了就是为矩阵而生的。你在飞控里看到的姿态矩阵、旋转矩阵、协方差矩阵,本质上都是矩阵。所以这一关必须过。
2.1.1 矩阵的创建
创建矩阵最简单的方式,就是直接敲。我刚开始学的时候,总觉得这玩意儿跟C语言数组差不多,但用起来才发现——真香。
% 直接输入
A = [1, 2, 3; 4, 5, 6; 7, 8, 9];
% 常用快捷函数
zeros(3,4) % 全零矩阵
ones(2,5) % 全一矩阵
eye(4) % 单位矩阵
rand(3,3) % 随机矩阵(均匀分布)
linspace(0,10,5) % 从0到10均匀取5个点
linspace 生成时间序列,比如仿真步长0.01秒,跑10秒,就是 t = linspace(0,10,1001)。比手动写循环快多了。
2.1.2 矩阵运算的核心操作
这里有个坑,我必须要讲清楚。MATLAB里 * 和 .* 是两码事。前者是矩阵乘法,后者是对应元素相乘。你想想看,飞控里你要做坐标变换,用的是矩阵乘法;你要做增益缩放,用的是点乘。搞混了,结果全错。
% 矩阵乘法(线性代数意义)
A = [1,2; 3,4];
B = [5,6; 7,8];
C = A * B; % 结果是 [19,22; 43,50]
% 对应元素相乘(点乘)
D = A .* B; % 结果是 [5,12; 21,32]
% 转置
A_trans = A'; % 单引号就是转置
% 求逆
A_inv = inv(A);
% 特征值与特征向量(飞控模态分析常用)
[V, D] = eig(A);
*,元素运算用 .*。
2.2 脚本与函数:让代码活起来
写飞控算法,你不能把所有代码都堆在一个文件里。那样调试起来,你会想砸电脑的。脚本和函数,就是帮你把代码组织起来的工具。
2.2.1 脚本文件(.m)
脚本就是按顺序执行的一堆命令。适合做一次性计算或者快速验证。我个人习惯是:做原型验证时用脚本,因为改起来快。
% 文件名:test_angle.m
% 一个简单的角度转换脚本
deg = 45;
rad = deg * pi / 180;
fprintf('%d 度 = %.4f 弧度\n', deg, rad);
2.2.2 函数文件
函数就不一样了。它有输入输出,有独立的工作空间。你想想看,飞控里的姿态解算、控制律计算,每个模块都应该是一个函数。这样你改一个模块,不会影响到其他部分。
% 文件名:deg2rad_custom.m
function rad = deg2rad_custom(deg)
% 角度转弧度
% 输入:deg - 角度值(标量或向量)
% 输出:rad - 弧度值
rad = deg * pi / 180;
end
% 调用方式
result = deg2rad_custom(45);
2.3 绘图基础:用眼睛看数据
做飞控调试,光看数字是看不出问题的。你得把数据画出来。比如姿态角的变化曲线、控制输出的响应、传感器的噪声特性——这些都得靠图。
2.3.1 二维绘图
plot 函数是最常用的。嗯,这里要注意:画图之前,先想清楚横轴是什么,纵轴是什么。
% 画一条正弦曲线
t = 0:0.01:2*pi;
y = sin(t);
plot(t, y, 'b-', 'LineWidth', 2);
xlabel('时间 (s)');
ylabel('幅值');
title('正弦波');
grid on; % 加网格,方便读数
2.3.2 多图与子图
飞控里经常要同时看多个信号,比如同时看滚转、俯仰、偏航角。用 subplot 可以在一张图里放多个子图。
% 子图示例
t = 0:0.01:10;
roll = sin(0.5*t);
pitch = cos(0.3*t);
yaw = sin(0.8*t + pi/4);
subplot(3,1,1);
plot(t, roll); ylabel('滚转角');
subplot(3,1,2);
plot(t, pitch); ylabel('俯仰角');
subplot(3,1,3);
plot(t, yaw); ylabel('偏航角');
xlabel('时间 (s)');
grid on 和 legend。有一次给客户看仿真结果,图里没加图例,客户问哪条线是期望值、哪条是实际值——场面一度很尴尬。
2.4 数据类型与结构体:管理复杂数据
飞控系统里数据种类很多:传感器数据、状态估计值、控制指令、参数配置……如果都用单独的变量,代码会乱成一锅粥。这时候就需要结构体和元胞数组了。
2.4.1 数值类型
MATLAB默认是double类型,也就是双精度浮点数。做飞控仿真,double完全够用。但如果你要部署到嵌入式平台,就得考虑单精度甚至定点数了。
| 数据类型 | 说明 | 飞控应用场景 |
|---|---|---|
| double | 双精度浮点(64位) | 仿真、离线分析 |
| single | 单精度浮点(32位) | 嵌入式实时计算 |
| int8/int16/int32 | 有符号整数 | 传感器原始数据 |
| logical | 逻辑值(true/false) | 状态标志、模式切换 |
2.4.2 结构体(struct)
结构体就像是一个文件夹,可以把相关的数据打包在一起。我在写飞控代码时,会把所有的传感器数据放在一个结构体里,所有的控制参数放在另一个结构体里。
% 定义飞控参数结构体
fc_param = struct();
fc_param.Kp = 2.5; % 比例增益
fc_param.Ki = 0.1; % 积分增益
fc_param.Kd = 0.05; % 微分增益
fc_param.dt = 0.01; % 控制周期(秒)
fc_param.enable = true; % 使能标志
% 访问结构体字段
disp(fc_param.Kp); % 输出 2.5
2.4.3 元胞数组(cell array)
元胞数组可以存放不同类型的数据。比如你要存一组不同长度的传感器数据序列,用元胞数组就很方便。
% 元胞数组示例
data = cell(3,1);
data{1} = [1,2,3,4]; % 向量
data{2} = 'IMU数据'; % 字符串
data{3} = struct('x',1,'y',2); % 结构体
% 访问元胞内容
disp(data{1}); % 输出 1 2 3 4
{} 访问内容,圆括号 () 访问的是元胞本身。这个区别我刚开始也搞混过,后来养成了习惯:取内容用花括号,取子集用圆括号。
好了,这一章的内容就到这里。矩阵运算是基础中的基础,脚本和函数帮你组织代码,绘图让你看得见数据,结构体和元胞数组帮你管理复杂信息。把这些练熟了,后面学飞控建模就会顺畅很多。