固定翼无人机Matlab/Simulink闭环仿真:从参数建模到航程计算
2026/9/11 17:16:04 网站建设 项目流程

简介:固定翼无人机Matlab代码.rar是面向高校理工科学生的仿真资源,适合计算机、电子信息工程、数学等专业用于课程设计、期末大作业或毕业设计。压缩包共55个文件、约8.08MB,以m脚本、slx模型、mat数据、pdf报告和png图示为主:m脚本覆盖参数化编程、飞行动力学计算、航程续航分析以及状态变量和飞行姿态可视化;slx模型提供Simulink闭环仿真环境;mat文件为可直接运行的案例数据;pdf内含项目展示与最终报告。压缩包内模块划分清晰,既包含固定翼的闭环仿真和航程计算,也附带多旋翼仿真模块作为对比,便于从整体理解不同飞行器的建模思路。代码适配Matlab 2014/2019a/2024a,参数可灵活修改,注释清晰,能够完整支持从模型搭建、仿真运行到结果分析的全流程,便于快速掌握固定翼无人机的设计与分析方法。目前已有112人学习,适合需要完整可运行代码和清晰思路注解的学生与研究者。

1. 固定翼无人机的 Matlab 闭环仿真包:结构、入口和第一印象

固定翼无人机Matlab代码的压缩包解压后,最先值得看的不是 .slx 模型,而是 run_fixwing_sim.m 和 parameters.m 两个脚本。它们决定了整个仿真包的打开方式:先运行参数脚本初始化工作区,再调用 Simulink 模型完成闭环解算,最后用 plotmavstatevariables.m 把 logsout 里的状态变量还原成曲线和三维轨迹。这个包同时包含固定翼和多旋翼两套模型,底层动力学函数 aircraft_dynamics.m 与多旋翼的 multirotor_dynamic_model_sim.slx 共用同一套参数结构体,只是力和力矩的来源不同。对做课程设计或期末大作业的学生来说,最实用的地方在于参数全部集中在 parameters.m 里,改动某个气动系数后重新运行脚本,不需要改 Simulink 内部连线就能看到响应变化。代码注释完整,2014 到 2024a 的 Matlab 环境都能找到兼容的打开方式。

2. 固定翼气动建模与参数初始化:从 aircraft_dynamics.m 到 parameters.m

在固定翼仿真包里,aircraft_dynamics.m 是核心的动力学计算函数。它接收状态向量和输入向量,输出状态导数,在 Simulink 的 MATLAB Function 块中被调用,也可以在独立脚本里通过 ode45 做快速验证。与之配套的 parameters.m 负责把所有质量、几何、气动导数、推进数据打包成结构体 param,二者靠字段名对接。下面这段代码展示了该函数的基本骨架,实际文件里通常也是按这个结构展开的。

function xdot = aircraft_dynamics(x, u, param) % 状态向量 x (12维):NED位置、机体速度、欧拉角、角速度 % 输入向量 u (4维):升降舵、副翼、方向舵、油门 pn = x(1); pe = x(2); pd = x(3); u_vel = x(4); v_vel = x(5); w_vel = x(6); phi = x(7); theta = x(8); psi = x(9); p = x(10); q = x(11); r = x(12); delta_e = u(1); delta_a = u(2); delta_r = u(3); delta_t = u(4); % 密度随海拔高度变化,简单按指数衰减,精细飞行可用 ISA 模型 rho = 1.225 * exp(-pd / 8400); V = norm([u_vel, v_vel, w_vel]); alpha = atan2(w_vel, max(u_vel, 1e-6)); beta = asin(v_vel / max(V, 1e-6)); % 升力、阻力、侧力系数 CL = param.CL0 + param.CLa * alpha + param.CLde * delta_e; CD = param.CD0 + param.K * CL^2; CY = param.CYb * beta + param.CYp * p + param.CYr * r ... + param.CYda * delta_a + param.CYdr * delta_r; % 推力:这里以油门线性近似,完整版推荐查 prop_data 插值表 T = 0.5 * rho * V^2 * param.S * param.CT * delta_t; % 位置导数:NED坐标中由机体速度经欧拉角旋转得到 % Rbn 是 phi,theta,psi 构成的标准方向余弦阵,完整版中给出具体表达式 Rbn = eye(3); % 占位,实际应替换为旋转矩阵 xdot = zeros(12,1); xdot(1:3) = Rbn * [u_vel; v_vel; w_vel]; % 后续继续补充引力、气动力矩、角加速度方程 end

代码中param.g是重力加速度,param.S是机翼参考面积,param.CT是推力系数。这里把复杂的气动力矩项省略了,实际aircraft_dynamics.m会补全滚转、俯仰、偏航力矩以及角加速度方程。需要注意状态顺序与 Simulink 模型中积分器输出顺序一致,调整任一端口都会影响整个模型连线。

2.1 参数结构体与文件约定

parameters.m是纯脚本,没有 function 声明,目的是在运行后把变量写入当前工作区,供sim调用。常见写法是先定义一个空结构体,然后按类别添加字段。下面给出典型的参数分组:

参数块变量名典型含义单位
质量与惯性mass, Jx, Jy, Jz, Jxz质量与转动惯量kg, kg·m²
几何S, b, cbar机翼面积、展长、平均气动弦m², m, m
基本气动CL0, CLa, CD0, K升力截距、升力线斜率、零升阻力、诱导阻力因子-
操纵导数CLde, CYda, CYdr, Clda, Cldr舵面效率1/rad
推进CT, prop_data推力系数或螺旋桨插值表-

初始化代码一般长这样:

% parameters.m 片段 param.mass = 1.56; % 起飞质量 kg param.S = 0.25; % 机翼面积 m^2 param.b = 1.2; % 翼展 m param.cbar = param.S / param.b; % 平均气动弦,矩形机翼可直接用几何弦 param.CL0 = 0.2; % 零迎角升力系数 param.CLa = 5.2; % 升力线斜率 1/rad param.CD0 = 0.03; % 零升阻力系数 param.K = 0.04; % 诱导阻力因子 load('aer1216_2023F_proj_prop_data.mat', 'prop_data'); param.prop_data = prop_data; % 推进数据用于插值

参数脚本里最后一条load是读取螺旋桨特性数据。aer1216_2023F_proj_prop_data.mat里有油门、空速、拉力、功率的关系表,航程计算和推力矩都要用到。注意parameters.mat是另一个文件,它保存的是已经跑过的参数工作区快照,可以直接load('parameters.mat')恢复环境,方便复现。

2.2 参数化编程的核心意义

把参数集中到一个脚本,而不是散落在 Simulink 的 Constant 块中,是这类课程设计的常见要求。这样当修改起飞重量或翼面积时,不需要打开模型去查找每一个魔法数字。例如param.CLa在升力计算和力矩计算中都会被引用,如果直接在 MATLAB Function 块里写死成 5.2,换一个机型就要改多处。参数化后只需要在run_fixwing_sim.m里改一行,重新运行脚本即可。建议在run_fixwing_sim.m的初始化部分输出参数摘要,方便确认当前使用的是哪一组数据。

2.3 跨 Matlab 版本的兼容性策略

压缩包给出的版本范围是 2014、2019a 和 2024a,这意味着代码不能使用 2014 之后引入的新语法。例如字符串常量"..."arguments块、tiledlayout都无法在 2014 上运行,所以parameters.maircraft_dynamics.m都采用了最基础的 if/else、struct 和函数写法。Simulink 模型.slx的版本则更容易出现兼容问题,如果 2024a 保存的模型用 2019a 打开通常没问题,但 2014 可能提示模型版本过高。实践中可以用 2019a 作为基准版本,生成的模型文件也便于在两个方向间迁移。slprj文件夹是 Simulink 编译产生的缓存,删除后会在下次运行仿真时重新生成,不影响代码本身。

在修改任何气动系数之前,建议先跑一遍原始代码保存基线结果。比如把param.CL0从 0.2 改成 0.4,对比高度响应曲线的稳态值。如果发现迎角或俯仰角出现非对称偏移,先检查迎角定义是alpha = atan2(w,u)还是atan2(w,V),不同定义会影响升力计算的横轴。这种对比方法比单看一组曲线更能发现参数脚本中的单位错误。

3. 闭环仿真运行与状态可视化:run_fixwing_sim.m 和 plotmavstatevariables.m 的数据契约

这个仿真包的工作方式不是双击 Simulink 模型然后点运行,而是用run_fixwing_sim.m脚本驱动。脚本先用run('parameters.m')初始化参数,再用set_param设置停止时间和输出选项,最后调用sim()把结果写入工作区。这样做的好处在于可以循环改变参数做批量验证。

3.1 仿真入口脚本的拆解

下面是固定翼入口脚本的核心片段,与实际文件中的结构基本一致:

% run_fixwing_sim.m 核心流程 clear all; close all; clc % 第一步:初始化参数 run('parameters.m'); % 第二步:设置仿真时长和初始状态 Tsim = 30; % 仿真时长 30s x0 = zeros(12,1); x0(4) = 15; % 初始前向速度 15 m/s x0(8) = deg2rad(3); % 初始俯仰角 3° assignin('base', 'x0', x0); assignin('base', 'param', param); % 第三步:配置模型 model = 'Fixed_Wing_Aircraft_Sim_closed_loop'; open_system(model); set_param(model, 'StopTime', num2str(Tsim)); set_param(model, 'SaveOutput', 'on'); set_param(model, 'SaveTime', 'on'); % 第四步:运行 out = sim(model, 'SrcWorkspace', 'current');

这里的assignin('base', ...)是为了保证 Simulink 模型的回调函数和外层脚本都可以从基础工作区读取x0param。如果直接在sim命令前只定义局部变量,模型内部可能找不到变量。SrcWorkspace设置为current表示使用当前函数工作区,如果模型里引用了param,也要保证该变量在当前工作区可见。多数情况下保持默认的base更省事。

3.2 从仿真输出对象中提取状态变量

sim返回的out是一个仿真对象,具体能取到哪些信号取决于模型里是否勾选了信号日志记录。这个包里用到的输出通道是logsout,常见读取方式如下:

% 获取日志对象 logsout = out.logsout; names = logsout.getElementNames(); % 查找名为 state 的信号 state = logsout.getElement('state').Values.Data; time = logsout.getElement('state').Values.Time;

state的列顺序需要与初始化时定义的x0对齐。如果你把x0定义为[pn, pe, pd, u, v, w, phi, theta, psi, p, q, r],那么state(:,3)是 NED 高度,注意 NED 坐标向下为正,画海拔高度时要用-state(:,3)。如果日志名称不同,可以用上面的names查看实际信号名,然后再替换。

在 Simulink 模型内部,控制器通常以 PID 模块为主。如果仿真发散,先看控制器输出是否饱和。用scope或者logsout查看控制器输出。修改控制器增益时,不要直接在模型里双击改数字,因为这样没法留痕;更好的做法是在run_fixwing_sim.m中用set_param定位到模块并设置增益值。示例:

set_param('Fixed_Wing_Aircraft_Sim_closed_loop/PID 控制器/P', 'Gain', '1.8');

注意这里的模块路径必须以 Simulink 模型中实际的名称和层级为准,如果模型尚未加载,需要先open_systemload_system,否则报错。在 for 循环里修改这个增益值并批量运行,可以快速观察闭环极点移动趋势,这对课程设计中的控制器分析很有用。

3.3 状态曲线与三维姿态绘制

plotmavstatevariables.m负责把state矩阵拆成多个子图,绘制高度、空速、迎角、俯仰角等常用变量。接着会调用drawAircraft.m来画三维机体的运动。drawAircraft.m的核心是把机体坐标系下的点乘以旋转矩阵,再平移到 NED 坐标。为了直观,通常把 NED 转换为北东地后显示,也有转换成东北下再取负高度的。关键代码如下:

% 从状态中取位置和姿态 pn = state(:,1); pe = state(:,2); pd = state(:,3); phi = state(:,7); theta = state(:,8); psi = state(:,9); % 绘制飞行轨迹(注意高度取负) figure plot3(pn, pe, -pd, 'b', 'LineWidth', 1.5); grid on xlabel('North (m)'); ylabel('East (m)'); zlabel('Altitude (m)'); axis equal % 调用飞机绘制函数,传入位置和姿态 drawAircraft(pn(1), pe(1), pd(1), phi(1), theta(1), psi(1));

这里drawAircraft的输入顺序如果写成phi, theta, psi,函数内部必须按同样的欧拉角顺序建立旋转矩阵。很多同学在三维绘制时发现飞机姿态与轨迹不匹配,基本都是旋转矩阵的乘法和欧拉角顺序不一致导致的。建议先从静点测试:把飞机平飞时的姿态代入,看三维模型是否水平。另外,slprj.slxc是仿真缓存,如果运行时报模型锁冲突,删除这两个文件夹重新打开模型即可。plots文件夹里的plot-x.pngplot-3d.png是别人跑的参考输出,可以作为结果对照。

4. 多旋翼对照:固定翼模型切换到 quadrotor 时的动力学差异与仿真复用

压缩包里除了固定翼模型,还带了完整的四旋翼模型,包括multirotor_full_system.slxmultirotor_dynamic_model_sim.slxrun_quadcopter_sim.mmultirotor_param.mQUAD_calc_range_and_endurance.mlx。对课程设计来说,这意味着你可以用同一套代码风格完成两种飞机的作业,但不要想当然地认为它们可以互相启动。

4.1 两个平台的入口与文件映射

固定翼的入口是run_fixwing_sim.m,四旋翼的入口是run_quadcopter_sim.m。两者结构非常相似,都是先运行各自的初始化脚本,再打开对应的.slx。不过模型内部的动力学模块完全不同。固定翼的力和力矩由气动导数决定,四旋翼的力和力矩由电机转速决定,因此需要单独运行multirotor_param.m,不能继续用固定翼的parameters.m

项目固定翼四旋翼
控制输入升降舵、副翼、方向舵、油门四个电机转速命令
输入维度44
升力来源机翼气动升力旋翼推力
姿态力矩舵面气动力矩电机转速差
参数文件parameters.mmultirotor_param.m
运行脚本run_fixwing_sim.mrun_quadcopter_sim.m
航程/续航calc_range_and_endurance.mQUAD_calc_range_and_endurance.mlx

从表面看两者输入都是 4 维,但物理含义完全不同。固定翼的第一个输入delta_e是升降舵偏角,四旋翼的第一个输入是第一个电机的转速命令。如果误把固定翼的舵命令给四旋翼模型,仿真会直接发散或报代数环错误。multirotor_full_system.slxmultirotor_dynamic_model_sim.slx的差异在于是否包含控制回路,前者是全状态闭环,后者通常只包含被控对象。如果作业要求只做四旋翼建模,可以用后者加扫描激励信号;如果要求做控制,则使用前者。

4.2 电机转速到力与力矩的分配

四旋翼建模中,最核心的分配关系是转速平方到推力和力矩。常见实现如下:

function [F, M] = quad_mixer(omega, param) % omega: 4x1 电机转速 (rad/s) % param.kF: 单个旋翼推力系数 % param.kM: 扭矩系数 % param.l: 机臂长度 F_total = param.kF * sum(omega.^2); % 力矩:滚转、俯仰、偏航 M = [param.l * param.kF * (omega(1)^2 - omega(3)^2); param.l * param.kF * (omega(2)^2 - omega(4)^2); param.kM * (omega(1)^2 - omega(2)^2 + omega(3)^2 - omega(4)^2)]; F = [0; 0; F_total]; % 机体坐标系下推力方向为 Z end

这里omega的顺序和电机位置关联,通常定义为 1、2、3、4 分别对应前左、前右、后左、后右。油门的权重是四个转速平方之和,滚转和俯仰由对称的电机转速差产生,偏航则由顺时针和逆时针旋翼的反扭矩差产生。multirotor_param.m里的kFkM可以从螺旋桨测试数据拟合,也可以用飞行器悬停时的拉力近似反推。multirotor_param.m中还应当包含电机数量、机臂长度和转向矩阵,这些字段与固定翼的参数结构体完全不同,混用会造成 Simulink 无法解析总线。

4.3 从固定翼模型复用控制算法的改造思路

如果你已经为固定翼写好了 PID 控制器,想把它用到四旋翼上,需要修改的是被控对象的输入映射,而不是控制器本身。固定翼控制器输出的是舵面偏角,四旋翼控制器输出的是期望推力或转速,所以正确做法是在控制器后加一个分配矩阵模块,把期望推力转换成四个转速。这个模块在 Simulink 中可以用 MATLAB Function 块直接调用上面的quad_mixer。如果文件包里没有现成的这种模块,可以自行新建,这也是把固定翼项目扩展成多旋翼项目的关键一步。

由于固定翼和四旋翼模型都使用了param结构体,但字段内容不同,切换前要注意清空工作区。在同一个 Matlab 会话中先运行固定翼脚本再运行四旋翼脚本,残留的param.CLa可能会被四旋翼模型误用。常见做法是在每个运行脚本开头加clear all,或者给多旋翼参数文件定义一个不同的结构体名称,比如quad_param,这样两个模型可以同时停留在工作区里而不冲突。

5. 航程与续航计算:calc_range_and_endurance.m 的电池模型与实用化改造

固定翼的calc_range_and_endurance.m通常要同时支持两种计算:一种是燃油动力用 Breguet 方程,另一种是电动无人机用电池能量除以巡航功率。这个包里提供了aer1216_2023F_proj_prop_data.mat螺旋桨数据,因此更实用的方式是直接从数据表插值出当前状态下的功率,再乘以电机效率。

5.1 从螺旋桨数据表到巡航功率

螺旋桨数据表通常包含空速、油门、功率、拉力。不要把推进效率设成常数,正确做法是先从数据表插值得到功率,再考虑电机和电调损耗。参考代码如下:

% calc_range_and_endurance.m 核心片段 load('aer1216_2023F_proj_prop_data.mat', 'prop_data'); V = 18; % 巡航空速 m/s throttle = 0.65; % 油门 0-1 P_shaft = interp2(prop_data.speed, prop_data.throttle, ... prop_data.power, V, throttle, 'linear'); eta_motor = 0.82; % 电机+电调效率 P_elec = P_shaft / eta_motor; E_battery = 250 * 3600; % 电池能量 J endurance = E_battery / P_elec; % 秒 range = endurance * V;

interp2需要输入为网格或网格化的矩阵。如果prop_data.power不是网格而是向量,需要先用meshgrid重建,或者改用griddata做散点插值。另一个坑是表格中油门和空速的排列顺序,建议在脚本前用size(prop_data.speed)检查维度,避免插值报错。

5.2 参数敏感性分析的实用技巧

在课程设计报告里,航程计算通常要给出“随着速度变化,航程如何变化”的曲线。遍历一组速度即可:

V_list = 12:2:24; range_list = zeros(size(V_list)); for i = 1:length(V_list) P = interp2(prop_data.speed, prop_data.throttle, prop_data.power, ... V_list(i), throttle, 'linear'); range_list(i) = E_battery / (P / eta_motor) * V_list(i); end plot(V_list, range_list / 1000, 'o-'); xlabel('Cruise Speed (m/s)'); ylabel('Range (km)');

这里油门throttle固定会导致低速和高速时功率曲线失真,更合理的是让推力和阻力相等时反求油门,再对每个速度分别用fzero求解匹配值。但作为课程设计,固定油门也是一种简化方案,在报告里注明假设即可。

5.3 防止单位错误和结果异常的检查

prop_data里的功率单位可能是 W 或 kW,拉力可能是 N 或 kgf,建议先做量级检查:将插值得到的推进功率与“重量乘以垂直下降速度”对比,如果功率小于这个物理下限,说明单位或插值有误。同理,QUAD_calc_range_and_endurance.mlx是四旋翼的续航实时脚本,脚本内对每个电机分别插值功率,再乘悬停效率。与固定翼的区别是四旋翼在巡航时前后电机转速不完全相同,不能简单用单个转速插值总值。最后把计算得到的续航时间与run_fixwing_sim.m仿真中的能量消耗对比,如果两者偏差在 15% 以内,说明模型闭合良好。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询