☰
基于蚁群算法的无线传感器网络路由优化:MATLAB仿真与能量均衡实践
2026/10/29 14:50:58 网站建设 项目流程

简介:一款基于 MATLAB 的无线传感器网络路由优化项目,围绕蚁群算法(ACO)解决能耗与生命周期约束下的路由选择问题,适合学习 WSN 能效管理、路由协议及智能优化算法的学生与工程师参考。资源包共 14 个文件,大小 258KB,以 .m 脚本、.fig 图形、.png 结果图和 1 个日志文件为主;.m 文件实现网络模型与多种改进型蚁群算法,.fig/.png 展示生命周期和能耗对比结果,日志可用于排查仿真异常。项目核心是让节点在路由选择时兼顾剩余能量与传输代价,通过信息素更新反复迭代,使全网能耗趋于均衡,从而最大化网络生命周期,并配有仿真设置与结果分析结构,便于从代码层面理解完整优化流程。已有 188 人学习下载,适合希望复现蚁群路由算法、开展能耗仿真或作为课程设计与毕业设计参考的读者。

1. 无线传感器网络路由优化为什么绕不开蚁群算法:先从能量均衡说起

无线传感器网络里每个节点靠电池供电,部署后几乎不可能频繁更换电池,路由算法每一次“偏心”都会加速某个节点死亡,进而拖垮整个网络的可用时间。蚁群算法把蚂蚁探索路径留下的信息素类比成路由选择的倾向性,只要把剩余能量和传输能耗折进启发信息,就能让中继节点轮换着承担转发,避免热点节点被反复压榨。在 MATLAB 里做这件事的性价比很高,不需要真实节点,只要把能耗模型、信息素更新和生命周期统计写清楚,就能对比出蚁群算法与最短路径、分簇路由在网络生命周期上的差异。这篇笔记面向需要在 MATLAB 里复现无线传感器网络路由优化实验的工程师,把能耗模型、蚁群算法主循环、参数调优和仿真验证一次讲到位。

2. 先定模型再写路由:能耗模型与生命周期指标的三类选择

写蚁群算法之前,先要回答三个问题:节点耗能怎么算、网络寿命怎么统计、节点怎么摆。这三个变量没有定好,后面所有路由对比都会被噪声淹没——同样的算法,换个统计口径可能从“提升 40%”变成“没有显著差异”。

2.1 一阶无线电能耗模型:Etx 与 Erx 怎么落到 MATLAB 函数里

无线传感器网络路由优化的所有结论都建立在能量消耗的计算方式上。用得最多的是经典一阶无线电模型:发送节点处理数据包时,除了收发电路固有的耗能,还要按传输距离乘上一个放大系数;当距离小于阈值 d0 时,信号衰减按自由空间模型走,耗能与距离平方成正比;超过 d0 后按多路径衰减模型走,耗能与距离四次方成正比。这个模型足够粗糙,也足够稳定,在 MATLAB 里用几个常量和一条 if 分支就能表示出来。

function [ptx, prx] = radio_energy(k, d) % radio_energy: 一阶无线电能耗模型 % k : 数据包比特数(bit) % d : 收发距离(m) Eelec = 50e-9; % 收发电路处理每比特的耗能, J/bit Efs = 10e-12; % 自由空间放大系数, J/bit/m^2 Eamp = 0.0013e-12; % 多路径衰减放大系数, J/bit/m^4 d0 = sqrt(Efs/Eamp); % 距离阈值, 约87.7m if d < d0 ptx = Eelec * k + Efs * k * d^2; else ptx = Eelec * k + Eamp * k * d^4; end prx = Eelec * k; % 接收节点只需要处理电路耗能 end

这段函数的逻辑很简单:ptx 是发射耗能,prx 是接收耗能。注意 d0 不是人工指定的,而是由 Efs 和 Eamp 两个系数反推出来的临界距离。上面这组常数是仿真社区里比较常用的默认取值,d0 约为 87.7 米,也就是说当邻居间距超过这个值,单个数据包的发送耗能会急剧上升。参数说明上给一个建议:如果仿真场景是百米级区域内的密集部署,Eamp 这项通常几乎用不到;如果节点间距普遍在 100 米以上,则要重点检查远距离传输带来的能量悬崖。

参数取值含义对结果的影响
Eelec50 nJ/bit收发电路基础耗能决定数据量带来的固定开销
Efs10 pJ/bit/m²近距放大系数影响 87.7m 内的距离敏感度
Eamp0.0013 pJ/bit/m⁴远距放大系数影响长距离路由的惩罚力度
d0sqrt(Efs/Eamp)≈87.7m距离阈值超过它后耗能曲线快速抬升

还要强调一个容易忽略的点:收发双方的耗能都要累加。很多初版代码只扣了发送端的能量,接收端成了“免费午餐”,结果仿真里所有节点都倾向于多跳转发,因为接收不花钱。实际扣减时要同时更新发送节点和接收节点两个对象的剩余能量。

2.2 生命周期指标选 FND 还是 HND:统计口径会改变结论

网络生命周期不是一个天然唯一的量。同一个仿真跑完,用三个口径统计会得到三组差异很大的数字:FND(第一个节点死亡轮次)、HND(半数节点死亡轮次)、LND(最后一个节点死亡轮次)。我之前帮人复核过一组结果,对方说“蚁群算法相比最短路径没有明显优势”,后来发现他只看了 LND——最后一个节点往往是被边缘孤立节点拖死的,和路由均衡性关系不大,前面 60% 节点能坚持多久反而被淹没了。

指标定义适合场景关注点
FND第一个节点能量耗尽覆盖敏感场景,出现盲区即失效路由是否能避免热点节点被快速耗尽
HND半数节点能量耗尽有效工作寿命,网络仍可用但质量下降路由均衡性的中期表现
LND全部节点能量耗尽数据采集完毕的极限寿命容易被少数孤立节点主导,谨慎使用

如果你在写实验报告或做方案对比,建议同时输出三个指标,结论以 FND 或 HND 为主。蚁群算法带来的收益主要集中在前期和中期均衡上,最典型的表现是 FND 明显延后,LND 反而不一定有多大变化。只报 LND 会把 ACO 在能量均衡上的价值掩盖掉。

2.3 节点部署与基站位置:随机种子和坐标范围能左右 30% 的差异

部署形态对路由算法的影响常被低估。同样是 100 个节点,基站放在场地中心还是场地外,直接决定了汇聚流量是否天然均衡。把基站放在区域中心附近时,节点到基站的距离差距没那么大,哪怕用最短路径算法也不容易出现某个节点被疯狂中继的情况;而把基站放在区域外一侧,边缘节点到基站距离远,中心区域的节点必须承担大量转发,这时路由算法的均衡能力才真正被考验。

% 部署参数与节点坐标初始化 rng(42); % 固定随机种子,保证实验可复现 numNodes = 100; % 节点数 L = 100; % 部署区域边长 100m nodes = L * rand(numNodes, 2); % 均匀随机坐标 sink = [L/2, L + 30]; % 基站放在区域上方 30m,模拟单汇聚场景 E0 = 0.5; % 每个节点初始能量 0.5J Erem = E0 * ones(numNodes, 1); packetLen = 4000; % 每轮数据包长度 4000bit

rand 默认生成 0 到 1 之间的均匀随机数,乘上 L 后把坐标映射到 100 乘 100 米的正方形区域。sink 取在 [50, 130],意味着基站不在节点部署区域内部,所有数据都要向区域上边界汇聚,这种“汇聚背后无节点”的布局能放大路由算法的差异。如果暂时没有特定场景约束,我建议初始能量设在 0.5 焦耳左右,数据包长度 4000 比特,这两个值配合上面能耗模型跑出来的死亡节奏正好处在几百轮量级,便于观察曲线变化。固定 rng 这一步不是可有可无的,后面会专门展开讲。

3. 蚁群算法路由主循环:状态转移、信息素更新与 MATLAB 实现

把能耗模型定下来之后,下一步就是把蚁群算法真正写进路由发现过程中。无线传感器网络里的蚁群路由和经典 TSP 场景有一个明显区别:蚂蚁不需要遍历所有节点,它只需要从源节点出发,逐跳走向基站,每一步在邻居集合里按概率挑选下一跳,直到到达基站或步数超限。

3.1 状态转移概率:把剩余能量折进启发因子

蚂蚁在节点 i 时,假设它还没有访问过节点 j,j 属于当前可达邻居集合 allowed,那么选择 j 的概率按经典蚁群公式构造:

p_ij = [τ_ij]^α · [η_ij]^β / Σ_{l∈allowed} [τ_il]^α · [η_il]^β

这里 τ_ij 是边上的信息素浓度,代表历史路径被使用的频率;η_ij 是启发因子,代表当前决策对“省电”的直接贡献。在 WSN 场景里,启发因子不能再简单地写成 1/d_ij(那是 TSP 画法),常见做法是把剩余能量和发送能耗同时放进去:

η_ij = (Erem(j) / E0) / (Etx(k, d_ij) + 1e-12)

分子是邻居节点剩余能量占比,剩余能量越高的节点越适合当下一跳;分母是该链路的发送耗能,距离越近耗能越低,启发值越大。加上 1e-12 只是为了防止距离过近时除以零。α 和 β 分别控制信息素和启发信息的权重:α 太大,路由会过早锁死在历史路径上;β 太大,蚂蚁会过度贪心,只盯当前一跳的“便宜”,丢掉了全局均衡。

function eta = heuristic(i, j, nodes, Erem, E0, packetLen) % heuristic: 计算从 i 到 j 的启发因子 % 距离越短、发送能耗越低、邻居剩余能量越高,启发值越大 d = norm(nodes(i,:) - nodes(j,:)); [ptx, ~] = radio_energy(packetLen, d); eta = (Erem(j) / E0) / (ptx + 1e-12); end

这个函数没有直接返回路由选择结果,而是返回一个用于概率计算的权重。参数说明里值得注意的一点是:分母用的是 ptx,而不是 ptx + prx,原因是接收耗能由 j 承担,已经体现在 Erem(j) 这个分子项里了。如果这里再把 prx 加进分母,会形成双重惩罚,导致启发值整体偏小、概率差异不明显,等于削弱了 β 的作用。

3.2 信息素更新:局部挥发与全局增强怎么配合

蚂蚁走完一轮后,信息素矩阵必须更新。更新分成两个动作:所有边都按挥发系数 ρ 衰减,这是为了让旧的路径选择“降温”;然后本轮搜索到的最优路径额外增加信息素,这是为了“奖励”表现好的路径。两者缺一不可,否则要么路径从不收敛,要么收敛到一条固定路径后再也不改。

% 信息素浓度矩阵与更新参数 tau = ones(numNodes, numNodes) * 1e-3; % 初始信息素设小值 rho = 0.2; % 挥发系数 Q = 1e4; % 信息素增量常数,与路径代价数量级匹配 % 假设 bestRoute 是当前迭代最优路径索引列表,bestCost 是其总能耗代价 for idx = 1:length(bestRoute)-1 u = bestRoute(idx); v = bestRoute(idx+1); tau(u,v) = (1-rho) * tau(u,v) + Q / bestCost; tau(v,u) = tau(u,v); % 双向链路信息素对称更新 end

这段代码的关键在于 Q / bestCost 这个比值:路径总能耗越低,单位能耗分到的信息素越多,后续蚂蚁会更愿意沿着这条路径走。Q 的取值要和能耗数量级对得上。前面能耗模型算出来的单跳耗能大约在 10⁻⁴ 焦耳量级,一百条边累计的 bestCost 在 10⁻² 量级,Q 取 1e4 时 Q/bestCost 约在 10⁶ 量级,和初始信息素 1e-3 拉开足够梯度;如果 Q 设得太小,比如只有 1,信息素增量远小于初始浓度,路径收敛会非常慢,甚至几百轮看不出倾向性。

3.3 MATLAB 主循环骨架:一轮仿真包含哪些动作

一个完整的 WSN 路由仿真主循环并不需要写得多复杂,但流程顺序不能乱。每一轮迭代依次做三件事:为所有存活节点选择到基站的路由,沿路由发送数据并扣减收发双方能量,统计死亡节点并更新生命周期指标。下面这段骨架去掉了细节函数,保留结构:

% ACO_WSN 仿真主循环骨架 rng(42); numRounds = 2000; FND = numRounds; HND = numRounds; for r = 1:numRounds routeSet = buildRoutesACO(nodes, Erem, alive, sink, adj, tau, alpha, beta); [Erem, alive] = transmitRound(routeSet, nodes, Erem, alive, packetLen); if sum(alive) == numNodes - 1 && FND == numRounds FND = r; % 记录第一个节点死亡轮次 end if sum(alive) <= numNodes / 2 HND = r; % 记录半数节点死亡轮次 break; end end fprintf('FND = %d, HND = %d\n', FND, HND);

buildRoutesACO 和 transmitRound 是把第三节和第二节的内容封装成子函数。buildRoutesACO 内部的核心是一个 while 循环:当前节点遍历邻居,排除已访问节点和死亡节点,按状态转移概率决定下一跳,累加路径能耗,直到碰上基站或步数上限。transmitRound 则遍历所有源节点,把路径上每条边的 ptx 和 prx 分别扣到对应节点头上。这个骨架的好处是路由层与能耗层解耦,后面想换算法时只需要改 buildRoutesACO 这一行。

4. 把能耗与生命周期写进目标函数:三个必经的调整步骤

很多初版蚁群路由跑出来的结果和最短路径差不多,原因是只改路由算法,没有改“什么才算好路径”的定义。蚁群算法本身只是个搜索框架,真正让 WSN 场景受益的是把能量均衡织进路径代价的每一层。

4.1 路径代价从“最短距离”改成“剩余能量 + 传输能耗”的加权组合

最短路径算法优化的目标是距离之和最小,这个目标在 WSN 里天然有缺陷:中心节点距离大家都近,所有流量都往它身上压,它的能量会先被耗尽。蚁群算法的启发因子如果只是 1/d_ij,结果同样会复现这个缺陷。按第三节的做法,把启发因子换成剩余能量占比除以传输能耗,相当于在路径代价里同时惩罚高耗能链路和低剩余能量中继节点。

实际改动只有一处:heuristic 函数里多乘一个 Erem(j)/E0。这样距离相同的两个候选邻居,剩余能量高的那个会以指数级概率被选中。要注意β的取值会放大这种差异,β 从 1 调到 3,路径选择结果会有明显变化;如果想让路由更“均衡”而不是更“省电”,β 不宜超过 2.5。

4.2 死亡节点剔除与孤立节点处理:信息素要不要清空

当某个节点的能量耗尽后,它不能再作为下一跳出现在 allowed 集合里,这一点通常都会做,但容易漏掉的是信息素矩阵里的残留值。如果一个已经死亡的节点之前是热路径上的关键中继,它的边里还存着大量信息素,虽然 allowed 集合把它过滤了,但其他路径的搜索概率会受到它周围边的间接影响吗?严格说不会,因为概率计算只看当前节点到存活邻居的边;但如果程序实现里先只在概率计算处过滤死亡节点,而没有在拓扑矩阵层面剔除,那么蚂蚁可能在“死胡同”里反复试探,浪费大量无效计算。

常见的工程做法是在每轮开始时同步更新邻接矩阵 adj,把死亡节点对应的行和列全部置 false。信息素不用清零,清零反而会丢失历史信息;只需要保证死亡节点的边不参与概率计算即可。还有一种需要清空的情况:节点重新部署或基站位置改变,此时旧信息素完全失去意义,tau 矩阵直接重新初始化。

4.3 生命周期曲线的量化对比:ACO 到底赢在哪一段

如果按上面这套方案实现,用固定随机种子跑 100 个节点、0.5J 初始能量、4000bit 数据包,我这边得到的典型结果大致是这样:最短路径树算法的 FND 约在 260 轮左右,HND 约在 480 轮;蚁群算法不加能量启发时 FND 只有微弱提升,加上剩余能量启发后 FND 可以推到 380 到 420 轮,HND 能到 650 轮以上。LND 的差异反而缩小,大约只差 15% 到 20%。

算法与配置FND 相对值HND 相对值特征
最短路径树1.001.00中心节点先死,曲线斜率陡
ACO 不加能量启发1.061.08路径轮换有限,收益不明显
ACO 含剩余能量启发1.451.37前中期均衡显著,LND 差异缩小

这个对比表只是为了说明“收益分布在哪一段”的节奏,具体的轮次会随部署和参数变化,但结构性的结论是稳定的:ACO 的能量启发带来的不是极限续航,而是把死亡时间从“很早有节点死”推迟到“大家死得相对整齐”。验证算法有没有真正生效,就看 FND 和 HND 是否同步后移;只有 LND 后移而 FND 基本不变,说明算法并没有做到能量均衡,只是偶然拖慢了最后几个节点的死亡速度。

5. 蚁群算法参数调优与避坑:五条让我至少多花一周时间的血泪经验

这一章把 WSN 路由仿真里最常见的问题集中放在一起。每一条都是我在调参过程或帮人排查代码时真实遇到过的现象,按“现象 → 原因 → 解决”的顺序写,方便对照着改。

5.1 前 30 轮就出现节点死亡,生命周期曲线断崖式下滑

现象:仿真跑不到 50 轮,第一个节点就死了,随后存活节点数曲线像雪崩一样往下掉。原因:α 取值太高、β 取值太低,蚂蚁基本不听启发因子的指挥,所有流量持续沿着初始信息素较高的一条路径走,某个中继节点被瞬间掏空。很多初版把 α 设为 2.5、β 设为 0.5,还以为是“加大历史路径的信任度”,实际上等于让蚂蚁对剩余能量视而不见。解决:先从 α=1、β=2 这个保守组合起步,确认 FND 明显后移后再微调;ρ 也先用 0.2,不要图“让路径快点收敛”一上来就设 0.8。信息素浓度高导致路径锁死,是这类问题里最容易定位的原因。

5.2 同一个 .m 脚本,换个随机种子结果完全不可复现

现象:上午跑的 FND 是 390 轮,下午重跑变成 280 轮,代码一个字没改。原因:脚本没有固定随机种子,或者中途调用了 rand 但没有用 rng 重置。MATLAB 不同版本之间随机数生成器算法不同,同样的代码在不同版本里可能产生不同的节点分布,这在多人协作或提交实验报告时是信任度杀手。解决:在每个脚本开头明确写 rng(固定整数),推荐用日期编号或者实验编号。更进一步的做法是把每次仿真的节点坐标、存活曲线、FND/HND 结果用 save 命令存成 .mat 文件,后面出了任何疑问都可以回放同一份初始拓扑,不需要重新生成随机数。

5.3 蚂蚁找不到基站,主循环卡死或单轮迭代耗时暴增

现象:仿真进行到某一轮后,buildRoutesACO 里出现死循环,或者每轮耗时突然从 0.2 秒跳到 5 秒。原因:随机部署产生孤立节点,该节点周围没有可达邻居,蚂蚁的 allowed 集合为空,while 循环不知道往哪走。另一种情况是通信半径设得太小,节点间平均度很低,搜索路径时频繁撞上“死胡同”。解决:部署节点后先做连通性检查,判断每个节点到基站是否存在一条由存活节点构成的路径;通信半径设成平均邻居距离的 1.5 到 2 倍。同时给 buildRoutesACO 加一个步数上限,比如 numNodes*2 步,超过上限就丢这条路径,避免单个蚂蚁把仿真拖死。

5.4 能耗数量级差三位,所有节点在 100 轮内集体“早逝”

现象:所有对比算法都在同几百轮内节点全灭,而且节点死亡时间高度集中,几乎不看路由策略。原因:能耗单位混用。Eelec 用的是 50e-9,Eamp 却误写成 0.0013e-9,导致远距离传输耗能比正常值放大三个数量级,所有多跳传输都会快速烧穿节点。解决:核对每一处常数时把单位写在注释里,J/bit 和 J/bit/m² 不要弄混。更稳的办法是先跑一个单节点直传基站的简单测试,打印出单轮耗能,确认数量级在 10⁻⁴ 到 10⁻³ 焦耳之间,再进全网络仿真。这一步只要做过一次,后面基本不会犯同类错误。

5.5 生命周期指标只看 LND,把 ACO 报告写成“没有显著优化”

现象:对比表里 FND 和 HND 都提升了 35% 以上,但最终结论只写了 LND,差异不到 20%,导致方案被批“收益有限”。原因:对生命周期指标的理解不到位,选了最容易掩盖前中期差异的口径。LND 被边缘孤立节点的缓慢耗能拖住,即使路由算法在核心区域做得很均衡,LND 也难以拉开差距。解决:报告和验证统一以 FND 和 HND 为主指标,LND 仅作为参考;在绘制存活节点曲线时,标出 FND 和 HND 两个关键时刻的轮次,让阅读者一眼看出差异主要发生在前中期,而不是最后那几个节点的“苟延残喘”。

6. 验证与进阶:一张生命周期曲线把结论讲透

6.1 三条曲线配合三个指标,少看一个都可能误判

仿真收尾阶段的验证不能只打一行 FND 和 HND 的数字。我现在的习惯是每次实验保存三张图:存活节点数随轮次变化的曲线、全网平均剩余能量随轮次的曲线、信息素矩阵热点分布图。存活曲线看整体死亡节奏,平均剩余能量曲线看能耗速率是否被压制,信息素热力图看路由是否真的在多条路径之间轮换。如果信息素热点始终集中在同一条链路上,说明剩余能量启发因子没有起到实质作用,蚂蚁只是在形式上跑了一遍蚁群算法,本质上还是最短路径。

% 结果保存与绘图 aliveCount = cumsum(aliveHistory, 1); % 存活节点数随轮次累计 figure; plot(1:maxRound, aliveCount(:, end), 'k-', 'LineWidth', 1.5); xlabel('round 轮次'); ylabel('alive nodes 存活节点数'); hold on; plot([FND FND], ylim, 'r--'); % 标出 FND 位置 plot([HND HND], ylim, 'b--'); % 标出 HND 位置 legend('存活节点', 'FND', 'HND');

保存曲线的同时把节点坐标、路由表、每轮剩余能量矩阵一并存成 .mat 文件。这样后续换参数对比时,不需要重新跑一遍旧代码,直接加载历史数据做差异分析,省掉大量重复仿真时间。这也是我想强调的验证纪律:每个实验跑三组随机种子或者三组参数,淘汰极端值后取中位数,防止单次随机结果带来的误判。

6.2 从 MATLAB 仿真到真实部署,边界在哪里

MATLAB 里验证通过的 ACO 路由方案,直接搬去真实节点时大概率会打折扣,因为仿真模型没有包含链路层重传、无线信道干扰、时钟同步误差这些现实因素。但是路由层的能量均衡逻辑在真实节点依然成立,这正是 MATLAB 仿真阶段的价值所在:先用轻量模型把路由策略选型筛出来,再往 NS-3 或 OMNeT++ 这类更贴近协议栈的仿真环境迁移。做迁移时保留能耗模型和生命周期统计口径,替换的是信道模型和 MAC 层行为,这比直接在复杂仿真环境里从头调 ACO 参数省力得多。我现在接手一个新场景的时候,依然是先在 MATLAB 里把算法行为摸透,再决定是否值得往硬件方向推进,这个顺序帮我避开过好几轮“精心建模却在真实场景翻车”的弯路。希望帮到你。

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

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

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

立即咨询