基于深度强化学习的动态覆盖控制

文献: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;
end

GJOGWO.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;
end

ObjFunction.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