
简介一份基于MATLAB的LEACH低能量自适应分层协议仿真代码面向无线传感器网络方向的研究者与学习者用于理解簇头轮换机制并评估网络能耗与生存时间。压缩包共1个文件为LEACH_11_6.m脚本大小仅3KB包含网络初始化、簇头概率选举、分簇、数据传输与能量统计等核心逻辑便于直接运行和修改参数。已有133人学习下载。通过调整节点数量、初始能量、选举概率p等参数可观察不同场景下节点死亡速度与网络寿命变化代码注释和结构也有助于对照论文复现LEACH算法过程还可作为进一步改进协议如LEACH-C的基线。适合需要快速搭建WSN仿真实验、完成课程设计或开展节能路由算法对比的读者。1. 无线传感网不能只靠蛮力从 LEACH 协议到 MATLAB 仿真在无线传感器网络里节点通常由电池供电通信耗电远比数据采集高距离一拉开远处节点的能量就会像漏水一样被快速放干。LEACH 的核心反常识在于它不做“人人平摊”的数据上传而是每轮随机抽一小部分节点当簇头让簇头负责收集同簇节点的数据、聚合后转给基站下一轮再换一批节点当簇头。这样能耗压力不再由某一个倒霉的远距离节点长期承担而是变成一种概率上的轮换整体寿命因此被拉长。LEACH_11_6.m就是 LEACH 在 MATLAB 下的一个仿真实现它把节点分布、能量模型、簇头选举、数据转发都落成可运行脚本。下文从协议原理、代码拆解、参数调整和边界条件四个角度把这份资源讲清楚。2. LEACH 算法原理与仿真参数建模要读懂.m文件里的主循环先要把 LEACH 的运行节奏拆清楚。LEACH 以“轮”为最小单元推进每一轮都包含簇头选举、簇形成、数据传输三个阶段。在仿真里这些阶段会体现为节点结构体字段的更新和能量值的扣减。2.1 分簇、周期与簇头轮换LEACH 并不保证每一轮簇头的总数严格相等而是通过概率保证平均簇头数为N * p。每个节点在每个周期开始时依据阈值 T 决定是否竞选簇头。标准阈值公式是% 当前轮数为 rp 为期望簇头比例 mod_r mod(r, round(1 / p)); threshold p / (1 - p * mod_r); if Node(i).alive 1 Node(i).G 0 rand threshold Node(i).CH 1; Node(i).G 1; % 本周期内不再重复当选 end这段代码里Node(i).G记录节点是否在本轮周期内已经当过簇头。mod(r, round(1/p))的作用是把轮数映射到当前周期内让阈值在周期开头最大化随后逐渐变小。rand是 0 到 1 的均匀随机数因此随机数落在阈值之下时就当选簇头。这样的机制可以让节点“轮流扛活”避免同一个节点反复承担转发任务。2.2 通信能耗模型和典型参数LEACH 仿真里常用一阶无线电模型计算收发能耗。发送 L bit 数据到距离 d 的节点要先算自由空间和多径衰减的临界距离 d0通常取d0 sqrt(eps_fs / eps_mp);若d d0发送能耗为L * E_elec L * eps_fs * d^2若d d0发送能耗为L * E_elec L * eps_mp * d^4接收能耗为L * E_elec数据融合能耗为L * E_DA下面是LEACH_11_6.m这类脚本里最常见的一组参数改仿真时通常会从这张表开始参数常用数值说明N100传感器节点数量p0.05期望簇头比例E_init0.5 J节点初始能量E_elec50 nJ/bit射频电路每比特耗能eps_fs10 pJ/bit/m²自由空间信道系数eps_mp0.0013 pJ/bit/m⁴多径衰减信道系数E_DA5 nJ/bit数据融合每比特耗能packet4000 bit单个数据包长度field100×100 m节点分布区域这些参数不是凭空来的它们影响两个关键指标簇头通信距离落在哪个区域以及每个包能耗占初始能量的比例。比如把field从 100 改成 200很多普通节点到簇头的距离会超过 d0能耗模型从平方关系跳到四次方关系网络寿命会明显变化。2.3 簇形成与最近簇头关联簇头选出来之后普通节点要决定加入哪个簇。最直接的做法是遍历所有簇头选择欧氏距离最小的一个。对应代码结构如下min_d inf; for k 1:ch_count d sqrt((Node(i).x - CH(k).x)^2 (Node(i).y - CH(k).y)^2); if d min_d min_d d; Node(i).clusterId k; end end这里ch_count是当前轮实际选出的簇头数量。Node(i).clusterId保存簇头编号后续计算发送能耗时直接取这个距离。需要注意如果某轮选举出的簇头数量为 0仿真脚本必须额外处理否则普通节点找不到可加入的簇整个数据转发阶段会出现空指针或NaN能耗。常见的做法是当ch_count 0时直接跳过本轮数据传输或者强制让剩余能量最高的节点补位。2.4 单轮仿真的主循环框架LEACH_11_6.m的主循环不会太复杂核心段落在逻辑上大概是这样for r 1:rmax % 更新周期标记 if mod(r, round(1 / p)) 0 for i 1:N Node(i).G 0; end end % 1. 选举簇头 % 2. 普通节点关联最近簇头 % 3. 普通节点把数据包发给簇头 % 4. 簇头聚合后转发给基站 % 5. 更新所有节点能量标记死亡节点 if sum([Node.alive]) 1 break; end end这个框架的优点是每一轮的逻辑边界清楚方便在选举、传输、能量扣减三个位置插入调试输出。实际脚本可能写成若干个函数也可能把所有变量都放在工作区里但整体顺序不会跳出这个骨架。理解了这一点再去看LEACH_11_6.m里的变量名就不会被循环嵌套绕晕。3. LEACH_11_6.m 关键模块逐个拆开很多下载到的仿真脚本不会带详细注释直接打开会看到密集的for、if和坐标运算。这一章把常见实现拆成几个功能模块每个模块对应一类逻辑。LEACH_11_6.m大概率没有按函数划分而是用循环顺序写完但模块边界是存在的。3.1 节点初始化和数据结构网络里每个传感器节点可以表达为一个结构体数组初始化代码通常长这样Node repmat(struct(x, 0, y, 0, E, 0, ... alive, 1, G, 0, CH, 0), 1, N); for i 1:N Node(i).x field_x * rand; Node(i).y field_y * rand; Node(i).E E_init; endrepmat的作用是预分配结构体数组避免循环里动态扩展导致性能下降。每个节点的字段含义如下字段作用初始值x, y节点坐标0~field 范围内随机产生E剩余能量E_initalive是否存活1 表示存活G本周期是否当过簇头0CH本轮是否为簇头0基站坐标在有些实现里放在区域中心有些放在区域上方。这个差别会显著影响簇头发送到基站的距离进而影响多径信道是否被触发。调试时可以先确认基站坐标和你的实验场景是否一致。3.2 簇头选举的完整判定簇头选举是 LEACH 的灵魂也是最容易写错的一段。标准阈值写法需要考虑“当前周期已经选过簇头的节点不能再选”以及“新周期所有节点重新获得竞选资格”。if Node(i).alive 1 if Node(i).G 0 select rand; threshold p / (1 - p * mod(r, round(1 / p))); if select threshold Node(i).CH 1; Node(i).G 1; end end end这段代码和第二章的阈值写法等价但把select单独取出来。这里的一个坑是round(1/p)处理非整数周期。当 p 取 0.05 时1/p 20是整数没有问题如果 p 取 0.071/p约等于 14.28直接mod会造成周期判断混乱。稳妥做法是用round(1/p)计算周期长度并且在周期边界时把 G 清零if mod(r, round(1 / p)) 0 for i 1:N Node(i).G 0; end end震荡点在于如果 p 太大每轮簇头数多数据融合和簇头到基站的能耗总额会上升如果 p 太小普通节点到簇头的平均距离变大自由空间系数平方项导致发费电。仿真的意义就是把这种权衡变成可观察的存活节点曲线。3.3 簇内数据聚合与转发能耗统计数据转发阶段要分别计算普通节点和簇头的能耗。普通节点只发送一次数据给簇头簇头要接收多个成员的数据、聚合再发送到基站。这段逻辑在脚本里通常表示为% 普通节点发送自己的数据到簇头 d_to_ch sqrt((Node(i).x - CH(chId).x)^2 (Node(i).y - CH(chId).y)^2); E_tx_member packet * E_elec packet * eps_fs * d_to_ch^2; % 簇头接收并聚合 E_rx_ch packet * E_elec * member_count; E_aggr packet * E_DA * member_count; % 簇头发送聚合结果到基站 d_to_bs sqrt((CH(chId).x - sink.x)^2 (CH(chId).y - sink.y)^2); if d_to_bs d0 E_tx_ch packet * E_elec packet * eps_fs * d_to_bs^2; else E_tx_ch packet * E_elec packet * eps_mp * d_to_bs^4; end注意这里的member_count是否包含簇头自身的数据。通常簇头把自己的感知数据也打包进聚合结果所以融合次数应为member_count 1。不少脚本在这里少计一次导致单轮能耗偏低、网络寿命偏长进而让你对协议性能产生误判。3.4 节点死亡判断和网络寿命记录能量扣减完成后脚本会把能量小于等于 0 的节点标记为死亡。这里需要额外处理负能量否则下一轮该节点还可能抢到簇头身份打乱统计结果。if Node(i).E 0 Node(i).alive 0; Node(i).E 0; end alive_count(r) sum([Node.alive]); if first_dead_round 0 alive_count(r) N first_dead_round r; end网络寿命可以看成三条关键曲线首节点死亡轮数、半数节点死亡轮数、全部节点死亡轮数。脚本里如果没有直接输出可以用上面的alive_count向量自己算。很多论文里的生命周期图本质上就是alive_count随轮数的下降曲线。4. 运行 LEACH_11_6.m 与观测网络生存期拿到压缩包里的LEACH_11_6.m后第一件事不是改参数而是把它跑起来观察输出变量和图形。许多仿真脚本运行后并不打印文字结果都保留在工作区变量里。4.1 在 MATLAB 里运行脚本解压后把工作目录切到对应文件夹再执行脚本cd(D:/downloads/LEACH); LEACH_11_6;如果脚本内部调用figure和plot会弹出存活节点数、总能量变化等曲线。如果没有弹图大概率是因为绘图代码被放在循环内但被跳过或者绘图代码在脚本末尾但没有加hold on。此时可以手动查看工作区whos alive_count first_dead_round plot(1:length(alive_count), alive_count) xlabel(round); ylabel(alive nodes);whos能列出变量名和尺寸帮助确认主循环是否执行完。如果根本看不到alive_count说明脚本可能把变量存在局部函数里或者脚本在clear之前运行工作区被清掉了。4.2 从仿真结果中读取关键指标跑通之后至少有四个指标值得提取指标提取方式物理含义存活节点曲线alive_count(r)每一轮存活节点数首节点死亡轮数first_dead_round网络开始淘汰节点半数节点死亡轮数find(alive_count N/2, 1)半网失效时间剩余总能量sum([Node.E])总能耗速度这四个指标其实是 LEACH 论文和课程设计中用的最频繁的对照指标。只盯着首节点死亡会得到偏向性结论因为 LEACH 的随机选举可能在某几轮运气不好导致个别节点提前死亡。半数节点死亡更稳定也更适合用来比较不同协议的优劣。4.3 固定随机种子与重复实验MATLAB 的rand每次运行都会生成不同随机序列所以哪怕同一个LEACH_11_6.m跑两次结果也会不同。这是正常的但也意味着你想验证参数改动时噪声可能大过参数差异。建议在脚本最开始加rng(2024);这样每次运行都使用同一套随机数结果可复现。做参数扫描时再循环修改rng的种子把多次运行的寿命取平均避免单次随机性误导判断。4.4 用封装函数做参数扫描LEACH_11_6.m很可能是一个直接执行的脚本而不是函数。直接写循环调用脚本会有问题脚本里的变量会覆盖外层循环变量导致p被内部定义值冲掉。比较推荐的做法是把脚本主体包成函数function alive_curve run_leach(sim_p, sim_Einit) N 100; p sim_p; E_init sim_Einit; % 原脚本循环体... alive_curve alive_count; end封装后就可以做简单扫描p_list [0.02, 0.05, 0.1]; figure; hold on; for i 1:length(p_list) alive run_leach(p_list(i), 0.5); plot(alive, DisplayName, [p num2str(p_list(i))]); end legend; xlabel(轮数); ylabel(存活节点数);这样改动的成本很低但能直接看出簇头比例对网络寿命的影响。对比曲线出现交叉也说明不存在一个万能 p 值具体数值高度依赖区域大小和基站位置。5. LEACH 协议的边界条件与可落地的改进方向LEACH 能跑通并不意味着它能直接被搬进实际部署。仿真里经常忽略一个问题随机选举产生的簇头位置分布不均匀。某一轮可能所有簇头都集中在区域左下角右侧的普通节点要用非常长的距离发送数据能量骤降。这是 LEACH 协议本身的边界条件不是代码 bug。看LEACH_11_6.m的结果时可以先统计CH_count的标准差如果波动太大就要考虑增加选举约束。一个实用的调整思路是把剩余能量纳入选择阈值。标准 LEACH 对低能量节点没有保护剩余能量只有 0.01 J 的节点仍然可能被选中当簇头下一轮直接死亡。常见改进阈值公式是E_factor Node(i).E / E_init; threshold E_factor * p / (1 - p * mod(r, round(1 / p)));这个写法让低能量节点更难被选中但要注意设置下限否则可能出现所有节点都因能量低而不竞选簇头的情况。可以加一个保护项threshold max(threshold, 0.05 * p);最后一个建议是在看仿真输出时针对单个节点手算一轮能耗。找一个中间节点打印它的E_tx_member和簇头的E_tx_chfprintf(r%d, member_tx%.2e J, ch_tx%.2e J\n, r, E_tx_member, E_tx_ch);把打印出来的数值代入距离公式很快就能确认自由空间系数和多径系数是否用反以及d0是否和参数表匹配。这种比对方法比直接看整条曲线更容易暴露能量模型里隐藏的单位问题。本文还有配套的精品资源点击获取