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

目录

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 : nsingle_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) == 1path_value(1, i) = path_value(1, i) + 1;elsepath_value(1, i) = path_value(1, i) + sqrt(2);endend
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 : nsingle_pop = pop{i, 1};[~, m] = size(single_pop);% 遍历一个个体的所有点for j = 1 : m - 2% 计算三个点的坐标 列 行  i i+1 i+2x_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?)/2bcb2 = (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 > 91path_smooth(1, i) = path_smooth(1, i) + 3;elseif angle <= 91 && angle > 46path_smooth(1, i) = path_smooth(1, i) + 15;elseif angle <= 46path_smooth(1, i) = path_smooth(1, i) + 20;endend
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 <= pxif(ms(newin)) < p_fit_value(fitin)% 判断哪一次落在哪个区间里面new_pop{newin, 1} = pop{fitin, 1};newin = newin+1;elsefitin = 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-1singal_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,然后再检查匹配的元素个数是否大于等于3if (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 == 1new_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 >= 100000breakendend% 不变异了if max_iteration >= 100000new_pop{i, 1} = pop{i, 1};% 如果未达到最大迭代次数,将变异后的个体重新组合,并保存到 new_pop 中。    elsenew_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_numx_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.mzph.cn/news/132828.shtml

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

相关文章

Java面向对象(进阶)-- super关键字的使用与子类对象实例化全过程

文章目录 一、super关键字的使用&#xff08;1&#xff09;为什么需要super&#xff1f;&#xff08;2&#xff09;super的理解&#xff08;3&#xff09;super可以调用的结构1、super调用方法举例1举例2举例3小结 2、super调用属性举例1举例2举例3小结 3、super调用构造器引入…

el-tree中展示项换行展示

文章目录 效果如下所示&#xff1a;没有换行展示的效果修改样式换行之后的展示效果 想要了解el-tree使用的详情往下看代码和数据如下所示Vue代码中可能使用到的数据如下Vue的代码如下&#xff1a;没有换行展示的效果换行之后的展示效果样式调试 效果如下所示&#xff1a; 没有…

数据库的备份和恢复

备份&#xff1a;完全备份&#xff0c;增量备份 完全备份&#xff1a;将整个数据库完整的进行备份 增量备份&#xff1a;在完全备份基础的之上&#xff0c;对后续新增的内容进行备份 备份的需求 1生产环境中&#xff0c;数据的安全性至关重要&#xff0c;任何数据都可能产生非…

【计算机架构】程序指令计数 | 功耗计算 | 电力功耗 | 安德尔定律(Amdahl‘s Law)

0x00 程序的指令计数 程序的指令计数&#xff08;Instruction Count&#xff09;由程序本身、ISA&#xff08;指令集架构&#xff09;和编译器决定。这表示一个程序中包含的指令数量受到程序编写方式、计算机体系结构和编译器的影响。 每条指令的平均周期数&#xff08;Averag…

在云上jupylab(codelab)常用的shell命令

1、切换当前文件目录位置&#xff1a; %cd /project/train/ 2、删除目标文件夹和文件夹下面的内容&#xff0c;注意这个r是不能少的&#xff1a; !rm -r /project/train/src_repo/dataset 3、创建数据集相关文件夹 !mkdir /project/train/src_repo/dataset 4、复制指定…

想学计算机编程从什么学起?零基础如何自学计算机编程?中文编程开发语言工具箱之渐变标签组构件

想学计算机编程从什么学起&#xff1f;零基础如何自学计算机编程&#xff1f; 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#xff0c;而且可以开发大型的软件&#xff0c;…

linux硬盘挂载(linux 修改某个磁盘挂载到新目录\lvm扩容)

文章目录 一、什么是硬盘挂载二、linux 修改某个磁盘挂载到新目录三、Esxi下扩容硬盘1. 判断一个已有的文件系统是否使用了LVM(逻辑卷管理)2. 原本文件系统没有使用lvm&#xff0c;还可以lvm扩容吗&#xff1f;3. 原有文件系统使用lvm场景下扩容(lvm扩容)了解LVMEsxi LVM扩容步…

NOIP2000提高组第二轮T4:方格取数

题目链接 [NOIP2000 提高组] 方格取数 题目描述 设有 N N N \times N NN 的方格图 ( N ≤ 9 ) (N \le 9) (N≤9)&#xff0c;我们将其中的某些方格中填入正整数&#xff0c;而其他的方格中则放入数字 0 0 0。如下图所示&#xff08;见样例&#xff09;: 某人从图的左上…

ES 报错问题汇总

报错1&#xff1a; curl -XGET http://192.168.56.115:9200/_license解决方式 在 es/config/elasticsearch.yml文件,把开启密码验证把此处也修改成false xpack.security.enabled: false 报错2&#xff1a; 解决方式&#xff1a; 查看服务器es的license信息&#xff0c;发现 …

用「埋点」记录自己,不妄过一生

最近有朋友问我「埋点怎么做」&#xff0c;给朋友讲了一些互联网广告的案例&#xff0c;从源头的数据采集讲到末尾的应用分析和流量分配等&#xff08;此处省略N多字&#xff09; 解释完以后&#xff0c;我想到一个问题&#xff1a;有了埋点可以做分析&#xff0c;那我们对自己…

机器学习概论

一、机器学习概述 1、机器学习与人工智能、深度学习的关系 人工智能&#xff1a;机器展现的人类智能机器学习&#xff1a;计算机利用已有的数据(经验)&#xff0c;得出了某种模型&#xff0c;并利用此模型预测未来的一种方法。深度学习&#xff1a;实现机器学习的一种技术 2…

yum

什么是yum? Linux中我们也要进行工具/指令/程序&#xff0c;安装&#xff0c;检查卸载等&#xff0c;需要yum的软件 安装软件的方式&#xff1a; 1.源代码安装--交叉编译工作 2.rpm包直接安装 3.yum / apt-get yum:yum是我们linux预装的一个指令&#xff0c;搜索&#x…

【数据结构】顺序表和链表

顺序表和链表 1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串… 线性表在逻辑上是线性结构&#xff0c;也就说是连…

uniapp 省市区三级联动选择器

还有半个小时下班&#xff0c;总想着发点光亮照耀他人。IT技术这东西&#xff0c;尤其是UI方面的东西&#xff0c;于用户体验至关重要&#xff0c;想想最近使用uni-data-picker的丑陋页面&#xff0c;自己重构了这个功能&#xff0c;新加实现&#xff0c;效果图如下&#xff0c…

SRC实战 | CORS跨资源共享漏洞

CORS跨资源共享 跨源资源共享 (CORS) 是一种浏览器机制&#xff0c;允许网页使用来自其他页面或域的资产和数据。 大多数站点需要使用资源和图像来运行它们的脚本。这些嵌入式资产存在安全风险&#xff0c;因为这些资产可能包含病毒或允许服务器访问黑客。 CORS响应头 CORS通…

类(class)

类是 C中一个非常重要的元素&#xff0c;可以说是 C的灵魂所在了&#xff0c;我们都知道 C说一种面向对象的编程语言&#xff0c;那么面向对象是一种什么概念呢&#xff1f;在 C程序设计中&#xff0c;所有一切东西都可以称之为对象&#xff0c;任何对象都应该具有属性和行为。…

C++基础——类与对象

1 概述 C是面向对象的语言&#xff0c;面向对象语言三大特性&#xff1a;封装、继承、多态。 C将万事万物抽象为对象&#xff0c;对象上有其属性和行为。 2 封装 2.1 封装的意义 封装是面向对象的三大特性之一&#xff0c;封装将属性和行为作为一个整体&#xff0c;对属性和…

灵活调整宣传策略,媒体发稿和新闻发布的优势所在

企业在当今信息爆炸的时代&#xff0c;要想在市场竞争中脱颖而出&#xff0c;提高公信力是至关重要的。而媒体发稿和新闻发布是提升企业公信力的重要手段之一。下面将从门户网站的权威展示、搜索引擎排名的提升、内容的持续稳定有效性、内容的可改性以及协助增加网站流量等方面…

浅谈自动化测试框架开发

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

Linux中for循环

for do done 复习知识点&#xff1a;cut命令&#xff0c;id命令&#xff0c;finger命令&#xff0c;for循环 程序如上&#xff0c;-d 接分隔符&#xff0c;-f后的数字表示分隔后的列 从结果可以看出&#xff0c;系统上没有finger这个命令&#xff0c;后面会学到yum安装命令&a…