ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

LEACH协议原理与MATLAB仿真:分簇路由及能耗模型全解析

LEACH协议原理与MATLAB仿真:分簇路由及能耗模型全解析 简介面向无线传感器网络中的节能路由研究提供LEACH低能量自适应聚类层次协议的MATLAB仿真代码适合通信、物联网方向的学生和科研人员开展算法验证与毕业设计。该协议通过随机动态成簇与簇头轮换实现负载均衡可有效延长网络寿命代码包仅包含1个M文件压缩后大小只有2KB轻量简洁便于直接阅读和运行。仿真脚本覆盖了节点二维随机分布、基于概率的簇头选举、簇内多播/单播通信、收发能量损耗模型以及多轮迭代过程等关键模块支持自行设定节点数量、初始能量和簇头概率等参数运行后可统计存活节点数、总能耗和数据传输成功率并通过图表直观展示网络生命周期变化。已有687人学习下载适合需要快速搭建LEACH基础仿真环境或在此基础上改进协议机制、进行多协议性能对比的读者可作为无线传感器网络方向课程设计与研究入门的参考实现。1. LEACH协议到底在解决什么问题做无线传感器网络研究的人对LEACH一定不陌生。LEACH的全称是Low Energy Adaptive Clustering Hierarchy低功耗自适应分簇路由协议1997年MIT的Heinzelman团队提出可以说是WSN路由协议里的一座里程碑。很多人第一次接触它不是在课堂上而是在跑论文复现时被导师丢来一句“你先把LEACH的MATLAB代码跑通”。我当时就是这么过来的啃了整整一周才把代码调明白。先说说LEACH为什么重要。无线传感器网络里的节点是靠电池供电的通常部署在人类难以到达的区域换电池根本不现实。如果你让每个节点直接把数据传给基站离基站远的节点很快就会因为长距离传输耗尽能量整片网络提前瘫痪。LEACH的核心思路是分簇网络里的节点自动划分为一个个簇每个簇选举一个簇头普通节点把数据发给簇头簇头把数据聚合后转发给基站。这样一来普通节点的通信距离大大缩短簇头承担远距离传输的任务而簇头是轮换着当的能量消耗被平均摊到每个节点上网络生命周期也因此被拉长。这套思路放到今天依然有很强的参考价值。虽然后来的LEACH-C、SEP、DEEC等改进算法层出不穷但万变不离其宗它们都是围绕“选簇头、分簇、聚合并传输数据”这个框架做优化。所以你把LEACH的原版代码吃透后面再去看任何变种算法都会轻松很多。对于正在做毕设、发小论文或者单纯对WSN感兴趣的朋友来说跑一个LEACH的MATLAB仿真不仅能把论文里的算法图和代码对应起来还能快速验证自己对分簇机制的理解。尤其建议新手不要直接上网下载一个大而全的代码包然后无脑运行那样除了得到一个结果图什么也没学到。更好的方式是先理解能量模型和阈值公式再亲手搭一个极简版本最后再对照别人的完整代码查漏补缺。这篇文章我就按这个思路来拆解。2. 跑通环境与代码整体骨架2.1 环境准备MATLAB版本与工具箱选择LEACH仿真对MATLAB版本的要求不高我最早是在R2016a上跑的后来换到R2021a也没问题。你不需要装任何额外的工具箱基础的MATLAB环境就够了只要能用rand、plot、min这类基础函数就行。如果电脑上还没装MATLAB建议装新一点的版本界面差别不大对后面处理图像导出也更友好。有些朋友习惯用Octave跑其实也可以但要注意rand函数的随机数种子处理在Octave和MATLAB里略有差异画图效果也会有一点区别。既然是做LEACH仿真我就默认用MATLAB了。2.2 代码结构怎么拆一个完整的LEACH仿真代码按功能可以拆成四个模块初始化模块定义区域大小、节点数量、基站位置、初始能量、包大小等参数。分簇与簇头选举模块计算每个节点是否成为簇头把普通节点划分到最近的簇头。数据传输模块普通节点发送数据给簇头簇头聚合数据发送给基站同时更新节点剩余能量。统计与可视化模块记录每轮存活节点数、网络总能量、数据包到达量最后画图。我在实际写代码时习惯把配置参数集中在文件开头的一个结构体里比如net.areaLength 100、net.numberNodes 100这样。好处是一轮仿真跑完你想调参数不用满文件找改一行就能重新跑。这也是很多开源代码包会采用的结构见得多了一眼就能认出来。2.3 关键参数初始化下面是我常用的初始化参数直接抄一个小版本示例% 仿真区域 100x100 米 areaLength 100; areaWidth 100; % 节点数量 numNodes 100; % 基站坐标放在区域外 sinkX 0.5 * areaLength; sinkY -50; % 节点初始能量(焦耳) E0 0.5; % 数据包大小(bit) packetLength 4000; % 能量模型参数 Eelec 50e-9; % 电路能耗 50nJ/bit Eamp 100e-12; % 放大能耗 100pJ/bit/m^2 EDA 5e-9; % 数据聚合能耗 5nJ/bit % 每轮簇头占比 p 0.05;这些参数我后面会详细解释这里先有个印象。Eelec和Eamp是经典一阶无线模型的两个核心参数你会在几乎所有LEACH代码里看到它们。3. 核心机制与代码实现逐段拆解3.1 簇头选举的阈值公式分簇算法是LEACH的核心。它的机制是预先设定一个目标簇头比例p比如5%的节点成为簇头。每一轮开始时每个节点独立产生一个0~1之间的随机数再根据阈值公式判断是否当选簇头阈值T(n)的计算公式T(n) p / (1 - p * (r mod (1/p))) 如果 n 属于未当过簇头的节点集合 T(n) 0 否则其中r是当前轮数。这个公式的精妙之处在于如果某个节点在最近的一轮任期内被选为簇头那么它在这期间内就不会再被选把机会让给其它节点。这就实现了“轮换”的效果能量消耗不会集中在个别节点身上。对应的MATLAB代码如下if (rand p / (1 - p * mod(r, round(1/p)))) isClusterHead(i) 1; end我第一次看这段代码时有个疑问为什么不是直接用rand p这么简单后来想明白了如果每轮都直接用固定概率p选择那么理论上每轮大概有p比例节点当选但实际可能出现某个节点连续多轮当选或者长时间没被选中导致能量分布不均。而上面的公式通过“最近1/p轮内只能当一次”的机制把公平性强制做了保证。注意这里的mod(r, round(1/p))是标准LEACH做法。有些改进代码会引入剩余能量因子把它改成加权概率那个就是另一类算法了后面扩展部分再细说。3.2 分簇形成与簇头归属簇头选出来之后普通节点需要决定加入哪个簇。标准LEACH采用就近原则计算普通节点到所有簇头的欧氏距离选最近的那个作为自己的簇头。代码如下minDist inf; minClusterHead 0; for k 1:numNodes if isClusterHead(k) dist sqrt((nodes(i).x - nodes(k).x)^2 (nodes(i).y - nodes(k).y)^2); if dist minDist minDist dist; minClusterHead k; end end end这段代码看起来简单但有个细节值得注意如果两个簇头离得很近它们之间的普通节点会被分配得不太均衡可能某个簇头要服务很多节点而另一个簇头几乎没活干。这是LEACH的一个固有缺陷因为簇头选出后没有考虑空间分布。你在代码里可以观察到偶尔会出现两个簇头挤在同一个角落的情况这是随机选举机制导致的属于正常现象。分簇完成后普通节点发给簇头的消息包括自己的数据包簇头收到后会做数据聚合。这里引入了一个参数EDA也就是聚合能耗。聚合后的数据包大小一般不会变也就是说簇头要把簇内所有节点的数据汇总成一个标准大小的包发给基站。这样做是为了节省带宽和传输能耗代价是基站看到的数据只是聚合后的摘要精度会损失一些。3.3 能耗模型与数据传输模拟LEACH的能耗模型是仿真中最关键的部分。一阶无线模型First Order Radio Model把发送和接收都当作用能事件来计算发送一个长度为L比特的数据包到距离d外的节点能耗为ETX L * Eelec L * Eamp * d^2 (如果d小于阈值d0) ETX L * Eelec L * Eamp * d^4 (如果d大于阈值d0)接收这个数据包的能耗为ERX L * Eelec这里Eelec是电路能耗Eamp是多径衰减系数。为什么会有d²和d⁴的区分因为短距离传输可以近似自由空间模型能量随距离平方衰减长距离传输要考虑地面反射和干扰衰减会更严重按四次方计算。阈值d0一般取sqrt(Efs / Emp)代码里通常写成d0 sqrt(Efs / Emp);我在改代码时发现一个很常见的问题有人把Efs和Emp的数值抄错量级。Efs一般是10e-11到20e-11量级Emp是1e-13到2e-13量级。如果抄错会导致节点几轮就全死或者一百轮还满血仿真结果完全失真。所以拿到代码后第一件事就是检查这两个参数的量级。在MATLAB代码中每轮数据传输的能耗更新大致是% 普通节点发数据给簇头 nodes(i).energy nodes(i).energy - (packetLength * Eelec packetLength * Eamp * dist^2); % 簇头接收所有成员数据 nodes(j).energy nodes(j).energy - (packetLength * Eelec * membersNum); % 簇头聚合数据 nodes(j).energy nodes(j).energy - (packetLength * EDA * membersNum); % 簇头发数据给基站 nodes(j).energy nodes(j).energy - (packetLength * Eelec packetLength * Eamp * distToSink^2);能量一旦小于等于0节点就标记为死亡不再参与后续轮次。4. 实验过程与结果分析4.1 完整仿真主循环有了前面这些模块主循环就很简单了。我给出的代码结构大致是这样的for r 1:maxRounds % 记录本轮的存活节点数 aliveNodes(r) numNodes - countDeadNodes(nodes); % 1. 选举簇头 for i 1:numNodes if nodes(i).energy 0 nodes(i).isClusterHead 0; if rand p / (1 - p * mod(r, round(1/p))) nodes(i).isClusterHead 1; end end end % 2. 普通节点分簇 for i 1:numNodes if nodes(i).energy 0 ~nodes(i).isClusterHead findNearestClusterHead(nodes, clusterHeads); end end % 3. 数据传输与能量更新 for i 1:numNodes if nodes(i).energy 0 transmitData(nodes, i, sink); end end % 4. 统计本轮数据包到达量 % ... 画图、记录数据 ... end跑完之后最常见的输出就是三张图存活节点数随时间轮数变化图、网络总剩余能量变化图、基站收到的数据包总数图。其中存活节点数曲线是最直观展示网络生命周期的指标。4.2 预期结果长什么样按照上面标准参数跑100个节点、2000轮左右你会看到平滑的第一阶段曲线。大概在800轮到1200轮之间曲线会突然快速下滑节点大批死亡进入“能量耗尽雪崩期”。为什么会雪崩因为部分节点能量耗尽后簇内通信距离被迫拉长剩余节点传输能耗变大形成正反馈。这也是LEACH的一个特点生命周期不是缓慢下降而是先稳定再断崖式下跌。如果你把p设得很大比如0.2早期分簇很多簇头数量过多导致聚合开销变大网络死得更快如果你把p设得很小比如0.01簇头又太少普通节点离簇头太远单跳传输能耗也高。所以p的取值是有一个最优平衡点的原论文在100节点、100m×100m环境下给出的结论是p0.05左右实测也验证了这一点。4.3 调参观察亲手验证一下我建议你跑通基础版本后试三组对比实验来加深理解p从0.01改成0.1观察存活曲线变化记录第一个节点死亡时间和半数节点死亡时间。把基站坐标从区域中心(50,50)改成区域外(50,-50)看总能耗变化感受长距离传输的代价。把节点数量从50改成200其他参数不变看分簇效果和网络密度对生命周期的影响。这三组实验就能让你直观理解LEACH为什么被称为“能量感知协议”。我上课时经常给学生布置这个作业能明显感觉到亲手跑过对比实验的人对分簇协议的理解深度完全不一样。5. 常见问题与调试技巧5.1 死节点数量一直不对很多人跑完代码后发现存活节点数曲线从一开始就在掉前几轮就有节点死亡。这一般不是算法问题而是随机数种子的问题。LEACH依赖rand生成每个节点是否成为簇头的判断如果你没有设置随机数种子每次运行结果都不一样个别运行里某些节点连续多轮当簇头能量耗光早期死亡也正常。想要复现结果在代码开头加一句rng(0);这样每次跑出来的结果就完全一致了。发论文时写清楚随机数种子审稿人复现也方便。5.2 rand在for循环里被反复调用导致结果诡异我见过一种错误写法是在for循环里反复重新计算每个节点的随机数但同时又在判断簇头时用了rand导致同一轮里有些节点被重复判断。这会引发一个奇怪的现象簇头比例远超预期能量消耗加快。排查方法很简单在进入主循环前一次性为每个节点生成一个随机数矩阵每轮只用一次用完就丢。randForClusterHead rand(numNodes, maxRounds);然后每轮直接取randForClusterHead(i, r)既快又不容易出bug。5.3 距离算错坐标与斜边距离的坑MATLAB里求两点距离最常见的就是上头那段手写欧氏距离。但如果节点坐标是用net.grid rand(numNodes, 2) * areaLength这种矩阵形式存的有些新手就喜欢直接写dist norm(nodeA - nodeB)这样没有问题但如果你在循环里成千上万次调用norm性能会很难看。更高效的方式是直接用sqrt((xi-xj)^2 (yi-yj)^2)或者用向量的pdist2一次算完所有点之间的距离矩阵。仿真规模小的时候无所谓节点数上到500的时候性能差距就很明显了。5.4 绘图卡顿检查先降低轮数如果你的仿真有几千轮每轮都画图MATLAB会非常卡。一个常见技巧是仿真中不画实时图只记录数据跑完之后统一画3张图。如果一定要实时观察最多每10轮或每50轮刷新一次画面。另外一个容易忽略的细节是把节点位置和当前存活状态画在图上时记得用hold on和不同着色区分簇头、普通成员和死亡节点否则画面会乱成一团。6. 从LEACH到更多改进算法6.1 常见的LEACH变种哪些值得跑原版LEACH代码跑通以后你可以很容易地往下面几个方向扩展LEACH-C用中央控制算法选簇头基站根据全局能量和位置信息计算最优簇头组合每轮多一次全局信息收集的开销但分簇更均匀生命周期更长。SEP异构场景下的LEACH让高能量节点有更高的概率成为簇头。实现起来也不难把阈值公式里加一个能量权重就行。DEEC动态能量感知协议根据全网平均剩余能量动态调整簇头选举概率复杂度略高适合作为进阶项目。我做过一个对比实验在相同初始能量下LEACH的首节点死亡时间在800轮左右LEACH-C能到1100轮左右SEP在含20%高能节点的场景下能耗均衡性明显更好。这些数据不一定要作为结论但可以作为你仿真验证的参考。6.2 用这套代码还能做什么LEACH仿真框架的价值并不局限于WSN路由。你可以把通信能耗模型换成物联网、无人机网络、水下网络的不同参数或者把分簇算法换成模糊聚类、强化学习等方法用来对比你在新场景下提出的改进方案。很多硕士论文的“仿真与性能分析”章节就是在这样一个框架上叠加自己的创新点然后和LEACH基线做对比。我自己后来自动化地写过一个批量调参脚本把所有实验参数写成一个配置数组循环跑多次最后自动把三条曲线画在同一张图上。这样改一版代码就可以生成一组对比图省了很多手工操作时间。如果你也在做论文实验建议学着写这种小工具非常值得。关于LEACH的MATLAB实现我实际跑下来的最大体会是这个东西看着简单真正调通并且理解每一个参数背后的物理含义需要一点耐心。但一旦把分簇、能耗、轮换这三个核心机制吃透你在WSN领域再去看任何协议代码都会有一种“原来都是老朋友”的感觉。本文还有配套的精品资源点击获取
返回列表