ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于Matlab的LEACH、LEACH-C与TS-I-LEACH分簇路由协议仿真对比

基于Matlab的LEACH、LEACH-C与TS-I-LEACH分簇路由协议仿真对比 做无线传感器网络研究的人应该没有不知道LEACH的。这个在上世纪九十年代末被提出的分簇路由协议直到今天依然是WSN能量效率研究里绕不开的参照基准。我这段时间用Matlab把LEACH、LEACH-C和TS-I-LEACH三种协议从分簇机制、能量模型到网络生命周期做了完整的仿真对比整个过程踩了不少坑也把协议背后的设计逻辑彻底理了一遍。这篇文章会把三种协议的原理差异、Matlab实现细节、结果对比方法一次说清楚适合正在做无线传感器网络课程设计、毕业设计或者准备复现经典路由协议做对比实验的同学直接参考。1. 项目背景与核心需求拆解1.1 无线传感器网络里路由协议为什么这么关键无线传感器网络由大量低成本、低功耗的传感器节点组成这些节点靠电池供电部署后基本没法更换电池。所以整个网络设计的第一原则就是省电而路由协议直接决定数据从哪条路径传、由哪些节点转发、转发几次这几件事几乎占据了节点绝大部分能耗。如果让每个节点都直接跟基站通信离基站远的节点会很快耗尽能量网络就出现“能量空洞”。LEACH这类分簇路由的核心思路是把节点分成若干簇每个簇选出一个簇头普通节点把数据发给簇头簇头做数据融合后再转发给基站。这样大多数节点只需要短距离通信长距离通信由少数簇头承担而且簇头每轮轮换避免个别节点过早死亡。这个思路现在看似乎不复杂但在当年是非常关键的一跳。后续很多改进协议包括LEACH-C和TS-I-LEACH都是在LEACH这个框架上做优化。所以我们做研究工作第一步一定是把LEACH的准确行为摸透。1.2 三种协议放在一起对比的逻辑LEACH是分布式随机分簇每个节点自己用随机数决定要不要当簇头优点是简单、不需要额外信息缺点是簇头分布可能很不均匀。LEACH-C把分簇决策收归基站BS节点先把位置和能量信息上报基站用全局优化算法算出簇头集合和分簇方案再广播回去。优点是分簇更均匀代价是每轮都要额外通信开销。TS-I-LEACH在标题里通常指Threshold-Sensitive Improved LEACH也就是阈值敏感改进型LEACH。它在LEACH基础上加入双阈值上报机制传感器只有读数超过硬阈值或相对上次上报的变化超过软阈值时才发送数据同时簇头选择也引入能量因子修正明显更贴合事件驱动类监测应用。把三者放在一起比较实质就是比较三种不同设计哲学本地随机决策、全局集中优化、事件感知加能量感知。这种对比能直观看出WSN路由协议演进过程中每一步改动解决了什么问题又付出了什么代价。1.3 为什么用Matlab而不是NS2/OMNeT很多同学一上手就想用NS2或OMNeT这类离散事件仿真器。但如果你是做协议层面的能量对比研究Matlab反而是更高效的方案。NS2的学习曲线很陡装环境、写Tcl脚本、分析trace文件可能一周都还没跑通一个LEACH。Matlab不需要搭复杂的仿真框架直接把100个节点的坐标、能量、通信规则写在脚本里几百行代码就能完整模拟出网络从初始状态到全部节点死亡的整个过程。而且Matlab的绘图能力很强剩余能量曲线、节点存活曲线都是现成的绘图函数出图效率远比Gnuplot高。我个人的建议是第一轮对比研究用Matlab把算法逻辑验证清楚后面如果确实需要更细粒度的MAC层仿真再转到OMNeT也不迟。这样能把精力集中在路由协议本身而不是环境的坑里。2. LEACH协议的仿真机理与问题定位2.1 LEACH的工作流程到底是怎么跑的LEACH把时间划分成固定长度的轮Round每轮又分为建簇阶段和数据传输阶段。在建簇阶段每个节点生成一个0到1之间的随机数如果这个随机数小于当前轮次的阈值T(n)节点就宣布自己成为簇头。T(n)的计算公式是T(n) P / (1 - P * mod(r, 1/P)) 当节点n在前1/P轮内没有当过簇头 T(n) 0 当节点n在前1/P轮内已经当过簇头P是期望的簇头比例r是当前轮数。这个公式的精妙之处在于随着轮数推进阈值会越来越大那些还没当过簇头的节点被选中的概率逐渐升高保证了在每1/P轮内几乎所有节点都有机会当一次簇头。选完簇头后各簇头广播自己成为簇头的消息普通节点收到多个广播后根据信号强度决定加入哪个簇实际仿真里通常简化为选择距离最近的簇头。簇头收到加入请求后给每个成员分配TDMA时隙。数据传输阶段每个节点只在属于自己的时隙里向簇头发数据簇头完成数据融合后直接发往基站然后进入下一轮。2.2 能量模型是整个仿真的地基LEACH仿真的能量模型用的是经典一阶无线电模型这也是几乎所有MATLAB复现LEACH的论文里都会出现的公式E_Tx(l, d) l * Eelec l * Efs * d^2 当d d0 E_Tx(l, d) l * Eelec l * Emp * d^4 当d d0 E_Rx(l) l * Eelec其中l是数据包长度d是传输距离Eelec是发射或接收电路每比特的耗能Efs和Emp是功放系数d0等于sqrt(Efs/Emp)。这套模型的核心意思是短距离传输时能量随距离平方增长距离超过d0后多径衰落主导能量随距离四次方增长。所以节点要尽量走簇头转发就是避免远距离直接通信。仿真里常用的参数是初始能量0.5焦耳Eelec取50nJ/bitEfs取10pJ/bit/m²Emp取0.0013pJ/bit/m⁴数据包4000bit控制包100bit。这里的单位特别容易踩坑后面我会专门说。2.3 LEACH在仿真中暴露的三个痛点第一是簇头分布不均。随机选举虽然保证节点当选概率的平均性但不保证每轮簇头在空间上均匀。如果某个区域随机选出了两个簇头另一个区域一个都没有区域内节点就不得不大范围跨区通信能耗立刻飙升。我在仿真中见过极端情况同一轮里三个簇头挤在二十米范围内其余区域没有簇头那一轮的网络能耗明显比正常轮次高出一截。第二是能量消耗不均衡。簇头意味着额外开销如果某个节点连续多轮被选为簇头即使阈值公式在概率上限制了重复当选但距离基站远的簇头发送数据消耗太大往往坚持不了多少轮就死亡。这种死亡会连锁影响后续分簇因为附近节点失去了廉价中继。第三是固定周期上报机制不灵活。LEACH的每个节点在每个框架里都按分配的时隙发数据不管监测目标有没有变化。这对温度、湿度这类连续采样的应用没问题但对火灾、入侵这类突发事件的响应就有明显延迟。TS-I-LEACH的出现正是为了解决这类问题。3. LEACH-C与TS-I-LEACH的改进思路对照3.1 LEACH-C从“自己抽签”到“上帝视角”LEACH-C的全称是LEACH-Centralized核心改动是把分簇决策放到基站来做。每一轮开始时所有节点先向基站上报自己的位置信息和当前剩余能量。基站收集齐后用模拟退火算法求解一个优化问题在簇头数量固定为N*P的前提下找出一组簇头使得所有非簇头节点到其所属簇头的距离平方和最小。这个目标函数本质上就是希望分簇在空间上紧凑簇头尽可能落在簇的中心附近。模拟退火算法在解决这个问题时有一套比较标准的流程先随机选一组簇头作为初始解计算总代价然后通过随机替换簇头生成新解如果新解代价更低就接受如果代价更高则以一个随时间递减的概率接受避免陷入局部最优。解出来之后基站把簇头编号和分簇结果广播给所有节点节点再按TDMA调度发送数据。实际效果是分簇质量明显比分布式随机方法稳定网络生命周期也因此延长。但代价是每轮的位置上报和结果广播都要消耗能量和带宽而且基站变成单点故障点。在小规模网络里收益大于开销节点规模一上来上报成本可能抵消优化收益。3.2 TS-I-LEACH阈值敏感能量感知的双重改进TS-I-LEACH不是某个单一标准而是一类带阈值敏感机制的改进型协议的总称。在我这个项目里我实现的TS-I-LEACH包含两块核心改动一块是数据传输策略。节点不再每个TDMA时隙都发数据而是先设置硬阈值HT和软阈值ST。当传感器读数第一次超过HT时节点立即上报一次之后只有当读数变化幅度超过ST时才再次上报。这样既保证了突发事件不会漏报又避免在数据变化平缓时反复发送重复信息大幅度减少空转能耗。这个机制非常适合森林防火、水质监测、目标跟踪这类“平时安静、突发时灵敏”的场景。另一块是簇头选择策略。LEACH的阈值公式对每个节点一视同仁不管这是刚开机的新节点还是快没电的老节点。TS-I-LEACH在T(n)基础上乘上一个修正因子包含当前剩余能量比和局部节点密度能量多的节点更容易当簇头周围节点密集的节点也更容易当簇头。矩阵修正的方式在不同论文里差别很大但思路都是让簇头选择从“纯随机”变成“能量感知”。我在实现时还有一个小改动在阈值触发上报的同时让节点每隔一定轮数发送一个极短的心跳包。心跳包保证基站能确认节点存活也保证在长时间没有触发事件时基站不会误以为节点全部死亡。这个心跳机制不在所有TS-I-LEACH版本里都有但对于仿真对比来说它让网络状态更透明。3.3 三种协议差异速查表对比维度LEACHLEACH-CTS-I-LEACH簇头决策位置节点本地随机基站集中计算节点本地加能量修正是否需要定位信息不需要需要可选择需要分簇目标就近加入全局距离平方和最小就近加入能量均衡数据上报方式固定周期固定周期阈值触发心跳每轮额外控制开销低中低事件响应实时性一般一般较好网络寿命表现基准明显优于LEACH事件型场景下最佳最适合场景周期数据采集小型静态网络事件驱动监测做横向对比时这三个协议不能简单说谁“更好”。LEACH-C在节点数较少、基站计算资源充足时生命周期延长最显著TS-I-LEACH的优势则体现在数据传输量的大幅下降以及对突发事件更快的响应上。你把三种协议看成三种不同的取舍思路就清晰了。4. Matlab仿真环境搭建与代码实现要点4.1 仿真参数怎么设置才有说服力温度参数设置决定了实验结果的可比性。我采用的是文献里最常见的设置方案在100m×100m的范围内随机部署100个节点基站放在坐标(50,175)处也就是区域外侧上方模拟野外监测中基站位于监控区域边缘的情况。也有一些研究把基站放在(50,50)区域中心两种布局结果差异很大选择哪种要跟你论文里描述的应用场景对应。能量模型参数我用的是初始能量0.5JEelec50nJ/bitEfs10pJ/bit/m²Emp0.0013pJ/bit/m⁴数据包4000bit控制包100bit簇头比例P0.05。d0由sqrt(Efs/Emp)算出约等于87.7m。只要节点间距超过这个值就启用四次方衰减模型但在这个场景里大部分簇成员到簇头的距离都在d0以内主要消耗的还是二次方部分。这里单位最容易出事。Efs10pJ/bit/m²如果在Matlab里直接写Efs10算出来就不是焦耳而是皮焦耳能量量级差了12个数量级。正确的做法是把所有能量系数统一换算成焦耳单位再参与计算。我看到很多复现代码在能量模型上动手脚故意把Efs放大或缩小某个倍数实质上是通过错误参数来美化曲线这个行为在学术上非常危险。4.2 LEACH核心代码拆解LEACH的主循环结构其实很清晰下面这段是簇头选举和建簇的核心逻辑for r 1:max_round % 簇头选举 CH_Flag zeros(1, n); for i 1:n if S(i).E 0 S(i).G 0 threshold P / (1 - P * mod(r, 1/P)); if rand() threshold CH_Flag(i) 1; S(i).G 1; end end end % 非簇头节点选择最近的簇头加入 for i 1:n if CH_Flag(i) 0 S(i).E 0 min_dist inf; for j 1:n if CH_Flag(j) 1 d sqrt((S(i).x - S(j).x)^2 (S(i).y - S(j).y)^2); if d min_dist min_dist d; CH_ID(i) j; end end end end end end选举完簇头之后关键步骤就是按能量模型扣能量。簇成员扣掉发数据的能耗簇头不仅要扣接收各成员数据的能量还要扣融合数据的能量再加上把融合结果发给基站的能耗。很多初版代码只扣了发数据的能量忘了给簇头计算接收能耗结果就是簇头能耗被低估仿真出来的生命周期虚高。还有一个容易忽略的细节当选过簇头的节点S(i).G标记不要清零太早。LEACH要求节点在最近1/P轮内只能当一次簇头所以S(i).G需要等过了1/P轮之后再复位。正确的做法是当mod(r, 1/P) 0的时候把所有节点的G标记清零而不是每轮都清。4.3 LEACH-C与TS-I-LEACH的关键改动位置LEACH-C的代码结构相比LEACH主要区别就在于每轮开头多了一个基站集中决策的环节。布尔数组CH_Flag的判断不再是节点本地随机数而是由基站计算返回的簇头集合。我在实现模拟退火的时候把目标函数写成所有节点到对应簇头的欧氏距离平方和初始候选簇头数设为N*P的整数值随机替换时限制总簇头数不变退火轮数控制在500次左右。模拟退火的代码如下% 模拟退火求解最优簇头集合 current_cost compute_cost(all_nodes, current_CH); for t 1:max_iter candidate_CH current_CH; pos randi(length(candidate_CH)); new_node randi(n); if ismember(new_node, candidate_CH) continue; end candidate_CH(pos) new_node; new_cost compute_cost(all_nodes, candidate_CH); if new_cost current_cost || rand() exp((current_cost - new_cost) / T) current_CH candidate_CH; current_cost new_cost; end T cooling_rate * T; endTS-I-LEACH的改动则在两个地方。第一处是簇头选举阈值公式换成带能量因子的版本代码上就是在threshold的基础上乘一个能量项energy_factor S(i).E / avg_energy; density_factor neighbors(i) / max_neighbors; threshold P / (1 - P * mod(r, 1/P)) * energy_factor * density_factor;第二处是数据上报阶段增加阈值判断。每个节点维护上次发送的值下一轮只有当读数超过硬阈值或者与上次发送值之间差值超过软阈值时才发送if sensor_value HT send_now 1; elseif sensor_value baseline abs(sensor_value - last_sent_value) ST send_now 1; else send_now 0; end这个判断必须在能耗计算之前做没有数据发送就不需要扣发射能耗整轮只有节点自身感应采样的微少能耗。4.4 可复现仿真的几个代码习惯第一一次性生成节点坐标并固定下来。有些同学把节点坐标放在每轮循环里重新生成这相当于每一轮都是一张全新的网络比较结果完全没有意义。正确做法是在仿真开始前用随机种子生成坐标矩阵后续无论跑LEACH还是LEACH-C都用同一份坐标。第二设置随机种子。Matlab里rng(0)一句就能保证每次跑出来的随机数序列一致。你发论文的时候审稿人如果想复现你没有写明随机种子和节点分布文件整个结果就不可复现。建议在主脚本开头加一句rng(0)或把随机种子跟场景编号一起存成一个参数。第三分步保存中间结果。我习惯把每一轮每个节点的剩余能量存成一个矩阵文件名带协议名和随机种子编号。这样后面画存活曲线、能量曲线、簇头数量曲线都不需要重新跑整个仿真。对于一轮迭代几千步的仿真来说中间结果保存对排查问题帮助巨大。第四控制包能量开销要单独计算。LEACH-C的每轮位置上报、TS-I-LEACH的心跳包都属于控制包不能跟数据包混在一起。控制包只有100bit但每轮都要发几百轮累积起来并不少。如果漏掉这部分开销你会发现仿真出的协议数据比论文里记录的好看太多了原因只是系统少了关键成本。5. 仿真结果对比与指标解读5.1 网络生命周期稳定期比总寿命更重要网络生命周期最常用的三个指标是第一个节点死亡轮数FND、半数节点死亡轮数HND和最后一个节点死亡轮数LND。FND常被视为网络稳定期的终点因为一个节点死亡后它负责的区域可能出现覆盖空洞网络服务质量开始下降。我用上述参数在100个节点场景下跑出来的结果大致落在这样的区间不同随机种子会有波动但趋势稳定指标LEACHLEACH-CTS-I-LEACHFND约850轮约1250轮约1450轮HND约1200轮约1650轮约1750轮LND约1900轮约2300轮约2100轮LEACH-C的LND比TS-I-LEACH更高这符合预期因为LEACH-C每轮有全局优化分簇整体能耗最均匀。TS-I-LEACH的FND最高说明它的能量感知簇头选择让网络稳定期延长得很明显后期LND略降则是因为事件触发上报让一些节点在事件密集时段集中耗能但这并不影响它在事件监测场景里的价值。如果你只盯着LND看会得出TS-I-LEACH不如LEACH-C的结论。但在一半以上节点都死亡的网络里覆盖质量和数据可靠性已经大打折扣。实际工程更关心FND和HND也就是网络能保持完整服务能力的时间长度。5.2 剩余能量分布与能耗曲线把每一轮的全局剩余能量做平均能得到一条随时间下降的能耗曲线。LEACH的曲线下降最快而且下降速率并不平稳在某些轮次会出现突兀的加速下滑那大概率就是那一轮簇头刚好随机分布在远端区域长距离传输拖垮了全局能耗。LEACH-C的曲线更平滑整体斜率更缓说明集中分簇确实在抑制能耗波动上有效果。TS-I-LEACH的曲线在无事件时段非常平缓因为大部分节点只是在等待阈值触发不做数据上报一旦事件发生曲线会短暂变陡然后恢复平缓。这种“阶梯式下降”是事件驱动型协议的正常特征。如果你想用TS-I-LEACH做周期上报场景这个优势就体现不出来曲线反而可能因为阈值判断开销变得更不划算。5.3 事件响应效率TS-I-LEACH的优势场景我在仿真中加入了一个模拟事件第500轮到第600轮之间让部分区域节点的监测值持续上升并超过硬阈值用来模拟火情或入侵事件。这时统计基站收到的事件相关数据包数量以及事件发生后第一份有效数据抵达基站的时延。LEACH用的是固定TDMA周期节点即使立刻发现事件也要等到自己分配的时隙才能发送这是结构性的响应延迟。TS-I-LEACH因为有硬阈值中断触发机制发现事件后能尽快上报事件响应延迟明显更短事件期间基站收到的有效事件数据也更多。事件期间的数据包总量上TS-I-LEACH发送的包仍比LEACH少。这个结果说明TS-I-LEACH消除的其实是冗余通信而不是把真实事件信息也一起消掉了。做结果分析时要把这个逻辑讲清楚数据包少了不代表信息少了这是阈值敏感协议最核心的卖点。6. 常见问题与排错经验实录6.1 我在Matlab仿真LEACH时踩过的坑第一个坑是rand和randi混用。LEACH里判断节点是否当选簇头用的是rand也就是0到1之间均匀分布的随机数有些同学手滑写成randi(100)导致阈值判断永远不成立或者簇头数量异常。这个错很隐蔽因为程序不报错只有曲线才对不上预期。第二个坑是能量单位量级。Efs10pJ/bit/m²换算成焦耳要写10e-12或10*10^-12如果写错d0的计算、能量扣除数值全都错乱。我见过一份流传很广的课程代码Eelec写50Efs写10d0算出来是87.7但最后能量曲线却正常原因是代码里根本没有对Efs做pJ到焦耳的换算整个能量体系其实是非物理的。第三个坑是死节点“复活”。某些实现每轮重新给节点赋能量或者在S(i).E 0时没做钳制处理下一轮计算又用负数能量继续参加选举导致死节点也能当簇头。正确做法是在每轮开始前把所有S(i).E 0的节点状态标死在簇头选举、数据传输、分簇三个环节都要跳过这些节点。第四个坑是LEACH-C的位置上报开销被漏掉。位置上报不是免费午餐每个节点每轮都要向基站发一条100bit的控制包仿真时必须扣除这部分发送能耗。否则LEACH-C的实际能耗被低估生命周期比真实情况虚高很多。6.2 仿真指标统计的三个误区第一个误区是FND统计口径不一致。有的代码把能量小于0判定为死亡有的是小于0.0001就算死亡结果差异很大。我建议统一用小于等于0判断并且所有协议用同一个判定逻辑否则对比数据没有可比性。第二个误区是数据包统计把控制包混进来。如果只是统计基站收到的总包数而不区分数据包和控制包LEACH-C因为每轮有额外广播可能显得收包很多但这个数量并不能代表实际数据吞吐量。统计时要把数据包和控制包分开计数。第三个误区是评估TS-I-LEACH时只比较数据包总量。TS-I-LEACH的传输量天然比固定周期协议少这是设计目标不是缺陷。如果你只比总数就会得出它“少传了数据所以更省电”这种过于简单的结论。正确做法是额外统计事件检出率、事件响应时延以及单位能耗下送达的有效事件信息量。6.3 让结果更具说服力的实测建议第一必须保证三种协议运行在完全相同的节点分布和能量参数下。只在相同拓扑下做对比结果才公平。我在每次仿真前会先把节点坐标固定成相同的变量然后在主脚本里切换协议类型这样三类曲线的差异全部来自协议本身而不是随机布点差异。第二多次独立实验取平均。随机性对WSN仿真影响非常大单次实验的结论往往不可靠。建议至少跑10次每次用不同的随机种子重新生成拓扑最后统计平均值和标准差。把标准差标在曲线图上读起来非常有说服力。第三对TS-I-LEACH的阈值参数做敏感性分析。硬阈值和软阈值设置不同网络表现差异很大。可以在仿真里把HT设置成不同数值跑多组实验画出网络寿命随阈值变化的曲线。这张图在论文里能清楚地展示阈值参数对事件响应和能耗的双向影响也方便你向读者解释为什么选这个阈值。第四把每一轮运行的中间数据存成文件。很多同学把仿真和分析放在同一个脚本里结果一旦有bug就要重新跑完整个程序。数据一步一存排查问题时快速定位是哪一轮、哪个节点、哪个环节出错效率会高很多。最后再分享一个实际项目里非常有用的习惯永远先跑通一个基础版本再加改动。我是先把原始LEACH完整跑通确认曲线符合预期后再在它基础上加T-I-LEACH的阈值上报逻辑。这样如果后来结果出问题我至少知道问题大概率出在新增模块里而不是整个协议从头到尾四处都有可能出错。做协议仿真的迭代和排错这个意识比任何技巧都更值钱。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进