MMG船舶操纵模型:仿真实现与航向控制实战解析
发布时间:2026/9/13 4:38:49 作者:尧图编辑部 阅读量:1,286

简介这是一个面向船舶运动控制学习者的MMG模型可视化仿真项目。MMG方法可综合模拟复杂海况下船舶纵向、横向、垂荡及横摇、纵摇、艏摇等六自由度运动项目通过Python实现核心仿真逻辑配合Web前端动态展示不同风浪、流速、舵角、载荷条件下的船舶状态便于学习者直观理解船舶运动规律与控制参数的影响。压缩包共28个文件主要包含Python仿真脚本、HTML/CSS/JavaScript可视化页面、模型参数、说明文档及少量字体和样式辅助文件整体459KB结构精简适合快速下载并运行。资源提供完整源代码、仿真脚本、参数文件和README文档既可支撑课程实验也可作为船舶运动控制算法验证与二次开发的基础使用者还能在可视化界面中手动调节不同工况参数实时观察船位、速度与姿态变化加深对船舶操纵性的理解。目前已有901人学习适合船舶与海洋工程、自动化控制相关方向的初学者和工程师参考实践。1. 从模拟器里那艘“发飘”的船说起在航海模拟器里调试自主靠离泊算法时最容易遇到的一种现象是船速降到 2 节以下你给舵船头几乎不动等个三秒钟船突然开始大幅转头回头修正又过了头。这时候模型里的“舵力响应”和真船行为对不上问题基本出在建模方式上——你用的是一阶惯性加纯延迟的简化模型而不是把船体、螺旋桨、舵三者受力拆开算的 MMG 模型。MMG 模型全称 Maneuvering Modeling Group是日本造船学会在 20 世纪 70 年代提出的船舶操纵运动数学模型。它把一个完整的船舶运动控制系统拆成裸船体、螺旋桨、舵三块独立受力再通过叠加耦合还原整体运动。这套思路早期用于实船操纵性预报后来被航海模拟器、自动舵研发和动态定位系统大量吸收。ship_mmg-master 这类项目在 GitHub 上之所以长期有人下载就是因为它给出了一个能直接改参数、能接控制器的 MMG 仿真骨架。这篇文章就顺着这个模型讲清楚坐标系怎么定、三个力怎么算、代码怎么写、闭环怎么调。2. 坐标系与运动量先把“船往哪走”这件事量化2.1 大地坐标系与随船坐标系的关系MMG 模型里有两个坐标系同时存在。地面坐标系 (O_0 - X_0Y_0) 固定在海面上用来记录船的位置和轨迹随船坐标系 (G - xy) 固连在船体上原点通常取在重心或重心投影x 轴指向船首y 轴指向右舷。两个坐标系在水平面内的相对旋转角度是艏向角 (\psi)。状态量的分工很明确(X_0, Y_0, \psi) 描述船在空间里的位置和姿态(u, v, r) 描述船体本身的运动速度。(u) 是纵向速度沿着船首方向(v) 是横向速度沿着右舷方向(r) 是转艏角速度。这里有一个常见混淆仿真结果里输出的经纬度或者屏幕坐标来自大地坐标系的积分而控制律中误差计算用的船速和侧向速度必须来自随船坐标系。两者之间靠一个旋转矩阵关联# 从随船速度转到大地坐标速度 psi state[2] u, v state[3], state[4] x_dot u * math.cos(psi) - v * math.sin(psi) y_dot u * math.sin(psi) v * math.cos(psi) psi_dot state[5]这段代码对应的物理含义可以从船速的合成来看当船不是正对着船首方向移动时比如有横漂、有风压(u) 和 (v) 的向量和才是船相对于大地的真实速度方向。把速度向量右手旋转一个角度 (\psi)就得到了大地坐标下的分量。对刚接触 MMG 的人我一般会建议先把这一步单独抽出来做单元测试——很多“船在图上斜着走”的 bug最后查下来往往是坐标系旋转方向写反了。2.2 状态量的选取与自由度取舍MMG 模型的自由度可以按研究目标裁剪。只做水平面运动控制三自由度就够纵荡surge、横荡sway、艏摇yaw。要考虑横倾造成的横向力变化要加第四自由度横滚roll方程涉及波浪中的垂荡和纵摇就要做到六自由度。ship_mmg-master 这类基础项目通常落在三到四自由度代码结构上会把状态量写成六维数组或字典其中三个位置量、三个速度量便于后续向全自由度扩展。自由度选取直接决定计算量。三自由度模型的每个时间步只需解 3 个耦合微分方程适合做实时仿真和控制器在环测试六自由度模型要考虑波形、遭遇频率、附加质量随频率变化计算开销大一到两个数量级。对于控制算法的初步验证三自由度 MMG 是性价比最高的选择。它的精度足以反映船舶操纵运动的核心特征——回转、Z 形操纵、横漂——同时又不会因为水动力系数的缺失让仿真完全失真。2.3 动力学方程的标准形式MMG 的动力学方程本质是牛顿第二定律在船体上的投影。考虑水平面三自由度方程写成如下形式[ (m m_x)\dot{u} - (m m_y)vr X ][ (m m_y)\dot{v} (m m_x)ur Y ][ (I_{zz} J_{zz})\dot{r} N ]这三个方程的输出是加速度 (\dot{u}, \dot{v}, \dot{r})输入是三部分力矩之和 (X, Y, N)。左边出现的 (m_x, m_y, J_{zz}) 是附加质量它的物理意义是船体加速运动时周围的水也会被带着加速这部分水折算到船体质量上会让船看起来“变重”。一艘 20 万吨的散货船纵向附加质量可能达到排水量的 5% 左右横向附加质量能达到 30%~50%不能忽略。方程右边的 (X, Y, N) 是 MMG 模型的精髓所在。它们分别是[ X X_H X_P X_R ][ Y Y_H Y_P Y_R ][ N N_H N_P N_R ]下标 (H) 代表裸船体水动力(P) 代表螺旋桨产生的力(R) 代表舵产生的力。在仿真主循环里这就是一个求和的动作但在建模层面每个力的表达式展开后都有五到十项且部分项之间存在耦合影响。为什么 MMG 能比整体模型Abkowitz 模型更受工程欢迎因为它的三部分用力是独立建模的——改一个舵型只需要动 (X_R, Y_R, N_R) 这组函数不用重新辨识整艘船的水动力系数这对工程迭代来说非常友好。3. 三部分力的核心计算船体、螺旋桨、舵各自在干嘛3.1 裸船体水动力惯性力与阻尼力裸船体这一部分在 MMG 里是基础。常见做法是把水动力按不同的物理机制拆开与加速度相关的是附加质量力与速度非线性相关的称为粘性阻尼力。在速度较低场景横向阻尼主要是由船体底部和舭部的涡流引起的与 (v) 和 (r) 的乘积项相关所以方程里会出现形如 (Y_H Y_v v Y_r r Y_{vv} v|v| \cdots) 的展开式。ship_mmg-master 这类开源项目为了减少参数标定负担通常使用线性加非线性项截断的形式。船在直航时 (v) 很小横荡和艏摇的线性阻尼项就足够但在回转中横向速度可能达到船速的 25% 以上线性的 (Y_v v) 会严重偏低必须保留平方非线性项 (Y_{vv} v|v|)。实际调试时这里经常出现一个现象直航稳得住一转舵船就“飞出去了”多半就是非线性阻尼系数取值偏小。还有一个容易被忽略的项是 (u) 和 (v) 的耦合。方程左边的 ((m m_y)vr) 和 ((m m_x)ur) 并不是真正的力而是坐标变换产生的惯性耦合项。它们在高速回转时贡献很大。比如一艘集装箱船以 25 节航速做满舵回转横向速度达到 8 节时(ur) 项产生的等效横向力可达排水量的十分之一。控制算法里如果不考虑这个耦合仿真的回转半径会比实船数据大不少。3.2 螺旋桨力推力计算与伴流系数的处理螺旋桨的推力通常表示为[ X_P (1 - t_P) \rho n^2 D_P^4 K_T(J) ]其中 (t_P) 是推力减额系数表示螺旋桨抽吸作用对船尾流场的影响会让船体阻力增加的部分不能转化为有效推力(n) 是螺旋桨转速(D_P) 是螺旋桨直径(K_T) 是推力系数它是进速比 (J) 的函数。进速比定义为[ J \frac{u(1 - w_P)}{n D_P} ]这里 (w_P) 是伴流系数它描述船体边界层对螺旋桨前方来流的减速效应。这个系数对低速工况影响特别明显——船几乎停的时候螺旋桨前方水流已经很慢(J) 趋近于零(K_T) 明显上升推力也变大。这就是为什么靠泊时给很小一个车钟指令螺旋桨推力比中速时按比例算出来的要大得多。在代码实现中(K_T) 曲线通常用一个多项式拟合。仿真时要特别关注 (n) 的正负号处理倒车时 (n) 为负(K_T) 曲线不再对称正车和倒车的推力系数曲线是完全不同的用同一个多项式会出大偏差。另外MMG 框架中螺旋桨对横向力和艏摇力矩的直接贡献很小它的主要作用是通过改变船尾流场影响舵的来流速度——这一点是理解随后舵力计算的钥匙。3.3 舵力为什么舵不只产生“转船力矩”舵力计算是 MMG 模型里 IP 保护最重、也最复杂的一块。舵的升力和阻力在随船坐标系下分解既产生纵向阻力 (X_R)也产生横向力 (Y_R) 和转艏力矩 (N_R)。许多初学者会把舵力简化成一个纯横向力乘以力臂这在舵角小于 10 度时误差尚可但大舵角下纵向阻力分量的贡献变得不可忽视。舵力的一般表达式为[ Y_R -\frac{1}{2} \rho A_R U_R^2 C_L(\alpha_R) \cos \delta ][ X_R \frac{1}{2} \rho A_R U_R^2 C_D(\alpha_R) \sin \delta ]其中 (A_R) 是舵面积(U_R) 是舵处的有效来流速度(\delta) 是舵角(\alpha_R) 是舵的有效攻角(C_L, C_D) 是升力与阻力系数。这里的 (U_R) 不是船速 (u) 本身。螺旋桨尾流在舵处会显著加速水流常用的经验公式是[ U_R \sqrt{u_P^2 C_{R} \cdot u_{P} \cdot \Delta U} ]其中 (\Delta U) 是螺旋桨尾流增量与推力载荷相关。这部分修正直接决定低速时的舵效。船舶停车淌航时螺旋桨转速低(\Delta U) 小舵处来流速度低舵效差——这是实际操船中尽人皆知的经验在 MMG 里就是通过这个公式定量还原的。还有一处典型处理是舵的整流作用舵位于螺旋桨后方实际上会吸收一部分螺旋桨尾流的旋转能量使得舵力效率高于单独舵的试验值工程上常用等效舵面积系数来近似这个效果。下表列出三部分力在典型参数下的相对量级以一条 70m 巡逻船、航速 15 节、中等舵角为例力的来源纵向力 (N)横向力 (N)备注裸船体约 6.0e4阻力约 1.5e4非线性阻尼直航时横向力近零螺旋桨约 8.0e4推力可忽略倒车时纵向力反向舵约 8.0e3阻力增量约 7.0e4大舵角下阻力增量显著这套量级关系给控制器调参提供了一个判断依据低速大舵角工况下船体横向阻尼力本身就在下降如果舵力模型没考虑螺旋桨尾流加速仿真出来的舵效会弱闭环控制的舵角指令会偏大容易触发饱和。4. 用 ship_mmg-master 搭一个可跑的三自由度 MMG 数值仿真4.1 项目结构里最值得优先读的三个文件拿到 ship_mmg-master 之后不要先看 README先按依赖关系打开三个文件定义船型参数的参数文件、计算三部分力的水动力模块、主仿真循环入口。参数文件里关注三个类别船舶主尺度船长、船宽、吃水、排水量、附加质量与阻尼系数、螺旋桨与舵的几何参数。水动力模块则展示了模型中每一部分力如何用这些参数拼出数值。主循环则告诉你状态更新用的是欧拉法还是龙格库塔法——这对仿真步长的选择有直接影响。如果这个项目用的是欧拉法那状态更新就是最直观的形式# 主仿真循环欧拉法示意 while t t_end: Xu, Yu, Nu hull_force(state) # 裸船体力 Xp, Yp, Np propeller_force(state) # 螺旋桨力 Xr, Yr, Nr rudder_force(state) # 舵力 X_total Xu Xp Xr Y_total Yu Yp Yr N_total Nu Np Nr # 求解加速度 u_dot (X_total (m my) * v * r) / (m mx) v_dot (Y_total - (m mx) * u * r) / (m my) r_dot N_total / (Izz Jzz) # 欧拉积分更新状态 state[3] u_dot * dt state[4] v_dot * dt state[5] r_dot * dt state[0] (state[3] * math.cos(state[2]) - state[4] * math.sin(state[2])) * dt state[1] (state[3] * math.sin(state[2]) state[4] * math.cos(state[2])) * dt state[2] state[5] * dt这段代码最需要解释的是加速度求解那一行方程左侧的 (vr) 和 (ur) 项被移到了等号右边当作已知量。这要求在同一时间步内先有当前的 (u, v, r)才能算加速度。在欧拉法里这没问题因为用的就是上一步的状态值。但如果在 RK4 的中间步里也这么写就必须把每个子步的即时速度代进去不能复用主步的旧值否则数值误差会累积。4.2 仿真步长怎么选稳定性与计算量之间找平衡仿真步长是这类项目里最“看似简单实则致命”的参数。三自由度 MMG 方程属于中等刚度的常微分方程组船体的大惯性环节响应慢但舵力和突然改变螺旋桨转速引起的加速度突变是快变过程。欧拉法对这类问题的稳定域很窄步长一旦超过某个阈值速度量会开始震荡发散。我一般的做法是先按螺旋桨转速变化的时间尺度预估转速从 0 升到额定值大约需要 5~10 秒但舵角执行机构响应只有 1~2 秒。步长应至少小于最快动态的 1/10也就是 0.1~0.2 秒。实际中取0.01~0.05 秒。用欧拉法时取 0.01 秒比较稳定用 RK4 可以放宽到 0.1 秒。判断标准很简单跑一个零舵角直航 60 秒的仿真观察横向速度 (v) 是否保持在零附近小幅波动如果 (v) 呈锯齿状发散那是步长过大导致的数值失稳不是模型参数的问题。与步长配套的一个细节是输出降采样。仿真内部要以小步长积分保稳定性但记录轨迹和控制指令时不需要每个步长都存否则一个 10 分钟的仿真会产生几十万个数据点画图和处理都不便。控制周期一般取 0.5~1 秒仿真内部仍跑 0.01 秒的步长。4.3 验模第一步零舵角直航和 35 度满舵回转拿到一个能跑通的 MMG 仿真第一个验证动作不是加控制器而是跑两条标准操纵性试验直航稳定性和满舵回转。直航试验的目的是确认模型在无舵角输入时能保持航向稳定如果船自动偏转说明水动力系数中的航向稳定性项主要是 (Y_r) 和 (N_v)配平有问题。回转试验的目的是验证模型的回转能力是否符合预期。对一般排水型船舶满舵 35 度回转的稳定回转半径约为船长的 2.5~4 倍战术直径约为 4~6 倍船长。实操中把舵角指令写成一个阶跃信号记录航向角和回转轨迹然后数出回转半径# 满舵回转试验航向角变化曲线中截取稳定段 # 找到航向角从 0 转到 360 度的时间段用轨迹坐标拟合圆 # 圆的半径即为稳定回转半径 R_c # 与船长 L 对比期望 R_c / L 处于 2.5~4.0 区间当回转半径明显偏大时优先检查裸船体横向阻尼系数中的非线性项 (Y_{vv})以及舵面积和舵的展弦比——这两个参数直接决定能产生多少转艏力矩。当回转半径偏小且初始操舵后船有明显横漂过冲时说明横荡惯性含附加质量参数可能偏小导致船对舵的初始响应过快。这些判断都来自特定参数引起的仿真结果特征变化可以建立“现象—参数”对应关系后续调参会高效很多。5. 接上船舶运动控制闭环航向 PID 与参数整定的实战门道5.1 控制律怎么写除了 PID 还要防积分饱和MMG 仿真骨架最常见的用途是验证自动舵算法。航向控制的标准回路由两部分组成外环是航向误差到期望转艏角速度的映射内环是转艏角速度到舵角的映射。简化实现时只用一个航向 PID 就能工作但要把微分项放在测量值的一阶滞后上而不是直接放在误差上。船在风浪中艏向高频摆动直接对误差求导会把噪声放大进舵令舵机频繁抖动。积分饱和是航向控制里最典型的问题。船在回转中偏航角持续存在积分项持续累积等船回到设定航向时残余的积分值还会让舵保持在一个非零角度船会冲过设定航向形成明显的振荡。解决方法很直接在舵角限幅处做积分钳位当舵角指令已经打满时停止积分项的累加。另一招是给积分项设定一个上限数值上不超过舵角限幅的 30%。# 航向 PID 控制器含积分限幅与微分滤波 error wrap_to_pi(setpoint_psi - state[2]) p_term kp * error integral error * dt integral clamp(integral, -integral_max, integral_max) i_term ki * integral deriv (error - error_prev) / dt d_term kd * lowpass_filter(deriv, tau_d) delta clamp(p_term i_term d_term, -delta_max, delta_max)在仿真中整定这组参数时临界比例度法仍然是最快的起点。把 (K_d) 和 (K_i) 设为零逐步增大 (K_p)直到航向角开始出现持续的等幅振荡记下此时的增益 (K_{u}) 和振荡周期 (T_{u})。然后按经典整定表补上 (K_p, K_i, K_d)。对 MMG 仿真里的排水型船初始值一般落在 (K_p 0.2K_u \sim 0.3K_u) 这个档位。5.2 不同工况下同一个 PID 会失效增益调度是必然选择线性 PID 在仿真里调好了参数换一个初始航速再试很可能控制品质明显变差。原因在于 MMG 模型本身就是强非线性系统。相同舵角下高速时的转艏力矩比低速时大得多舵效“增益”随着船速升高而升高。一个在 12 节航速下调好的控制器拿到 5 节工况会表现得反应迟钝拿到 20 节工况则可能振荡。解决方法是做增益调度。按船速分几个区间低速区、中速区、高速区每个区间单独整定一组 PID 参数然后在运行时根据当前 (u) 插值切换。这个逻辑在船舶运动控制工程里已经被各种实际系统验证过航海模拟器里的自动舵大多也是这么处理的。MMG 仿真正好可以用来测调度表的合理性——在速度突变时观察舵角和航向是否平滑过渡。5.3 验证控制效果时要看的四个关键指标闭环调试完成后光看“船到头”的轨迹是不充分的。我建议在仿真中同时记录四个指标稳态航向误差控制在 1 度以内算优秀、艏向超调量一般要求不超过 10 度、舵角饱和占比整段仿真中舵角到达限幅累计时长占比不宜超过 15%、以及操舵次数反映舵机磨损和能耗。四者是一个矛盾的组合追求极小的稳态误差会逼迫积分项加大进而让超调变大追求小超调需要更积极的微分项但这会放大测量噪声。有一个实用的验证技巧把同一个 PID 参数组分别在直航、10 度小转向、35 度大回转三种场景下跑一遍对比四类指标。如果大回转场景中舵角饱和占比超过 40%说明让控制器在一个无法达成的物理极限里硬挣此时要么减小初始转向命令的角速度限制要么接受更大的瞬态超调。最后检查仿真结束时舵角是否归零、船是否稳定在设定航向上——这两点通过了这套 MMG 仿真和控制器配合就算验证完成。本文还有配套的精品资源点击获取