自动驾驶算法(七):基于遗传算法的路径规划(下)

news2024/11/24 4:44:30

目录

1 遗传选择

2 遗传交叉

3 遗传变异

4 结语


1 遗传选择

        我们书接上回,我们完成了种群的初始化,将所有的种群放入了new_pop1中,这个new_pop1是一个(种群大小 * 路径)的一个矩阵,我们来看如何进行遗传选择:

% 循环迭代操作
for i = 1 : max_gen
    % 计算适应度值
    % 计算路径长度
    path_value = cal_path_value(new_pop1, x)
    % 计算顺滑度
    path_smooth = cal_path_smooth(new_pop1, x)
    % 计算适应度
    fit_value = 1 .* path_value .^ -1 + 1 .* path_smooth .^ -1;
    %  这行代码计算了路径长度的均值,并将其赋值给名为 mean_path_value 的数组的第 i 个元素。
    mean_path_value(1, i) = mean(path_value);
    % 这行代码找到了适应度值中的最大值,并将其索引赋值给 m。
    [~, m] = max(fit_value);
    % 这行代码将在适应度值中找到的最大值对应的路径长度赋值给 min_path_value 数组的第 i 个元素。
    min_path_value(1, i) = path_value(1, m);
    
    % 选择操作
    new_pop2 = selection(new_pop1, fit_value);
    % 交叉
    new_pop2 = crossover(new_pop2, pc);
    % 变异 
    new_pop2 = mutation(new_pop2, pm, G, x);
    % 
    new_pop1 = new_pop2;
    
end

        我们这里迭代50次,也就是说50代,我们进行50代的进化。我们首先计算路径长度:

% 计算路径长度函数 传进来的是个体
function [path_value] = cal_path_value(pop, x)
[n, ~] = size(pop);
path_value = zeros(1, n);
for i = 1 : n
    single_pop = pop{i, 1};
    [~, m] = size(single_pop);
    for j = 1 : m - 1
        % 点i所在列 (从左到右编号1.2.3...)
        x_now = mod(single_pop(1, j), x) + 1; 
        % 点i所在行(从上到下编号1,2,3...)
        y_now = fix(single_pop(1, j) / x) + 1;
        % 点i+1所在行、列
        x_next = mod(single_pop(1, j + 1), x) + 1;
        y_next = fix(single_pop(1, j + 1) / x) + 1;
        % 左右上下相连
        if abs(x_now - x_next) + abs(y_now - y_next) == 1
            path_value(1, i) = path_value(1, i) + 1;
        else
            path_value(1, i) = path_value(1, i) + sqrt(2);
        end
    end
end

        我们传进来的是所有的个体,在循环中遍历每一个个体for i = 1 : n,pop{i, 1}  表示从 pop 中提取第 i 行、第 1 列的元素。我们将绝对栅格坐标值转化为栅格坐标求两坐标的距离,如果相连则路径+1如果是斜对角则路径+根号2。最后我们得到了一个(1,n)的数组,保存了每一个路径的代价值。

        我们在来看计算顺滑度:

% 计算顺滑度
function [path_smooth] = cal_path_smooth(pop, x)
[n, ~] = size(pop);
path_smooth = zeros(1, n);
% 遍历所有个体
for i = 1 : n
    single_pop = pop{i, 1};
    [~, m] = size(single_pop);
    % 遍历一个个体的所有点
    for j = 1 : m - 2
        % 计算三个点的坐标 列 行  i i+1 i+2
        x_now = mod(single_pop(1, j), x) + 1; 
        y_now = fix(single_pop(1, j) / x) + 1;
        x_next1 = mod(single_pop(1, j + 1), x) + 1;
        y_next1 = fix(single_pop(1, j + 1) / x) + 1;
        x_next2 = mod(single_pop(1, j + 2), x) + 1;
        y_next2 = fix(single_pop(1, j + 2) / x) + 1;
        % cos A=(b?+c?-a?)/2bc
        b2 = (x_now - x_next1)^2 + (y_now - y_next1)^2;
        c2 = (x_next2 - x_next1)^2 + (y_next2 - y_next1)^2;
        a2 = (x_now - x_next2)^2 + (y_now - y_next2)^2;
        cosa = (c2 + b2 - a2) / (2 * sqrt(b2) *  sqrt(c2));
        % 度数
        angle = acosd(cosa);
        
        if angle < 170 && angle > 91
            path_smooth(1, i) = path_smooth(1, i) + 3;
        elseif angle <= 91 && angle > 46
            path_smooth(1, i) = path_smooth(1, i) + 15;
        elseif angle <= 46
            path_smooth(1, i) = path_smooth(1, i) + 20;
        end
    end
end

        我们遍历每一个个体,计算三个点的夹角,越平滑的话角度越大,我们给予角度大的较小权值。

        我们计算适应度:

        综上所述,越好的路径适应度越大,适应环境也就越强。

        下面计算了路径长度的均值,并将其赋值给名为 mean_path_value 的数组的第 i 个元素。又找到了适应度值中的最大值,并将其索引赋值给 m。又将在适应度值中找到的最大值对应的路径长度赋值给 min_path_value 数组的第 i 个元素。

    % 计算适应度
    fit_value = 1 .* path_value .^ -1 + 1 .* path_smooth .^ -1;
    %  这行代码计算了路径长度的均值,并将其赋值给名为 mean_path_value 的数组的第 i 个元素。
    mean_path_value(1, i) = mean(path_value);
    % 这行代码找到了适应度值中的最大值,并将其索引赋值给 m。
    [~, m] = max(fit_value);
    % 这行代码将在适应度值中找到的最大值对应的路径长度赋值给 min_path_value 数组的第 i 个元素。
    min_path_value(1, i) = path_value(1, m);

        到此为止,我们的准备工作就完成了,我们进入选择工作:

% 选择操作
new_pop2 = selection(new_pop1, fit_value);

        我们看下选择操作的代码:

% 用轮盘赌法选择新的个体
% 输入变量 pop元素种群 fitvalue适应度值
% 输出变量 newpop选择以后的元素种群
function [new_pop] = selection(pop, fit_value)
% 构造轮盘
% px存放有多少个个体
[px, ~] = size(pop);
% 这行代码计算了适应度值的总和,将结果赋值给变量 total_fit。
total_fit = sum(fit_value);
%  这行代码计算了每个个体的适应度相对于总适应度的比例,将结果存储在向量 p_fit_value 中。相当于一个大的转盘。每个部分占比多少
p_fit_value = fit_value / total_fit;
% 这行代码对适应度比例进行累积求和,得到了一个逐步递增的概率分布。 0.2 0.5 0.8 1.0
p_fit_value = cumsum(p_fit_value);   
% 随机数从小到大排列 生成了若px=20 个0-1的列向量
ms = sort(rand(px, 1));
fitin = 1;
newin = 1;
% 举个例子 px = 4 ms = 0.1 0.2 0.3 0.4   p_fit_value =  0.3 0.6 0.65 0.75
% 好像没有做选择呢??
% D1 1<=4 ms(1)=0.1<p_fit_value(1)0.3 new_pop[1,1]=pop[1,1] newin=2
% D2 2<=4 ms(2)=0.2<p_fit_value(1)0.3 new_pop[2,1]=pop[1,1] newin=3
% D3 3<=4 ms(3)=0.3!=p_fit_value(1)0.3 fit_in = 2
% D4 3<=4 ms(3)=0.3<=p_fit_value(2)0.6 new_pop[3,1]=pop[2,1] newin=4
% D5 4<=4 ms(4)=0.4<=p_fit_value(2)0.6 new_pop[4,1]=pop[2,1] newin=4
while newin <= px
    if(ms(newin)) < p_fit_value(fitin)
        % 判断哪一次落在哪个区间里面
        new_pop{newin, 1} = pop{fitin, 1};
        newin = newin+1;
    else
        fitin = fitin+1;
    end
end

        输入变量:pop种群,fitvalue为种群的每个个体适应度值的列表。上面我也用具体例子解释了,选择类似轮盘赌的方式,到这为止,我们从种群出选择出了new_pop作为自然选择的结果,其他种群全部抛弃。

2 遗传交叉

function [new_pop] = crossover(pop, pc)
[px,~] = size(pop);
% 判断路经点是奇数倍还是偶数倍 如果是奇数的话那么最后我们就不做处理了
parity = mod(px, 2);
new_pop = {};
% 这是一个循环,它会以步长为2从1开始遍历到 px-1,目的是处理两两配对的个体。
for i = 1:2:px-1
        singal_now_pop = pop{i, 1};
        singal_next_pop = pop{i+1, 1};
        % 这行代码使用 ismember 函数找出 singal_now_pop 中与 singal_next_pop 相同的元素,并返回一个逻辑数组 lia 和对应的索引 lib。
        [lia, lib] = ismember(singal_now_pop, singal_next_pop);
        % 这行代码找出逻辑数组 lia 中为 1 的元素的索引,将结果存储在向量 n 中。
        [~, n] = find(lia == 1);
        % 这行代码获取向量 n 的长度(即匹配的元素个数),并将结果存储在变量 m 中。
        [~, m] = size(n);
    % 这是一个条件判断,它首先检查随机数是否小于交叉概率 pc,然后再检查匹配的元素个数是否大于等于3
    if (rand < pc) && (m >= 3)
        % 如果上述条件成立,这行代码会生成一个介于2和m-1之间的随机整数 r。
        r = round(rand(1,1)*(m-3)) +2;
        % 这两行代码分别得到要进行交叉的位置索引
        crossover_index1 = n(1, r);
        crossover_index2 = lib(crossover_index1);
        % 这两行代码进行了交叉操作,生成了新的个体。
        new_pop{i, 1} = [singal_now_pop(1:crossover_index1), singal_next_pop(crossover_index2+1:end)];
        new_pop{i+1, 1} = [singal_next_pop(1:crossover_index2), singal_now_pop(crossover_index1+1:end)];
        
    else
        % 如果交叉条件不满足,保持原个体不变。
        new_pop{i, 1} =singal_now_pop;
        new_pop{i+1, 1} = singal_next_pop;
    end
% 如果个体数量为奇数,将最后一个个体直接放入新一代。
if parity == 1
    new_pop{px, 1} = pop{px, 1};
end
end

        我们调用的函数是:

    new_pop2 = crossover(new_pop2, pc);

        这里的pc = 0.8代表的是交叉处理频率,也就是我们有80%的几率进行交叉操作,内部是一个循环,它会以步长为2从1开始遍历到种群数量-1,目的是处理两两配对处理基因重组的个体。

        我们先取出第一个种群和第二个种群,使用 ismember 函数找出 singal_now_pop 中与 singal_next_pop 相同的元素,并返回一个逻辑数组 lia 和对应的索引 lib。找出逻辑数组 lia 中为 1 的元素的索引,将结果存储在向量 n 中。获取向量 n 的长度(即匹配的元素个数),并将结果存储在变量 m 中。

        如果路径的共同元素数量大于3且要进行遗传交叉操作我们将随机选取第一个种群的基因打乱拼接到第二个种群上,图示如下:

        到这为止,我们已经对两两种群进行了基因重组。

3 遗传变异

% 变异频率 栅格地图 20
function [new_pop] = mutation(pop, pm, G, x)
% 获取路径长度
[px, ~] = size(pop);
new_pop = {};
% 它将会迭代处理种群中的每一个个体
for i = 1:px
    % 初始化最大迭代次数
    max_iteration = 0;
    % 从种群 pop 中取出第 i 个个体,并将其赋值给变量 single_new_pop。
    single_new_pop = pop{i, 1};
    % 这行代码获取了 single_new_pop 的维度信息,并将列数保存在变量 m 中。
    [~, m] = size(single_new_pop);
    % single_new_pop_slice初始化
    single_new_pop_slice = [];
    % 这是一个条件语句,它检查一个随机数是否小于变异率 pm。
    if(rand < pm)
        while isempty(single_new_pop_slice)
            % 生成两个随机整数 mpoint,这两个整数位于 2 到 m-2 之间。
            mpoint = sort(round(rand(1,2)*(m-3)) + [2 2]);
            % 从 single_new_pop 中取出索引为 mpoint(1,1)-1 和 mpoint(1,2)+1 的两个元素,构成 single_new_pop_slice。
            single_new_pop_slice = [single_new_pop(mpoint(1, 1)-1) single_new_pop(mpoint(1, 2)+1)];
            % 使路径连续
            single_new_pop_slice = generate_continuous_path(single_new_pop_slice, G, x);
            if max_iteration >= 100000
                break
            end
        end
        % 不变异了
        if max_iteration >= 100000
            new_pop{i, 1} = pop{i, 1};
        % 如果未达到最大迭代次数,将变异后的个体重新组合,并保存到 new_pop 中。    
        else
            new_pop{i, 1} = [single_new_pop(1, 1:mpoint(1, 1)-1), single_new_pop_slice(2:end-1), single_new_pop(1, mpoint(1, 2)+1:m)];
        end
        % 将 single_new_pop_slice 重置为空,准备进行下一次循环。
        single_new_pop_slice = [];
    else
        % 直接将未发生变异的个体复制到 new_pop 中。
        new_pop{i, 1} = pop{i, 1};
    end
end

        这里的调用函数如下:

new_pop2 = mutation(new_pop2, pm, G, x);

        是我们在交叉里面得到的种群,pm是变异比率,我们设置为0.2。这里是对种群中的每一个个体进行变异的,对其随机两个点进行拼接,若拼接成功则变异成功。

4 结语

        最后我们不断迭代出了最优路径:

  • 接下来的代码段是用来将最优路径的节点坐标转换成具体的坐标值。它通过取模和整除操作来计算 x 和 y 的坐标值。

  • 最后一段代码用红色绘制了最优路径在图形上。

min_path_value(1, end)
[~, min_index] = max(fit_value);
min_path = new_pop1{min_index, 1};
figure(2)
hold on;
title('hah'); 
xlabel('x'); 
ylabel('y');
DrawMap(G);
[~, min_path_num] = size(min_path);
for i = 1:min_path_num
    x_min_path(1, i) = mod(min_path(1, i), x) + 1; 
    y_min_path(1, i) = fix(min_path(1, i) / x) + 1;
end
hold on;
plot(x_min_path, y_min_path, 'r')

        最后看一下效果吧~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1178541.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件外包开发需要注意的问题

软件外包开发是一种常见的商业实践&#xff0c;可以帮助企业降低成本、提高效率和获得专业技能。然而&#xff0c;要确保成功的外包开发项目&#xff0c;需要注意以下一些关键问题&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司…

数组的存储结构、特殊矩阵和稀疏矩阵的压缩存储

数组的存储结构、特殊矩阵和稀疏矩阵的压缩存储 1.数组的存储结构、特殊矩阵、稀疏矩阵的压缩存储1.1 数组的存储结构1.1.1 一维数组的存储结构关系式1.1.2 多维数组的存储结构关系式 1.2 特殊矩阵的压缩存储1.2.1 对称矩阵1.2.2 下三角矩阵1.2.3 上三角矩阵1.2.4 三对角矩阵 1…

Cesium:WFS请求两种方式

以本地发布的上海市浦东区行政区划WMS地图服务为例,讲述Cesium中WFS请求的两种方式及其优缺点。 服务加载地址及其参数如下, 服务加载地址:http://localhost:8089/geoserver/pudong/wms 加载参数:layerName:pudong:distractservice: "WMS",request: "GetMa…

基于材料生成算法的无人机航迹规划-附代码

基于材料生成算法的无人机航迹规划 文章目录 基于材料生成算法的无人机航迹规划1.材料生成搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用材料生成算法来优化无人机航迹规划。 …

以华为为例:GTM岗位主要是做什么的?如何做好GTM工作?

如何让产品上市以后卖得更好&#xff1f;这是一个系统工程。 许多公司在学习华为&#xff08;尤其是做消费者业务&#xff0c;通俗地说就是2C业务的公司或产品&#xff09;&#xff0c;设立GTM相关的岗位。我们来看一下&#xff0c;GTM岗位主要做些什么&#xff0c;如何才能胜…

宠物领养系统jsp+servlet+mysql

设计不同用户的操作权限、注册和登录方法。 管理员可以在管理员管理、用户管理、宠物管理、评论管理、团队活动管理、志愿者的申请等等模块中进行查询、添加、删除、修改。 管理员可以在领养管理中通过领养时间查询所有宠物被领养的信息&#xff0c;修改是否同意领养宠物&#…

色彩大师:纽约公寓的大胆装修之旅

这对夫妇刚从西海岸搬到了纽约&#xff0c;最初尝试自己布置家居。但在设计中心寻找面料和家具时&#xff0c;他们感到有些不知所措。 在海外期间&#xff0c;他们深受英国乡村别墅装饰的魅力所吸引&#xff0c;希望将类似的风格带到他们的纽约公寓。我们喜欢英国乡村别墅的随…

nn.embedding函数详解(pytorch)

提示&#xff1a;文章附有源码&#xff01;&#xff01;&#xff01; 文章目录 前言一、nn.embedding函数解释二、nn.embedding函数使用方法四、模型训练与预测的权重变化探讨 前言 最近发现prompt工程(如sam模型)&#xff0c;也有transform的detr模型等都使用了nn.Embedding函…

时序预测 | MATLAB实现基于SVM-Adaboost支持向量机结合AdaBoost时间序列预测

时序预测 | MATLAB实现基于SVM-Adaboost支持向量机结合AdaBoost时间序列预测 目录 时序预测 | MATLAB实现基于SVM-Adaboost支持向量机结合AdaBoost时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.Matlab实现SVM-Adaboost时间序列预测&#xff08;风…

解决ERR: cURL error 77: Unable to initialize NSS: -8023

研发反映一个问题,上传文件时失败,日志内错误信息如下: ERR: cURL error 77: Unable to initialize NSS: -8023 (SEC_ERROR_PKCS11_DEVICE_ERROR) ... 这个功能使用了腾讯云的点播服务。因此立即联系了腾讯云客服。 搞了很久问题依旧。 反复测试,发现上传视频文件,错…

03【保姆级】-GO语言变量和数据类型和相互转换

03【保姆级】-GO语言变量和数据类型 一、变量1.1 变量的定义&#xff1a;1.2 变量的声明、初始化、赋值1.3 变量使用的注意事项 插播-关于fmt.Printf格式打印%的作用二、 变量的数据类型2.1整数的基本类型2.1.1 有符号类型 int8/16/32/642.1.2 无符号类型 int8/16/32/642.1.3 整…

涉及法律诉讼和负债670万美元的【工务园】申请纳斯达克IPO上市

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;总部位于东莞的人力资源SaaS平台Baiya International Group Inc&#xff08;简称&#xff1a;工务园&#xff09;近期已向美国证券交易委员会&#xff08;SEC&#xff09;提交招股书&#xff0c;申…

【pytorch源码分析--torch执行流程与编译原理】

背景 解读torch源码方便算子开发方便后续做torch 模型性能开发 基本介绍 代码库 https://github.com/pytorch/pytorch 模块介绍 aten: A Tensor Library的缩写。与Tensor相关的内容都放在这个目录下。如Tensor的定义、存储、Tensor间的操作&#xff08;即算子/OP&#xff…

StripedFly恶意软件:悄无声息运行5年,感染百万设备

导语&#xff1a;最近&#xff0c;俄罗斯网络安全公司Kaspersky发布的一项调查显示&#xff0c;一种名为StripedFly的高级恶意软件伪装成加密货币挖矿程序&#xff0c;悄无声息地在全球范围内运行了超过5年&#xff0c;感染了100万台设备。这是一种复杂的模块化框架&#xff0c…

【Unity实战】最全面的库存系统(二)(附源码)

文章目录 先来看看最终效果前言箱子库存箱子存储物品玩家背包快捷栏满了,物品自动加入背包修复开着背包拾取物品不会刷新显示的问题将箱子库存和背包分开,可以同时打开源码完结先来看看最终效果 前言 本期紧跟着上期,继续来完善我们的库存系统,实现箱子库存和人物背包 箱…

RocketMq简介及安装、docker安装rocketmq、安装rocketmq可视化管理端

前言 本文主要简单介绍rocketmq及使用docker安装rocketmq的方法。 rocketmq简介 rocketmq有两部分&#xff0c;nameserver和broker&#xff0c;nameserver用来维护broker的地址、向生产者、消费者推送broker的最新地址&#xff1b;broker用来存储、转发消息&#xff1b;也就…

Java根据一个List内Object的两个字段去重

背景 在Java开发过程中&#xff0c;我们经常会遇到需要对List进行去重的需求。 其中常见的情况是&#xff0c;将数组去重&#xff0c;或者将对象依据某个字段去重。这两种方式均可用set属性进行处理。 今天讨论&#xff0c;有一个List&#xff0c;且其中的元素是自定义的对象&…

Linux学习第34天:Linux LCD 驱动实验(一):星星之火可以燎原

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 LCD显示屏是由一个一个的像素点构成的。当你能控制一个像素点的亮暗及颜色变化的时候&#xff0c;你就能让LCD显示瓶显示五颜六色的整幅图案。甚至可以让LCD屏幕…

uboot启动linux kernel的流程

目录 前言流程图autoboot_commandrun_command_listdo_bootmdo_bootm_statesdo_bootm_linuxboot_prep_linuxboot_jump_linux 前言 本文在u-boot启动流程分析这篇文章的基础上&#xff0c;简要梳理uboot启动linux kernel的流程。 流程图 其中&#xff0c; autoboot_command位于…

合成数据的被需要的5 个重要原因

若要训练机器学习模型&#xff0c;需要数据。数据科学任务通常不是 Kaggle 竞赛&#xff0c;在竞赛中&#xff0c;你有一个很好的大型策划数据集&#xff0c;并预先标记。有时&#xff0c;您必须收集、组织和清理自己的数据。在现实世界中收集和标记数据的过程可能非常耗时、繁…