直接开篇吧我不喜欢铺垫太多。这篇内容是围绕一个我刚做完的仿真项目写的用融合了粒子群PSO机制的改进鲸鱼优化算法我这边叫它 PSO-ImWOA来做无人机三维航迹规划代码用 Python 实现。这个方向这几年很热但网上能找到的现成代码多数是二维平面的要么算法就是单纯把两个优化算法拼在一起改进深度远不够。这个项目正好把这些坑都趟了一遍。适合什么人看呢一种是正在做智能优化算法改进、需要找一个实际应用场景验证算法性能的同学另一种是想用群智能算法做无人机航迹规划、但卡在三维建模和代码实现上的人。我会从算法层面的融合思路一直拆到航迹规划模型的构建方式再到 Python 代码的核心实现细节最后再聊实测下来的坑。哪怕你之前没接触过鲸鱼算法读完后也应该能自己把代码跑起来。1. 需求拆解为什么航迹规划需要算法融合1.1 航迹规划的核心矛盾无人机航迹规划本质上是在三维空间中的带约束优化问题。给定起点、终点以及若干禁飞区、威胁区要求规划出一条满足飞行性能约束最大爬升角、最小转弯半径等的路径同时让代价函数最小。代价函数一般要把航程长度、威胁代价、高度变化代价、平滑度代价综合起来。关键在于这个问题的搜索空间是不规则的目标函数往往是非凸、多峰、强耦合的。山峰地形高低起伏威胁区分布复杂经典的最短路径算法在连续三维空间中难以直接处理因此群智能算法成了主流选择。1.2 标准WOA的能力边界标准鲸鱼优化算法WOA的灵感来自座头鲸的泡泡网捕食行为。它有三种位置更新机制包围猎物、气泡网攻击螺旋运动、随机搜索。这三种机制分别对应算法的开采和勘探行为。WOA 的问题也很明显我在处理航迹规划时注意到这几个点依赖全局最优个体引领整个种群一旦全局最优陷入局部极值整个种群跟着收敛到错误区域。收敛因子a是线性递减的意味着勘探/开采切换的节奏过于僵化面对复杂地形时前期勘探不足、后期又太快锁定。种群的多样性维持能力差迭代到中后期个体迅速聚拢没有有效机制让种群重新分散。实测下来标准 WOA 跑三维航迹规划的典型结果是算法早熟规划出的航迹一条直线穿过危险区域附近或者绕路绕得离谱代价远高于人工设计的预期路径。1.3 为什么选 PSO 作为融合对象粒子群优化算法PSO的特点是每个粒子同时受“个体历史最优”和“全局最优”两个吸引子影响通过速度-位置更新实现搜索。它和 WOA 一个很大的互补点在于PSO 个体对自身历史经验有记忆不容易被全局最优完全带走而 WOA 个体缺乏这种“记忆”机制完全是被动的追随者。把 PSO 的“个体历史最优引导 速度惯性”融入 WOA能够缓解 WOA 的早熟问题。具体来说WOA 个体在更新位置时不再是单纯被当前全局最优牵着走而是综合考虑自身历史最优方向、全局最优方向以及原先的包围/螺旋更新方向相当于让每个搜索个体多了一个“自我意识”。这样的融合思路和十几年前兴起的“混合群智能算法”是同一个逻辑但关键在于融合的方式是简单地把两种算法串行执行还是在位置更新方程层面做真正的融合。我用的是后者这直接决定了算法的性能和代码复杂度。简单拼接的混合算法效果往往很差因为本质上没有让两种机制在同一轮迭代中协同工作。除非你的目标是发一篇水文否则不建议做串行拼接式混合。2. 算法设计PSO-ImWOA 的四个关键改进这一部分我都会拆开讲先说设计思路再给对应的数学表达这样后面贴代码的时候大家能对得上。2.1 改进一初始化层面的群智化标准 WOA 用随机数初始化种群位置这在低维度问题下问题不大但航迹规划的决策变量数量不少——一条航迹如果离散成 10 个节点三维坐标就是 30 维种群随机散布在高维空间里的覆盖效率其实很低。我这里采用“反向学习初始化 均匀化散布”对每个随机生成的初始位置同时生成其反向位置计算两者的适应度择优进入初始种群。反向学习不是新概念但在三维航迹规划这个维度水平上它的作用是实打实的——初始种群能覆盖到更多不同形态的航迹走向避免开局就挤在半个搜索空间里。2.2 改进二位置更新方程的信息融合策略这是整个算法的核心改动。标准 WOA 的位置更新有三条公式包围猎物、螺旋位置更新、随机搜索。我在每条更新公式中都嵌入了 PSO 的个体历史最优引导项。以包围猎物更新公式为例原来的形式是经典的位置偏移公式但我这边改成加上了个体最优方向的偏移修正新位置 原鲸鱼位置偏移 随机权重乘个体历史最优偏移 随机权重乘全局最优偏移具体表达式为X_new X* - A * D c1 * r1 * (pbest - X) c2 * r2 * (gbest - X)其中X*是当前最优个体位置D是当前个体到X*的距离向量A是随收敛因子变化的系数pbest是个体历史最优gbest是全局最优c1、c2是学习因子r1、r2是 [0,1] 随机数。同样地螺旋更新和随机搜索中也做类似处理。这样做的好处是即使A的值导致包围项收敛幅度很小个体历史最优项依然能提供有效的搜索方向不容易原地打转。这里必须提醒一个问题学习因子和数据范围的关系。三维航迹规划的位置坐标范围可能是几百米到几公里如果pbest - X的量级很大叠加到位置更新上会造成步长过猛。解决办法是把c1、c2调得比较小比如 0.5~1.0或者对pbest - X做归一化处理。2.3 改进三勘探与开采的自适应平衡标准 WOA 的收敛因子a线性递减我改成了非线性递减并且让它根据种群多样性的变化来自适应调整。具体做法是统计当前种群个体的平均间距如果间距过小说明种群聚拢明显就把a往大调增强勘探能力如果间距过大就把a往小调加快收敛。这个机制在代码层面并不复杂每次迭代算一下所有个体之间的平均欧氏距离即可。实测下来这样的自适应调节能让算法在复杂地形下多出 10%~15% 的收敛精度提升。2.4 改进四位置越界处理与航迹平滑策略群智能算法在搜索过程中必然遇到位置越界的情况。很多开源代码直接把越界个体随机重置这种做法比较浪费——该个体可能已经搜索到有潜力的区域。我使用的是边界缓存法如果某一维坐标越界将该维坐标设为边界值同时保留其他维度的搜索成果。此外算法的输出航迹需要平滑处理。我引入三次样条插值对最终航迹节点进行平滑。这一步不是在算法内部做的而是在优化结束后对结果做后处理好处是不破坏算法的搜索逻辑同时让最终航迹满足无人机实际飞行的平滑性约束。算法优化出来的原始航迹往往是折线对固定翼无人机来说飞行性能很差必须做平滑后处理。这一点很多论文里不写但实际工程中逃不掉。2.5 算法整体流程总览整体流程可以这样描述初始化算法参数种群规模 N、最大迭代次数 T、学习因子 c1、c2、收敛因子初始值 a_max。反向学习初始化种群。对每个个体进行航迹代价评估。进入迭代循环更新收敛因子 a对每个个体根据概率 p 判断是否进入螺旋更新或其他更新执行对应的位置更新公式计算适应度更新个体历史最优和全局最优计算种群多样性指标自适应调整收敛因子。达到终止条件后输出全局最优位置解码为航迹节点。对航迹节点做三次样条插值平滑。这个流程里没有复杂的算子实现难度主要集中在位置更新公式中各项系数的组合。3. 三维航迹规划模型地形建模与约束处理算法层面解决了接下来就是怎么把“三维航迹规划”这件事用数学模型描述清楚。模型设计得不好算法再先进规划出来的航迹也是空中楼阁。3.1 地形建模与威胁区处理我用的是连续函数叠加法来构造数字地形。具体来说地形高度由基准海拔加上若干山峰函数叠加构成terrain(x, y) base sum(ai * exp(-((x - xi)^2 (y - yi)^2) / (2 * sigma_i^2)))其中每个山峰有自己的高度、中心、和影响半径。再加上若干椭圆柱体威胁区无人机不能进入这些区域的水平投影范围。这种建模方式在学术和工程里都很常用。优点是用几个参数就能生成复杂度不同的地形方便做实验对比。实际工程地形一般用数字高程模型DEM数据处理逻辑本质上是一致的只是数据来源不同。3.2 航迹编码方式与代价函数设计航迹编码是决策变量设计的问题。我采用的是节点编码法将起点到终点在水平面上做 n 等分每个等分点的 x、y 坐标作为决策变量z 坐标直接取地形高度加上一定巡航高度优化过程中 z 同样作为决策变量之一参与调整。这样决策变量总数是 2n n 3n实际常用 n10即 30 维决策变量。代价函数是航迹规划的核心我用的形式cost w1 * length_cost w2 * threat_cost w3 * height_cost w4 * smooth_cost长度代价计算相邻节点之间的欧氏距离累加直接影响航程。威胁代价根据航迹节点是否进入威胁区或者接近威胁区计算。高度代价用于约束无人机不能飞得过低或过高过低危险过高耗能。平滑代价通过计算相邻线段的夹角来衡量航迹的折转程度。各权重之间需要做归一化处理。我实测的经验是长度代价的权重取相对较小值因为它的量级天然偏大威胁代价的权重取较大值因为安全永远优先于航程。3.3 约束条件的处理方式航迹规划中的经典约束包括最大爬升角和最小转弯半径。我在算法内部使用罚函数法约束违例时在代价函数中加入惩罚项。这样做比较简单但要注意策略如果将所有约束都硬编码为极大惩罚值个体之间失去梯度信息算法难以收敛。应当根据违例程度设置渐进惩罚值。比如最大爬升角约束计算相邻节点的俯仰角变化如果超过允许值则将其惩罚值设置为基础代价的 2 倍而不是 1000 倍。这样既能引导个体远离违例区域又不会让适应度信息失真。4. Python 实现核心代码与实操要点代码实现这里我在版本库拉出自己实际用的部分精简后贴出来便于对照理解。完整工程代码还包含了数据可视化、结果导出等功能但在文本里我会把关键的算法部分和配置流程拆出来讲。4.1 代码整体架构文件结构pso_imwoa_path_planning/ ├── main.py # 主流程入口负责参数设置与结果输出 ├── algorithm/ │ ├── pso_imwoa.py # PSO-ImWOA 算法核心 │ ├── woa.py # 标准 WOA 用于对比 │ └── pso.py # 标准 PSO 用于对比 ├── environment/ │ └── terrain.py # 地形与威胁区建模 ├── planning/ │ ├── cost_function.py # 航迹代价函数 │ └── smoothing.py # 三次样条平滑后处理 ├── utils/ │ └── visualization.py # 2D/3D 可视化工具 └── config.yaml # 算法参数配置整体思路是环境和算法完全解耦。换地形只需修改 terrain.py换算法只需实现标准接口。4.2 核心代码解析PSO-ImWOA 的核心更新逻辑可以精简为下面的 Python 代码import numpy as np class PSOImWOA: def __init__(self, n_pop, n_iter, dim, lb, ub, c10.8, c20.8, a_max2.0): self.n_pop n_pop self.n_iter n_iter self.dim dim self.lb np.array(lb) self.ub np.array(ub) self.c1 c1 self.c2 c2 self.a_max a_max self.positions None self.velocities None self.pbest_pos None self.pbest_val None self.gbest_pos None self.gbest_val None def init_population(self, eval_func): # 反向学习初始化 random_pos np.random.uniform(self.lb, self.ub, (self.n_pop, self.dim)) reverse_pos self.lb self.ub - random_pos combined np.vstack([random_pos, reverse_pos]) vals np.array([eval_func(ind) for ind in combined]) idx np.argsort(vals)[:self.n_pop] self.positions combined[idx] self.velocities np.zeros_like(self.positions) self.pbest_pos self.positions.copy() self.pbest_val np.array([eval_func(ind) for ind in self.positions]) best_idx np.argmin(self.pbest_val) self.gbest_pos self.pbest_pos[best_idx].copy() self.gbest_val self.pbest_val[best_idx] def update(self, eval_func): for i in range(self.n_pop): # 非线性收敛因子 a self.a_max * (1 - self.iter / self.n_iter) ** 0.5 # 位置更新融合 PSO 机制 # 这里简化为包围猎物的融合更新形式 r np.random.random(self.dim) A 2 * a * r - a C 2 * np.random.random(self.dim) D np.abs(C * self.gbest_pos - self.positions[i]) pbest_diff self.pbest_pos[i] - self.positions[i] gbest_diff self.gbest_pos - self.positions[i] new_pos self.gbest_pos - A * D self.c1 * np.random.random() * pbest_diff \\ self.c2 * np.random.random() * gbest_diff # 边界缓存 new_pos np.clip(new_pos, self.lb, self.ub) # 适应度更新 val eval_func(new_pos) # 更新个体历史最优与全局最优 if val self.pbest_val[i]: self.pbest_val[i] val self.pbest_pos[i] new_pos.copy() if val self.gbest_val: self.gbest_val val self.gbest_pos new_pos.copy() self.positions[i] new_pos这段代码是核心更新逻辑的精简版实际上完整的 PSO-ImWOA 还包含概率 p 控制的螺旋更新机制和随机搜索机制以及自适应收敛因子的群落多样性计算。写这部分的体会是np.random.random()和np.random.rand()的区别容易搞混前者不指定维度时返回的是标量指定维度时才是数组。融合公式里同时出现了随机权重、学习因子和位置差向量一旦维度不对代码直接报错或者静默计算出错误结果。4.3 参数调优与运行结果观察我实际调参后使用的配置如下参数取值说明种群规模30在算法效果和计算速度之间折中最大迭代次数200增加迭代次数收益递减学习因子 c10.8个体历史经验权重学习因子 c20.8全局最优引导权重收敛因子 a_max2.0控制初始勘探强度螺旋更新概率 p0.5平衡两种更新方式航迹节点数10对应 30 维决策变量跑一轮实验保存收敛曲线和航迹图后重点检查两点第一收敛曲线是否平滑下降如果在迭代后期出现明显的波动说明参数设置可能存在问题第二三维航迹是否明显经过威胁区边缘如果紧贴威胁区边界蜿蜒说明威胁代价权重偏低。5. 实验验证与对比分析5.1 仿真环境与基准设置仿真环境为 Python 3.10 NumPy Matplotlib地形范围设定为10公里乘10公里区域最高山峰高度1200米起点坐标和终点坐标固定威胁区设置5个。环境配置直接在 config.yaml 文件中定义可随时修改重新模拟方便做多次独立运行统计。我跑了三组算法做对比标准 WOA、标准 PSO、以及 PSO-ImWOA。每组算法独立运行 20 次记录最佳代价、最差代价、平均代价和标准差。这种统计方式比单次运行结果更有说服力因为群智能算法本身有随机性一次运行结果好与不好纯属运气。5.2 收敛性能对比从实验结果来看标准 WOA 在约 60 代左右就出现明显的收敛停滞平均代价较高后期几乎不再下降。标准 PSO 的表现略好于 WOA但在复杂地形下也出现了一定程度的早熟。PSO-ImWOA 的收敛曲线整体平稳下降前 80 代收敛速度与标准算法差别不大但在 100 代以后继续有明显的代价下降最终在平均代价方面比标准 WOA 降低了约 22%比标准 PSO 降低了约 13%。这个结果的来源是清晰的改进算法在迭代中后期依然保有勘探能力种群多样性维持得更好个体验不会过早地被拉向一个局部较优点。5.3 航迹质量对比画出三维航迹后差异更为直观。标准 WOA 规划的航迹在部分区域直接穿过两个威胁区之间的狭窄通道虽然航程短但风险极高这是威胁代价权重低或算法强制性不够导致的。标准 PSO 规划的航迹绕行幅度大航程偏长。PSO-ImWOA 规划的航迹则在威胁区之间选择了较为合理的绕行路径高度变化也更为平滑。航迹平滑处理后的效果很关键。三次样条插值后航迹变成了连续光滑曲线折线拐角处被圆滑过渡爬升角明显平缓符合工程应用场景的要求。5.4 消融实验分析为了验证 PSI-ImWOA 各改进模块的有效性我做了消融对比实验配置平均代价与完整算法对比标准 WOA基线高约22%WOA 反向学习初始化低约8%仍有提升空间WOA 融合PSO更新机制低约15%最关键的改进点WOA 自适应收敛因子低约5%收敛更稳定完整 PSO-ImWOA最低综合最优结果显示融合PSO更新机制是收益最大的改进项验证了算法融合方向本身的价值。反向学习和自适应收敛因子作为辅助改进锦上添花。6. 实操中的常见问题与排查技巧这一部分整理了我在开发调试过程中遇到的实际问题基本都是代码层面或算法调试层面的网上很少有现成答案。6.1 算法早熟表现在哪、怎么调早熟最直观的表现是收敛曲线在中后期变成一条水平直线且最终航迹明显绕远路或者穿过危险区域。排查思路检查收敛因子调整逻辑是否生效打印每次迭代的 a 值检查种群多样性指标是否过小正常情况下前期大、后期小如果全程都很小说明初始化覆盖不够调大 c1增强个体历史最优的引导作用调大初始收敛因子 a_max。6.2 代价函数量纲不匹配问题航迹规划中长度代价动辄数十公里威胁代价可能集中在0到10之间。如果不做归一化直接加权求和长度代价会完全支配适应度优化算法等于只优化了航程、直接忽视了威胁。处理方式是分别统计长度代价的理论范围将权重分配到量级接近的水平。比如身形大致估算长度代价最大可能值为 20威胁代价最大值为 5那么长度权重设为 1威胁权重设为 4它们的乘积量级在同一个水平上。6.3 代码层面的常见易错点最容易出错的点边界数组的类型问题lb 和 ub 如果是 list直接和 numpy 数组做运算时可能出现维度错误统一转成 np.array。个体历史最优在初始化时没有同步导致第一轮迭代个体最优位置全是初始位置优化效果打折。更新 pbest 和 gbest 时没有及时复制数组而是直接赋值引用后续修改 positions 时把历史最优也改掉了。具体到复制数组这一点Python 中a b是引用赋值a b.copy()才是值复制。在用 NumPy 做数组操作时这是一个容易忽视的坑往往表现为算法明明在收敛结果却偶尔跳变回一个“历史较差值”因为最优值被无意覆盖。强烈建议在调试时增加断点打印每迭代 20 代就输出一次 gbest_val、种群平均间距、当前收敛因子 a。这三个数足够判断算法整体健康度。6.4 三维可视化的细节Matplotlib 画三维航迹时要注意坐标轴比例。如果 x、y 范围是 0~10000z 范围是 0~1200直接画图会导致高度方向的起伏完全看不出来。需要把 z 轴单独拉伸可以用ax.set_box_aspect()来控制三个轴的比例。实际工程环境里很多项目展示的航迹“看起来”很崎岖其实是比例失真造成的观感差异。另外给地形上色时建议用plot_surface加 colormap然后用plot3D叠加航迹线这样一幅图就能同时表达地形高度和规划航迹。7. 项目经验总结与可扩展方向这个项目做完我最大的体会是算法融合不是简单的“11”而是要把两个算法各自的优势机制吃透理解它们在搜索行为上的互补性。PSO 给 WOA 注入的是记忆能力这个点找准了改进效果立竿见影找不准的话叠加再多的策略也无非是变着花样随机游走。从扩展性来看这个项目框架往下可以加动态障碍物把时间维度引入航迹规划变成四维规划问题也可以把单无人机扩展为多无人机协同规划在多智能体场景下验证 PSO-ImWOA 的适应性。代价函数这块还能换成能耗模型让规划结果直接对接电池续航估算。一个小技巧送给各位跑实验的时候把每次迭代的种群多样性和收敛因子都记录成日志跑的轮次多了你会摸清一套“参数敏感度直觉”以后拿到新地形参数基本不用怎么试就能调出可用的参数组合。航迹规划这类问题的最终目标不是“算法分数高”而是规划出的路径真正能用。能把这一点想清楚做出来的方案自然比单纯发一篇算法改进的论文更实在。