Matlab代码及解析(可运行) 基于改进遗传算法求解带时间窗约束多卫星任务规划

本文介绍了一种使用遗传算法解决卫星观测任务分配问题的方法,涉及地面设备有限、卫星可观测时间窗、设备转换时间等约束。通过编码策略、约束处理和种群优化,目标是最小化观测结束时间。作者详细阐述了编码、变异和选择策略,以及如何处理约束并保持算法收敛性。
摘要由CSDN通过智能技术生成

问题介绍

假设全国现共有M个地面观测设备(每个观测设备都需要对卫星执行相应的观测任务),N个待观测卫星,且M<<N。每个待观测卫星相对于不同的地面设备都有P个可供选择的可见时间窗口。其中,每个可观测设备都可以在任何待观测卫星与之对应的可见时间窗口内对该卫星进行观测,观测的时长根据实际任务中该卫星所需观测时间而不同。同时,任意一颗卫星都可在其可见时间窗口内被地面观测设备所观测。由于观测设备自身的物理特性,每个地面观测设备对一颗卫星进行观测结束后对下一颗卫星观测之前,都需要经过设备转换时间,设备的转换时间根据设备的自身特性不同而不同。

简而言之,有M个地面观测设备,N个待观测卫星,需要为每个卫星指定地面站以及观测时间。

目标函数 是使得 观测结束的时间最短
约束条件 可以表示为:

  1. 每个卫星都需要被观测一次
  2. 地面站同时只能观测一个卫星
  3. 卫星需要在特定的时间窗口内,才能被地面站观测
  4. 卫星需要被观测足够长的时间

具体数学模型较为简单,不做展示。
决策变量: 1)卫星对应哪个地面站,2)卫星被观测的开始时间、结束时间

问题难点

使用遗传算法对该问题进行优化求解,存在的难点主要为:

  1. 如何对该问题进行编码(怎么表示一个解)
  2. 怎么处理问题中存在的约束条件
  3. 如何确保收敛性。一方面要保持种群的多样性,防止出现聚堆现象导致进化停滞不前;另一方面,如何设计合理的交叉变异方法。

以上问题基本就是使用进化算法求解实际工程问题中存在的共性问题。

分析

编码方法介绍

卫星带时间窗的任务规划,类似于车间调度问题。对车间调度问题来说,存在多个工件,多台机床,每个工件又需要多道工序,每个工序只能在指定的机床上加工。

本文中的问题可以理解为车间调度问题的简化版,卫星对应工件,机床对应地面站。多道工序这里简化为卫星只需要被观测一次。同时该问题增加了一个时间窗,即卫星跟地面站只能在特定的时间段内可见,时间段长度、数量不定。

其实针对车间调度已经有很多成熟的编码方法,这里只介绍本文使用的编码方法。该编码分成两层,第一层是卫星的顺序编码,第二层是卫星对应的地面站编号。假设共有12个卫星,4个地面站,那么其中一个解可以表示如下:
编码表示
图中第一个红框表示卫星的观测顺序,第二个框表示对应的地面站编号。只要确定了这两个,那么卫星对应的观测时间就可以计算出来。

对应的,遗传算法种群编码函数为

// Init.m
function population = Init(N)

global Global
empty.decs = [];
empty.objs = [];
empty.cons = [];

population = repmat(empty,1,N);
for i=1:N
    population(i).decs = [randperm(Global.num_satellite,Global.num_satellite) ...
     randi([1,Global.num_ground],1,Global.num_satellite)];
end
population = CalObj(population);

*randperm(Global.num_satellite,Global.num_satellite)*表示产生卫星顺序的序列,*randi([1,Global.num_ground],1,Global.num_satellite)*表示指定的地面站编号

种群的数据结构表示为
在这里插入图片描述

目标函数的计算

基本思路为:卫星序列从头到尾遍历一遍,然后看当前卫星指定的地面站的时间窗口是什么,如果第一个时间窗口被别的卫星占用或者时间窗的持续时间不够观测卫星,那么就看看下一个时间窗满不满足约束。如果全部时间窗都不满足,那么计这个解违反约束,违反的程度为卫星需要被观测的时间。代码如下:

// CalObj.m
function population = CalObj(population)
% population = Init(1);

global Global

N = length(population);

for i=1:N
    ind = population(i);
    satellite_list = ind.decs(1:Global.num_satellite);
    ground_list = ind.decs(Global.num_satellite+1:end);
    
    ground_next_release_time = zeros(1,Global.num_ground); %地面站的下一次可观测时间
    
    time_start_guance = zeros(1,Global.num_satellite); %开始观测时间
    time_end_guance = zeros(1,Global.num_satellite); %结束观测时间
    index_window_guance = zeros(1,Global.num_satellite); %观测窗口的编号
    cons = 0; %违反约束的情况
    
    for j = 1:Global.num_satellite
        cur_satellite = satellite_list(j); %当前卫星
        cur_ground = ground_list(j); %当前卫星选择的地面站
        
        % 依次检查当前卫星的观测时间窗
        flag = 0;
        for m = 1:Global.num_visible_window(cur_satellite,cur_ground)
            time_start = Global.visible_window{cur_satellite,cur_ground}(2*m-1); %观测窗口的开始时间
            time_end = Global.visible_window{cur_satellite,cur_ground}(2*m); %观测窗口的结束时间
            if ground_next_release_time(cur_ground) > time_end
                continue;
            end
            time_begin = max(ground_next_release_time(cur_ground),time_start);
            
            if time_begin < time_end - Global.sat_need_time(cur_satellite) %当前观测窗口可以用来观测
                time_start_guance(cur_satellite) = time_begin;
                time_end_guance(cur_satellite) = time_start_guance(cur_satellite) + Global.sat_need_time(cur_satellite);
                ground_next_release_time(cur_ground) = time_end_guance(cur_satellite) + 60; %设备的反应时间
                index_window_guance(cur_satellite) = m;
                flag=1;
                break;
            end
        end
        if flag == 0 %说明这个卫星没有被安排到地面站
            cons = cons + Global.sat_need_time(cur_satellite);
        end
    end
    
    %% 计算目标函数
    T = max(time_end_guance);
    total_rank = 0;
    for j = 1:Global.num_satellite
        cur_satellite = satellite_list(j); %当前卫星
        cur_ground = ground_list(j); %当前卫星选择的地面站
        total_rank = total_rank + Global.rank_ground(cur_ground) * Global.rank_satellite(cur_satellite);
    end
    
    %% 传出值
    population(i).objs = [T - 10*total_rank];
    population(i).cons = cons;
    population(i).time_start_guance = time_start_guance;
    population(i).time_end_guance = time_end_guance;
    population(i).ground_list = ground_list;
    population(i).index_window_guance = index_window_guance;
    population(i).ground_next_release_time = ground_next_release_time;
end

个体变异方法介绍

采用上面所说的编码方式,那么第一层编码非常类似常见的旅行商问题,编码表示为一串序列。那么类比于TSP问题,本文设计了两种变异方法。

  1. 随机挑选另一个个体,然后随机选择两个位置,将另一个个体两个位置之间的编码付给当前个体的相同位置;
  2. 随机挑选两个位置,将两个位置之间的编码逆转。

具体代码表示为:

// Mutate.m
function offspring=Mutate(population,state)
% 本函数完成变异操作
% population = Init(10);

global Global
N=length(population);

offspring = population;
for i=1:N
    p1 = population(i).decs;
    if rand < 0.8 % 交叉
        p2 = i;
        while p2==i
           p2 = randperm(N,1); 
        end
        p2 = population(p2).decs;
        pos = sort(randperm(Global.num_satellite,2)); %随机挑选两个位置进行片段交叉
        for j=pos(1):pos(2)
           if p1(j) ~= p2(j)
               ind = find(p1(1:Global.num_satellite)==p2(j));
               p1(ind) = p1(j);
               p1(j) = p2(j);
           end
        end
        
        p1(pos(1)+Global.num_satellite:pos(2)+Global.num_satellite) = p2(pos(1)+Global.num_satellite:pos(2)+Global.num_satellite);
    end
    
    if rand < 0.4 % 变异
        pos = sort(randperm(Global.num_satellite,2)); %随机挑选两个位置进行片段逆转
        tmp = p1;
        p1(pos(1):pos(2)) = tmp(pos(2):-1:pos(1));
        pos = pos + Global.num_satellite;
        p1(pos(1):pos(2)) = tmp(pos(2):-1:pos(1));
    end
    
    offspring(i).decs = p1;
end
offspring = CalObj(offspring);

约束处理方法、种群收敛性及多样性

常见的使用遗传算法来处理实际工程问题,约束的处理可以使用罚函数方法。具体来说,将个体违反约束的程度,乘以一个系数加到目标函数中,那么违反约束的个体,会比满足约束的个体更加具有竞争力。从而推动算法向满足约束条件的方向进化。同时,遗传算法采用轮盘赌来选择下一代个体,具有更好的目标值的个体被选中的概率更大。

经典的算法存在很多问题,例如

  1. 罚函数的系数怎么设置?如果约束很难被满足,那么算法一直处于 在不满足约束的情况下优化,得到的解没有用。
  2. 轮盘赌的选择策略,导致每一代最优秀的个体可能没被选上;或者经过很多次的迭代,发现种群中的个体全部一样,那么丧失了多样性,算法就停滞不前。对于第一个问题,有精英保留策略,虽有一定效果,但是保存多少个精英个体合适呢?对于第二个问题,轮盘赌之前的适应度值怎么计算是一个问题。

对于这个问题,改进的遗传算法作出如下调整:

  1. 个体的违反约束情况作为第一排序准则,个体的适应度值作为第二排序准则。这种做法可以理解为可行性法则。具体来说,1)如果两个个体都违反约束,那么违反程度小的个体较好;2)如果两个个体一个违反、一个满足,那么满足约束的较好;3)如果两个个体都满足约束,那么,目标函数值小的个体较好。
  2. 在排序完成之后,删除种群中重复的个体(可能由变异产生)。这里可以理解为,决策变量完全一致的个体(在保持多样性上,还有其他方法可以选择,本文研究的问题是离散问题,判断冲不重复即可,其他情况可以判断个体之间的距离)。
  3. 挑选前N个个体组成下一代。

具体代码如下:

// Select.m
function population=Select(population,offspring,N)
% 本函数对每一代种群中的染色体进行选择,以进行后面的交叉和变异

joint = [population,offspring];
objs = [joint.objs]';
cons = [joint.cons]';

[~,index] = sortrows([cons,objs]);

joint = joint(index);

% 删除重复个体
del = [];
for i=1:length(joint)-1
    if find(i==del)
        continue;
    end
   for j=i+1:length(joint)
       if isequal(joint(i).decs,joint(j).decs)
          del = [del j]; 
       end
   end
end
joint(del) = [];

population = joint(1:N);

程序主体

采用基本的遗传算法流程,代码如下:

// RunMe.m
%% 清空环境
clc
clear
close all

%% 模型参数
global Global
Global.num_ground = 4;    %设备数
Global.num_satellite = 12;    %卫星数

%% 读取数据
[a,~,~] = xlsread('data\G.csv');
Global.rank_ground = a';%设备优先级(列表/矩阵)
[a,~,~] = xlsread('data\P.csv');
Global.rank_satellite = a';%卫星优先级(列表/矩阵)
[a,~,~] = xlsread('data\need.csv');
Global.sat_need_time = a'*1.2;%卫星观测时长(列表/矩阵)

Global.visible_window = cell(Global.num_satellite,Global.num_ground);
Global.num_visible_window = zeros(Global.num_satellite,Global.num_ground);
for i=1:Global.num_satellite
    datfile = ['data\sat' num2str(i) '.csv'];
    [a,~,~] = xlsread(datfile);
    
    for j=1:Global.num_ground
        index = a(j,:)~=0;
        Global.visible_window{i,j} = a(j,index);
        Global.num_visible_window(i,j) = numel(Global.visible_window{i,j})/2;
    end
end

%% 算法参数
maxgen = 1;
popsize = 150;
population = Init(popsize);

trace_obj = zeros(1,maxgen);
trace_con = zeros(1,maxgen);

%% 进化开始
for i=1:maxgen
    % 交叉变异
    offspring = Mutate(population,i/maxgen);
    % 挑选新个体
    population = Select(population,offspring,popsize);
    
    % 记录信息
    bestobj = population(1).objs;
    trace_obj(i) = bestobj;
    trace_con(i) = population(1).cons;
    
    if ~mod(i,10)
        cons = [population.cons];
        num = sum(cons==0);
        avgcons = mean(cons);
        disp(['第' num2str(i) '代,满足约束个体数量:' num2str(num), ',最佳个体:' num2str(bestobj)])
    end
end
%进化结束

%% 展示结果
figure
plot(trace_obj)
title('最优目标值进化示意图')

bestsol = population(1);
drawresult

结果展示

代码如下:

// drawresult.m
close all

figure
global Global

% c_space = linspecer(Global.num_satellite);
c_space = colormap(jet(12));
for i=1:Global.num_satellite
    cur_satellite = bestsol.decs(i);
    cur_ground = bestsol.ground_list(i);
    ind_window = bestsol.index_window_guance(cur_satellite);
    
    subplot(4,3,cur_satellite)
    
    t_s = bestsol.time_start_guance(cur_satellite);
    t_e = bestsol.time_end_guance(cur_satellite);
    
    if t_s == 0 && t_e ==0
        continue;
    end
    
    t_s_window = Global.visible_window{cur_satellite,cur_ground}(2*bestsol.index_window_guance(cur_satellite)-1);
    t_e_window = Global.visible_window{cur_satellite,cur_ground}(2*bestsol.index_window_guance(cur_satellite));
    rec = [t_s_window,cur_ground-0.1,t_e_window-t_s_window,0.2];
    rectangle('Position',rec,'LineWidth',0.5,'LineStyle','-','FaceColor',c_space(i,:),'Curvature',0.5);%draw every rectangle
%     for j=1:Global.num_visible_window(cur_satellite,cur_ground)
%         t_s_window = Global.visible_window{cur_satellite,cur_ground}(2*j-1);
%         t_e_window = Global.visible_window{cur_satellite,cur_ground}(2*j);
%         rec = [t_s_window,cur_ground-0.1,t_e_window-t_s_window,0.2];
%         rectangle('Position',rec,'LineWidth',0.5,'LineStyle','-','FaceColor',c_space(i,:),'Curvature',0.5);%draw every rectangle
%     end
    
    rec = [t_s,cur_ground-0.25,t_e-t_s,0.5];
    rectangle('Position',rec,'LineWidth',0.5,'LineStyle','-','FaceColor',c_space(i,:),'Curvature',0.5);%draw every rectangle
    text(t_s+100,cur_ground,num2str(cur_satellite),'FontWeight','Bold','fontsize',8);
    ylim([0,5])
    title(['Satellite' num2str(cur_satellite)])
end

figure
for i=1:Global.num_satellite
    cur_satellite = bestsol.decs(i);
    cur_ground = bestsol.ground_list(i);
    ind_window = bestsol.index_window_guance(cur_satellite);
    
    t_s = bestsol.time_start_guance(cur_satellite);
    t_e = bestsol.time_end_guance(cur_satellite);
    
    t_s_window = Global.visible_window{cur_satellite,cur_ground}(2*bestsol.index_window_guance(cur_satellite)-1);
    t_e_window = Global.visible_window{cur_satellite,cur_ground}(2*bestsol.index_window_guance(cur_satellite));
    
    if t_s == 0 && t_e ==0
       continue; 
    end
    
    x = [t_s_window,t_e_window,t_e_window,t_s_window];
    y = [cur_ground-0.02,cur_ground-0.02,cur_ground+0.02,cur_ground+0.02]+i/50;
    patch(x,y,c_space(i,:),'facealpha',0.5);
    
    x = [t_s,t_e,t_e,t_s];
    y = [cur_ground-0.1,cur_ground-0.1,cur_ground+0.1,cur_ground+0.1]+i/50;

    patch(x,y,c_space(i,:),'facealpha',0.8);
    text(t_s+50,cur_ground+i/50,num2str(cur_satellite),'FontWeight','Bold','fontsize',16);
    ylim([0,5])
end
for i=0.5:1:4.5
   line([min(bestsol.time_start_guance),max(bestsol.time_end_guance)],[i,i],'linestyle','-.') 
end

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

最后,本文所用代码结构如下:
在这里插入图片描述
代码所用数据以及模型,可以私聊。

写文不易,转载请注明。 @运筹不帷幄

最后,博主专注于论文的复现工作,有兴趣的同学可以私信共同探讨。相关代码已经上传到资源共享,点击我的空间查看分享代码。

鲸鱼算法是一种模拟鲸鱼集群捕食行为的优化算法,具有全局搜索、性能稳定等优点。而在车辆路径问题中,时间的开放式问题更加复杂,需要考虑时间限制以及车辆的容量等多个约束条件。 基于matlab鲸鱼算法求解时间开放式车辆路径问题,首先需要确定问题的目标函数以及各个约束条件。目标函数可以设定为最小化总路程或最小化总时间等,约束条件包括时间、容量、出发点和到达点等。 然后,可以利用matlab编写求解程序,采用鲸鱼算法进行全局搜索。具体来说,可以将路线规划问题转化为一个优化问题,使用遗传算法或粒子群算法等优化算法进行求解,同时考虑各个约束条件。 在程序中,可以使用矩阵存储车辆的容量、位置、时间等信息,采用突变、选择、交叉等操作进行遗传变异。在每次迭代中,根据当前种群中每个个体的适应度值对其进行排序,以选择较优的个体进行交叉和变异,从而逐渐优化解决方案。同时,可以设置停止迭代的条件,以保证程序的效率。 最后,需要对求解结果进行评估,并进行可视化展示。评估可以使用各种准则进行,如各辆车的路程、总路程、服务时间等指标。可视化可以使用matlab中的绘图工具进行展示,包括路线图、车辆调度图等。 总之,基于matlab鲸鱼算法求解时间开放式车辆路径问题,需要深刻理解问题本质,熟练掌握编程技能,对算法进行适当优化,并进行评估和可视化。
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

运筹不帷幄

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

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

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

打赏作者

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

抵扣说明:

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

余额充值