Leach代码分析报告.docx
《Leach代码分析报告.docx》由会员分享,可在线阅读,更多相关《Leach代码分析报告.docx(17页珍藏版)》请在冰豆网上搜索。
Leach代码分析报告
一、Leach协议与NS的关系2
二、算法设计思想4
三、簇头建立算法流程图5
四、难点解决7
五、算法运行结果分析10
参考文献19
一、Leach协议与NS的关系
为了实现leach协议,对ns进行扩展。
在ns中增加了一个事件驱动模拟器支持模拟无线传感器网络协议。
这些扩展包括MAC协议,用于计算和交互的能量分配模型和leach协议的体系结构。
网络拓扑结构可以通过简单的Nodes,Links,Agents和Applications描述。
Nodes相当于网络中的终端主机,Links是用于Nodes交互的连接器,Agent用来实现不同网络协议,是支持分组产生和丢弃的节点。
Applications用来产生数据和实现不同的应用函数。
一旦网络拓扑结构建立起来后,模拟通过启动节点上的Applications运行。
为了在ns中支持无线传感器网络,在ns中增加了mobilenodes,MAC协议和信道传播模型Channel。
Applications类的头文件用Tcl语言写的,节点中的其他函数功能用C++语言写成的。
数据包的发送过程:
Applications创建数据包(datapackets),然后发送给Agent.Agent执行协议栈中运输层和网络层的功能,将数据包发送给CMUTrace,。
CMUTrace将packets的统计数据写到trace文件,然后将packets发至Connector。
Connector将数据包传送给用于数据链路处理的链路层(LL).经过一小段时间的延迟后,数据包由LL发送给Queue缓冲队列。
如果是还没有传送过的数据包,Queue将以队列进行存储。
然后Queue将数据包出队列,发送到MAC层。
然后开始运行MAC(媒体访问控制)协议。
最终,packets被发送到网络接口层(NetworkInterface),网络接口层将packets加上正确的传输能量,然后将packets发送到Channel.Channel将packets进行拷贝,并发往连接信道的每一个节点。
发送过程可参考如下图1
数据包的接收过程:
数据包被节点的网络接口接收,并被向上传送至MAC层,Link-Layer,Connector,CMUTrace,和Agent函数.Agent对数据包进行判定,并将数据包到达的信息通知给Application.
接收过程与发送过程传输的路径相反。
二、算法设计思想
Leach协议跨越几个层次实现的协议,Leachapp应用在最高层Application。
它是自适应分簇拓扑算法。
周期执行,每轮循环分为簇头的建立阶段和稳定的数据通信阶段。
(1)簇头建立阶段:
初始阶段,每个节点从0和1中随机产生一个数,如果这个数小于阀值T(n),该节点就成为当前轮的簇头。
其中,P是期望的簇头数在所有节点中占的百分比,r是选举轮数,rmod(1/p)代表这一轮循环中当选过簇头的节点个数,G是这一轮循环中未当选过簇头的节点集合。
每个节点自主选择是否成为当前轮的簇头并通过广播的形式报告给其他节点。
簇头通过CSMAMAC协议进行广播,所有的簇头以相同的传输能量进行广播。
簇头建立起来之后,每个非簇头节点要决定在当前轮中自己属于哪个簇头。
非簇头节点根据收到的广播信号强度决定加入哪个簇头。
非簇头节点决定了自己属于哪个簇头后,必须通知簇头节点它是该簇的成员。
非簇头节点同样通过CSMAMAC协议将自己加入该簇的信息报告给簇头节点。
簇头节点收到所有的非簇头节点加入的信息后,基于本簇加入的节点数目创建TDMA调度,通知每个节点什么时间可以传输数据。
在leach协议中,具体通过calculatePi()函数计算门限值thresh.
doubleLeachApp:
:
calculatePi()
{
registerintn=config_.numberNodes_;//节点个数
registerintk=config_.desiredClusters_;//期望簇头数
doublethresh;//阀值
if(hasBeenClusterHead())
thresh=0;//已经是簇头,本轮中不再成为簇头
elseif(n-k*round_<1)
thresh=1;//将节点设置为簇头
else
thresh=(double)k/(n-k*round_);
returnthresh;
}
(2)数据传输阶段:
一个簇的信息传输会影响相邻簇。
为了减少这种信号干扰,各个簇的信息交互通过不同的CDMA编码。
簇头可以决定本簇中节点所用的CDMA编码。
这个用于当前阶段的CDMA编码在广播簇头的时候发送给簇节点。
具体在advertiseClusterHead()中实现。
此外,簇头根据本簇的节点个数创建TDMA调度。
具体的,簇头在findBestCluster()函数中调用createSchedule(),而由createSchedule()函数具体创建TDMA调度。
当簇节点收到这个消息后,它们会在各自的时间槽发送数据。
簇头节点收到所有的数据后执行信号处理函数压缩数据为一个信号,并将这个合成的信号发给基站。
三、簇头建立算法流程图
簇头的建立是在decideClusterHead()函数实现。
具体流程图如图1
图1簇头建立算法流程图
四、难点解决
1.CDMA编码问题
Leach协议中不同簇用不同的CDMA编码,同一个簇采用同一个CDMA编码进行数据传输。
如果以各个簇头为结点,建立完全图。
为了使各个簇采用不同的编码,利用PCA边着色。
所谓PCA边着色问题,指在完全图中给节点的每条邻接边分配不同的码。
每个节点用一个码在其邻接边(即链路)上进行发送或接收数据。
以下,图2是PCA着色问题的一个示例。
图2PCA边着色示意图
如果记PCA需要的最大可用码数为:
#(PCA)
根据图论知识:
#(PCA)<=2⊿-1,其中⊿指图中节点的最大度数
例如:
在图2中,节点的最大度数为6,故⊿为6
在leach协议中,假定期望的簇头数为n,再加上汇聚节点,所以,节点的最大度数⊿为(n+1)。
因此,
#(PCA)<=2(n+1)-1=2n+1
在leachApp.cc程序中,簇头建立后,簇头决定本簇的CDMA编码。
这是在广播簇头时确定的,即advertiseClusterHead()函数中。
numCodesAvail=2*config_.spreading_-1;//计算最大可用码
clusterCode=(mac_->myADVnum()%numCodesAvail)+1;//设置CDMA编码
在leachApp.cc程序中,structleachConfig中对desiredClusters_(期望的簇头数)和config_.spreading进行了定义。
在initializeConfig()函数中语句:
config_.spreading_=config_.desiredClusters_+1
在LeachApp的构造函数LeachApp(intnNodes,intnClusters,doublemaxDist)中语句:
config_.desiredClusters_=nClusters
在TCL脚本中
setval(n_common)10//普通节点个数可任意设置,此处设为10
setval(n_ch)0//簇头数初始值为0
setval(n_ch)[exprint($val(n_common)*2/10)]//对期望的簇头数进行了设置,为普通节点个数的20%(即上式中的2/10)
因此,可以计算得出numCodesAvail
在mac-sensor.h中,
intmyADVnum_;//收到的广播消息,即邻近的簇头节点的个数
inlineint&myADVnum(){returnmyADVnum_;}
myADVnum()是在MAC层中计算求得。
启动运行后,计算每个簇头的邻近簇头发来的ADV。
因此,可求得clusterCode
2.TDMA调度
在findBestCluster()函数中,当判定节点是簇头节点时需要createScheduler。
在createScheduler函数中,如果簇节点不空,就需要创建TDMA时分复用帧。
frameTime表示该簇头节点分配的一个时间帧;
clusterNodes_.size()表示一个簇的节点个数
config_.ssSlotTime_表示一个时间帧的小的时隙
lstRndDelay表示缓冲时间
xmitTime_表示簇所有节点的数据发送时间
createScheduler函数主要语句如下:
frameTime_=(5+clusterNodes_.size())*config_.ssSlotTime_;//计算时间帧
lstRndDelay_=Random:
:
uniform(0,0.01);//随机选取缓冲时间
xmitTime_=config_.ssSlotTime_*(clusterNodes_.size())+lstRndDelay_;
Scheduler:
:
instance().schedule(
eventHandler_,
newLeachEvent(&LeachApp:
:
sendDataToBS),
xmitTime_);
3.clearClusterChoices()
由于各个簇头形成和建立起来的时间不同,而簇头建立起来后需要广播ADV,通知其他节点加入。
簇头广播的ADV会被网络中的所有节点接收到,即簇头和普通节点都能收到先建立起来的簇头发来的ADV。
普通节点收到簇头发来的通知包后都会将该数据包加入自己的一个接收队列。
对后来建立起来的簇头来说,一旦自己成为簇头,就会删除其他簇头发来的广播包;对没有成为簇头的普通节点来说,需要出接收的簇头队列中选出一个距离最近的簇头加入,然后删除接收队列中的广播包。
在decideClusterHead()函数中,当节点成为簇头后,需要执行clearClusterChoices(),函数clearClusterChoices()主要语句如下:
for(CHs:
:
iteratorit=clusterChoices_.begin();it!
=clusterChoices_.end();it++)
{
chadvelement=(chadv)*it;
if(element.object!
=NULL)
deleteelement.object;
}
而普通节点则需要在findBestCluster()中找到最优簇头(即距离最近的簇头)后,执行clearClusterChoices()
4.一些定义
(1)virtualdoubleTxTime(intn){returnn*8.0/1000000.0;}
TxTime指以1Mbps的速度传输nbit数据所需要的时间
(2)doublelstRndDelay_;//上次随机延迟时间
intcurrentCH_;//当前簇头
intcurrentCHMAC_;//当前簇头所用的MAC协议
boollistenADV_;//是否收听ADV
boollistenJOINREQ_;//是否监听加入请求
五、算法运行结果分析
1.场景介绍
用ns模拟每个节点向基站传输数据
BasicConfiguration:
图3BasicConfiguration配置图
AccessPoint:
图4AccessPoint配置图
CommonNode:
图5CommonNode配置图
输出得到TCL文件。
在ns环境下运行该TCL文件,得到trace文件。
2.trace 文件分析
trace的功能是详细记录模拟的过程,可以根据用户的需要记录模拟过程中的任何一个细节。
所有对模拟的分析是基于trace文件。
截取一部分文件代码如下:
s-t0.007580973-Hs1-Hd-2-Ni1-Nx48.64-Ny86.26-Nz0.00-Ne10.000000-NlAGT-Nw----Ma0-Md1000000-Ms0-Mt0-Is1.0-Id-1.0-Itrca-Il4-If0-Ii0-Iv32
r-t0.007580973-Hs1-Hd-2-Ni1-Nx48.64-Ny86.26-Nz0.00-Ne10.000000-NlRTR-Nw----Ma0-Md1000000-Ms0-Mt0-Is1.0-Id-1.0-Itrca-Il4-If0-Ii0-Iv32
s-t0.007580973-Hs1-Hd-2-Ni1-Nx48.64-Ny86.26-Nz0.00-Ne10.000000-NlRTR-Nw----Ma0-Md1000000-Ms0-Mt0-Is1.0-Id-1.0-Itrca-Il4-If0-Ii0-Iv32
在文件分析中主要用到t,Ni,Ne这几个数据。
其中,t后面的数字代表时间,Ni后面的数字代表节点ID,Ne后面的数字代表节点能量
使用语言gwak,绘图工具gnuplot.上述场景中生成的trace文件名为:
trace.tr
去掉所有以N开头的行数,该行为统计数据,得到文件trace1.tr
(1)单个节点能量变化统计:
以节点1为例,提取所有Ni等于1的节点的时间和相应能量,存入文件1.txt.
在gawk环境中,输入代码如下:
gawk‘$9==/1/{print$3,$17}’trace1.tr>1.txt
得到统计数据如下:
0.00758097310.000000
0.00758097310.000000
0.00758097310.000000
0.00760597310.000000
2.4613463769.963363
2.4613713769.963363
2.4613713769.963363
3.5363729739.945803
3.5363729739.945803
3.5363729739.945803
3.5363979739.945803
在gnuplot环境中输入:
gnuplot‘1.txt’using1:
2
得到的能量变化图如下图所示:
图6节点1能量变化图
(2)工作节点能量统计:
从trace.tr文件中提取普通节点的数据。
gawk‘$1~/N/{print$3,$5,&7}’trace.tr>n.txt//第3列代表时间,第5列代表节点ID,第7列代表能量值
gawk‘$2!
=0{print$1,$3}’n.txt>2.txt//去掉sink节点,sink节点ID为0
再从2.txt中进行能量统计,统计时间间隔为0.5秒
gawk‘{if($1<0.5)sum+=$2};
END{printsum}’2.txt>3.txt
gawk‘{if($1<1.0)sum+=$2};
END{printsum}’2.txt>>3.txt
gawk‘{if($1<2.5)sum+=$2};
END{printsum}’2.txt>>3.txt
gawk‘{if($1<3.0)sum+=$2};
END{printsum}’2.txt>>3.txt
gawk‘{if($1<3.5)sum+=$2};
END{printsum}’2.txt>>3.txt
gawk‘{if($1<4.0)sum+=$2};
END{printsum}’2.txt>>3.txt
gawk‘{if($1<4.5)sum+=$2};
END{printsum}’2.txt>>3.txt
得到文件3.txt的统计数据如下:
0.53918.84
1.02937.01
2.51395.12
3.04700.22
3.55194.79
4.03271.12
4.51132.38
全网间隔时间为0.5秒工作节点能量变化图:
图7工作节点能量变化图
3.全网所有节点能量和变化统计
在gawk环境下输入:
gawk‘$9!
=0{print$3,$9,$17}’trace1.tr>4.txt//提取普通节点的时间,ID,能量
将以下程序写入文件1.awk
BEGIN{
FS=""
unit=0.5;
ftime=0;
time=0;
for(i=1;i<=50;i++)
{e[i]=10.0;
sum+=e[i];
}
printf"%f,%f\n",time,sum;
time+=unit;
}
{
if(ftime<$1&&$1