ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

粒子群算法在多无人机任务分配中的应用:原理、编码与工程实现

粒子群算法在多无人机任务分配中的应用:原理、编码与工程实现

简介:这是一份基于 Python 开发的粒子群算法多无人机任务分配源码,面向计算机、通信、人工智能、自动化等专业的学生、教师及从业者,尤其适合毕业设计、课程设计、期末大作业等场景,帮助解决多无人机编队中任务分配、路径搜索与资源调度等问题。压缩包共 15 个文件,包含 9 个 Python 脚本和 4 张仿真图片,另有说明文档与补充文件,整体仅 1.41MB。代码模块划分清晰,覆盖粒子群迭代、距离计算、适应度评估、条件判断、结果显示等关键环节,经过调试可直接运行,便于快速验证算法效果。目前已有 168 人学习下载,借鉴该资源既能掌握粒子群算法在多无人机任务分配中的完整实现思路,也可根据实际需求修改参数、替换数据或扩展功能模块,具备较高的学习与二次开发价值。

1. 粒子群算法做多无人机任务分配,到底解决什么问题

毕业设计选这个题目的人,通常是手里任务书只写了“多无人机协同任务分配”,打开搜索引擎却发现满屏都是看不懂的公式,或者干脆被论文里的“遗传算法”“蚁群算法”“匈牙利算法”劝退。粒子群算法(PSO)是你性价比最高的选择:原理直观到可以用“鸟群找食物”一句话讲清楚,代码实现只依赖numpy,而且分配结果能画成图放进论文里当创新点。这个源码解决的是典型的“N架无人机、M个任务点,怎么分配让总飞行距离最短、耗能最低、约束不冲突”的组合优化问题。它和调度问题、路径规划问题共用同一套建模思路,适合作为多无人机系统、智能优化算法、任务规划方向的毕设核心模块,也是少数拿得到源码就能跑出图、能继续改出花样的方向。

2. 先立理论:多无人机任务分配如何用手写粒子群解决

2.1 任务分配问题为什么是离散的,PSO却是连续的:编码与映射

多无人机任务分配的标准描述是:有N架无人机,各自从不同起点出发,M个任务点需要被执行,每个任务点只需要被一架无人机访问一次,目标是所有无人机总航程最短,同时满足每架无人机航程上限、任务优先级等约束。这类问题在数学上是NP-hard的,组合爆炸意味着你用穷举法只能跑通5架无人机、5个任务点的小规模算例,而粒子群算法能在几十个粒子的迭代中搜索出工程上可用的近似最优解。

如果你只记这四件事,粒子群的核心就握住了:粒子代表一个候选分配方案;粒子速度代表方案在解空间里移动的方向和步长;个体最优pBest记录每个粒子自己历史上最好的方案;全局最优gBest记录整个种群历史最好的方案。每次迭代,每个粒子都被往pBest方向拉一把、往gBest方向拉一把,同时保留自己原来的惯性。这个机制对应到代码里就是四条更新公式,但你马上会碰到第一个坑:速度更新公式里粒子位置xi是连续实数,而任务分配要输出的是一组离散的“谁去哪个任务”的方案。

常见的做法是用连续值编码位置,再通过优先级解析规则(Smallest Position Value,SPV)把连续向量转成离散的任务序列。举个例子,5个任务点,某个粒子的位置向量是[3.2, 1.7, 4.9, 0.6, 2.3],对值从小到大排序得到任务顺序[4, 2, 5, 1, 3],再把任务序列按断点切给各架无人机。这样连续位置向量能进PSO更新公式,输出的又是合法的离散分配方案。这也是为什么同样是优化算法的热门对比对象——遗传算法天然用排列编码、交叉变异更顺滑,但粒子群胜在参数少、收敛快、代码量小,毕设答辩时你能讲得清楚。

2.2 设计适应度函数:不是只算总航程,还要把约束变成惩罚项

适应度函数是任务分配问题的“裁判”,直接决定算法在找什么。最简单直接的版本是让总航程最小,但真实情况里无人机不是无限续航的,最大航程约束必须进目标函数。常见做法是看一段论文,欠约束时加惩罚项,约束越界则给一个相对很大的惩罚值,避免方案被选为最优。

我一般这样写目标函数:先算所有无人机到其分配任务的路径总长度,这是主目标;再遍历每架无人机的航程,找出所有超出最大航程的越界程度,乘以一个不小的惩罚系数,加进总目标。同时任务点可能有不平等权重——某些任务点必须优先完成,这些权重也可以放进目标里。这样适应度函数所需的信息就能统一成矩阵运算,一个多维数组就能算完所有粒子的适应度,跑起来比for循环快一个数量级。

有个容易被忽略的细节是断点的分配逻辑:粒子位置向量按SPV转换成任务序列后,怎么判断第几段是第几架无人机的任务,还要保证每架无人机至少分到一个任务。少的处理方式是不处理,任务数大于无人机数时随缘分配,但边界条件一旦出现空集就可能让矩阵运算报错,所以一般在转换函数里加一个计数判断,空集则随机补一个任务,保证每架无人机都有事可干。这种小修正在答辩时也是加分项,因为体现的是对工程边界的理解,不是单纯背公式。

2.3 收敛机理:速度钳制与惯性权重,粒子群唯一的命门

PSO虽然是几行公式就可以实现,但“能收敛”和“能收敛到好方案”是两回事。速度更新公式会面临一个工程细节:如果某一维的速度值一直为正且不断累积,粒子的位置向量就会越跑越远,超出任务数量级。比如任务数只有5,某个粒子的位置值可能被更新到50,SPV排序看不出问题,但搜索效率早已退化。因此“速度钳制”——限制每个维度的速度绝对值不超过位置范围的一半——往往能立竿见影地提升效果,而且实现成本只有一行取min和max的操作。

惯性权重则是另一个更好的寻优与开发平衡开关:权重大的时候粒子更倾向于飞向未搜索的区域,权重小的时候粒子更容易聚集在最优值附近精细搜索。线性递减惯性权重是毕业设计里最容易收获差异化的点:迭代初期权重0.9,后期衰减到0.4,让算法前期全局搜索、后期局部精细搜索。学习因子c1和c2通常取2.0,但也会有人调成1.5和1.5的对称组合。这些参数在下一个章节会看到具体的代码位置和调参方法。

3. 跑通源码:粒子群多无人机任务分配的核心代码拆解

3.1 工程结构:一个能跑的格式化程序长什么样

拿到源码时你面对的可能是几个py文件加几张图,也可能是一个几乎不做拆解的几百行主文件。如果是后者,我建议你先不要急着改算法,而是先把它拆成五个模块——数据生成、粒子初始化、适应度计算、PSO主循环、结果可视化。这样做的意义不只是让代码更好看,而是你后面每调一次参数、每增加一个约束,都只需要改动一个模块而不是全部重来。

一个便于改动的最小文件结构是这样的:data.py负责生成或读取任务集和无人机起点;pso.py放粒子类或独立的速度更新、位置更新函数;objective.py放适应度函数;main.py负责实例化粒子群并跑迭代;plot_result.py画分配地图和收敛曲线。项目下一步的扩展方向(比如把静态任务换成动态任务)会因此顺畅得多,展示给老师看的时候,模块拆解本身就是“系统设计能力”的体现。

3.2 任务分配初始化的最小代码:生成粒子和解码

先看粒子如何编码、初始化以及解码分配方案。为了方便演示,假设无人机数量固定,每个粒子是一个二维数组,第一维是粒子的位置向量,第二维对应速度向量,任务序列按SPV规则解码。

import numpy as np # np.random.seed(42) # 固定随机种子,保证每次跑出的实验可复现 def init_particles(pop_size, n_tasks, n_drones, x_max): """ 初始化粒子群 pop_size: 粒子数量 n_tasks: 任务点数量 n_drones: 无人机数量 x_max: 位置边界(建议取 n_tasks 的 1.5~2 倍) """ positions = np.random.uniform(0, x_max, (pop_size, n_tasks)) velocities = np.random.uniform(-1, 1, (pop_size, n_tasks)) return positions, velocities def decode_by_spv(position, n_tasks, n_drones): """ 按 SPV 规则把连续位置向量解码成任务分配矩阵 position: 单个粒子的位置向量,长度等于任务数量 """ order = np.argsort(position) # 按位置值从小到大得到任务顺序 assign = np.zeros((n_drones, n_tasks), dtype=int) # 将任务按顺序均分成 n_drones 段,每段代表一架无人机的任务集合 seg_size = n_tasks // n_drones for d in range(n_drones): start = d * seg_size if d == n_drones - 1: segment = order[start:] else: segment = order[start:start + seg_size] for t in segment: assign[d][t] = 1 # 无人机 d 执行任务 t # 确保每架无人机至少有 1 个任务:空段从其他段里随机抽一个任务补上 for d in range(n_drones): if assign[d].sum() == 0: for t in range(n_tasks): if assign[:, t].sum() == 1 and np.argmax(assign[:, t]) != d: assign[d][t] = 1 assign[np.argmax(assign[:, t])][t] = 0 break return order, assign

这段代码里np.argsort负责把连续位置向量变成从小到大的索引序列,也就是任务访问顺序。分段逻辑则是把排序后的任务序列切块分给各架无人机。要注意的是seg_size整除逻辑:如果任务数不能整除无人机数,最后一段会拿到更多任务,这是一种“非均匀分配”的默认方案,是常见的做法,若需要均衡分配可以改成分组策略。空段补任务的逻辑是处理边界情况的“兜底”——它在每轮迭代中都会触发,避免后面矩阵乘法报错,实际执行中虽然不常在最优方案里出现,但不能不写。

3.3 适应度函数实现:总航程 + 航程约束的惩罚项

接下来是一段会被你反复改动的代码——目标函数。它的输入是分配矩阵和无人机起点、任务点坐标,输出是总航程加不满足约束的惩罚值。

def fitness_function(assign, drones, tasks, max_range, penalty=1000): """ 计算单个粒子的适应度 assign: n_drones x n_tasks 的分配矩阵 drones: 无人机起点坐标数组 tasks: 任务点坐标数组 max_range: 单架无人机最大航程 penalty: 约束违反惩罚系数 """ total_dist = 0.0 violate = 0.0 n_drones, n_tasks = assign.shape for d in range(n_drones): # 找到无人机 d 要执行的任务编号 task_ids = np.where(assign[d] == 1)[0] if len(task_ids) == 0: continue # 路径顺序:起点 -> 按任务编号顺序访问(简化处理) path = [drones[d]] + [tasks[t] for t in task_ids] dist = 0.0 for i in range(len(path) - 1): delta = path[i + 1] - path[i] dist += np.sqrt(delta[0] ** 2 + delta[1] ** 2) total_dist += dist if dist > max_range: violate += dist - max_range # 超出航程越多,惩罚越大 return total_dist + penalty * violate

这个函数把“任务访问顺序”默认成了“按任务编号从小到大访问”,虽然算是简化的路径处理,但在这个任务分配题目里已经完全够用。如果你希望路径规划得更精细,就需要在适应度计算里嵌套一个旅行商问题求解,这也正是部分进阶版毕业设计把“任务分配”和“路径规划”串起来做的常见路径。罚函数本身是任务分配优化里最常见的约束处理方式,它的好处是不用改动PSO本身的更新公式,坏处是惩罚系数如果设得太大,粒子会集中于硬约束内丧失搜索多样性——这个坑会在避坑章节重点展开。实际运行时,可以把这个函数参数里的penalty从500试到5000,观察最优解的变化。

3.4 PSO主循环:速度更新、位置更新、边界处理

粒子群的迭代主循环是整个程序的心脏。先把标准PSO的更新公式写出来,再贴代码,这样你的论文也可以直接复用这一段公式描述。速度更新由三块相加:惯性项w∗v,个体认知项c1∗r1∗(pBest−x),社会认知项c2∗r2∗(gBest−x)。位置更新则是x = x + v。

def pso_optimize(n_pop, n_tasks, n_drones, max_iter, x_max=10.0, w_start=0.9, w_end=0.4, c1=2.0, c2=2.0): """ PSO 主循环,返回最优位置、最优适应度和收敛曲线 """ positions, velocities = init_particles(n_pop, n_tasks, n_drones, x_max) # 个体最优与全局最优初始化 pbest_pos = positions.copy() pbest_val = np.full(n_pop, np.inf) # 对每个粒子解码并计算适应度 for i in range(n_pop): order, assign = decode_by_spv(positions[i], n_tasks, n_drones) pbest_val[i] = fitness_function(assign, drones, tasks, max_range) gbest_idx = np.argmin(pbest_val) gbest_pos = pbest_pos[gbest_idx].copy() gbest_val = pbest_val[gbest_idx] converge_curve = [gbest_val] # 速度上限设为位置边界的一半,避免粒子飞出搜索空间 v_max = x_max / 2.0 for it in range(max_iter): w = w_start - (w_start - w_end) * it / max_iter # 惯性权重线性递减 for i in range(n_pop): r1 = np.random.random(n_tasks) r2 = np.random.random(n_tasks) # 速度更新:三部分加和,再钳制在 [-v_max, v_max] 内 velocities[i] = (w * velocities[i] + c1 * r1 * (pbest_pos[i] - positions[i]) + c2 * r2 * (gbest_pos - positions[i])) velocities[i] = np.clip(velocities[i], -v_max, v_max) # 位置更新,并把越界位置拉回边界内 positions[i] = positions[i] + velocities[i] positions[i] = np.clip(positions[i], 0, x_max) # 解码并计算适应度,更新个体最优和全局最优 order, assign = decode_by_spv(positions[i], n_tasks, n_drones) val = fitness_function(assign, drones, tasks, max_range) if val < pbest_val[i]: pbest_val[i] = val pbest_pos[i] = positions[i].copy() if val < gbest_val: gbest_val = val gbest_pos = positions[i].copy() converge_curve.append(gbest_val) # 可选:提前终止条件,连续 30 代改进小于阈值就退出 return gbest_pos, gbest_val, converge_curve

np.clip对速度做钳制是很多简版源码容易遗漏的环节,但实际效果影响很大。位置向量的边界取x_max,速度上界取x_max的一半,跑起来很少出现发散。惯性权重线性递减这一行代码就是你要在论文里重点写的改进点:标准PSO采用固定w=0.8,而线性递减让算法前期具备更强的全局搜索能力、后期更精细地收敛。如果要跑对比实验,就把固定权重版本和线性递减版本各跑20次,统计平均最优值和方差,这个数据足以撑起毕设里“改进PSO”的核心结果。r1、r2每次迭代都要重新随机,这样算法才具备随机搜索能力,这也是粒子群不同于梯度下降法的标志之一。

3.5 最小可运行脚本:把上面三段串成一次完整实验

有了初始化、解码、适应度、主循环,最后需要一个入口脚本把它们组装成可复现的结果。对于这类源码少的项目,入口脚本往往只有几十行,同时负责生成测试数据、调用优化器、打印结果、绘图。“下载即用”要求的就是这一段干净利落。

if __name__ == "__main__": n_drones = 3 n_tasks = 9 pop_size = 50 max_iter = 200 x_max = 15.0 # 用固定随机种子生成无人机起点和任务点,保证实验可复现 rng = np.random.default_rng(7) drones = rng.uniform(0, 100, (n_drones, 2)) tasks = rng.uniform(0, 100, (n_tasks, 2)) max_range = 300 gbest_pos, gbest_val, curve = pso_optimize( pop_size, n_tasks, n_drones, max_iter, x_max=x_max ) order, assign = decode_by_spv(gbest_pos, n_tasks, n_drones) print("任务访问顺序:", order) print("分配矩阵:\n", assign) print("最短总航程:", round(gbest_val, 2)) # 画出分配地图和收敛曲线,代码在 plot_result.py 里实现

这里固定随机种子有两个层面的作用:第一层是测试可复现,跑多次实验得到同一结果,方便你答辩现场重跑;第二层是可以做公平对比,对比改进算法和原始算法时保证两组实验的初始种群一致,排除随机性干扰。np.default_rng是numpy 1.17之后推荐的随机数接口,比起老代码里的np.random.rand,它的优点是不会因为全局状态被其他模块污染而导致“这次能复现、下次不能”的玄学问题。这个入口跑完后保存的分配图和收敛曲线图,就是毕设论文里最重要的两张实验图。

4. 参数怎么调:从收敛曲线判断当前算法的真实状态

4.1 核心参数表:含义、推荐范围、调试优先级

粒子群算法参数不多,能真正影响结果的其实就是五六个。先看一张参数表,我按调试优先级从高到低排列,这是最常被追问到的价值信息。调试优先级的意思是:你先调哪个参数最可能明显改变结果,哪些参数轻易不要动。

参数含义推荐范围调试优先级说明
迭代次数 max_iter搜索轮数100~500高太小不收敛,太大浪费时间。观察收敛曲线是否平了,平了即停止
种群大小 pop_size粒子数量30~100高任务规模不大时50足够,再大对结果帮助有限,耗时线性增长
惯性权重 w延续之前运动趋势的分量固定0.6~0.9,或0.9→0.4线性递减高这是PSO的灵魂参数,不同取值影响最大
学习因子 c1/c2向个体最优/全局最优学习的力度1.0~2.5中常见取2.0/2.0。c1太大会过度搜自己,c2太大会过早聚集
速度钳制 v_max单步最大变化量x_max的0.2~0.5倍中太大会发散或跳过最优,太小会原地打转
惩罚系数 penalty约束违反的处罚强度500~5000中太小约束形同虚设,太大会丢失可行解多样性

这里迭代次数和种群大小的关系很微妙。如果你观察跑出的收敛曲线是一条斜率陡降然后走平的折线,说明迭代次数可能过多,有些段是无意义的空转。如果200次迭代结束时收敛曲线还在以一个肉眼可见的斜率下降,说明迭代次数不够,或者惯性权重衰减太快。曲线形态是判断PSO收敛状态最直观也最可靠的工具,比单纯记录最终数值可靠得多。

4.2 惯性权重与学习因子的搭配逻辑:从固定值到线性递减

固定惯性权重时,w=0.8是黄金默认值,很多算法的参数设置都沿用它。但稍微动一下w就对结果影响巨大的原因在于:它折算的是上一轮速度在当前速度中的占比。w太大,粒子沿原来方向的惯性远大于向更优解学习的趋势,结果就是种群迟迟不在最优区域聚集;w太小,前期搜索区域太窄,容易一开始就陷进某个局部最优,后面无论怎么精细搜索都跳不出来。线性递减的意义在于把两种行为在时间维度上拼接起来——前期全局撒网,后期局部搜索,相当于用最简单的参数调度实现“快速找到好区域”和“在好区域精细找”的兼顾。

学习因子c1和c2可以逐步尝试一项技巧:如果收敛曲线在中后期出现“缓慢下降但长期不更新”的状态,你可以把c1适当调小、c2调大,比如2.0/2.0改成1.7/2.3。这背后的直觉是——迭代到后期,个体最优的引导价值逐渐下降,中心化的全局最优更有参考意义,向gBest多学一点有助于种群集中火力攻下最后的局部最优。如果你跑的对比实验发现两组参数下最优值差距很小,也正常,差距会体现在方差上。方差是毕设论文一个很关键的统计量,它反映算法的稳定性,比“平均最优值”更能体现出改进方法的优势。

4.3 用numpy的随机数机制消除“这次跑好、下次跑差”的玄学

每次跑出的最优总航程不一致,让很多同学误以为算法有bug,其实这正是随机优化算法的正常行为。从统计角度说,多无人机任务分配是一个带随机初始化的启发式搜索过程,初始解随机、位置和速度更新中间也引入了随机扰动,不同随机种子必然导致不同的搜索结果。所以一个严谨的实验设计必须包含多次重复实验,用均值±标准差来评价算法性能。我在处理这类问题时通常会让每个算法配置独立跑20次,记录每次的最优值,再计算平均值和标准差。20次重复实验的结果表可以直接放进论文的实验章节,比单次运行结果更有说服力。

跑重复实验时的另一个关键点是固定随机种子,但要注意“固定到什么层级”。较规范的做法是在每组实验调用优化器之前生成一个独立的np.random.default_rng(seed),并且用seed编号来区分实验组。这样整个实验设计是“种子变化但过程可追踪”的,每个seed对应一次独立实验,整组实验可以复现。实际操作中我会写一个循环,把seed从0到19依次传入,每次实验都重置新的rng,避免全局np.random状态被污染,这也是很多现成源代码里未能处理好的一处雷区——很多源码直接用全局np.random,你在两段代码之间调用了别的随机库函数,后面实验就畸变了。你可以在代码诊断时加一行随机种子测试:同一seed连跑两次,若结果完全一致,说明随机隔离没问题。

5. 避坑清单:粒子群任务分配最常见的5个翻车现场

5.1 现象:总航程算出负值或报NaN

这是第一个最可能出现的崩溃问题。造成NaN的根源往往不是公式错了,而是适应度函数里出现了距离的负值进而被平方根处理失败——无人机坐标或任务坐标生成了负数并且计算距离时坐标差小于0,或位置向量越界后变成NaN传进解码函数。解法是排查坐标生成和边界钳制:对position和velocity都加上np.clip,确保输入适应度函数的坐标是有限的。这个问题的排查位置和方法较为固定,但初学者容易忽略矩阵里某一个元素被污染,继而整个数组运算全部崩坏。

5.2 现象:所有粒子逃逸出可行搜索区域,代码跑完但分配矩阵错乱

这是没有做速度钳制的典型后果。速度值可以累加到几十上百,位置向量与任务数量的比例严重失衡,SPV排序后任务编号虽然不会越界,但搜索空间被极大浪费,最优解往往很差。解法是在速度更新后加一行np.clip(velocities[i], -v_max, v_max),这是粒子群代码里看似简单但实际上决定性能的“后悔药”。有些源码不提供速度钳制,理由是PSO的搜索空间被位置边界限制也能工作,但实际跑任务分配这类规模只有几十维的问题,加与不加的差距可以用肉眼在收敛曲线上分辨。

5.3 现象:约束几乎不生效,分配的路径超过了最大航程

这个坑出在罚函数设计不够合理。当惩罚系数只有50而最大航程是300时,超出航程100带来的罚项只有5000,而合法的最优解总航程可能已经到几千,于是算法认为“超一点航程”完全可接受,结果漫游路径频繁出现。解决方法是把penalty提高到总航程预期的10~20倍,或者把罚函数从线性改成平方,例如使用violate的平方和乘以penalty。需要注意的是惩罚系数不是越大越好——极端大的系数会让算法以为所有包含越界解的粒子都不值得搜索,从而过早收回搜索范围,这也是一个需要平衡的地方,通常的做法是先测一组固定种子下的最优值曲线,看何时稳定再决定取多少。

5.4 现象:改了几行代码后,前后两次结果完全不可复现

这基本是被numpy全局随机状态坑了。你在主循环里调用了np.random.random,而数据生成阶段也用np.random.rand,两者会共享同一个全局随机流。一旦加入了新的随机函数或者调了调用顺序,整个随机序列全部变异。解法是使用np.random.default_rng(seed)创建独立随机流并显式传给数据生成函数与PSO主循环,或者至少在脚本开头固定np.random.seed,保证同一份代码在同一环境下的输出完全一致。这是被大量现成源码忽视的工程化细节,但答辩时把它解释清楚,比多跑几个对比实验更显专业。

5.5 现象:代码在Python 3.8里运行报错,提示map、zip或其他内置函数类型不对

粒子群源码一般只依赖numpy和matplotlib,但下载下来的代码可能是别人在Python 2时代写的——print语句没有括号、地图与坐标点绘制设置不一样、np.float和np.int被移除,都会诱发报错。解决方法是先把环境固定到Python 3.8及以上、numpy 1.20及以上、matplotlib 3.5及以上,这是本源码最可能跑得顺的组合,然后逐一把老语法改成兼容写法。如果环境里还没有numpy,安装方法是先确认python版本,再执行pip install numpy matplotlib,安装完成后在命令行运行python -c “import numpy; print(numpy.version)”验证是否成功。此类兼容性问题不涉及算法本身,但却是“下载即用”的最大障碍之一。

6. 验证与进阶:把“论文能用”变成“真能说服人”

跑通源码只是完成了整个项目的第一步。要让任务分配结果站得住脚,你需要做三个层面的验证。第一个层面是最优性验证——用穷举法在中小规模下算出理论最优值,对比PSO的结果。比如3架无人机、6个任务点的组合总数在可枚举范围内,你可以用itertools生成所有排列逐一计算目标函数,得到最优值,再把PSO的最优值除以穷举最优值,得到一个“逼近率”。如果逼近率在95%以上,你的参数调校就算过关;如果低于90%,优先检查惯性权重衰减和罚函数设计而不是盲目增加迭代次数。第二个层面是鲁棒性验证——把算法接到另一组随机生成的地图上运行30次,统计最优值均值和标准差,看结果是否在可接受范围内波动。第三个层面是可视化验证——这是毕设答辩最实用的技巧,把每架无人机走过的路径用不同颜色画在同一张图上,用matplotlib的plot方法把起点、任务点、路径连线画出来,一张清晰的任务分配图比你写满三页文字更有说服力。

进阶方向上,最值得投入的是把静态任务分配扩展成“考虑任务时间窗”的版本,即在任务点数据里加入最早开始时间和最晚开始时间,在适应度函数中增加等待时间惩罚。这是当前多无人机协同规划里很典型的真实需求,你可以通过给每个任务点增加一个时间窗属性来实现,改造量不大,但论文的创新点会非常明确。另一个投入产出比较高的方向是混合模拟退火的PSO——每次迭代结束后,对全局最优粒子做一次小概率的邻域扰动,这能有效避免PSO早熟。改造要点是在主循环结束处加一段退火操作:对gbest_pos的某一维加上一个服从正态分布的随机扰动,再解码、计算适应度,如果更优则替换。这种方式比单纯调参数的提升更稳定,也更容易写出“算法改进”的章节。顺带一提,代码的运行耗时也可以做一个统计表:记录种群大小从20到100时达到同精度最优值的时间变化,这个数据能说明你的算法在大规模任务下的扩展性边界。

最后说一个我从这类项目里总结出来的习惯:拿到任何源码,第一步不是读算法,而是把入口脚本、数据生成、适应度函数三层之间传递的每一个数组shape打印出来。只要shape对得上,这程序就跑得起来;shape对不上,算法写得再漂亮也白搭。把这个习惯带进你的毕设调试里,能帮你省下大把的排查时间。希望帮到你——祝你的多无人机任务分配项目顺利完成。

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

返回列表