基于深度强化学习的动态覆盖控制
文献:S. Meng和Z. Kan, 《Deep Reinforcement Learning-Based Effective Coverage Control With Connectivity Constraints》, IEEE Control Syst. Lett., 卷 6, 页 283~288, 2022, doi: 10.1109/LCSYS.2021.3070850.
仿真实验设置:
监测区域的工作空间设置为10个×10单位,虚拟边界设置为30个×30单位。假设有20个静态点和4个移动代理随机分布在每集开始的区域内。每个agent的感知半径为r = 0.8个单位,通信范围为r = 2个单位。感知质量峰值为Mp=1。
MATLAB代码:
main_MADRL.m
% =========================================================================
% MADRL 覆盖控制仿真主入口
% =========================================================================
% 1. 清理工作区
clear;
clc;
close all;
% 2. 添加路径 (如果你的代码分文件夹存放,可以在这里 addpath)
% addpath('./CoreFunctions');
fprintf('正在启动多智能体覆盖控制仿真...\n');
% 3. 运行仿真函数
% 可以在这里尝试包裹 try-catch 以防止绘图句柄报错导致整个程序卡死
try
SimpleCoverageDemo();
catch ME
fprintf('仿真运行期间发生错误:\n%s\n', ME.message);
fprintf('出错位置: %s (Line %d)\n', ME.stack(1).name, ME.stack(1).line);
end
fprintf('\n程序运行结束。\n');
% 4. (可选) 如果需要保存数据或结果图,可以在这里写代码
% saveas(gcf, 'LastSimulationResult.png');SimpleCoverageDemo.m
function SimpleCoverageDemo()
% === 1. 参数 参数设置 (完全依照文献 Section IV 设定) ===
% [cite: 177] 工作区 10x10
Params.W = 10;
% [cite: 178] 20 个 PoI, 4 个智能体
Params.M = 20;
Params.N = 4;
% [cite: 180] 感知半径 r=0.8, 通信半径 R=2
Params.r_sense = 0.8;
Params.R_comm = 2.0;
% [cite: 84, 181] 峰值感知质量
Params.Mp = 1.0;
% [cite: 181] 期望覆盖阈值
Params.E_star = 4.0;
% 仿真步长
Params.dt = 0.2;
% 智能体最大速度
Params.MaxSpeed = 0.6;
% === 2. 初始化环境 ===
close all; clc;
% 随机分布 PoI 和 智能体
PoI_Pos = Params.W * rand(Params.M, 2);
Agent_Pos = Params.W * rand(Params.N, 2) * 0.5 + 2.5; % 让智能体初始聚在一起,避免开局就断连
% 累积覆盖量 [cite: 104]
E_accumulation = zeros(Params.M, 1);
PoI_Done = false(Params.M, 1);
% === 3. 绘图初始化 ===
figure('Color', 'w', 'Position', [100 100 700 600]);
ax = axes; box on; hold on; axis equal;
axis([0 Params.W 0 Params.W]); grid on;
xlabel('X (m)'); ylabel('Y (m)');
% 绘制对象句柄
h_PoI = scatter(PoI_Pos(:,1), PoI_Pos(:,2), 40, 'r', 'filled', 'DisplayName', 'Uncovered PoI');
h_Agents = plot(Agent_Pos(:,1), Agent_Pos(:,2), 'k^', 'MarkerSize', 10, 'MarkerFaceColor', 'k', 'DisplayName', 'Agents');
h_Links = plot(NaN, NaN, 'b-', 'LineWidth', 1.5, 'DisplayName', 'Comm Links');
h_Sense = viscircles(ax, Agent_Pos, repmat(Params.r_sense, Params.N, 1), 'Color', [0.5 0.5 0.5], 'LineStyle', ':');
title_handle = title('Initializing...');
legend([h_PoI, h_Agents, h_Links], 'Location', 'northeastoutside');
fprintf('=== 仿真开始 ===\n');
fprintf('这是一个基于规则的演示,用于验证环境模型和连通性计算。\n');
fprintf('智能体将尝试向最近的未覆盖点移动,同时保持聚集。\n');
% === 4. 主循环 ===
max_steps = 300;
for t = 1:max_steps
% --- A. 简易决策逻辑 (替代神经网络) ---
% 规则:每个智能体受到两个力
% 1. 目标引力:飞向最近的未完成 PoI
% 2. 聚集引力:如果离队友太远,就往队友中心飞 (模拟连通性约束)
Move_Vec = zeros(Params.N, 2);
for i = 1:Params.N
% 1. 寻找最近的未覆盖 PoI
active_indices = find(~PoI_Done);
if isempty(active_indices)
target = [Params.W/2, Params.W/2]; % 任务完成,回中心
else
dists = sum((PoI_Pos(active_indices,:) - Agent_Pos(i,:)).^2, 2);
[~, min_idx] = min(dists);
target = PoI_Pos(active_indices(min_idx), :);
end
% 计算目标引力向量
vec_to_target = target - Agent_Pos(i,:);
dist_to_target = norm(vec_to_target);
if dist_to_target > 0
force_goal = (vec_to_target / dist_to_target);
else
force_goal = [0 0];
end
% 2. 计算聚集引力 (Cohesion) - 简单的"连通性保持"策略
center_mass = mean(Agent_Pos);
vec_to_center = center_mass - Agent_Pos(i,:);
dist_to_center = norm(vec_to_center);
% 如果离中心太远(接近通信半径的一半),强行拉回来
if dist_to_center > Params.R_comm * 0.4
force_group = (vec_to_center / dist_to_center) * 2.0; % 权重加大
else
force_group = [0 0];
end
% 合成动作
total_force = force_goal + force_group;
% 归一化并应用最大速度
force_mag = norm(total_force);
if force_mag > 0
Move_Vec(i,:) = (total_force / force_mag) * Params.MaxSpeed;
end
end
% 更新位置
Agent_Pos = Agent_Pos + Move_Vec;
% 边界限制 (0~10)
Agent_Pos = max(0, min(Params.W, Agent_Pos));
% --- B. 连通性计算 (核心验证点) ---
% 构建邻接矩阵 A
Adj = zeros(Params.N);
for i = 1:Params.N
for j = i+1:Params.N
if norm(Agent_Pos(i,:) - Agent_Pos(j,:)) <= Params.R_comm
Adj(i,j) = 1; Adj(j,i) = 1;
end
end
end
% 拉普拉斯矩阵 L
Deg = diag(sum(Adj, 2));
L = Deg - Adj;
% 代数连通度 lambda_2
eigenvals = sort(eig(L));
lambda_2 = eigenvals(2); % 第二小特征值
isConnected = lambda_2 > 1e-4;
% --- C. 覆盖计算与奖励 ---
current_step_reward = 0;
% 连通性惩罚 [cite: 143]
if ~isConnected
current_step_reward = current_step_reward - 1; % 惩罚
status_str = '断开 (Disconnected)';
col_str = 'r';
else
status_str = '连通 (Connected)';
col_str = 'k';
end
% PoI 感知积分
for j = 1:Params.M
% 计算所有智能体对该点 j 的感知质量总和
dists_sq = sum((Agent_Pos - PoI_Pos(j,:)).^2, 2);
% 公式 (1): (1 / (d^2 + 1)) * Is_Inside
P_vals = (Params.Mp ./ (dists_sq + 1)) .* (dists_sq <= Params.r_sense^2);
% 累加本步的覆盖量
gain = sum(P_vals) * Params.dt;
E_accumulation(j) = E_accumulation(j) + gain;
% 检查阈值
if ~PoI_Done(j) && E_accumulation(j) >= Params.E_star
PoI_Done(j) = true;
current_step_reward = current_step_reward + 0.1; % 奖励
end
end
% === 5. 可视化更新 ===
% 智能体位置
set(h_Agents, 'XData', Agent_Pos(:,1), 'YData', Agent_Pos(:,2));
% 画连线 - 完全重写的安全版本
[row, col] = find(triu(Adj));
link_x_data = [];
link_y_data = [];
if ~isempty(row)
% 创建正确的向量结构:每条线的坐标被NaN分隔
num_links = length(row);
temp_x = zeros(num_links * 3, 1);
temp_y = zeros(num_links * 3, 1);
for idx = 1:num_links
pos_start = row(idx);
pos_end = col(idx);
% 每条线占三个元素:[起点x, 终点x, NaN]
start_pos = (idx-1)*3 + 1;
temp_x(start_pos) = Agent_Pos(pos_start, 1);
temp_x(start_pos+1) = Agent_Pos(pos_end, 1);
temp_x(start_pos+2) = NaN;
temp_y(start_pos) = Agent_Pos(pos_start, 2);
temp_y(start_pos+1) = Agent_Pos(pos_end, 2);
temp_y(start_pos+2) = NaN;
end
link_x_data = temp_x;
link_y_data = temp_y;
else
% 没有连接时设置为单值NaN
link_x_data = NaN;
link_y_data = NaN;
end
% 安全的设置数据
try
set(h_Links, 'XData', link_x_data, 'YData', link_y_data);
catch ME
warning('无法更新通信链接: %s', ME.message);
% 作为后备方案,删除并重建连线
delete(h_Links);
h_Links = plot(link_x_data, link_y_data, 'b-', 'LineWidth', 1.5, 'DisplayName', 'Comm Links');
legend([h_PoI, h_Agents, h_Links], 'Location', 'northeastoutside');
end
% 更新感知圆
delete(h_Sense);
h_Sense = viscircles(ax, Agent_Pos, repmat(Params.r_sense, Params.N, 1), 'Color', [0.8 0.8 0.8], 'LineStyle', ':');
% 更新 PoI (未完成=红, 完成=绿, 大小随覆盖度变大)
cdata = repmat([1 0 0], Params.M, 1);
cdata(PoI_Done, :) = repmat([0 1 0], sum(PoI_Done), 1);
sdata = 40 + 20 * E_accumulation;
set(h_PoI, 'CData', cdata, 'SizeData', sdata);
% 标题信息
title_text = sprintf('Step: %d | Lambda2: %.3f | Status: %s\nUncovered PoIs: %d', ...
t, lambda_2, status_str, sum(~PoI_Done));
set(title_handle, 'String', title_text, 'Color', col_str, 'FontSize', 10);
% 任务全部完成则提前退出
if all(PoI_Done)
fprintf('所有 PoI 已覆盖!仿真结束。\n');
break;
end
pause(0.05);
end
end基于改进金豺算法的静态覆盖控制
文献:J. Geng等, 《Coverage optimization of wireless sensor networks with improved golden jackal optimization》, 收入 2023 4th International Conference on Electronic Communication and Artificial Intelligence (ICECAI), Guangzhou, China: IEEE, 5月 2023, 页 1~4. doi: 10.1109/ICECAI58670.2023.10176640.
仿真实验设置:
设置监测区域为50×50方形区域,传感器节点数为30个,种群数为50个,迭代数为500次,传感半径为5米,通信半径为10米。
MATLAB代码:
main_GJOGWO.m:
% =========================================================================
% 文件名: Main_GJOGWO.m
% 描述: 基于改进金豺算法(GJOGWO)的WSN覆盖优化主程序
% 参考文献: Coverage optimization of wireless sensor networks with improved
% golden jackal optimization (ICECAI 2023)
% =========================================================================
clc;
clear;
close all;
%% 1. 参数设置 [对应文献 Source: 97]
L = 50; % 区域长度 50m
W = 50; % 区域宽度 50m
N = 30; % 传感器节点数量
Rs = 5; % 感知半径 5m
% Rc = 10; % 通信半径 10m (本仿真主要计算覆盖率,暂不涉及连通性约束)
pop_size = 50; % 种群规模 [Source: 97]
max_iter = 500; % 最大迭代次数 [Source: 97]
dim = N * 2; % 优化变量维度 (每个节点有x,y坐标,共30*2=60维)
lb = 0; % 下界 (坐标最小值)
ub = 50; % 上界 (坐标最大值)
%% 2. 运行 GJOGWO 算法
disp('正在运行 GJOGWO 算法进行 WSN 覆盖优化...');
[Best_Score, Best_Pos, Convergence_Curve] = GJOGWO(pop_size, max_iter, lb, ub, dim, N, L, W, Rs);
%% 3. 结果显示与绘图
% 3.1 绘制收敛曲线 [对应文献 Figure 2]
figure(1);
plot(Convergence_Curve, 'LineWidth', 2, 'Color', 'c'); % 青色对应文中 GJOGWO
title('收敛曲线 (Convergence Curve)');
xlabel('迭代次数 (Iteration)');
ylabel('覆盖率 (Coverage Rate)');
grid on;
axis([0 max_iter 0.5 0.8]); % 根据文献图2调整坐标轴范围
% 3.2 绘制最优节点部署图 [对应文献 Figure 1]
figure(2);
DrawSensors(Best_Pos, N, Rs, L, W);
title(['IGJO 优化部署 (覆盖率: ' num2str(Best_Score) ')']);
disp(['最优覆盖率: ', num2str(Best_Score)]);
%% 辅助函数: 绘制传感器覆盖结果
function DrawSensors(Pos, N, Rs, L, W)
% 解析坐标
x = Pos(1:2:end);
y = Pos(2:2:end);
hold on;
% 绘制圆形覆盖区域
t = linspace(0, 2*pi, 100);
for i = 1:N
xc = x(i) + Rs * cos(t);
yc = y(i) + Rs * sin(t);
fill(xc, yc, 'c', 'FaceAlpha', 0.5, 'EdgeColor', 'none'); % 青色填充
end
% 绘制节点位置
plot(x, y, 'k*', 'MarkerSize', 5);
axis([0 L 0 W]);
box on;
xlabel('X (m)');
ylabel('Y (m)');
axis square;
endGJOGWO.m:
function [Best_Score, Best_Pos, Convergence_Curve] = GJOGWO(pop_size, max_iter, lb, ub, dim, N, L, W, Rs)
%% 初始化
% 随机初始化种群
X = lb + rand(pop_size, dim) * (ub - lb);
Fit = zeros(1, pop_size);
% 计算初始适应度
for i = 1:pop_size
Fit(i) = ObjFunction(X(i,:), N, L, W, Rs);
end
% 初始化 GJO 的 Male (最优) 和 Female (次优)
[Sorted_Fit, idx] = sort(Fit, 'descend'); % 覆盖率越大越好,故降序
Male_Jackal_Pos = X(idx(1), :);
Male_Jackal_Score = Sorted_Fit(1);
Female_Jackal_Pos = X(idx(2), :);
Female_Jackal_Score = Sorted_Fit(2);
% 初始化 GWO 的 Alpha, Beta, Delta
% 在本文中,GJO的最优和GWO的Alpha其实是同一个概念(全局最优)
Alpha_Pos = X(idx(1), :);
Alpha_Score = Sorted_Fit(1);
Beta_Pos = X(idx(2), :);
Beta_Score = Sorted_Fit(2);
Delta_Pos = X(idx(3), :);
Delta_Score = Sorted_Fit(3);
Best_Pos = Alpha_Pos;
Best_Score = Alpha_Score;
Convergence_Curve = zeros(1, max_iter);
%% 主循环
for t = 1:max_iter
% 1. 更新非线性能量参数 E [Source: 72-80]
% 文中公式(4)识别乱码,根据描述“非线性递减”,采用常用的非线性余弦或指数衰减策略模拟
% 原始GJO是 E1 = 1.5 * (1 - t/max_iter);
% 这里采用一种典型的非线性策略:
E1 = 1.5 * (1 - (t/max_iter)^2); % 或者使用 cos(0.5*pi*t/max_iter)
RL = 0.05 * levy(pop_size, dim, 1.5); % Levy飞行向量
for i = 1:pop_size
% 计算猎物能量 E
r1 = rand();
E0 = 2*r1 - 1;
E = E1 * E0; % 能量因子
% 2. 混合策略机制 [Source: 91-92]
% "Each individual is updated with a random choice of GJO strategy or GWO strategy"
if rand < 0.5
% === 执行 GJO 策略 ===
% [Source: 41, 65] 基本 GJO 更新公式
if abs(E) >= 1 % 探索阶段
% 这里的公式基于标准GJO逻辑
X(i,:) = Male_Jackal_Pos - E * abs(Male_Jackal_Pos - RL(i,:) .* X(i,:));
% 注意:标准GJO通常同时利用Male和Female,这里简化为向Male移动或两者的平均
% 更标准的GJO写法:
% D_Male = abs((Male_Jackal_Pos - RL(i,:).*X(i,:)));
% D_Female = abs((Female_Jackal_Pos - RL(i,:).*X(i,:)));
% X1 = Male_Jackal_Pos - E * D_Male;
% X2 = Female_Jackal_Pos - E * D_Female;
% X(i,:) = (X1 + X2) / 2;
else % 开发阶段
D_Male = abs((Male_Jackal_Pos - RL(i,:).*X(i,:)));
D_Female = abs((Female_Jackal_Pos - RL(i,:).*X(i,:)));
X1 = Male_Jackal_Pos - E * D_Male;
X2 = Female_Jackal_Pos - E * D_Female;
X(i,:) = (X1 + X2) / 2;
end
else
% === 执行 GWO 策略 === [Source: 81-90]
% 线性递减的 a
a = 2 - t * (2 / max_iter);
% 计算与 Alpha, Beta, Delta 的距离
r1 = rand(1, dim); r2 = rand(1, dim);
A1 = 2*a*r1 - a; C1 = 2*r2;
D_alpha = abs(C1 .* Alpha_Pos - X(i,:));
X1 = Alpha_Pos - A1 .* D_alpha;
r1 = rand(1, dim); r2 = rand(1, dim);
A2 = 2*a*r1 - a; C2 = 2*r2;
D_beta = abs(C2 .* Beta_Pos - X(i,:));
X2 = Beta_Pos - A2 .* D_beta;
r1 = rand(1, dim); r2 = rand(1, dim);
A3 = 2*a*r1 - a; C3 = 2*r2;
D_delta = abs(C3 .* Delta_Pos - X(i,:));
X3 = Delta_Pos - A3 .* D_delta;
% 更新位置
X(i,:) = (X1 + X2 + X3) / 3;
end
% 边界检查
X(i,:) = max(X(i,:), lb);
X(i,:) = min(X(i,:), ub);
end
% 计算新种群的适应度
for i = 1:pop_size
Fit(i) = ObjFunction(X(i,:), N, L, W, Rs);
end
% 更新全局最优和各级领导者
% 合并旧的最优和新的种群进行排序(可选,或者直接在当前种群找)
[Sorted_Fit, idx] = sort(Fit, 'descend');
% 更新 GJO 领导者
if Sorted_Fit(1) > Male_Jackal_Score
Male_Jackal_Score = Sorted_Fit(1);
Male_Jackal_Pos = X(idx(1), :);
end
if Sorted_Fit(2) > Female_Jackal_Score
Female_Jackal_Score = Sorted_Fit(2);
Female_Jackal_Pos = X(idx(2), :);
end
% 更新 GWO 领导者 (Alpha, Beta, Delta)
Alpha_Score = Sorted_Fit(1); Alpha_Pos = X(idx(1), :);
Beta_Score = Sorted_Fit(2); Beta_Pos = X(idx(2), :);
Delta_Score = Sorted_Fit(3); Delta_Pos = X(idx(3), :);
% 记录全局最优
Best_Score = Alpha_Score; % 或者 Male_Jackal_Score,两者通常一致
Best_Pos = Alpha_Pos;
Convergence_Curve(t) = Best_Score;
% 输出每轮进度
if mod(t, 50) == 0
disp(['Iteration ' num2str(t) ': Best Coverage = ' num2str(Best_Score)]);
end
end
end
% Levy 飞行函数 (GJO 需要)
function o = levy(n, m, beta)
num = gamma(1+beta)*sin(pi*beta/2);
den = gamma((1+beta)/2)*beta*2^((beta-1)/2);
sigma_u = (num/den)^(1/beta);
u = random('Normal', 0, sigma_u, n, m);
v = random('Normal', 0, 1, n, m);
z = u./(abs(v).^(1/beta));
o = z;
endObjFunction.m:
function coverage = ObjFunction(x, N, L, W, Rs)
% x: 种群个体,维度为 1 * (2*N),格式为 [x1, y1, x2, y2, ...]
% 将区域离散化为 1x1 的网格点 [Source: 49]
% 为了计算速度,这里设置步长为 1 (50x50 = 2500个点)
step = 1;
[X_grid, Y_grid] = meshgrid(0.5:step:L-0.5, 0.5:step:W-0.5);
grid_points = [X_grid(:), Y_grid(:)];
total_points = size(grid_points, 1);
% 提取传感器坐标
sensor_x = x(1:2:end);
sensor_y = x(2:2:end);
sensors = [sensor_x', sensor_y'];
% 计算每个网格点到所有传感器的距离 [Source: 54]
% 使用 pdist2 加速计算
dists = pdist2(grid_points, sensors);
% 找到每个网格点到最近传感器的距离
min_dists = min(dists, [], 2);
% 判断是否被覆盖 (距离 <= Rs) [Source: 58-60]
covered_points = sum(min_dists <= Rs);
% 计算覆盖率 [Source: 62]
coverage = covered_points / total_points;
end