在start中调用下面这个方法。
Application/LEACH instproc decideClusterHead {} {
global ns_ chan opt node_
$self instvar alive_ TDMAschedule_
$self instvar begin_idle_ begin_sleep_
# Check the alive status of the node. If the node has run out of
# energy, it no longer functions in the network.
set ISalive [[[$self node] set netif_(0)] set alive_]
if {$alive_ == 1} {
if {$ISalive == 0} {
puts "Node [$self nodeID] is DEAD!!!!"
$chan removeif [[$self node] set netif_(0)]
set alive_ 0
set opt(nn_) [expr $opt(nn_) - 1]
set ISalive [[[$self node] set netif_(0)] set alive_] #从网络接口netif中查看当前节点状 况
如果节点存活,但是节点能量耗光,则$chan removeif [[$self node] set netif_(0)]将节点信道中移出,并将节点设置为死亡。节点的总数目减少一个。
if {$opt(eq_energy) == 1} {
#
# Pi(t) = k / (N - k mod(r,N/k))
# where k is the expected number of clusters per round
# N is the total number of sensor nodes in the network
# and r is the number of rounds that have already passed.
#
set nn $opt(nn_)
if {[expr $nn - $opt(num_clusters) * $round_] < 1} {
set thresh 1
} else {
set thresh [expr double($opt(num_clusters)) / \
[expr $nn - $opt(num_clusters) * $round_]]
# Whenever round_ is 0, all nodes are eligible to be cluster-head.
if {$round_ == 0} {
$self hasnotbeenClusterHead
}
}
# If node has been cluster-head in this group of rounds, it will not
# act as a cluster-head for this round.
if {[$self hasbeenClusterHead?]} {
set thresh 0
}
} else {
#
# Pi(t) = Ei(t) / Etotal(t) * k
# where k is the expected number of clusters per round,
# Ei(t) is the node's current energy, and Etotal(t) is the total
# energy from all nodes in the network.
#
set Etotal 0
# Note! In a real network, would need a routing protocol to get this
# information. Alternatively, each node could estimate Etotal(t) from
# the energy of nodes in its cluster.
for {set id 0} {$id < [expr $opt(nn)-1]} {incr id} {
set app [$node_($id) set rca_app_]
set E [[$app getER] query]
set Etotal [expr $Etotal + $E]
}
set E [[$self getER] query]
set thresh [expr double([expr $E * $opt(num_clusters)]) / $Etotal]
}
上面是对thresh的计算,当(N - k mod(r,N/k))<1,则将thresh设置为1,否则节点thresh=k / (N - k mod(r,N/k)),
每个节点在一个1/p中都要成为簇头节点一次。p=簇头节点占所有节点的比例,在r=0的时候每个节点都有机会吃呢更为簇头节点。如果节点成为过簇头节点则thresh=0,则这个节点在1/p轮后才可以成为簇头节点。
if {[$self getRandomNumber 0 1] < $thresh} {
puts "$nodeID: *******************************************"
puts "$nodeID: Is a cluster head at time [$ns_ now]"
$self setClusterHead
set random_access [$self getRandomNumber 0 $opt(ra_adv)] #opt(ra_adv) in leach.tcl
$ns_ at [expr $now_ + $random_access] "$self advertiseClusterHead"
} else {
puts "$nodeID: *******************************************"
$self unsetClusterHead
}
如果thresh>getRandomNumber,则节点成为簇头节点。然后调用advertiseClusterHead方法。
set next_change_time_ [expr $now_ + $opt(ch_change)]
$ns_ at $next_change_time_ "$self decideClusterHead"
$ns_ at [expr $now_ + $opt(ra_adv_total)] "$self findBestCluster"
当节点成为簇头节点,则节点调用 advertiseClusterHead方法。
set chID [$self nodeID]
set currentCH_ $chID
pp "Cluster Head $currentCH_ broadcasting ADV at time [$ns_ now]"
set mac_dst $MAC_BROADCAST
set link_dst $LINK_BROADCAST
set msg [list $currentCH_]
set datasize [expr $BYTES_ID * [llength $msg]]
# Send beacons opt(max_dist) meters so all nodes can hear.
$self send $mac_dst $link_dst $ADV_CH $msg $datasize $opt(max_dist) $code_
将该节点设置为簇头节点,设置当前节点所处的簇号。然后发送数据,广播该节点为簇头信息到全局网络。
在$ns_ at [expr $now_ + $opt(ra_adv_total)] "$self findBestCluster"调用findBestCluster方法。