leach.alive文件分析仿真

本文介绍使用LEACH协议分析无线传感器网络中节点存活情况的方法。通过编写awk脚本提取wireless.alive文件中的时间、节点ID及状态信息,并利用gnuplot绘制节点存活曲线。

2010-11-24 wcdj

 

在leach协议装好后,可以开始对wireless.alive文件进行分析。wireless.alive的结构如下:
第一列表示:运行时间,第二列表示:节点ID,第三列表示:节点状态(如果是1,表示该节点还存活;如果是0,则表示节点死亡)。
用awk编写脚本提取自己需要的信息。

下面是leach协议剩余节点和时间关系的awk脚本:(可参考如下)


[1] leach_alive1.awk

[2] leach_alive2.awk

 

把awk文件放在~/ns-allinone-2.27/ns-2.27/mit/leach_sims目录下:
cd ~/ns-allinone-2.27/ns-2.27/mit/leach_sims
[1] awk   -f   leach_alive1.awk   leach.alive   >   leach_alive.txt
[2] gwak   –v   outfile=leach_alive.txt   –f   leach_alive2.awk   leach.alive
然后会生成一个leach_alive.txt文件,里面是提取的数据。下一步就是用gnuplot画图了,具体操作见下图所示。
PS: Cygwin运行时一般只是进入字符操作界面,这时由于X-server没有启动,因此与图形界面相关的程序无法显示,只要先执行startx或者xinit后再运行gnuplot即可。在gnuplot运行后,可以通过set terminal命令查看此工具支持的图片格式。

 

pic

 

退出gnuplot之后,就会在~/ns-allinone-2.27/ns-2.27/mit/leach_sims目录下生成一个leach_alive.gif文件。
pic

 

从leach_alive.gif结果中,可以看出在每轮中还存活的节点数目。

PS:在leach中,可以从leach.out文件分析可知,一轮20秒,即每20秒选举一次簇首节点。上述图中横坐标注释为time更为合适。基站的位置为(50,175),注意基站的位置对仿真的影响比较大,可以测试不同的位置进行对比。

 

更多可参考:Jerry

 

 

%% 实验二:LEACH路由协议仿真 - 军用无线传感器网络 % 功能:实现LEACH分簇算法,分析网络能量消耗和生存周期 % 作者:根据实验指导书要求编写 % 日期:2024年 clear; close all; clc; %% 参数设置 num_nodes = 100; % 节点数量 area_size = 100; % 区域大小 (100×100) p = 0.05; % 簇头概率 num_rounds = 500; % 最大仿真轮数 k_rounds = 10; % 记录前k轮的分簇情况 % 能量参数 initial_energy = 1000; % 初始能量 energy_threshold = 0; % 能量耗尽阈值 % 通信能量消耗(根据实验指导书) energy_receive_CH_info = 1; % 簇成员:接收候选簇头信息 energy_send_join_msg = 2; % 簇成员:通知簇头成为其成员 energy_CH_send_info = 2; % 候选簇头:发送信息 energy_CH_receive_join = 1; % 候选簇头:被通知成为簇头 energy_member_send_data = 2; % 稳定阶段:成员发送数据 energy_CH_receive_data = 1; % 稳定阶段:簇头接收数据 data_trans_per_round = 10; % 每轮数据传输次数 %% 初始化节点 nodes = struct(); for i = 1:num_nodes nodes(i).id = i; nodes(i).x = rand * area_size; nodes(i).y = rand * area_size; nodes(i).type = 'N'; % 'N':普通节点, 'C':簇头 nodes(i).selected = false; % 是否当选过簇头(本轮) nodes(i).ever_selected = false;% 是否曾经当选过簇头 nodes(i).cluster_head = -1; % 所属簇头ID nodes(i).energy = initial_energy; nodes(i).temp_rand = rand; % 随机数 nodes(i).times_CH = 0; % 成为簇头的次数 nodes(i).alive = true; % 节点是否存活 nodes(i).last_CH_round = -1; % 上次成为簇头的轮数 end %% 存储结果 cluster_history = cell(k_rounds, 1); first_dead_round = -1; energy_history = zeros(num_rounds, 1); alive_nodes_history = zeros(num_rounds, 1); cluster_head_history = zeros(num_rounds, 1); %% LEACH算法主循环 fprintf('开始LEACH协议仿真...\n'); fprintf('节点数量: %d, 区域大小: %dx%d, 簇头概率: %.2f\n', ... num_nodes, area_size, area_size, p); for r = 1:num_rounds % 检查是否所有节点都死亡 alive_nodes = sum([nodes.alive]); alive_nodes_history(r) = alive_nodes; if alive_nodes == 0 fprintf('所有节点在第 %d 轮全部死亡!\n', r-1); break; end % 重置节点类型和簇头归属 for i = 1:num_nodes if nodes(i).alive nodes(i).type = 'N'; nodes(i).cluster_head = -1; nodes(i).selected = false; nodes(i).temp_rand = rand; end end %% 簇头选择阶段 cluster_heads = []; for i = 1:num_nodes if ~nodes(i).alive continue; end % 计算阈值 T(n) - 修正的LEACH阈值公式 if nodes(i).ever_selected T = p / (1 - p * mod(r, round(1/p))); else T = p; end % 检查是否成为簇头 if nodes(i).temp_rand <= T nodes(i).type = 'C'; nodes(i).selected = true; nodes(i).ever_selected = true; nodes(i).times_CH = nodes(i).times_CH + 1; nodes(i).last_CH_round = r; cluster_heads = [cluster_heads, i]; end end cluster_head_history(r) = length(cluster_heads); %% 簇形成阶段 - 普通节点选择最近的簇头 for i = 1:num_nodes if nodes(i).alive && nodes(i).type == 'N' && ~isempty(cluster_heads) min_dist = inf; nearest_CH = -1; % 找到最近的存活簇头 for j = 1:length(cluster_heads) ch_index = cluster_heads(j); if nodes(ch_index).alive dx = nodes(i).x - nodes(ch_index).x; dy = nodes(i).y - nodes(ch_index).y; dist = sqrt(dx*dx + dy*dy); if dist < min_dist min_dist = dist; nearest_CH = ch_index; end end end if nearest_CH ~= -1 nodes(i).cluster_head = nearest_CH; end end end %% 能量消耗计算 current_round_energy = 0; for i = 1:num_nodes if ~nodes(i).alive continue; end energy_consumption = 0; if nodes(i).type == 'C' % 簇头节点 % 计算该簇头的成员数量 member_count = 0; for j = 1:num_nodes if nodes(j).alive && nodes(j).cluster_head == i member_count = member_count + 1; end end % 簇头能量消耗(根据实验指导书) % 簇建立阶段:发送信息(-2) + 接收加入消息(成员数 × -1) energy_consumption = energy_CH_send_info + member_count * energy_CH_receive_join; % 稳定阶段:接收数据(成员数 × 10 × -1) energy_consumption = energy_consumption + member_count * data_trans_per_round * energy_CH_receive_data; else % 普通节点 if nodes(i).cluster_head ~= -1 % 有归属簇头 % 簇建立阶段:接收簇头信息(-1) + 发送加入消息(-2) energy_consumption = energy_receive_CH_info + energy_send_join_msg; % 稳定阶段:发送数据(10 × -2) energy_consumption = energy_consumption + data_trans_per_round * energy_member_send_data; else % 没有归属簇头,只接收信息 energy_consumption = energy_receive_CH_info * length(cluster_heads); end end nodes(i).energy = nodes(i).energy - energy_consumption; current_round_energy = current_round_energy + energy_consumption; % 检查节点是否死亡 if nodes(i).energy <= energy_threshold nodes(i).alive = false; nodes(i).energy = 0; % 记录第一个节点死亡 if first_dead_round == -1 first_dead_round = r; fprintf('第一个节点在第 %d 轮能量耗尽!\n', r); end end end energy_history(r) = current_round_energy; %% 记录前k轮的分簇情况 if r <= k_rounds round_data = struct(); round_data.round = r; round_data.cluster_heads = cluster_heads; round_data.node_states = []; for i = 1:num_nodes node_state = struct(); node_state.id = nodes(i).id; node_state.type = nodes(i).type; node_state.cluster_head = nodes(i).cluster_head; node_state.energy = nodes(i).energy; node_state.x = nodes(i).x; node_state.y = nodes(i).y; node_state.alive = nodes(i).alive; round_data.node_states = [round_data.node_states, node_state]; end cluster_history{r} = round_data; end % 显示进度 if mod(r, 50) == 0 fprintf('已完成 %d 轮仿真,存活节点: %d\n', r, alive_nodes); end end actual_rounds = r; % 实际仿真轮数 %% 可视化前k轮的分簇情况 fprintf('\n生成前%d轮分簇可视化...\n', k_rounds); figure('Position', [100, 100, 1400, 800], 'Name', 'LEACH分簇过程'); for r = 1:min(k_rounds, actual_rounds) if r > length(cluster_history) || isempty(cluster_history{r}) continue; end subplot(2, 5, r); hold on; grid on; axis equal; round_data = cluster_history{r}; % 绘制普通节点 normal_nodes_x = []; normal_nodes_y = []; cluster_head_x = []; cluster_head_y = []; for i = 1:length(round_data.node_states) node = round_data.node_states(i); if node.alive if node.type == 'N' if node.cluster_head == -1 % 孤立节点 plot(node.x, node.y, 'k^', 'MarkerSize', 6, 'MarkerFaceColor', 'black'); else % 有簇头的普通节点 normal_nodes_x = [normal_nodes_x, node.x]; normal_nodes_y = [normal_nodes_y, node.y]; end else % 簇头节点 cluster_head_x = [cluster_head_x, node.x]; cluster_head_y = [cluster_head_y, node.y]; end end end % 绘制有簇头的普通节点 if ~isempty(normal_nodes_x) plot(normal_nodes_x, normal_nodes_y, 'b*', 'MarkerSize', 6); end % 绘制簇头节点 if ~isempty(cluster_head_x) plot(cluster_head_x, cluster_head_y, 'ro', 'MarkerSize', 10, 'LineWidth', 2, 'MarkerFaceColor', 'red'); end % 绘制连接线 for i = 1:length(round_data.node_states) node = round_data.node_states(i); if node.alive && node.type == 'N' && node.cluster_head ~= -1 CH_id = node.cluster_head; if CH_id <= length(round_data.node_states) && round_data.node_states(CH_id).alive CH_node = round_data.node_states(CH_id); plot([node.x, CH_node.x], [node.y, CH_node.y], 'g-', 'LineWidth', 0.5); end end end title(sprintf('第 %d 轮 - 簇头: %d个', r, length(round_data.cluster_heads))); xlabel('X坐标'); ylabel('Y坐标'); xlim([0 area_size]); ylim([0 area_size]); end sgtitle('LEACH协议前10轮分簇情况'); %% 显示详细的分簇信息 fprintf('\n=== 前%d轮分簇详情 ===\n', k_rounds); for r = 1:min(k_rounds, length(cluster_history)) if ~isempty(cluster_history{r}) round_data = cluster_history{r}; fprintf('\n第%d轮: 簇头%d个\n', round_data.round, length(round_data.cluster_heads)); % 统计每个簇头的成员数量 CH_members = containers.Map(); isolated_nodes = 0; for i = 1:length(round_data.node_states) node = round_data.node_states(i); if node.alive && node.cluster_head ~= -1 CH_key = num2str(node.cluster_head); if isKey(CH_members, CH_key) CH_members(CH_key) = CH_members(CH_key) + 1; else CH_members(CH_key) = 1; end elseif node.alive && node.cluster_head == -1 && node.type == 'N' isolated_nodes = isolated_nodes + 1; end end % 显示簇头及其成员数 CH_keys = keys(CH_members); fprintf(' 簇头详情:\n'); for j = 1:length(CH_keys) fprintf(' 节点%s: %d个成员\n', CH_keys{j}, CH_members(CH_keys{j})); end fprintf(' 孤立节点: %d个\n', isolated_nodes); end end %% 绘制性能分析图 fprintf('\n生成性能分析...\n'); figure('Position', [100, 100, 1200, 900], 'Name', 'LEACH协议性能分析'); % 截取实际仿真轮数的数据 x_rounds = 1:actual_rounds; subplot(2, 3, 1); plot(x_rounds, alive_nodes_history(1:actual_rounds), 'b-', 'LineWidth', 2); hold on; if first_dead_round ~= -1 plot([first_dead_round, first_dead_round], [0, num_nodes], 'r--', 'LineWidth', 1.5); % 修正文本标注,避免使用换行符 text(first_dead_round, num_nodes/2, sprintf('第一个节点死亡 第%d轮', first_dead_round), ... 'HorizontalAlignment', 'center', 'BackgroundColor', 'white', 'FontSize', 8); end xlabel('轮数'); ylabel('存活节点数'); title('网络生存情况'); grid on; legend('存活节点数', 'Location', 'northeast'); subplot(2, 3, 2); plot(x_rounds, energy_history(1:actual_rounds), 'r-', 'LineWidth', 2); xlabel('轮数'); ylabel('每轮总能量消耗'); title('网络能量消耗趋势'); grid on; subplot(2, 3, 3); plot(x_rounds, cluster_head_history(1:actual_rounds), 'g-', 'LineWidth', 2); xlabel('轮数'); ylabel('簇头数量'); title('每轮簇头数量变化'); grid on; % 计算网络平均能量 avg_energy_history = zeros(actual_rounds, 1); for r_idx = 1:actual_rounds alive_indices = find([nodes.alive]); if ~isempty(alive_indices) avg_energy_history(r_idx) = mean([nodes(alive_indices).energy]); else avg_energy_history(r_idx) = 0; end end subplot(2, 3, 4); plot(x_rounds, avg_energy_history, 'm-', 'LineWidth', 2); xlabel('轮数'); ylabel('平均能量'); title('网络平均能量变化'); grid on; % 绘制节点能量分布(第1轮和第k_rounds轮) subplot(2, 3, 5); if ~isempty(cluster_history) && ~isempty(cluster_history{1}) energies_round1 = [cluster_history{1}.node_states.energy]; histogram(energies_round1, 20, 'FaceColor', 'blue', 'FaceAlpha', 0.7); xlabel('节点能量'); ylabel('节点数量'); title('第1轮节点能量分布'); grid on; end subplot(2, 3, 6); last_round = min(k_rounds, actual_rounds); if last_round <= length(cluster_history) && ~isempty(cluster_history{last_round}) energies_last = [cluster_history{last_round}.node_states.energy]; histogram(energies_last, 20, 'FaceColor', 'red', 'FaceAlpha', 0.7); xlabel('节点能量'); ylabel('节点数量'); title(sprintf('第%d轮节点能量分布', last_round)); grid on; end %% 输出最终结果 fprintf('\n=== 仿真结果汇总 ===\n'); fprintf('节点总数: %d\n', num_nodes); fprintf('仿真区域: %d×%d\n', area_size, area_size); fprintf('簇头概率: %.2f\n', p); fprintf('初始能量: %d\n', initial_energy); fprintf('实际仿真轮数: %d\n', actual_rounds); fprintf('第一个节点死亡轮数: %d\n', first_dead_round); fprintf('最终存活节点数: %d\n', alive_nodes_history(actual_rounds)); fprintf('网络生存周期: %.1f%%\n', (alive_nodes_history(actual_rounds)/num_nodes)*100); % 计算成为簇头的平均次数 alive_indices = find([nodes.alive]); if ~isempty(alive_indices) avg_CH_times = mean([nodes(alive_indices).times_CH]); fprintf('节点平均成为簇头次数: %.2f\n', avg_CH_times); end %% 保存结果 results = struct(); results.parameters.num_nodes = num_nodes; results.parameters.area_size = area_size; results.parameters.initial_energy = initial_energy; results.parameters.cluster_head_prob = p; results.first_dead_round = first_dead_round; results.final_alive_nodes = alive_nodes_history(actual_rounds); results.total_rounds = actual_rounds; results.cluster_history = cluster_history; results.energy_history = energy_history(1:actual_rounds); results.alive_nodes_history = alive_nodes_history(1:actual_rounds); results.cluster_head_history = cluster_head_history(1:actual_rounds); save('leach_simulation_complete.mat', 'results', 'nodes'); fprintf('\n仿真结果已保存到 leach_simulation_complete.mat\n'); fprintf('\nLEACH协议仿真完成!\n'); 修改代码MATLAB
最新发布
11-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值