基于MATLAB/Simulink的AUV六自由度运动建模与仿真实现
2026/9/12 8:09:11 网站建设 项目流程

简介:面向水下无人自主航行器(AUV)研发与仿真学习,这份MATLAB/Simulink程序包提供了完整的建模与控制系统示例,尤其适合船舶与海洋工程、自动化等相关专业的研究生和工程师。资源共62个文件,以C源码(.c/.h)、M脚本和Simulink模型(.mdl)为核心,辅以TXT说明、PDF文档与MAT数据文件;C头文件与源码便于查看底层算法实现,M脚本与MDL模型则可直接打开运行,TXT、PDF与MAT文件提供说明文档与数据支撑。压缩包仅441KB,目录层次清晰,阅读和二次开发都很方便。目前已有1750人浏览学习,属于实用型参考代码库。通过研读源码,可快速掌握基于Simulink搭建水下航行器仿真环境的方法,并针对自身课题修改参数与控制器结构;尤其适合课程设计、毕业设计或科研预研阶段使用,既能学习S函数的编写方法,也能由此扩展实现不同运动控制策略,是一份难易适中、可直接运行学习的参考资料。

1. 做水下无人自主航行器仿真,卡住的往往不是控制器而是模型参数

在水下无人自主航行器(AUV)控制算法验证里,我最常遇到的情况是:控制律写完了,Simulink 却跑不出一个可信的深度剖面。问题通常不在控制参数,而在于六自由度运动模型、推进器作用方式和仿真步长没有对齐。这套基于 MATLAB/Simulink 的 AUV 仿真程序提供了一套可以直接落地的运动模型载体,附带 S 函数、M 文件和说明文档,适合做定深、定航向、路径跟踪的前期验证,也适合当作研究生课题的对比基线。使用者只需具备基础的 Simulink 操作能力,把重心放在理解参数含义和仿真设置上,而不是从零推导整机运动方程。

2. 自主航行器建模:vehicle.m 里的载体参数与六自由度运动学

2.1 先理清 AUV 仿真常用的两组坐标系

打开模型之前,需要先明确 vehicle.m 中状态量的坐标定义。AUV 仿真普遍采用北东地(NED)坐标系作为惯性系,载体坐标系固连在航行器重心附近,x 轴指向艏向,y 轴指向右舷,z 轴指向底部。状态向量一般写成 eta = [x, y, z, phi, theta, psi]ᵀ,速度向量写成 nu = [u, v, w, p, q, r]ᵀ,其中前三项是线速度,后三项是角速度。vehicle.m 参数文件中所有与浮心、重心、转动惯量有关的参数都按这个约定书写,改动时要对应检查符号,否则模型会出现“看起来在自动下沉”的假象。

常见做法是预先定义一个结构体 vehicle,字段包括长度、质量、排水体积、重心位置、浮心位置、转动惯量主对角线项、流体动力导数和推进器推力系数。这份资源里的 vehicle.m 返回的就是这样一个结构体,后续所有模块都通过这个结构体读取参数。

% vehicle.m 的典型结构,用于后续 Simulink S-Function 读取 function veh = vehicle() veh.name = 'shark-auv'; veh.g = 9.81; veh.rho = 1025; % 海水密度 kg/m^3 veh.m = 220; % 质量 kg veh.volume = 0.215; % 排水体积 m^3 veh.rg = [0; 0; 0]; % 重心相对载体坐标系原点位置 veh.rb = [0; 0; -0.02]; % 浮心位置,通常略低于重心 veh.I = diag([15 16 18]); % 转动惯量 kg*m^2 veh.Xu = -70; % 纵向线性阻尼系数 veh.Yv = -80; % 横向线性阻尼系数 veh.Zw = -85; % 垂向线性阻尼系数 veh.Kp = -8; % 横滚阻尼 veh.Mq = -15; % 俯仰阻尼 veh.Nr = -16; % 偏航阻尼 end

这里需要说明的是,阻尼系数在不少 AUV 模型里被简化成与速度线性相关,真实潜艇运动模型还会加入二次阻尼项。作为 Simulink 仿真演示,保留线性项便于观察控制器作用与参数敏感性;S-Function 读入 vehicle 结构体后,每一步用当前速度向量计算阻尼力和附加质量力,输出到积分器模块。

2.2 六自由度运动学与欧拉角更新的取舍

运动学方程部分,S-Function 的核心任务是把载体系速度转换到 NED 系位置变化率。欧拉角表示简单直观,但在俯仰角接近 ±90° 时会出现万向锁。AUV 一般不会长期保持大俯仰角,因此这里用欧拉角更新是合理选择;如果想做全姿态机动,再在后半段替换成四元数更新即可。

% 从当前状态向量 x 中提取欧拉角 phi = x(4); theta = x(5); psi = x(6); % 线速度变换矩阵 J1,把载体系速度转到 NED 系 J1 = [cos(psi)*cos(theta), -sin(psi)*cos(phi)+cos(psi)*sin(theta)*sin(phi), ... sin(psi)*sin(phi)+cos(psi)*cos(phi)*sin(theta); sin(psi)*cos(theta), cos(psi)*cos(phi)+sin(phi)*sin(theta)*sin(psi), ... -cos(psi)*sin(phi)+sin(theta)*sin(psi)*cos(phi); -sin(theta), cos(theta)*sin(phi), cos(theta)*cos(phi)]; deta(1:3) = J1 * nu(1:3);

代码中 J1 是线速度变换矩阵,实际调试时不需要把整个矩阵手工写到 Simulink 模块里,通常封装进 Level-2 M-file S-Function 的 Derivatives 部分。仿真过程中,如果发现深度输出有高频抖动,先检查这里的角度变换是否拿错了旋转顺序,因为 MATLAB 的旋转正方向习惯与部分文献不一致。

2.3 vehicle 参数表:从实验数据到仿真输入的映射

参数含义在 vehicle.m 中字段调整影响
m航行器质量veh.m决定加减速响应快慢
volume排水体积veh.volume影响净浮力和下潜稳性
rb(3)浮心 z 向坐标veh.rb决定纵向恢复力矩大小
I(3,3)偏航转动惯量veh.I影响转艏响应速度
Xu纵向线性阻尼veh.Xu影响最大航速和稳态误差
Nr偏航阻尼veh.Nr影响航向保持稳定性

很多使用者拿到程序后,第一件事是修改质量或阻尼让模型“更好控制”,这样会让后续滑模控制、自适应控制的结果失去可解释性。我建议只微调浮心位置和推进器推力增益,把原模型视为标称模型,其他参数先不改。

提示:修改 vehicle.m 后,一定要清空 Simulink 的缓存,或者在初始化脚本里强制刷新,否则 S-Function 会继续使用旧参数。

3. 动力学模型与 shark.m:S-Function 内部在算什么

3.1 从 Level-2 S-Function 的端口结构入手

当 Simulink 模型开始运行,shark.m 以 Level-2 M-file S-Function 的形式被调用。每个仿真步长依次执行初始化、计算导数、输出三个阶段。初始化阶段读取 vehicle 参数,把位置、姿态和速度共 12 个状态做成连续状态;Derivatives 阶段计算载体坐标系下的加速度;Output 阶段输出位置和姿态供控制器、Scope 和记录模块使用。这种设计把仿真内核放在一个函数文件里,调试时可以直接在 MATLAB 编辑器里设置断点,观察每一步中间变量,比把公式全画在 Simulink 模块图里更容易排查问题。

% shark_sfun.m 的框架,对应资源中 shark.m 的 S-Function 封装 function shark_sfun(block) setup(block); end function setup(block) block.NumInputPorts = 3; block.NumOutputPorts = 1; block.InputPort(1).Dimensions = 6; % 推进器控制力/力矩 block.InputPort(2).Dimensions = 6; % 海流等外部扰动力/力矩 block.InputPort(3).Dimensions = 1; % 控制器开关 block.OutputPort(1).Dimensions = 6; % 输出的位置和姿态 block.NumContStates = 12; % 位置3+姿态3+速度6 block.SampleTimes = [0 0]; % 连续采样时间 block.RegBlockMethod('InitializeConditions', @InitConditions); block.RegBlockMethod('Derivatives', @Derivatives); block.RegBlockMethod('Outputs', @Outputs); end

上面的 setup 函数定义了端口维数和连续状态数量。输入端口 1 和 2 都是 6 维信号,这在 Simulink 连线时容易混淆,常见错误是把控制力接到扰动端口,导致开环仿真结果异常。建议在模型里给两条信号线分别命名 tau 和 tau_dist,减少接错的可能。

3.2 动力学方程在 Derivatives 里的落法

动力学方程采用经典的刚体加流体形式:M·ν̇ + C(ν)ν + D(ν)ν + g(η) = τ。其中 M 包含刚体惯量和附加质量,C(ν) 是科氏力和向心力矩阵,D(ν) 是阻尼矩阵,g(η) 是重力与浮力产生的恢复力。shark.m 中通常把这些子矩阵写成单独的函数,方便替换和单独测试。

% Derivatives 回调中的核心计算 function Derivatives(block) x = block.ContStates; u = block.InputPort(1).Data; veh = get_param(block.BlockHandle, 'UserData'); eta = x(1:6); nu = x(7:12); M = inertia_matrix(veh) + added_mass(veh); C = coriolis_matrix(veh, nu); D = damping_matrix(veh, nu); g = restoring_forces(veh, eta); dnu = M \ (u - C * nu - D * nu - g); deta = kinematic_transform(eta) * nu; block.Derivatives = [deta; dnu]; end

这段代码中,dnu 是载体坐标系下的加速度,deta 是 NED 系下的位置变化率。注意最后一行 block.Derivatives 的拼接顺序必须与 setup 里状态向量定义一致,否则输出的轨迹曲线会乱掉。实际调试时,可以在这一行设置条件断点,比如当 z 大于 500 时暂停,快速定位是控制器发散还是推进器模型写错。

3.3 mex5、mex6 文件与 Simulink C Function 的关系

资源里出现 mex5、mex6 文件,这是作者按 MATLAB 版本区分编译出来的 S-Function MEX 文件。MEX 文件在 MATLAB 中执行速度快于纯 M 文件,适合把 S-Function 函数体编译成本地代码。如果本地 MATLAB 版本是 64 位,旧版 32 位 MEX 文件往往无法直接加载,需要重新编译。

常见做法是先把 shark.m 按 Level-2 S-Function 规范写成模板,再用 mex 命令编译 C 版本,或直接使用 Simulink 内置的 C Function 模块。在较新的 MATLAB 版本中,C Function 模块可以直接指定 C 源码文件并填写函数签名,省去手工编译 MEX 的复杂性。对于这套 AUV 仿真资源,我建议先跑 M 文件版本,确认模型行为符合预期后再尝试编译 C 版本,这样能把数学错误与编译问题分开排查。

S-Function 类型速度适合场景主要问题
Level-1 M-file简单演示无状态端口扩展
Level-2 M-file本资源 shark.m步长较小时性能不足
C MEX长时间仿真、硬件在环跨版本需重编译
C Function 模块新版本 Simulink需要手动管理代码文件

3.4 附加质量对响应曲线的实际影响

附加质量矩阵在 shark.m 中用 added_mass(veh) 函数计算,一般取对角阵,只保留 u、v、w、p、q、r 六个方向的主项。对于细长型 AUV,纵向附加质量大约是自身质量的 5%~15%,横向和垂向的附加质量更大。实际调试时,可以比较开环响应曲线来判断取值是否合理:如果阶跃响应上升速度明显偏离水池实验数据,优先调整附加质量而不是控制增益。

注意:mex5 与 mex6 这类文件名没有官方标准含义,通常是作者为区分 MATLAB 版本生成的。一切以 source 目录下的 .c 和 .m 源码为准。

4. 运行 shark demos.m 与构建 Simulink 仿真环境

4.1 先处理文件名和路径问题

原资源中有一个文件叫 shark demos.m,文件名里带空格。MATLAB 对带空格的脚本支持不友好,直接键入文件名会被解析为命令语句。我建议先复制一份并重命名为 shark_demos.m,然后放到已加载的路径下。

% shark_demos.m 的推荐初始化头部 function shark_demos() % 添加 source 和 doc 子目录到路径 addpath(fullfile(pwd, 'source')); addpath(fullfile(pwd, 'doc')); % 加载 AUV 参数到 base workspace veh = vehicle(); assignin('base', 'veh', veh); % 打开并运行主模型 open_system('Shark_AUV_Demo.slx'); sim('Shark_AUV_Demo.slx'); end

这段代码先把 source 子目录加入 MATLAB 搜索路径,再把 vehicle 结构体写入 base workspace。这样 Simulink 模型内部如果通过 eval 或 .m 脚本读取 veh 变量,就能直接拿到参数。注意 assignin 写入 base workspace 是必要操作,因为 S-Function 初始化阶段默认在 base workspace 查找参数,如果只在函数内部定义 veh,模型初始化会报“未定义变量”。

4.2 Simulink 模型内部结构拆解

Shark_AUV_Demo.slx 的典型信号链路是 Reference → Controller → tau → S-Function → eta → Sensor → Scope。模型里至少包含五个模块组:

  • Motion Plant:S-Function 模块,对应 shark.m,输入控制力和扰动力,输出位置姿态
  • Controller:MATLAB Function 或另一路 S-Function,计算推进器推力
  • Reference:阶跃信号或深度剖面生成器,用来给定目标值
  • Sensor:测量模块,把真实状态转换为带噪声的测量值
  • Scope / To Workspace:记录仿真数据,保存到 tout 和 yout

在模型中调整控制器参数时,不要直接在条件子系统里改常量,而应把 PID 系数放到 MATLAB 工作区变量里,用 set_param 或模型回调统一管理。这样后期做批量参数扫描时只需要修改一个脚本,不需要反复打开模型窗口。

4.3 求解器、步长和模型回调参数

AUV 仿真里的主要时间常数来自推进器响应和浮力恢复力矩,一般比飞行器慢得多,步长可以适当放大。但加入高频传感器噪声或滑模控制器后,模型会变刚,需要切换到隐式求解器。

求解器步长设置适用阶段
ode450.01~0.1模型初调、理论验证
ode23t自适应加入非线性扰动后
ode4固定 0.01硬件在环、实时仿真
ode15s自适应模型出现刚性发散

如果仿真停在某个固定时间点不前进,或输出曲线出现锯齿,先看是否使用了固定步长配合连续 S-Function。更稳妥的做法是在模型属性回调中使用 set_param 统一配置停止时间和求解器。

% 模型回调或脚本中设置仿真参数 set_param('Shark_AUV_Demo.slx', 'SolverType', 'Fixed-step'); set_param('Shark_AUV_Demo.slx', 'Solver', 'ode4'); set_param('Shark_AUV_Demo.slx', 'FixedStep', '0.01'); set_param('Shark_AUV_Demo.slx', 'StopTime', '120');

这段命令把模型切换为固定步长 ode4,每步 0.01 秒。固定步长仿真虽然精度相对自适应求解器低一些,但结果可以离线回放,也能直接用 Simulink 的代码生成功能导出 C 代码,后续做控制器在环测试时不需要改变模型结构。

5. 仿真实战:定深控制、航向保持与传感器噪声注入

5.1 定深控制的推进器映射

AUV 定深控制的最终控制量是垂向推力,推进器模型通常包含饱和限幅。可以写成 MX 函数,输入深度误差和当前俯仰角,输出垂向推力。

function tau_z = depth_controller(depth_ref, depth_now, theta, Ts) persistent err_int err_prev if isempty(err_int) err_int = 0; err_prev = 0; end err = depth_ref - depth_now; err_int = err_int + err * Ts; tau_z = 180 * err + 40 * err_int + 25 * (err - err_prev) / Ts; tau_z = max(-320, min(320, tau_z)); % 推进器饱和限幅 err_prev = err; end

这个控制器是带饱和限幅的 PI-D 结构。比例 180 控制响应速度,积分 40 消除稳态误差,微分 25 抑制超调。输出限幅 320 N 对应推进器最大推力。仿真时如果把深度目标从 20 m 阶跃到 40 m,观察俯仰角是否先抬头再下潜,这是 AUV 定深的标准动作,如果模型只平移下潜,说明动力学耦合里缺少了俯仰恢复力矩。

5.2 航向保持控制与解耦

航向保持用偏航力矩 tau_r 控制。AUV 在定深模式下,偏航控制与深度控制耦合较小,可以独立调试。把航行器转向看作一阶惯性环节加积分器,便可用比例控制加前馈补偿转向阻尼。

function tau_r = heading_controller(psi_ref, psi_now, r_now, veh) err = wrapToPi(psi_ref - psi_now); tau_r = 45 * err - veh.Nr * r_now; end

wrapToPi 把角度误差限制在 [-pi, pi] 区间,避免误差在 ±180° 附近跳变。veh.Nr * r_now 是阻尼前馈项,能补偿偏航阻尼。调试这段代码时,建议把参考航向从 0° 改成 90°,观察是否有明显超调;如果超调超过 20°,在模型里把微分项加回,或在控制律中加入偏航角速度反馈。

5.3 传感器噪声与海流扰动注入

纯仿真跑通后,要在 Sensor 模块中加入噪声,否则控制器在真实环境中会因测量噪声过大而失稳。可以采用零均值高斯白噪声,深度噪声标准差 0.1 m,航向角噪声标准差 0.5°,并通过 band-limited white noise 模块实现。

场景扰动形式设置方法
定深深度测量噪声 0.1 mSensor 模块加离散白噪声
航向航向角噪声 0.5°Angle 测量后加噪声
航行海流 x 向 0.2 m/s扰动端口输入常值
抗扰海流 y 向脉动使用正弦叠加

海流扰动建议加到第二输入端口,即 6 维扰动信号。用常值海流测试系统鲁棒性,用正弦海流测试控制器的动态响应。加上扰动后再跑一百秒仿真,能看出积分项是否存在饱和,饱和后是否需要 anti-windup。

6. 批量仿真加速与数值稳定性验证

6.1 用 SimulationInput 做参数扫描

定深控制器和航向控制器调好后,下一步验证模型在不同阻尼系数下是否稳定。可以在脚本里用 Simulink.SimulationInput 批量设置 vehicle 参数,循环调用 sim。

% 对 Xu 阻尼系数做扫描 for i = 1:length(xu_list) simIn(i) = Simulink.SimulationInput('Shark_AUV_Demo.slx'); simIn(i) = simIn(i).setVariable('veh.Xu', xu_list(i)); end simOut = sim(simIn, 'ShowProgress', 'off');

把参数放在 SimulationInput 中而不是直接 assignin,能避免循环中工作区变量被覆盖。电脑核心多时,可以把 sim 换成 parsim,并行执行所有扫描任务,但要注意 vehicle 结构体里如果有随机噪声种子,需为每次仿真设定不同随机数,避免结果完全相同。

仿真完成后,用最小二乘拟合深度响应曲线,计算超调量和调整时间,并把结果汇总到表格中,就能快速判断阻尼变化对控制品质的影响。

6.2 数值稳定性验证策略

在做下一组仿真前,先跑一段 5 秒开环仿真,观察速度导数和位置导数是否出现 NaN 或 Inf。出现数值发散时,优先怀疑力矩矩阵 M 是否奇异。把 M 矩阵输出到 MATLAB,用 cond() 检查条件数,如果条件数大于 1e12,说明附加质量设置不合理,需要减小附加质量或改用伪逆求解。

另一个常用验证方法是能量检查。把仿真结果中的动能和势能提取出来,加上耗散功,总能量应当随时间缓慢下降,绝不应该持续增长。能量曲线持续上升大概率是阻尼矩阵符号写反,维修时把对手的阻尼系数取反即可。把这些检查项写进模型的 InitFcn 回调,下次改完参数重新跑一遍,就能立刻看出哪个设定值在破坏仿真。

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

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

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

立即咨询