一、实验仿真数据信息
说明:关于无线传感器路由协议,仿真数据均可以参考以上数据
二、传感器节点包含功能
说明:这里的节点相关是关乎编程的,路由包含簇头的产生、簇的形成和簇的路由,但是程序实现的时候不是这样分步去实现的,因为簇头的一部分功能是要在知道自己的簇成员之后才能实现的,这里的节点相关就是该功能要在知道自己的簇成员之后才能编写的功能。距离相关是说明只要发送就要判断与接收目标的距离d,d与d0的关系不同,能耗公式不同。
所以:编程时,簇头的产生包含的功能有:广播、基站
簇的形成包含的功能有:除了广播、基站以外的功能
三、现实中的功能运作顺序图
说明:实验仿真并不是按照以上顺序实现的,也没必要。
四、算法说明
LEACH算法的精华就是这个公式,其中:p是簇头占所有节点的百分比,即节点当选簇头的概率;r是目前循环进行的轮数;G是最近1∕p轮中还未当选过簇头的节点集合.从T(n)我们可以看出,当选过簇头的节点在接下p来的1∕p轮循环中将不能成为簇头,剩节点当选簇头的阈值T(n)增大,节点产生小于T(n)的随机数的概率随之增大,所以节点当选簇头的概率增大。
注意:这个r必须是从0开始的,因为每个历元最后一轮的阈值T是等于1的,这时候必定所有节点都当选了一次簇头,随便举个例子,节点数n = 1000,簇头当选概率p = 0.05,每轮平均选np=50个簇头,进行1/p=20轮,r就是在0~19之间变化的,当r = 19时,会有T = 0.05/(1-0.05x(19mod20))=0.05/0.05=1。
五、仿真代码
%% 清空环境变量
clear;clc;
close all;
%% 1、初始参数设定模块
%现场尺寸-x和y最大值(单位:米)
xm = 100;
ym = 100;
%基站的坐标
sink.x = 0.5 * xm;
sink.y = 0.5 * ym;
%场地中的节点数
n = 100;
packetLength = 4000;%数据包长度
ctrPacketLength = 100;%控制包长度
%能量模型(所有值均以焦耳为单位)
Eo = 0.5;%初始能量
ETX = 50*0.000000001;%耗传输能耗
ERX = 50*0.000000001;%接收能
EDA = 5*0.000000001;%数据聚合能量
%发射放大器类型
Efs = 10*0.000000000001;%小于do
Emp = 0.0013*0.000000000001;%大于do
do = sqrt(Efs/Emp);
%最大轮数
rmax = 2000;
p=0.1;%最佳簇头概率(根据最优簇头公式得来)
%% 2、无线传感器网络模型产生模块
figure;
%构建无线传感器网络,在区域内均匀投放100个节点,并画出图形
for i = 1:n
S(i).xd = rand(1,1)*xm;%坐标
S(i).yd = rand(1,1)*ym;
S(i).G = 0;
S(i).type = 'N';%普通节点
S(i).E = Eo;
plot(S(i).xd,S(i).yd,'o');
hold on;
end
S(n+1).xd = sink.x;
S(n+1).yd = sink.y;
plot(S(n+1).xd,S(n+1).yd,'p');
%% 3、网络运行模块
% 死亡节点数
dead = 0;
first_dead = 0;%第一个死亡节点
teenth_dead = 0;%10%的死亡节点
all_dead = 0;%节点都死亡
%标记
flag_first_dead = 0;
flag_teenth_dead = 0;
flag_all_dead = 0;
% 传输到基站和簇头的比特计数器
packets_TO_BS = 0;
packets_TO_CH = 0;
% 主循环
for r = 0:rmax
%每过一轮周期,重置G
if(mod(r, round(1/p) ) == 0)
for i = 1:n
S(i).G = 0;
end
end
dead = 0;
energy = 0;% 每轮节点剩余总能量
for i = 1:n
% 检查有无死亡节点
if S(i).E <= 0
dead = dead+1;
% (3)第一个死亡节点的产生时间(用轮次表示)
% 第一个节点死亡时间
if dead == 1
if flag_first_dead == 0
first_dead = r;
flag_first_dead = 1;
end
end
% 10%的节点死亡时间
if dead == 0.1*n
if flag_teenth_dead ==0
teenth_dead = r;
flag_teenth_dead = 1;
end
end
if dead == n
if flag_all_dead == 0
all_dead = r;
flag_all_dead = 1;
end
end
end
if S(i).E > 0
energy = energy + S(i).E;%统计每轮节点总能量和
S(i).type = 'N';
end
end
% if flag_all_dead == 1
% break;
% end
STATISTICS.DEAD(r+1) = dead;
STATISTICS.alive(r+1) = n-dead;
STATISTICS.energy(r+1) = energy;
cluster = 0;%计数簇头数
%次循环(选簇头)
if energy > 0%这个判断可以很大程度优化程序,当网络没有能量时,后面的都不用再运行了
for i=1:n
if(S(i).E>0)
temp_rand=rand;
if ( (S(i).G)<=0) %如果该节点在候选集合中
%选簇头
if( temp_rand <= (p/(1-p*mod(r,round(1/p)))))
cluster = cluster+1;
S(i).type = 'C';
S(i).G = round(1/p)-1;
C(cluster).xd = S(i).xd;
C(cluster).yd = S(i).yd;
distance=sqrt( (S(i).xd-(S(n+1).xd) )^2 + (S(i).yd-(S(n+1).yd) )^2 );%到sink的距离
C(cluster).distance = distance;
C(cluster).id = i;
distanceBroad = sqrt(xm^2+ym^2);
%全网广播自成为簇头,距离是distanceBroad
if (distanceBroad > do)
S(i).E = S(i).E- ( ETX * ctrPacketLength + Emp* ctrPacketLength*distanceBroad^4);
else
S(i).E = S(i).E- ( ETX * ctrPacketLength + Efs * ctrPacketLength*distanceBroad^2);
end
%簇头向基站发送数据包能耗
if (distance > do)
S(i).E = S(i).E- ( (ETX+EDA)*packetLength + Emp * packetLength*distance^4);
else
S(i).E = S(i).E- ( (ETX+EDA)*packetLength + Efs * packetLength*distance^2);
end
packets_TO_BS = packets_TO_BS + 1;
end
end
end
end
end
STATISTICS.COUNTCHS(r+1) = cluster;
%次循环(成簇)
if energy > 0
for i = 1:n
if ( S(i).type=='N' && S(i).E>0 ) %普通节点
if(cluster>= 1)%如果有簇头存在
length = zeros(cluster,1);
%加入最近的簇头
for c = 1:cluster
length(c) = sqrt( (S(i).xd - C(c).xd)^2 + (S(i).yd - C(c).yd)^2 );
%接收簇头发来的广播的消耗
S(i).E = S(i).E - ERX * ctrPacketLength;
end
[min_dis, min_dis_cluster] = min(length);%min_dis返回最短距离,min_dis_cluster返回最短距离对应的簇号
%向簇头发送加入消息、向簇头发送数据包
if (min_dis > do)
S(i).E = S(i).E - ( ETX*ctrPacketLength + Emp * ctrPacketLength*min_dis^4); %向簇头发送加入控制消息
S(i).E = S(i).E - ( ETX*packetLength + Emp*packetLength*min_dis^4); %向簇发送头数据包
else
S(i).E = S(i).E - ( ETX*ctrPacketLength + Efs*ctrPacketLength*min_dis^2); %向簇头发送加入控制消息
S(i).E = S(i).E - ( ETX*packetLength + Efs*packetLength*min_dis^2); %向簇头发送数据包
end
%接收簇头确认加入控制消息
S(i).E = S(i).E - ERX*ctrPacketLength;
%簇头接收簇成员的加入消息和数据包,簇头向簇成员发送确认加入的信息
if(min_dis > 0)
S(C(min_dis_cluster).id).E = S(C(min_dis_cluster).id).E - ERX *ctrPacketLength ;%接收加入消息
S(C(min_dis_cluster).id).E = S(C(min_dis_cluster).id).E - ( (ERX + EDA)*packetLength ); %接受簇成员发来的数据包
%簇头向簇成员发送确认加入的信息
if (min_dis > do)
S(C(min_dis_cluster).id).E = S(C(min_dis_cluster).id).E - ( ETX*ctrPacketLength + Emp * ctrPacketLength*min_dis^4);
else
S(C(min_dis_cluster).id).E = S(C(min_dis_cluster).id).E - ( ETX*ctrPacketLength + Efs * ctrPacketLength*min_dis^2);
end
end
S(i).min_dis = min_dis;
S(i).min_dis_cluster = min_dis_cluster;
packets_TO_CH = packets_TO_CH + 1;
else%如果本轮没有簇头,则普通节点直接将数据直接发送给基站
min_dis = sqrt((S(i).xd-S(n+1).xd)^2 + (S(i).yd-S(n+1).yd)^2);
if min_dis > do
S(i).E = S(i).E- (ETX*packetLength + Emp*packetLength*min_dis^4);
else
S(i).E = S(i).E- (ETX*packetLength + Efs*packetLength*min_dis^2);
end
packets_TO_BS = packets_TO_BS+1;
end
end
end
end
STATISTICS.PACKETS_TO_CH(r+1) = packets_TO_CH;
STATISTICS.PACKETS_TO_BS(r+1) = packets_TO_BS;
end
%% 绘图显示
figure;
plot(0:rmax, STATISTICS.DEAD, 'r', 'LineWidth', 2);
xlabel('轮数'); ylabel('死亡节点数');
figure;
plot(0:rmax, STATISTICS.alive, 'b', 'LineWidth', 2);
xlabel('轮数'); ylabel('活动节点数');
figure;
plot(0:rmax, STATISTICS.PACKETS_TO_BS, 'm', 'LineWidth', 2);
xlabel('轮数'); ylabel('基站收到数据包数');
figure;
plot(0:rmax, STATISTICS.COUNTCHS, 'g', 'LineWidth', 2);
xlabel('轮数'); ylabel('簇头数');
figure;
plot(0:rmax, STATISTICS.energy, 'k', 'LineWidth', 2);
xlabel('轮数'); ylabel('剩余能量');
六、运行结果