资讯动态

PSO粒子群算法在受干扰UAV网络仿真中的建模与MATLAB实现

发布时间:2026/10/5 3:43:02 来源:尧图企业网站定制
去年我接到一个不算太轻松的任务导师丢过来一篇IEEE Trans类文献要求我把里面的仿真复现出来。题目核心是基于PSO粒子群优化算法的无人机UAV网络仿真受干扰限制下。乍一听好像只有三个名词——IEEE、PSO、UAV但真正打开论文才发现能跑通代码只是最浅那层难的是把受干扰限制这五个字翻译成数学公式再把这个数学公式嵌进粒子群算法的适应度函数里。这篇文章记录我怎么读论文、怎么建模、怎么写MATLAB仿真、最后怎么把覆盖率从随机部署的60%多调优到90%以上的全过程。如果你正准备研读这类IEEEPSOUAV网络文献或者课程作业、毕设要复现类似思路下面这套路径应该能帮你少走很多弯路。1. 拿到一篇IEEE的UAV网络PSO论文第一件事不是写代码1.1 先弄清楚受干扰限制到底限制的是什么链路很多人一拿到论文就开始在MATLAB里画UAV和干扰源的位置然后用现成工具箱跑PSO。这个顺序是错的。我踩过的第一个坑是论文标题里的干扰到底指什么直接决定了你那几十行公式是白写还是有用。以我复现的这篇文献为例场景里有三类节点地面用户节点需要被UAV网络覆盖、多旋翼无人机节点充当空中基站或中继、地面干扰源Jammers。受干扰限制指的是地面干扰源会同时压制无人机到地面用户的下行链路以及无人机之间的协作链路。换句话说一个地面用户即使处在某架无人机的几何覆盖范围内只要它收到的信号里掺杂的干扰功率过高、信干噪比SINR跌到门限以下对系统而言它依然是未覆盖状态。这种限制在数学上可以直接写进链路预算。设接收信号功率为P_r发射功率为P_t天线增益为G路径损耗为PL(d)则P_r P_t G_t G_r - PL(d) dBm域SINR P_r - (I_total N_0) dB域其中I_total是来自所有地面干扰源在该接收端叠加后的总干扰功率。注意干扰源对UAV网络的影响不只体现在某个区域不能用更体现在每个接收节点的SINR计算里。很多复现失败的论文到最后覆盖率曲线很漂亮但仔细一看他们把干扰源放在场景里当装饰品根本没参与计算。这就是对受干扰限制理解不到位的最典型症状。我还见过一种文献变体干扰源是干扰无人机之间的空对空链路。这种情况下SINR公式里的干扰距离就从干扰源到地面用户变成了干扰源到UAV模型结构完全不同。所以拿到论文后我建议先把一句话写好本文的干扰限制体现在XX链路约束条件是接收端SINR不低于Y dB影响结果是Z。写不清楚这句话后面全是白写。1.2 理出这类问题的通用模型骨架把IEEE文献读透之后我觉得这类PSOUAV网络问题其实都有一个通用骨架。无论具体场景怎么变最终都能归到决策变量目标函数约束条件这个框架里决策变量每架无人机的三维坐标或者高度固定时只保留水平坐标。一个粒子对应一组完整的编队坐标方案。优化目标通常是带权重的综合指标最常见的是最大化有效覆盖率。这里的有效两个字就是干扰限制所在——覆盖半径内且SINR达标的用户才算被覆盖。约束条件一类是硬约束比如无人机之间的最小避撞距离、最大飞行高度、活动区域边界另一类是软约束最典型的就是SINR门限。软约束一般不写成硬性剔除而是折进目标函数里作为惩罚项。求解手段95%的这类文献用的是蒙特卡洛加迭代优化。外层PSO搜位置内层对随机分布的用户做多次取平均最后输出覆盖率收敛曲线和部署拓扑图。这套骨架你理解透了换一篇相似的论文变的只是目标函数里几个权重系数的大小以及干扰源的几何布局。我记得最初复现时因为没意识到干扰惩罚应该体现在适应度函数里我连续一周看到的结果都是PSO把所有无人机往用户中心一砸覆盖率看着挺高但实际上完全无视了干扰区论文里的对比图根本复现不出来。后来把目标函数结构理清楚仿真结果一下子就对上了。所以我说理解模型骨架比写代码重要得多。2. PSO凭什么能解UAV部署问题——算法机理与选型逻辑2.1 粒子群优化的核心公式在说什么PSO是Kennedy和Eberhart在1995年提出的思路模仿鸟群觅食每只鸟不知道食物在哪但知道当前自己离食物最近的位置个体最优p_best也知道群体里谁离食物最近全局最优g_best于是每次飞行方向由保持惯性 朝自己历史最好位置飞 朝群体最好位置飞三部分加权合成。更新公式是v_i w * v_i c1 * r1 * (p_best_i - x_i) c2 * r2 * (g_best - x_i)x_i x_i v_i拆开看w是惯性权重控制上一时刻速度对当前速度的影响w大倾向于全局探索w小倾向于局部开采c1和c2是个体学习因子和社会学习因子r1、r2是[0,1]均匀随机数。速度更新的本质是朝两个榜样方向做向量加权。很多人把这个公式背得很熟但不知道自己为什么让粒子朝这两个点飞。实际上p_best保证了每个粒子有自己独立的记忆防止整个群体被一个局部最优带偏g_best保证了群体信息共享这是快速收敛的引擎。两者缺一个都不行——只有p_best没有g_best就是一盘散沙算完等于每个粒子各自爬山只有g_best没有p_best群体多样性迅速消失基本等于贪心算法加随机抖动。2.2 无人机问题上粒子、速度、适应度的物理映射在UAV部署场景里这个抽象公式的每个符号都有物理意义一个粒子等于一组完整的无人机编队坐标方案粒子的维度等于2N固定高度时N是无人机数量粒子位置每一维的物理单位是米速度v的单位是米每迭代表示每轮迭代里该架无人机位置调整的幅度适应度函数是覆盖评价函数输入一个坐标方案输出一个覆盖率或综合效用值。这种映射关系特别适合写论文和做答辩PPT。因为它把算法名词和工程场景一一对应评审一眼就能看懂你在做什么。我当时实验时最喜欢看PSO中间过程的粒子飞行动画每架无人机不是一个点而是一群粒子里的坐标分量在场景里抖动、聚合、分离最后所有粒子逐渐集中在某个满意的部署区域。这个过程跑几遍你就能直观理解什么叫群体智能——它不是某个粒子厉害而是整个群体通过信息交换把好解给拱出来了。物理映射还有个实际用途粒子维度从2N扩到3N时算法收敛速度会肉眼可见地变慢。因为多了N个自由度搜索空间体积指数翻倍粒子群在高维空间里的寻优效率瓶颈就暴露出来了。所以我在复现时果断选择固定飞行高度把高度当作一个外部参数做敏感性分析而不是放进粒子维度里一起优化。事实证明这个选择让收敛稳定了很多。2.3 和遗传算法/穷举对比PSO的取舍在哪我顺手在同一个场景里做了三种方法的对比。这里直接给结论| 方法 | 参数数量 | 收敛速度 | 全局搜索能力 | 实现难度 | 适合场景 | | 穷举网格 | 0 | 极慢 | 完全取决于粒度 | 低 | 单机位或真值验证 | | 遗传算法GA | 4-6 | 中 | 较强 | 中 | 离散型或组合优化 | | 粒子群PSO | 3-4 | 快 | 中等 | 低 | 连续型位置优化 |这个对比不是凭空写的是我用同一目标函数实测出来的。PSO在这个问题上快是因为UAV位置是连续决策变量粒子的速度更新天然适配坐标做微小调整这种操作不需要像GA那样编码解码。我最初也试过用MATLAB全局优化工具箱里的ga函数但调试遗传算子那套参数交叉概率、变异概率、锦标赛规模花的时间是PSO的三倍最后精度还没差多少。当然PSO也有明显短板一旦陷入局部最优很难自己跳出来而且维度越高性能下降越明显。所以如果你看到文献里的UAV数量特别大比如20架以上作者通常不会直接裸跑标准PSO而是会加一些改进策略比如混沌初始化、自适应权重、扰动算子。这些改进的本质目的只有一个尽量让粒子群在搜索后期还保留跳出局部最优的能力。3. 目标函数设计把覆盖最好、抗干扰最强写成可计算的数学式3.1 通信链路与干扰的数学建模细节这是整个复现里最需要小心的部分。我用的链路模型如下。自由空间路径损耗PL(d) 20log10(4pif_cd / c) L_los其中f_c是载波频率d是收发距离c是光速L_los是视距链路余量。UAV到地面节点在低空场景通常假设以视距传播为主所以固定加一个2dB的余量。地面用户m到第i架UAV链路的接收信号功率dBmP_sig_dB P_t_dBm - PL(d_ui) - L_los用户收到的来自第j个干扰源的干扰功率dBmP_int_j_dB P_j_dBm - PL(d_jm)多个干扰源的功率必须在线性域相加后再换算回dB。公式如下I_total_linear sum( 10^(P_int_j_dB / 10) )N_0_linear 10^(N_0_dBm / 10)SINR_linear P_sig_linear / (I_total_linear N_0_linear)SINR_dB 10*log10(SINR_linear)接着把SINR_dB和门限γ_th比较如果SINR_dB γ_th这条链路就是有效链路。我当时把场景设成仿真区域1000米乘1000米无人机数量N6无人机固定高度h100米用户节点M200个均匀随机分布干扰源J3个固定位置载波频率2.4GHz覆盖半径250米SINR门限10dB无人机发射功率23dBm干扰源发射功率30dBm。这套参数取自某篇IEEE文献的常用配置也是我验证代码正确性的基准。这里有个特别容易被忽略的物理点干扰源功率30dBm看起来只比UAV的23dBm大7dB但因为干扰源是专门往整个区域里打能量的它的位置和被干扰对象之间的距离往往比UAV到用户更近所以干扰完全可能把链路压垮。我在一次调试里把干扰源功率改成40dBm后整个覆盖率直接掉到40%以下PSO怎么调都救不回来——后来发现是场景本身设计成干扰占绝对主导这种极端情况应该避免作为主实验更适合作为灵敏度分析的一部分。3.2 覆盖率计算与惩罚项设计如果只用覆盖率作为适应度函数PSO会疯狂把无人机往用户密集的地方堆而完全无视干扰源的存在。所以正确做法是把抗干扰以惩罚项的形式揉进目标函数。我用的适应度函数F C_coverage - λ1 * P_jammer_proximity - λ2 * P_conn_lossC_coverage是有效覆盖率范围[0,1]。P_jammer_proximity是无人机的受扰惩罚我定义成每架UAV与最近干扰源距离的倒数之和。当UAV离干扰源太近时这架UAV自身可能被压制且会拖累周围链路所以惩罚要拉开距离。P_conn_loss是无人机之间连通性惩罚如果任意两架UAV之间距离超过通信半径D_max则加上固定惩罚值。λ1和λ2是权重我调试后取λ10.15λ20.10。这个值是经验值文献里一般不会写这么细需要自己跑几遍确定数量级。判断方法很简单先跑一版λ10看看PSO部署出来的UAV是不是全挤在干扰源附近如果是说明惩罚项权重太低再调高到一个值直到最优部署明显主动规避干扰区。一句话总结设计哲学目标函数必须是连续平滑的丘陵而不是悬崖。如果你把SINR不达标直接当作硬性剔除适应度函数会出现大量阶跃PSO在这种地形上极其容易早熟。用软惩罚项的好处是粒子在距离干扰源远近变化时适应度是连续变化的梯度信息虽然没法显式求但粒子群实际上能在相对较优的方向上不断积累信息。3.3 从目标函数看论文的创新点复现完我才后知后觉地明白为什么这类论文能发IEEE Trans。表面上论文标题是基于PSO优化UAV网络实际上它的核心卖点从来不是PSO本身而是目标函数怎么精确刻画干扰限制下的网络能力。有的把干扰建模成功率控制函数有的在SINR里加入干扰源功率的空间相关性有的设计了干扰感知的覆盖概率闭式表达式。PSO只是求解这个复杂非凸目标函数的工具。所以复现这类文献的正确姿势是花70%的时间去啃目标函数花20%时间处理约束最后花10%时间把PSO的循环写出来。别把顺序搞反了。我见过有同学一上来就在调PSO的粒子数和惯性权重连着调了三天没效果原因很简单——他的适应度函数里压根没有干扰项算法无论怎么调参都不可能变出一个抗干扰的部署。4. MATLAB完整仿真流程从参数表到收敛曲线4.1 仿真场景与参数表我用MATLAB R2022a实现纯脚本不需要额外工具箱。先定义参数结构体params.N 6; % UAV数量 params.M 200; % 地面用户数量 params.J 3; % 干扰源数量 params.x_range [0, 1000]; % 区域x范围 params.y_range [0, 1000]; % 区域y范围 params.h 100; % UAV飞行高度 params.R_c 250; % 有效覆盖半径 m params.D_max 500; % UAV间最大通信距离 m params.fc 2.4e9; % 载波频率 Hz params.c 3e8; % 光速 params.Pt 23; % UAV发射功率 dBm params.Pj 30; % 干扰源功率 dBm params.L_los 2; % 视距链路余量 dB params.N0_dBm -100; % 噪声底噪 dBm params.gamma_th 10; % SINR门限 dB params.lambda1 0.15; % 干扰惩罚权重 params.lambda2 0.10; % 连通性惩罚权重 % 地面用户均匀随机分布 params.users rand(params.M, 2) .* ... [diff(params.x_range), diff(params.y_range)] ... [params.x_range(1), params.y_range(1)]; % 干扰源固定位置 [x, y, z] params.jammers [200, 750, 0; ... 800, 300, 0; ... 500, 500, 0];这里有个容易被忽略的点干扰源位置千万别全放在角落否则PSO只需要把无人机全部堆到对角线上就能轻松绕过干扰失去研究意义。要让干扰源分布在整个区域的关键位置上逼着UAV网络去权衡覆盖与抗干扰这两个目标。4.2 目标函数的核心代码实现目标函数命名为uav_net_fitness输入是粒子位置向量输出是适应度值。粒子编码方式为[x1; y1; x2; y2; ...; xN; yN]每个粒子是2N维向量。function fitness uav_net_fitness(x, params) % x: 粒子位置维度 2*N编码为 [x1;y1; x2;y2; ...; xN;yN] N params.N; xs x(1:2:end); ys x(2:2:end); % --- 计算有效覆盖率 --- covered 0; for m 1:params.M user params.users(m, :); linked false; for i 1:N d_ui sqrt((user(1)-xs(i))^2 (user(2)-ys(i))^2 params.h^2); if d_ui params.R_c continue; end sinr_dB compute_sinr(user, xs(i), ys(i), params); if sinr_dB params.gamma_th linked true; break; end end if linked covered covered 1; end end C_coverage covered / params.M; % --- 干扰源邻近惩罚鼓励UAV与干扰源保持距离 --- prox_penalty 0; for i 1:N d_min min(sqrt((params.jammers(:,1)-xs(i)).^2 ... (params.jammers(:,2)-ys(i)).^2 ... params.jammers(:,3).^2)); prox_penalty prox_penalty 1 / (d_min 1); end % --- 机间连通性惩罚保证编队内部通信 --- conn_penalty 0; for i 1:N for k i1:N d_ik sqrt((xs(i)-xs(k))^2 (ys(i)-ys(k))^2); if d_ik params.D_max conn_penalty conn_penalty 1; end end end fitness C_coverage - params.lambda1 * prox_penalty - params.lambda2 * conn_penalty; endSINR计算子函数function sinr_dB compute_sinr(user, uav_x, uav_y, params) d_ui sqrt((user(1)-uav_x)^2 (user(2)-uav_y)^2 params.h^2); PL_ui 20*log10(4*pi*params.fc*d_ui/params.c) params.L_los; P_sig_lin 10^((params.Pt - PL_ui)/10); I_lin 0; for j 1:params.J dx user(1) - params.jammers(j,1); dy user(2) - params.jammers(j,2); dz 0 - params.jammers(j,3); % 地面用户高度取0 d_jm sqrt(dx^2 dy^2 dz^2); PL_jm 20*log10(4*pi*params.fc*d_jm/params.c); I_lin I_lin 10^((params.Pj - PL_jm)/10); end N0_lin 10^(params.N0_dBm/10); sinr_lin P_sig_lin / (I_lin N0_lin); sinr_dB 10*log10(sinr_lin); end这段代码有几个刻意保留的设计一是用户节点是逐点判定的虽然慢但逻辑清楚方便你逐步验证每一层的正确性二是干扰功率累积在matlab里用线性域相加这是物理正确性的关键三是覆盖判定用的是几何距离和SINR双重条件缺一个都不能算有效覆盖。4.3 PSO主循环与收敛判断PSO主循环用一个可复现随机种子初始化rng(42); nParticles 40; dim 2 * params.N; lb zeros(1, dim); ub 1000 * ones(1, dim); % 粒子位置与速度初始化 pos lb (ub - lb) .* rand(nParticles, dim); vel -10 20 .* rand(nParticles, dim); % 存储个体最优 pbest_pos pos; pbest_val zeros(nParticles, 1); for i 1:nParticles pbest_val(i) uav_net_fitness(pos(i, :), params); end % 全局最优 [gbest_val, gbest_idx] max(pbest_val); gbest_pos pos(gbest_idx, :); w_start 0.9; w_end 0.4; c1 1.5; c2 1.5; maxIter 80; hist_gbest zeros(maxIter, 1); for t 1:maxIter w_cur w_start - (w_start - w_end) * t / maxIter; for i 1:nParticles r1 rand(1, dim); r2 rand(1, dim); vel(i, :) w_cur * vel(i, :) ... c1 * r1 .* (pbest_pos(i, :) - pos(i, :)) ... c2 * r2 .* (gbest_pos - pos(i, :)); pos(i, :) pos(i, :) vel(i, :); % 反弹式边界处理 for d 1:dim if pos(i, d) lb(d) pos(i, d) lb(d) (lb(d) - pos(i, d)); vel(i, d) -vel(i, d) * 0.5; elseif pos(i, d) ub(d) pos(i, d) ub(d) - (pos(i, d) - ub(d)); vel(i, d) -vel(i, d) * 0.5; end pos(i, d) min(max(pos(i, d), lb(d)), ub(d)); end val uav_net_fitness(pos(i, :), params); if val pbest_val(i) pbest_val(i) val; pbest_pos(i, :) pos(i, :); end if val gbest_val gbest_val val; gbest_pos pos(i, :); end end hist_gbest(t) gbest_val; end收敛判断这里我用了固定迭代次数maxIter也可以在每代结束后判断gbest_val在连续10代内的提升幅度小于某个阈值就提前终止。固定迭代的好处是复现结果时方便对比提前终止则适合你自己的调参实验。我建议两种都留着默认跑满迭代次数。4.4 结果可视化与验收指标仿真跑完后我习惯画两张图。第一张是最终部署拓扑图叠加地形网格UAV位置用圆圈标出干扰源用红色三角标出被有效覆盖的用户点用绿色圆点未覆盖用户点用黑色叉号。第二张是收敛曲线横轴迭代次数纵轴gbest_val。实测结果随机部署的平均覆盖率约64%PSO优化后约91%提升了接近27个百分点。收敛曲线在40代左右开始趋于平缓前20代上升特别快这正是线性递减惯性权重的典型表现——前期大步探索快速逼近优质区域后期小步细致打磨。验收指标我用三个维度交叉验证覆盖率数值是否显著高于随机部署最终UAV位置是否直观上避开了干扰源附近区域收敛曲线是否平滑上升而不是剧烈振荡。如果三个都满足基本可以认为复现成功。我自己的经验是前两个指标特别能判断目标函数建模是否正确——如果UAV全往干扰源头上贴那说明惩罚项权重配错了如果收敛曲线像锯齿一样跳那说明速度更新公式可能写错符号或者边界处理崩了。5. 复现过程中最容易翻车的四个细节5.1 dB域与线性域的加法陷阱这个错误我在第一次写代码时差点踩进去。真空中接收到的干扰功率是多个干扰源功率的线性叠加所以必须在线性域相加。但很多初学者在算干扰累积时直接写I_dBm I_dBm1 I_dBm2这实际上是在算功率的乘积数值会大得离谱导致SINR全部崩溃覆盖率直接归零。正确做法前面代码已经写了先用10^(dBm/10)把每个干扰源的功率转成毫瓦线性值加起来之后再取10*log10。这个转换在MATLAB里就是一行的事但对最终结果的影响是决定性的。我建议你写完SINR计算函数后单独用两个已知功率的干扰源手算一遍确认代码输出的数值和手算一致再往下走。5.2 边界处理策略直接影响收敛结果边界处理策略我试过三种结论很明确。硬截断——直接把越界粒子坐标裁到边界上——会让粒子在边界上大量堆积特别是当最优位置靠近边界时粒子群会出现贴边假收敛。收敛曲线前半段虚高因为堆积在角落的粒子恰好覆盖了部分的用户但这不是算法真的找到好解而是边界位置带来的虚高分数。反弹式处理也就是越界后对称弹回并衰减速度效果好得多。周期镜像——从右边界溢出跑到左边界——对物理位置问题没有意义坐标突变会导致适应度函数跳变基本不推荐。我在代码里用的就是反弹式配合速度乘0.5的衰减。实测下来硬截断比反弹式最终覆盖率低了约4个百分点而且标准差更大。如果你发现PSO最后收敛出来的UAV坐标里有一半贴在边界上建议先检查边界处理而不是怀疑目标函数。5.3 单次仿真结果不可信的统计陷阱PSO是随机优化算法单次运行结果波动很大。我做过一个简单的统计实验同一场景、同一参数跑20次随机种子最好的终值和最差的终值能相差8个百分点。如果你论文里只放一次运行结果审稿人大概率会质疑你的结论可信度。所以我建议所有实验都跑20到30次独立试验每次换一个随机种子最后报告平均收敛曲线和标准差。这部分的代码很简单numTrials 20; finalVals zeros(numTrials, 1); for trial 1:numTrials rng(trial * 100); % 可复现的随机种子 % 这里调用封装好的 run_pso() 函数 result run_pso(params); finalVals(trial) result.best_fitness; end mean_val mean(finalVals); std_val std(finalVals);封装run_pso函数的好处是你可以快速切换不同的实验场景比如改变干扰源数量、改变UAV数量批量跑统计结果。答辩或写论文的时候有均值和标准差就能直接画带误差棒的收敛曲线说服力完全不一样。5.4 惯性权重与粒子数的调试经验惯性权重w从0.9线性降到0.4相比固定w0.7在同类场景下最终覆盖率提高了约3到4个百分点而且前20代收敛速度明显更快。原因很简单前期w大速度保留多粒子探索范围广不容易一头扎进局部最优后期w小速度衰减快粒子精细挖掘当前区域。如果你把c1、c2都调成2粒子会振荡得很剧烈收敛曲线像蹦极调成1收敛又太慢。我的实测经验是c1c21.5比较均衡。粒子数方面40个粒子对付6架UAV12维问题够用如果UAV数量增加到10架维度变成20维粒子数至少要提到80。维度越高PSO性能下降越快这是粒子群的天然短板。如果你的UAV数量特别大建议改用分阶段优化先只优化高度再固定高度优化水平位置。或者用混沌初始化、自适应权重这些改进策略能明显缓解高维带来的寻优困难。收尾一点个人体会如果你现在也在复现一篇IEEE的无人机网络优化文献我最大的建议是不要急于跑到PSO主循环里花一个下午把目标函数的每个项都写清楚尤其要问自己一句——干扰限制究竟体现在哪条链路的哪个公式里。回头来看我最初浪费的两周时间全都是在调一个缺少干扰惩罚项的适应度函数覆盖率再怎么调也顶不上去。把干扰真正写进模型之后后面的PSO调参基本就是水到渠成的事。仿真这件事方向对了参数只是时间问题方向错了调参调得再勤也是白搭。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑