基于PSO的分簇路由协议

  本文模拟仿真TL-EBC协议,将LEACH算法与TL-EBC对比。

一、算法简介

1、PSO-C(2007)

  LEACH算法选簇头是分布式随机选取的,存在很多缺陷,集中式选取簇头,一般是将能量不小于网络平均能量的节点作为候选簇头,然后再从这些候选簇头中选出适应度比较好的簇头,这是一个NP问题,一般可采用元启发算法解决。
  假设网络包含N个节点,预先定义分为K个簇头,候选簇头数为M(一般情况M>>K),则可能的分簇方式有C(M,K)种,在其中确定最佳分簇方式,是一个最优化问题。应用PSO算法解决这个问题,使每个粒子代表一种可能的分簇方式,用目标函数评价其性能,设置m个粒子组成群体在C(M,K)种可能的分簇方式种寻找最优解,使目标函数取得最小值,该目标函数定义如下:
在这里插入图片描述
在这里插入图片描述

2、TL-EBC(2012)

  TL-EBC协议在PSO-C协议的基础上加入了一个总簇头的机制,将网络设计成了两层分簇的体系结构。
  总簇头的选择综合考虑节点能量、各簇头节点距离和 与基站距离 3 个方面的因素。首先,在每个簇中选择能量 最大的节点(不包括簇头)为候选总簇头。然后,计算每个候选总簇头的评价函数,具有最小评价函数值的候选总簇 头成为总簇头。评价函数定义如下:
在这里插入图片描述
在这里插入图片描述

二、仿真与分析

1、参数设置

  将200个传感器节点随机部署在200m x 200m的范围内,基站坐标(100,275),位于网络外部。数据包长度为2000bit;控制包长度50bit;簇头的数量设定为节点总数的5%,则K=10;总簇头的数据不进行压缩。PSO算法的参数设置为:种群规模Q=30,c1=c2=2,惯性权重w = 1(这里的设计不同于论文,本人实验过,在该模型种,固定w=1,比线性变化和非线性变化的w设定更加好,不论是在网络循环中,还是在PSO循环中),最大循环次数MaxIter = 50(论文种的MaxIter = 30是不够的)。评价因子权重系数 β \beta β = 0.5, α \alpha α = 0.2; η \eta η = 0.4; λ \lambda λ = 0.4。网络只进行同构网络的分析。

2、MATLAB 程序实现

实验1、不考虑控制包,对比LEACH与TL-EBC

%不考虑控制包
%% 清空环境变量
clear;clc;
close all;

%% 1、初始参数设定模块
%监测区域大小(单位:米)
xm = 200;
ym = 200;

%基站的x和y坐标
sink.x = 0.5 * xm;
sink.y = 275;

%场地中的节点数
n = 200;

%簇头概率
p=0.05;

%最大循环轮数
rmax = 500;

%能量模型(所有值均以焦耳为单位)
Eo = 0.1;%初始能量
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);%距离阈值

%数据包和控制包长度
packetLength = 2000;%数据包长度 
ctrPacketLength = 50;%控制包长度

%% 2、无线传感器网络模型产生模块
%构建无线传感器网络,在区域内均匀投放所有节点,并画出图形
figure;
for i = 1:n
    S(i).xd = rand(1,1)*xm;%坐标
    S(i).yd = rand(1,1)*ym;
    S(i).E = Eo;%初始化节点能量
    %最初没有簇头只有簇成员
    S(i).type = 'N';%簇成员(普通节点) 
    plot(S(i).xd,S(i).yd,'o');
    hold on;
    N(i).xd = S(i).xd;%坐标
    N(i).yd = S(i).yd;
    N(i).G = 0;%"G = 0"表示节点本周期内未当选过簇头,当选则改为"G = 1"
    N(i).E = Eo;%初始化节点能量
    %最初没有簇头只有簇成员
    N(i).type = 'N';%簇成员(普通节点) 
end
%加入基站信息
S(n+1).xd = sink.x;
S(n+1).yd = sink.y;
N(n+1).xd = sink.x;
N(n+1).yd = sink.y;
plot(S(n+1).xd,S(n+1).yd,'p');

%% 3、PSO参数
MaxIter = 50;      % 最大迭代次数
nPop = 30;        % 种群规模
wmax = 0.9;
wmin = 0.4;
w = 1;
c1 = 2.0;         % 个人学习系数
c2 = 2.0;         % 全局学习系数
plimit = [0, 200];                % 位置参数限制
vlimit = [-20, 20];               % 速度限制

%数据初始化
particle.Position = cell(1,nPop);
particle.Cost = zeros(1,nPop);
particle.Velocity = cell(1,nPop);
particle.Best.Position = cell(1,nPop);
particle.Best.Cost = ones(1,nPop)*inf;
GlobalBestCost = inf;
GlobalBestPosition = [];


%% 4、网络运行模块 
% 死亡节点数指标
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 
    dead = 0;%计算死亡节点数
    energy = 0;%每轮节点剩余总能量
    Node = [];%存活节点集合
    C = [];%候选节点集合
    j = 0;
    for i = 1:n
        %检查有无死亡节点
        if S(i).E <= 0
            dead = dead+1;
            %第一个节点死亡时间
            if dead == 1
                if flag_first_dead == 0
                    first_dead = r+1;
                    flag_first_dead = 1;
                end
            end
            % 10%的节点死亡时间
            if dead == 0.1*n
                if flag_teenth_dead ==0
                    teenth_dead = r+1;
                    flag_teenth_dead = 1;
                end
            end
            if dead == n
                if flag_all_dead == 0
                    all_dead = r+1;
                    flag_all_dead = 1;
                end
            end
        end
        if S(i).E > 0
            energy = energy + S(i).E;%统计每轮节点总能量和
            S(i).type = 'N';
            j = j+1;
            Node(j,:) = [S(i).xd S(i).yd];%存活节点集合
        end
    end
    
    STATISTICS.DEAD(r+1) = dead;%每轮死亡节点数
    STATISTICS.alive(r+1) = n-dead;%每轮存活节点数
    STATISTICS.energy(r+1) = energy;%每轮剩余总能量
    
    if n-dead == 0
        STATISTICS.COUNTCHS(r+1) = 0;
        continue;
    end
    
%% 4.1、应用PSO选簇头
    %候选簇头集合
    j = 0;
    for i = 1:n
        if r ==0 %因为matlab最大精度16位,后面数据不准,第一轮会出现这种情况,所以这样编程
            j = j+1;
            C.d(j,:) = [S(i).xd S(i).yd];%候选簇头坐标
            C.E(j) = S(i).E;%候选簇头剩余能量
            C.id(j) = i;%候选簇头对应的节点编号
        else
            if S(i).E >= energy/(n-dead) %节点能量大于或等于总的平均能量
                j = j+1;
                C.d(j,:) = [S(i).xd S(i).yd];%候选簇头坐标
                C.E(j) = S(i).E;%候选簇头剩余能量
                C.id(j) = i;%候选簇头对应的节点编号
            end
        end
    end
    
    M = size(C.d,1);%候选簇头数
    K = ceil((n-dead)*p);% 簇头数
    %初始化种群位置和速度
    for i = 1:nPop
        % 初始化位置
        C_k = randperm(M,K);
        particle.Position{i} = C.d(C_k,:);
    
        % 初始化速度
        v = zeros(K,2);
        particle.Velocity{i}=v;
    
        % 适应度
        energe_Q = sum(C.E((C_k)));
        isB = ismember(Node,particle.Position{i});
        Cluster_member = reshape(Node(~isB),[],2);%传感器簇成员节点矩阵
        particle.Cost(i)=Cost(Cluster_member,particle.Position{i},K,energy,energe_Q);
    end
    
    Iter = 1;%计数
    while Iter <= MaxIter
        %更新粒子个体最佳适应度、位置   
        for i = 1:nPop      
           if particle.Cost(i) < particle.Best.Cost(i) 
               particle.Best.Cost(i) = particle.Cost(i);%更新个体历史最佳适应度
               particle.Best.Position{i} = particle.Position{i};%更新个体历史最佳位置
           end 
        end

        %更新群体最佳适应度、位置
        if min(particle.Best.Cost) < GlobalBestCost  
            [GlobalBestCost, index1] = min(particle.Best.Cost);%更新群体历史最佳适应度
            GlobalBestPosition = particle.Best.Position{index1};%更新群体历史最佳位置
        end

        % 速度更新
        for i = 1:nPop
            particle.Velocity{i} = particle.Velocity{i}.*w + c1*rand*(particle.Best.Position{i}-particle.Position{i}) ...
                + c2*rand*(GlobalBestPosition-particle.Position{i});% 速度更新
        end

        % 边界速度处理
        for i = 1:nPop
            particle.Velocity{i}(particle.Velocity{i}>20) = 20;
            particle.Velocity{i}(particle.Velocity{i}<-20) = -20;
        end

        % 位置更新
        for i = 1:nPop
            particle.Position{i} = particle.Position{i} + particle.Velocity{i};
        end

        % 边界位置处理
        for i = 1:nPop
            particle.Position{i}(particle.Position{i}>200)=200;
            particle.Position{i}(particle.Position{i}<0)=0;
        end

        %根据距离最近候选簇头位置调整粒子位置,计算相应适应度
        for i = 1:nPop
            distance = pdist2(C.d,particle.Position{i});
            [~, index2] = min(distance);
            particle.Position{i} = C.d(index2,:);

            % 适应度
            energe_Q = sum(C.E((index2)));
            isB = ismember(Node,particle.Position{i});
            Cluster_member = reshape(Node(~isB),[],2);%传感器簇成员节点矩阵
            particle.Cost(i)=Cost(Cluster_member,particle.Position{i},K,energy,energe_Q);
        end
        Iter = Iter+1;
    end

    %根据距离最近候选簇头位置得到簇头信息
    distance = pdist2(C.d,GlobalBestPosition);
    [~, index2] = min(distance);
    
    %如果簇头重复,需要调整(这一步处理的不够好)
    length_index2 = length(unique(index2));
    cha = K-length_index2;%重复个数
    while cha ~= 0
        for i = 1:K-1
            for j = i+1:K
                if index2(i) == index2(j)
                    distance_cut = distance(:,j);%取distance的第j列
                    [~,Number] = sort(distance_cut);
                    Num = 1;
                    while length(unique(index2))~=K-(cha-1)  && Num<size(distance_cut,1)
                        Num = Num+1;
                        index2(j) = Number(Num);
                    end
                    cha = cha-1;
                end
            end
        end
    end
                  
    for i = 1:K
        %簇头接受基站的广播分簇信息
        S(C.id(index2(i))).E =  S(C.id(index2(i))).E - ERX * ctrPacketLength;
    end

    %重置群体和个体最佳适应度、位置
    GlobalBestCost = inf;
    GlobalBestPosition = [];
    particle.Best.Cost = ones(1,nPop)*inf;
    particle.Best.Position = cell(1,nPop);

%% 4.2选总簇头
    %确定簇头
    for i = 1:K
        j = C.id(index2(i));
        S(j).type = 'C';
    end

    Each_cluster = zeros(K,2);%第一列放每个簇的能量最大的节点的能量信息,第二列放节点标号,行对应簇号

    %预成簇
    for i = 1:n
        if ( S(i).type=='N' && S(i).E>0 ) %普通节点
            %加入最近的簇头
            distance_to_cluster = pdist2(C.d(index2,:),[S(i).xd S(i).yd]);
            [min_dis, dis_index] = min(distance_to_cluster);%min_dis返回最短距离,dis_index返回最短距离对应的簇号
            if S(i).E > Each_cluster(dis_index,1)
                Each_cluster(dis_index,1) = S(i).E;
                Each_cluster(dis_index,2) = i;
            end 
        end
    end

    %若有空簇,将其候选总簇头节点假定为1
    for i = 1:K
        if Each_cluster(i,2) == 0
            Each_cluster(i,2) = 1;
        end
    end

    %每个候选总簇头至所有簇头距离和
    sum_distance_HCH_to_CH = sum(pdist2(C.d(index2,:),reshape([S(Each_cluster(:,2)).xd S(Each_cluster(:,2)).yd],[],2)));
    %每个候选总簇头至基站距离
    distance_HCH_to_BS = pdist2([S(n+1).xd S(n+1).yd],C.d(index2,:));

    CostofHCH = zeros(1,K);
    for i = 1:K
        CostofHCH(i) = Cost_HCH(Each_cluster(:,1),sum_distance_HCH_to_CH,distance_HCH_to_BS,i);
    end
    [~,index3] = min(CostofHCH);
    S(Each_cluster(index3,2)).type = 'T';%总簇头
    S(Each_cluster(index3,2)).E = S(Each_cluster(index3,2)).E - ERX * ctrPacketLength;%总簇头接收基站发来的分簇信息
%% 4.3成簇,簇内通信
    for i = 1:n
        if ( S(i).type=='N' && S(i).E>0 ) %普通节点
            %加入最近的簇头
            distance_to_cluster = pdist2(C.d(index2,:),[S(i).xd S(i).yd]);
            [min_dis, dis_index] = min(distance_to_cluster);%min_dis返回最短距离,min_dis_cluster返回最短距离对应的簇号
            %接收基站发来的广播的消耗(收到基站发来的分簇信息)
            S(i).E = S(i).E - ERX * ctrPacketLength;
            %向簇头发送数据包
            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
            %簇头接收簇成员的数据包
            if(min_dis > 0)
                S(C.id(dis_index)).E = S(C.id(dis_index)).E - ( (ERX + EDA)*packetLength ); %接受簇成员发来的数据包
            end
        end
    end
%% 4.4簇头和总簇头通信
    TCnumber = Each_cluster(index3,2);%总簇头编号
    for i = 1:K
        j = C.id(index2(i));
        S(j).type = 'C';
        %簇头到总簇头的距离
        distance = sqrt((S(j).xd-S(TCnumber).xd)^2 + (S(j).yd-(S(TCnumber).yd))^2 );
        %簇头向总簇头发送数据包能耗
        if (distance > do)
            S(j).E = S(j).E- ( ETX * (packetLength) + Emp * packetLength*distance^4);
        else
            S(j).E = S(j).E- ( ETX * (packetLength) + Efs * packetLength*distance^2); 
        end
        %总簇头接收簇头的的数据包(不融合数据)
        if(distance > 0)
            S(TCnumber).E = S(TCnumber).E - ERX * packetLength; %接受簇头发来的数据包
        end
    end
%% 4.5总簇头和基站通信
    distance_to_BS = pdist2([S(n+1).xd S(n+1).yd],[S(TCnumber).xd S(TCnumber).yd]);
    if (distance_to_BS > do)
        S(TCnumber).E = S(TCnumber).E- (K * ETX * (packetLength) + Emp * packetLength*distance^4);
    else
        S(TCnumber).E = S(TCnumber).E- (K * ETX * (packetLength) + Efs * packetLength*distance^2); 
    end
    STATISTICS.COUNTCHS(r+1) = K;
end

%% 4、网络运行模块(Leach)
% 死亡节点数指标
first_dead1 = 0;%第一个死亡节点
teenth_dead1 = 0;%10%的死亡节点
all_dead1 = 0;%节点都死亡

%节点死亡数指标对应标记
flag_first_dead1 = 0;
flag_teenth_dead1 = 0;
flag_all_dead1 = 0;

%传输到基站和簇头的比特计数器
packets_TO_BS1 = 0;
packets_TO_CH1 = 0;

%主循环
for r = 0:rmax 
    %每过一个周期,重置G
    if(mod(r, round(1/p)) == 0)
        for i = 1:n
            N(i).G = 0;
        end
    end
    dead1 = 0;%计算死亡节点数
    energy1 = 0;%每轮节点剩余总能量
    for i = 1:n
        %检查有无死亡节点
        if N(i).E <= 0
            dead1 = dead1+1;
            %第一个节点死亡时间
            if dead1 == 1
                if flag_first_dead1 == 0
                    first_dead1 = r+1;
                    flag_first_dead1 = 1;
                end
            end
            % 10%的节点死亡时间
            if dead1 == 0.1*n
                if flag_teenth_dead1 ==0
                    teenth_dead1 = r+1;
                    flag_teenth_dead1 = 1;
                end
            end
            if dead1 == n
                if flag_all_dead1 == 0
                    all_dead1 = r+1;
                    flag_all_dead1 = 1;
                end
            end
        end
        if N(i).E > 0
            energy1 = energy1 + N(i).E;%统计每轮节点总能量和
            N(i).type = 'N';
        end
    end

    %节点死亡,退出循环,但是一般都是与其他算法比较,由于不同算法最终循环伦次不同
    %所以节点死亡并不退出循环,而是在达到最大循环次数后才结束循环
%     if flag_all_dead == 1
%         break;
%     end
    %r从0开始,但是计算机中数组从1开始,所以采用r+1的下标
    STATISTICS1.DEAD(r+1) = dead1;%每轮死亡节点数
    STATISTICS1.alive(r+1) = n-dead1;%每轮存活节点数
    STATISTICS1.energy(r+1) = energy1;%每轮剩余总能量
    cluster=0;%计数簇头数
    
    %次循环(选簇头)
    if energy1 > 0%网络还剩余能量,这一步在节点都死亡后才有用
        for i=1:n
            if(N(i).E>0)%节点必须有能量
                temp_rand=rand;     
                if ( (N(i).G)<=0) %该节点在候选集合中
                    %选簇头
                    if( temp_rand <= (p/(1-p*mod(r,round(1/p)))))
                        cluster = cluster+1;
                        N(i).type = 'C'; %簇头
                        N(i).G = round(1/p)-1;%换成"S(i).G = 1"也行,只要不是0
                        C(cluster).xd = N(i).xd;
                        C(cluster).yd = N(i).yd;
                        distance=sqrt( (N(i).xd-(N(n+1).xd))^2 + (N(i).yd-(N(n+1).yd))^2 );%距离基站的距离
                        C(cluster).distance = distance;
                        C(cluster).id = i;
                        distanceBroad = sqrt(xm^2+ym^2);
                        %全网广播自成为簇头,广播TDMA时间表,距离是distanceBroad
                        if (distanceBroad > do)
                            N(i).E = N(i).E- (2* ETX * ctrPacketLength + Emp * ctrPacketLength*distanceBroad^4);
                        else
                            N(i).E = N(i).E- (2* ETX * ctrPacketLength + Efs * ctrPacketLength*distanceBroad^2); 
                        end
                        %簇头向基站发送数据包能耗
                        if (distance > do)
                            N(i).E = N(i).E- ( ETX*(packetLength) + Emp * packetLength*distance^4);
                        else
                            N(i).E = N(i).E- ( ETX*(packetLength) + Efs * packetLength*distance^2); 
                        end
                    end     
                end
            end 
        end
    end
    STATISTICS1.COUNTCHS(r+1) = cluster;

    %次循环(成簇)
    if energy1 > 0%网络还剩余能量,这一步在节点都死亡后才生效
        for i = 1:n
            if ( N(i).type=='N' && N(i).E>0 ) %普通节点
                %如果有簇头存在
                if(cluster>= 1)
                    length = zeros(cluster,1);
                    %加入最近的簇头
                    for c = 1:cluster
                        length(c) = sqrt( (N(i).xd - C(c).xd)^2 + (N(i).yd - C(c).yd)^2 );
                        %%接收簇头发来的广播消耗
                        N(i).E = N(i).E - ERX * ctrPacketLength;
                    end
                    [min_dis, min_dis_cluster] = min(length);%min_dis返回最短距离,min_dis_cluster返回最短距离对应的簇号
                    %向簇头发送数据包
                    if (min_dis > do)
                        N(i).E = N(i).E - ( ETX*packetLength + Emp*packetLength*min_dis^4); %向簇发送头数据包
                    else
                        N(i).E = N(i).E - ( ETX*packetLength + Efs*packetLength*min_dis^2); %向簇头发送数据包
                    end
                    %簇头接收簇成员的数据包
                    if(min_dis > 0)
                        N(C(min_dis_cluster).id).E = N(C(min_dis_cluster).id).E - ( (ERX + EDA)*packetLength ); %接受簇成员发来的数据包
                    end
                %如果本轮没有簇头,则普通节点直接将数据直接发送给基站
                else
                    min_dis = sqrt((N(i).xd-N(n+1).xd)^2 + (N(i).yd-N(n+1).yd)^2);
                end
            end
        end
    end
end
%% 绘图显示
figure;
plot(0:rmax, STATISTICS.DEAD, 'r',0:rmax, STATISTICS1.DEAD, 'g', 'LineWidth', 2);
xlabel('轮数'); ylabel('死亡节点数');
legend('mypso','Leach')
figure;
plot(0:rmax, STATISTICS.alive, 'r',0:rmax, STATISTICS1.alive, 'g', 'LineWidth', 2);
xlabel('轮数'); ylabel('活动节点数');
legend('mypso','Leach')
figure;
plot(0:rmax, STATISTICS.energy, 'r',0:rmax, STATISTICS1.energy, 'g', 'LineWidth', 2);
xlabel('轮数'); ylabel('剩余能量');
legend('mypso','Leach')  
figure;
plot(0:rmax, STATISTICS.COUNTCHS, 'r',0:rmax, STATISTICS1.COUNTCHS, 'g', 'LineWidth', 2);
xlabel('轮数'); ylabel('簇头数');
legend('mypso','Leach')

实验2、虑控制包,对比LEACH与TL-EBC

%% 清空环境变量
clear;clc;
close all;

%% 1、初始参数设定模块
%监测区域大小(单位:米)
xm = 200;
ym = 200;

%基站的x和y坐标
sink.x = 0.5 * xm;
sink.y = 275;

%场地中的节点数
n = 200;

%簇头概率
p=0.05;

%最大循环轮数
rmax = 500;

%能量模型(所有值均以焦耳为单位)
Eo = 0.1;%初始能量
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);%距离阈值

%数据包和控制包长度
packetLength = 2000;%数据包长度 
ctrPacketLength = 50;%控制包长度

%% 2、无线传感器网络模型产生模块
%构建无线传感器网络,在区域内均匀投放所有节点,并画出图形
figure;
for i = 1:n
    S(i).xd = rand(1,1)*xm;%坐标
    S(i).yd = rand(1,1)*ym;
    S(i).E = Eo;%初始化节点能量
    %最初没有簇头只有簇成员
    S(i).type = 'N';%簇成员(普通节点) 
    plot(S(i).xd,S(i).yd,'o');
    hold on;
    N(i).xd = S(i).xd;%坐标
    N(i).yd = S(i).yd;
    N(i).G = 0;%"G = 0"表示节点本周期内未当选过簇头,当选则改为"G = 1"
    N(i).E = Eo;%初始化节点能量
    %最初没有簇头只有簇成员
    N(i).type = 'N';%簇成员(普通节点) 
end
%加入基站信息
S(n+1).xd = sink.x;
S(n+1).yd = sink.y;
N(n+1).xd = sink.x;
N(n+1).yd = sink.y;
plot(S(n+1).xd,S(n+1).yd,'p');

%% 3、PSO参数
MaxIter = 50;      % 最大迭代次数
nPop = 30;        % 种群规模
wmax = 0.9;
wmin = 0.4;
w = 1;
c1 = 2.0;         % 个人学习系数
c2 = 2.0;         % 全局学习系数
plimit = [0, 200];                % 位置参数限制
vlimit = [-20, 20];               % 速度限制

%数据初始化
particle.Position = cell(1,nPop);
particle.Cost = zeros(1,nPop);
particle.Velocity = cell(1,nPop);
particle.Best.Position = cell(1,nPop);
particle.Best.Cost = ones(1,nPop)*inf;
GlobalBestCost = inf;
GlobalBestPosition = [];


%% 4、网络运行模块 
% 死亡节点数指标
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 
    dead = 0;%计算死亡节点数
    energy = 0;%每轮节点剩余总能量
    Node = [];%存活节点集合
    C = [];%候选节点集合
    j = 0;
    for i = 1:n
        %检查有无死亡节点
        if S(i).E <= 0
            dead = dead+1;
            %第一个节点死亡时间
            if dead == 1
                if flag_first_dead == 0
                    first_dead = r+1;
                    flag_first_dead = 1;
                end
            end
            % 10%的节点死亡时间
            if dead == 0.1*n
                if flag_teenth_dead ==0
                    teenth_dead = r+1;
                    flag_teenth_dead = 1;
                end
            end
            if dead == n
                if flag_all_dead == 0
                    all_dead = r+1;
                    flag_all_dead = 1;
                end
            end
        end
        if S(i).E > 0
            energy = energy + S(i).E;%统计每轮节点总能量和
            S(i).type = 'N';
            j = j+1;
            Node(j,:) = [S(i).xd S(i).yd];%存活节点集合
        end
    end
    
    STATISTICS.DEAD(r+1) = dead;%每轮死亡节点数
    STATISTICS.alive(r+1) = n-dead;%每轮存活节点数
    STATISTICS.energy(r+1) = energy;%每轮剩余总能量
    
    if n-dead == 0
        STATISTICS.COUNTCHS(r+1) = 0;
        continue;
    end
    
%% 4.1、应用PSO选簇头
    %候选簇头集合
    j = 0;
    for i = 1:n
        if r ==0 %因为matlab最大精度16位,后面数据不准,第一轮会出现这种情况,所以这样编程
            j = j+1;
            C.d(j,:) = [S(i).xd S(i).yd];%候选簇头坐标
            C.E(j) = S(i).E;%候选簇头剩余能量
            C.id(j) = i;%候选簇头对应的节点编号
        else
            if S(i).E >= energy/(n-dead) %节点能量大于或等于总的平均能量
                j = j+1;
                C.d(j,:) = [S(i).xd S(i).yd];%候选簇头坐标
                C.E(j) = S(i).E;%候选簇头剩余能量
                C.id(j) = i;%候选簇头对应的节点编号
            end
        end
    end
    
    M = size(C.d,1);%候选簇头数
    K = ceil((n-dead)*p);% 簇头数
%     w = 0.9-0.5*(10-K);%惯性重量
    %初始化种群位置和速度
    for i = 1:nPop
        % 初始化位置
        C_k = randperm(M,K);
        particle.Position{i} = C.d(C_k,:);
    
        % 初始化速度
        v = zeros(K,2);
        particle.Velocity{i}=v;
    
        % 适应度
        energe_Q = sum(C.E((C_k)));
        isB = ismember(Node,particle.Position{i});
        Cluster_member = reshape(Node(~isB),[],2);%传感器簇成员节点矩阵
        particle.Cost(i)=Cost(Cluster_member,particle.Position{i},K,energy,energe_Q);
    end
    
    Iter = 1;%计数
    while Iter <= MaxIter
        %更新粒子个体最佳适应度、位置   
        for i = 1:nPop      
           if particle.Cost(i) < particle.Best.Cost(i) 
               particle.Best.Cost(i) = particle.Cost(i);%更新个体历史最佳适应度
               particle.Best.Position{i} = particle.Position{i};%更新个体历史最佳位置
           end 
        end

        %更新群体最佳适应度、位置
        if min(particle.Best.Cost) < GlobalBestCost  
            [GlobalBestCost, index1] = min(particle.Best.Cost);%更新群体历史最佳适应度
            GlobalBestPosition = particle.Best.Position{index1};%更新群体历史最佳位置
        end

        % 速度更新
        for i = 1:nPop
            particle.Velocity{i} = particle.Velocity{i}.*w + c1*rand*(particle.Best.Position{i}-particle.Position{i}) ...
                + c2*rand*(GlobalBestPosition-particle.Position{i});% 速度更新
        end

        % 边界速度处理
        for i = 1:nPop
            particle.Velocity{i}(particle.Velocity{i}>20) = 20;
            particle.Velocity{i}(particle.Velocity{i}<-20) = -20;
        end

        % 位置更新
        for i = 1:nPop
            particle.Position{i} = particle.Position{i} + particle.Velocity{i};
        end

        % 边界位置处理
        for i = 1:nPop
            particle.Position{i}(particle.Position{i}>200)=200;
            particle.Position{i}(particle.Position{i}<0)=0;
        end

        %根据距离最近候选簇头位置调整粒子位置,计算相应适应度
        for i = 1:nPop
            distance = pdist2(C.d,particle.Position{i});
            [~, index2] = min(distance);
            particle.Position{i} = C.d(index2,:);

            % 适应度
            energe_Q = sum(C.E((index2)));
            isB = ismember(Node,particle.Position{i});
            Cluster_member = reshape(Node(~isB),[],2);%传感器簇成员节点矩阵
            particle.Cost(i)=Cost(Cluster_member,particle.Position{i},K,energy,energe_Q);
        end
        Iter = Iter+1;
    end

    %根据距离最近候选簇头位置得到簇头信息
    distance = pdist2(C.d,GlobalBestPosition);
    [~, index2] = min(distance);
    
    %如果簇头重复,需要调整(这一步处理的不够好)
    length_index2 = length(unique(index2));
    cha = K-length_index2;%重复个数
    while cha ~= 0
        for i = 1:K-1
            for j = i+1:K
                if index2(i) == index2(j)
                    distance_cut = distance(:,j);%取distance的第j列
                    [~,Number] = sort(distance_cut);
                    Num = 1;
                    while length(unique(index2))~=K-(cha-1)  && Num<size(distance_cut,1)
                        Num = Num+1;
                        index2(j) = Number(Num);
                    end
                    cha = cha-1;
                end
            end
        end
    end

    distanceBroad = sqrt(xm^2+ym^2)/3;%假定簇头和簇成员最远距离是对角线的1/3(懒得去后面算这个实际距离了,在分簇均匀的情况下其实是对角线的1/6)                    
    for i = 1:K
        %簇头接受基站的广播分簇信息
        S(C.id(index2(i))).E =  S(C.id(index2(i))).E - ERX * ctrPacketLength;
        %簇头广播TDMA表
        if (distanceBroad > do)
            S(C.id(index2(i))).E = S(C.id(index2(i))).E - ( ETX*ctrPacketLength + Emp*packetLength*distanceBroad^4);
        else
            S(C.id(index2(i))).E = S(C.id(index2(i))).E - ( ETX*ctrPacketLength + Efs*packetLength*distanceBroad^2);
        end
    end

    %重置群体和个体最佳适应度、位置
    GlobalBestCost = inf;
    GlobalBestPosition = [];
    particle.Best.Cost = ones(1,nPop)*inf;
    particle.Best.Position = cell(1,nPop);

%% 4.2选总簇头
    %确定簇头
    for i = 1:K
        j = C.id(index2(i));
        S(j).type = 'C';
    end

    Each_cluster = zeros(K,2);%第一列放每个簇的能量最大的节点的能量信息,第二列放节点标号,行对应簇号

    %预成簇
    for i = 1:n
        if ( S(i).type=='N' && S(i).E>0 ) %普通节点
            %加入最近的簇头
            distance_to_cluster = pdist2(C.d(index2,:),[S(i).xd S(i).yd]);
            [min_dis, dis_index] = min(distance_to_cluster);%min_dis返回最短距离,dis_index返回最短距离对应的簇号
            if S(i).E > Each_cluster(dis_index,1)
                Each_cluster(dis_index,1) = S(i).E;
                Each_cluster(dis_index,2) = i;
            end 
        end
    end

    %若有空簇,将其候选总簇头节点假定为1
    for i = 1:K
        if Each_cluster(i,2) == 0
            Each_cluster(i,2) = 1;
        end
    end

    %每个候选总簇头至所有簇头距离和
    sum_distance_HCH_to_CH = sum(pdist2(C.d(index2,:),reshape([S(Each_cluster(:,2)).xd S(Each_cluster(:,2)).yd],[],2)));
    %每个候选总簇头至基站距离
    distance_HCH_to_BS = pdist2([S(n+1).xd S(n+1).yd],C.d(index2,:));

    CostofHCH = zeros(1,K);
    for i = 1:K
        CostofHCH(i) = Cost_HCH(Each_cluster(:,1),sum_distance_HCH_to_CH,distance_HCH_to_BS,i);
    end
    [~,index3] = min(CostofHCH);
    S(Each_cluster(index3,2)).type = 'T';%总簇头
    S(Each_cluster(index3,2)).E = S(Each_cluster(index3,2)).E - ERX * ctrPacketLength;%总簇头接收基站发来的分簇信息
%% 4.3成簇,簇内通信
    for i = 1:n
        if ( S(i).type=='N' && S(i).E>0 ) %普通节点
            %加入最近的簇头
            distance_to_cluster = pdist2(C.d(index2,:),[S(i).xd S(i).yd]);
            [min_dis, dis_index] = min(distance_to_cluster);%min_dis返回最短距离,min_dis_cluster返回最短距离对应的簇号
            %接收基站发来的广播的消耗(收到基站发来的分簇信息)
            S(i).E = S(i).E - ERX * ctrPacketLength;
            %接收簇头的广播TDMA时间表信息
            S(i).E = S(i).E - ERX * ctrPacketLength;
            %向簇头发送数据包
            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
            %簇头接收簇成员的数据包
            if(min_dis > 0)
                S(C.id(dis_index)).E = S(C.id(dis_index)).E - ( (ERX + EDA)*packetLength ); %接受簇成员发来的数据包
            end
        end
    end
%% 4.4簇头和总簇头通信
    TCnumber = Each_cluster(index3,2);%总簇头编号
    for i = 1:K
        j = C.id(index2(i));
        S(j).type = 'C';
        %簇头到总簇头的距离
        distance = sqrt((S(j).xd-S(TCnumber).xd)^2 + (S(j).yd-(S(TCnumber).yd))^2 );
        %接收总簇头的广播TDMA时间表信息
        S(j).E = S(i).E - ERX*ctrPacketLength;
        %簇头向总簇头发送数据包能耗
        if (distance > do)
            S(j).E = S(j).E- ( ETX * (packetLength) + Emp * packetLength*distance^4);
        else
            S(j).E = S(j).E- ( ETX * (packetLength) + Efs * packetLength*distance^2); 
        end
        %总簇头接收簇头的的数据包(不融合数据)
        if(distance > 0)
            S(TCnumber).E = S(TCnumber).E - ERX * packetLength; %接受簇头发来的数据包
        end
    end
%% 4.5总簇头和基站通信
    %总簇头广播时隙表,距离是maxdistance
    maxdistance = max(pdist2(C.d(index2,:),[S(TCnumber).xd S(TCnumber).yd]));%距离最远的簇头的距离
    if (maxdistance > do)
        S(TCnumber).E = S(TCnumber).E- ( ETX * ctrPacketLength + Emp * ctrPacketLength*maxdistance^4);
    else
        S(TCnumber).E = S(TCnumber).E- ( ETX * ctrPacketLength + Efs * ctrPacketLength*maxdistance^2); 
    end
    distance_to_BS = pdist2([S(n+1).xd S(n+1).yd],[S(TCnumber).xd S(TCnumber).yd]);
    if (distance_to_BS > do)
        S(TCnumber).E = S(TCnumber).E- (K * ETX * (packetLength) + Emp * packetLength*distance^4);
    else
        S(TCnumber).E = S(TCnumber).E- (K * ETX * (packetLength) + Efs * packetLength*distance^2); 
    end
    STATISTICS.COUNTCHS(r+1) = K;
end

%% 4、网络运行模块(Leach)
% 死亡节点数指标
first_dead1 = 0;%第一个死亡节点
teenth_dead1 = 0;%10%的死亡节点
all_dead1 = 0;%节点都死亡

%节点死亡数指标对应标记
flag_first_dead1 = 0;
flag_teenth_dead1 = 0;
flag_all_dead1 = 0;

%传输到基站和簇头的比特计数器
packets_TO_BS1 = 0;
packets_TO_CH1 = 0;

%主循环
for r = 0:rmax 
    %每过一个周期,重置G
    if(mod(r, round(1/p)) == 0)
        for i = 1:n
            N(i).G = 0;
        end
    end
    dead1 = 0;%计算死亡节点数
    energy1 = 0;%每轮节点剩余总能量
    for i = 1:n
        %检查有无死亡节点
        if N(i).E <= 0
            dead1 = dead1+1;
            %第一个节点死亡时间
            if dead1 == 1
                if flag_first_dead1 == 0
                    first_dead1 = r+1;
                    flag_first_dead1 = 1;
                end
            end
            % 10%的节点死亡时间
            if dead1 == 0.1*n
                if flag_teenth_dead1 ==0
                    teenth_dead1 = r+1;
                    flag_teenth_dead1 = 1;
                end
            end
            if dead1 == n
                if flag_all_dead1 == 0
                    all_dead1 = r+1;
                    flag_all_dead1 = 1;
                end
            end
        end
        if N(i).E > 0
            energy1 = energy1 + N(i).E;%统计每轮节点总能量和
            N(i).type = 'N';
        end
    end

    %节点死亡,退出循环,但是一般都是与其他算法比较,由于不同算法最终循环伦次不同
    %所以节点死亡并不退出循环,而是在达到最大循环次数后才结束循环
%     if flag_all_dead == 1
%         break;
%     end
    %r从0开始,但是计算机中数组从1开始,所以采用r+1的下标
    STATISTICS1.DEAD(r+1) = dead1;%每轮死亡节点数
    STATISTICS1.alive(r+1) = n-dead1;%每轮存活节点数
    STATISTICS1.energy(r+1) = energy1;%每轮剩余总能量
    cluster=0;%计数簇头数
    
    %次循环(选簇头)
    if energy1 > 0%网络还剩余能量,这一步在节点都死亡后才有用
        for i=1:n
            if(N(i).E>0)%节点必须有能量
                temp_rand=rand;     
                if ( (N(i).G)<=0) %该节点在候选集合中
                    %选簇头
                    if( temp_rand <= (p/(1-p*mod(r,round(1/p)))))
                        cluster = cluster+1;
                        N(i).type = 'C'; %簇头
                        N(i).G = round(1/p)-1;%换成"S(i).G = 1"也行,只要不是0
                        C(cluster).xd = N(i).xd;
                        C(cluster).yd = N(i).yd;
                        distance=sqrt( (N(i).xd-(N(n+1).xd))^2 + (N(i).yd-(N(n+1).yd))^2 );%距离基站的距离
                        C(cluster).distance = distance;
                        C(cluster).id = i;
                        distanceBroad = sqrt(xm^2+ym^2);
                        %全网广播自成为簇头,广播TDMA时间表,距离是distanceBroad
                        if (distanceBroad > do)
                            N(i).E = N(i).E- (2* ETX * ctrPacketLength + Emp * ctrPacketLength*distanceBroad^4);
                        else
                            N(i).E = N(i).E- (2* ETX * ctrPacketLength + Efs * ctrPacketLength*distanceBroad^2); 
                        end
                        %簇头向基站发送数据包能耗
                        if (distance > do)
                            N(i).E = N(i).E- ( ETX*(packetLength) + Emp * packetLength*distance^4);
                        else
                            N(i).E = N(i).E- ( ETX*(packetLength) + Efs * packetLength*distance^2); 
                        end
                    end     
                end
            end 
        end
    end
    STATISTICS1.COUNTCHS(r+1) = cluster;

    %次循环(成簇)
    if energy1 > 0%网络还剩余能量,这一步在节点都死亡后才生效
        for i = 1:n
            if ( N(i).type=='N' && N(i).E>0 ) %普通节点
                %如果有簇头存在
                if(cluster>= 1)
                    length = zeros(cluster,1);
                    %加入最近的簇头
                    for c = 1:cluster
                        length(c) = sqrt( (N(i).xd - C(c).xd)^2 + (N(i).yd - C(c).yd)^2 );
                        %%接收簇头发来的广播和TDMA时间表的消耗
                        N(i).E = N(i).E - 2*ERX * ctrPacketLength;
                    end
                    [min_dis, min_dis_cluster] = min(length);%min_dis返回最短距离,min_dis_cluster返回最短距离对应的簇号
                    %向簇头发送加入消息、向簇头发送数据包
                    if (min_dis > do)
                        N(i).E = N(i).E - ( ETX*ctrPacketLength + Emp * ctrPacketLength*min_dis^4); %向簇头发送加入控制消息
                        N(i).E = N(i).E - ( ETX*packetLength + Emp*packetLength*min_dis^4); %向簇发送头数据包
                    else
                        N(i).E = N(i).E - ( ETX*ctrPacketLength + Efs*ctrPacketLength*min_dis^2); %向簇头发送加入控制消息
                        N(i).E = N(i).E - ( ETX*packetLength + Efs*packetLength*min_dis^2); %向簇头发送数据包
                    end
                    %接收簇头确认加入控制消息
                    N(i).E = N(i).E - ERX*ctrPacketLength;
                    %簇头接收簇成员的加入消息和数据包,簇头向簇成员发送确认加入的信息
                    if(min_dis > 0)
                        N(C(min_dis_cluster).id).E = N(C(min_dis_cluster).id).E - ERX *ctrPacketLength ;%接收加入消息
                        N(C(min_dis_cluster).id).E = N(C(min_dis_cluster).id).E - ( (ERX + EDA)*packetLength ); %接受簇成员发来的数据包
                        %簇头向簇成员发送确认加入的信息
                        if (min_dis > do)
                            N(C(min_dis_cluster).id).E = N(C(min_dis_cluster).id).E - ( ETX*ctrPacketLength + Emp * ctrPacketLength*min_dis^4);
                        else
                            N(C(min_dis_cluster).id).E = N(C(min_dis_cluster).id).E - ( ETX*ctrPacketLength + Efs * ctrPacketLength*min_dis^2);
                        end
                    end
                %如果本轮没有簇头,则普通节点直接将数据直接发送给基站
                else
                    min_dis = sqrt((N(i).xd-N(n+1).xd)^2 + (N(i).yd-N(n+1).yd)^2);
                    if min_dis > do
                        N(i).E = N(i).E- (ETX*packetLength + Emp*packetLength*min_dis^4);
                    else
                        N(i).E = N(i).E- (ETX*packetLength + Efs*packetLength*min_dis^2);
                    end
                end
            end
        end
    end
end
%% 绘图显示
figure;
plot(0:rmax, STATISTICS.DEAD, 'r',0:rmax, STATISTICS1.DEAD, 'g', 'LineWidth', 2);
xlabel('轮数'); ylabel('死亡节点数');
legend('mypso','Leach')
figure;
plot(0:rmax, STATISTICS.alive, 'r',0:rmax, STATISTICS1.alive, 'g', 'LineWidth', 2);
xlabel('轮数'); ylabel('活动节点数');
legend('mypso','Leach')
figure;
plot(0:rmax, STATISTICS.energy, 'r',0:rmax, STATISTICS1.energy, 'g', 'LineWidth', 2);
xlabel('轮数'); ylabel('剩余能量');
legend('mypso','Leach')  
figure;
plot(0:rmax, STATISTICS.COUNTCHS, 'r',0:rmax, STATISTICS1.COUNTCHS, 'g', 'LineWidth', 2);
xlabel('轮数'); ylabel('簇头数');
legend('mypso','Leach')

三、实验结果

实验1、不考虑控制包,对比LEACH与TL-EBC

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实验2、考虑控制包,对比LEACH与TL-EBC

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

结果分析

  很明显,这样设计网络性能是得到了优化的,不论是否考虑控制包,对比LEACH算法,网络性能都得到了很大的提升,一般网络节点死亡超过30%,其网络就认定工作性能不达标,TL-EBC算法实现的网络节点几乎同时死亡,使网络有效运转寿命得到很大的提升。
  其实读者会发现,是否加入控制包相关耗能,对LEACH算法的影响小,对TL-EBC算法的影响大,其实不是这样的(这样认为说明读者对该领域的了解太浅显了),这是因为TL-EBC算法的网络几乎直到网络死亡都是全部节点在工作,LEACH算法在大部分时间都是部分节点在工作,只有部分节点运转的网络是有很多缺点的。
  本人对控制包相关的功能考虑的比较充分,下面我将论文的实验效果与我的实验效果做对比。
加入控制包相关能耗:
在这里插入图片描述
不加入控制包相关能耗:
在这里插入图片描述
  对比分析,本人没加入控制包的图比作者的好,加入了控制包的图没作者的好。不难发现,论文原作者是折中处理过了的,即加入了控制包,但控制包相关功能只考虑了一部分。

四、参考文献

[1]蒋畅江,向敏,唐贤伦.基于PSO的无线传感器网络分簇路由协议[J].计算机工程,2012,38(17):59-62.
[2]Latiff N M A, Tsimenidis C C, Sharif B S. Energy-aware Clustering for Wireless Sensor Networks Using Particle Swarm Optimization[C]//Proc. of the 18th IEEE International Symposium on Personal, Indoor and Mobile Radio Communications. Athens, Greece: IEEE Press, 2007: 1-5.

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

御息无

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值