-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
98 lines (45 loc) · 129 KB
/
search.xml
File metadata and controls
98 lines (45 loc) · 129 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>Dijkstra && Constellation design</title>
<link href="/2023/07/14/%E9%80%9A%E4%BF%A1%E7%BD%91%E7%BB%9C%E4%BB%BF%E7%9C%9F%E8%AF%BE%E7%A8%8B%E8%AE%BE%E8%AE%A1%E6%8A%A5%E5%91%8A_2200200714_%E8%83%A1%E6%AD%A3%E7%9D%BFlinux/"/>
<url>/2023/07/14/%E9%80%9A%E4%BF%A1%E7%BD%91%E7%BB%9C%E4%BB%BF%E7%9C%9F%E8%AF%BE%E7%A8%8B%E8%AE%BE%E8%AE%A1%E6%8A%A5%E5%91%8A_2200200714_%E8%83%A1%E6%AD%A3%E7%9D%BFlinux/</url>
<content type="html"><![CDATA[<h2 id="题目1:利用计算机语言编程实现Dijkstra算法"><a href="#题目1:利用计算机语言编程实现Dijkstra算法" class="headerlink" title="题目1:利用计算机语言编程实现Dijkstra算法"></a>题目1:利用计算机语言编程实现Dijkstra算法</h2><ol><li><strong>课程设计目的</strong></li><li>理解和掌握Dijkstra算法在通信网络中的应用。通信网络中存在大量的节点和边,通过学习和实践Dijkstra算法,可以了解其在路由算法中的作用和原理。</li><li>学习如何利用计算机语言编程实现Dijkstra算法,并将其应用于通信网络的路由算法设计。通过编程实现,可以加深对算法的理解,并将其应用于实际的通信网络问题。</li><li>掌握图形化界面设计和展示在通信工程领域的应用。在通信工程中,图形化界面常用于可视化网络拓扑、路由路径和性能等信息。通过课程设计,可以学习如何设计和展示与通信网络相关的图形界面。</li><li>培养学生在通信工程领域中的问题解决能力。通过完成课程设计,学生将面临实际的通信网络问题,需要分析问题、设计算法和编程实现来解决这些问题。</li><li>通过学习和实现Dijkstra算法,可以加深对图论和最短路径算法的理解,并掌握对其进行优化的方法。在通信领域中,最短路径算法常用于寻找信号传输路径或网络中的最佳通信路由,因此对算法性能的理解和优化至关重要。</li><li>在通信工程中,需要处理大量的通信数据和传感器数据。通过实现Dijkstra算法,可以提高对数据的处理和分析能力,以更好地应对实际通信系统中的数据管理和处理需求。</li></ol><p>总体而言,通过上述算法课程设计,通信工程专业的大学生将获得更深入的专业知识,提高问题解决能力,并培养实际应用和团队合作能力,为未来在通信工程领域的发展打下坚实基础。</p><ol><li><strong>课程设计要求</strong></li></ol><p>要求:</p><ol><li><p>输入必要参数,包括:结点个数、节点间路径长度、给定节点;</p></li><li><p>输出给定节点到其它各节点的最短路径、径长;</p></li><li><p>节点间路径长度用矩阵形式表示;</p></li><li><p>可使用MATLAB或者其他语言进行设计都可以;</p></li><li><p>设计图形化界面展示本人的工作;</p><p>例子:无向图共有7个节点,如下图所示。</p></li></ol><p>计算机输入的节点间路径长度为7×7矩阵:</p><p>若为指定节点,则到其它各节点的最短路径及径长的计算机计算结果为:</p><table><thead><tr><th>节点</th><th></th><th></th><th></th><th></th><th></th><th></th><th></th></tr></thead><tbody><tr><td>最短路径</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>径长</td><td>0</td><td>1</td><td>2</td><td>3</td><td>7</td><td>6</td><td>14</td></tr></tbody></table><ol><li><strong>基本原理</strong></li></ol><p>Dijkstra算法是一种用于计算图中单源最短路径的算法。它的基本原理是从起始节点开始,逐步确定到达其他节点的最短路径,直到找到所有节点的最短路径为止。</p><p>下面是Dijkstra算法的详细原理:</p><p>1. 创建数据结构:创建一个距离数组 dist[],用于存储从起始节点到每个节点的最短距离。初始时,将起始节点的距离设为0,其他节点的距离设为无穷大或一个较大的值。创建一个集合 visited,用于记录已经确定最短路径的节点。</p><p>2. 选择起始节点:将起始节点设置为当前节点。</p><p>3. 更新距离数组:对于当前节点的所有邻居节点,计算通过当前节点到达邻居节点的路径长度,并与邻居节点当前已知的最短路径长度进行比较。如果新计算得到的路径长度小于已知的最短路径长度,则更新邻居节点的最短路径长度为新值。</p><p>4. 标记当前节点:将当前节点标记为已访问,并将其从未访问节点集合中移除。</p><p>5. 选择下一个当前节点:从未访问节点中选择一个距离最短的节点作为下一个当前节点。即从距离数组 dist[] 中选择值最小的节点,该节点将成为下一次迭代的当前节点。</p><p>6. 重复步骤3、步骤4和步骤5,直到所有节点都被标记为已访问,或者没有可达节点为止。</p><p>7. 最短路径结果:完成上述步骤后,每个节点的最短路径长度将被计算出来,并存储在距离数组 dist[] 中。此外,可以通过回溯记录的路径信息,找到从起始节点到每个节点的最短路径。</p><p>Dijkstra算法的核心思想是通过不断选择距离当前节点最近的未访问节点,并更新最短路径长度,逐步扩展最短路径,直到到达所有节点或找到目标节点的最短路径为止。</p><ol><li><strong>仿真程序代码及分析</strong></li></ol><table><thead><tr><th><strong>步骤一 定义距离信息</strong></th><th></th></tr></thead><tbody><tr><td>实验程序: %%图定义 nodes_dist=cell(0); for i=1:nodes_number nodes_dist(i,:)={i,1:nodes_number,dist_list(i,:)}; end U=[];</td><td>分析: 首先,创建了一个名为nodes_dist的空的cell数组。这个数组将用于存储每个节点与其他节点之间的距离信息。 接下来,通过一个循环,遍历节点的数量(假设为nodes_number),并对每个节点进行处理。</td></tr><tr><td><strong>步骤二 节点初始化</strong></td><td></td></tr><tr><td>实验程序: %% 初始化 % S和U保存节点,第一列为节点编号,第二列为源点到对应节点的最短距离 U(:, 1) = [1:1:nodes_number]’; U(:, 2) = inf*ones(nodes_number, 1); for i = 1 : length(nodes_dist{starting_point, 2}) % 找到与源点相邻的点 U(nodes_dist{starting_point,2}(i), 2) = nodes_dist{starting_point, 3}(i); end % 将源点放进S U(starting_point, :) = []; S = [starting_point, 0]; % 每个节点的前驱节点,用于最后生成路径 nodes_parent(:, 1) = (1:1:nodes_number)’; nodes_parent(:, 2) = -ones(nodes_number,1); % 与源点相邻的节点的前驱节点设为源点(源点直接到相邻点的距离肯定最短) for i = 1 : length(nodes_dist{starting_point, 2}) if starting_point~=nodes_dist{starting_point,2}(i) nodes_parent(nodes_dist{starting_point,2}(i), 2) = starting_point; end end</td><td>分析: 首先,通过初始化U数组,将每个节点的编号存储在第一列,并将第二列的距离初始化为无穷大。U数组将用于保存节点及其对应的最短距离。 接下来,通过循环遍历与源点相邻的节点,并将这些节点与源点的距离存储在U数组的相应位置。这样,通过遍历相邻节点,我们可以更新它们的最短距离。 然后,将源点从U数组中移除,并将其添加到已确定最短路径的节点集合S中,初始化其最短距离为0。 在初始化前驱节点部分,通过创建nodes_parent数组,将每个节点的编号存储在第一列,并将第二列的初始值设置为-1,表示没有前驱节点。然后,通过循环遍历与源点相邻的节点,将它们的前驱节点设置为源点。这是因为从源点直接到相邻节点的距离肯定是最短的。</td></tr><tr><td><strong>步骤三 寻找路径</strong></td><td></td></tr><tr><td>实验程序: %%寻找路径 while~isempty(U) %如果仅仅只是想找到起点到终点的最短距离以及路径,那么在将终点从U集移动到S集后算法即可结束。 %寻找U中距离最小的节点值及其索引,将其从U中放入S [dis_min,idx]=min(U(:,2)); node_min=U(idx,1); S=[S;node_min,dis_min]; U(idx,:)=[]; %依次遍历最小距离节点的邻节点,判断是否在U集合中更新邻节点的距离值 fori=1:length(nodes_dist{node_min,2}) %需要判断的邻节点 node_temp=nodes_dist{node_min,2}(i); %找出U集合中节点node_temp的索引值 idx_temp=find(node_temp==U(:,1)); if~isempty(idx_temp) ifU(idx_temp,2)>dis_min+nodes_dist{node_min,3}(i) U(idx_temp,2)=dis_min+nodes_dist{node_min,3}(i); %更新该点的前驱节点 nodes_parent(node_temp,2)=node_min; end end end end</td><td>分析: 首先,通过找到U集合中距离最小的节点及其索引,将该节点从U集合中移动到已确定最短路径的节点集合S中。这样,我们确定了从起始节点到该节点的最短距离。 然后,遍历最小距离节点的邻节点,检查是否需要更新其距离值。对于每个邻节点,我们首先找到它在U集合中的索引,然后判断是否需要更新距离值。如果通过最小距离节点到达邻节点的路径长度小于邻节点当前已知的最短路径长度,则更新邻节点的最短路径长度为新值,并更新其前驱节点为最小距离节点。 通过循环的迭代,不断更新最短路径和前驱节点,直到U集合为空,即所有节点的最短路径都已确定。</td></tr><tr><td><strong>步骤四 保存路径</strong></td><td></td></tr><tr><td>实验程序: %% 保存路径 str_all = “”; all_nodes = {}; for i = 1 : nodes_number % 距离 str1 = sprintf(“起点 %d 到节点 %d 的距离为:%d”, starting_point, S(i, 1), S(i, 2)); % 路径 nodes_along = []; [str2, nodes_along] = find_parent(nodes_parent, S(i, 1), S(i, 1),nodes_along); all_nodes(i,1) = {nodes_along}; str_all = [str_all str1]; end function[str2,nodes_along]=find_parent(nodes_parent,node,des,nodes_along) %递归函数,find_parent()用于寻找前驱,直到找到源点 nodes_along=[nodes_alongnode]; idx=find(nodes_parent(:,1)==node); ifnodes_parent(idx,2)==-1%递归结束条件:找到源点r parent=nodes_parent(idx,1); else [str2,nodes_along]=find_parent(nodes_parent,nodes_parent(idx,2),des,nodes_along); end ifnode==des str2=sprintf(“%d.”,node); else str2=sprintf(“%d->“,node); end end</td><td>分析: 首先,创建一个空字符串str_all用于存储所有路径信息,创建一个空的单元格数组all_nodes用于存储所有路径上的节点。 接下来,通过一个循环遍历每个节点,对于每个节点,执行以下操作: 使用sprintf函数生成起始节点到当前节点的距离信息,并将其存储在字符串变量str1中。 创建一个空数组nodes_along,用于存储当前节点的路径上的所有节点。 调用find_parent函数,该函数用于找到起始节点到当前节点的路径上的所有节点,并返回路径字符串str2和节点数组nodes_along。 将nodes_along存储在all_nodes单元格数组的对应位置。 将距离信息str1添加到字符串str_all中。 通过循环的迭代,生成了所有节点的最短路径信息和节点数组。</td></tr><tr><td><strong>步骤五 UI界面设计与相应</strong></td><td></td></tr><tr><td>实验程序: function pushbutton2_Callback(hObject, eventdata, handles) % hObject handle to pushbutton2 (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) nodes_number = str2num(get(handles.edit1,’string’)); assignin(‘base’, ‘nodes_number’, nodes_number); dist_list = str2num(get(handles.edit2,’string’)); assignin(‘base’, ‘dist_list’, dist_list); starting_point = str2num(get(handles.edit3,’string’)); assignin(‘base’, ‘starting_point’, starting_point); final_point = str2num(get(handles.edit4,’string’)); assignin(‘base’, ‘final_point’, final_point); [S nodes_all str_all] = dijkstra(nodes_number,dist_list, starting_point); set(handles.text6, ‘String’, str_all); indices = find(dist_list == 1000); dist_list(indices) = 0; G = graph(dist_list); h = plot(G, ‘Layout’, ‘force’, ‘EdgeLabel’, G.Edges.Weight); assignin(‘base’, ‘h’, h); % 获取图形句柄的坐标数据 xData = get(h, ‘XData’); yData = get(h, ‘YData’); for i=1:length(nodes_all) if nodes_all{i,1}(1) == final_point as=nodes_all{i,1}; end end for i=1:length(as) hix(i) = xData(as(i)); % 示例操作:显示元素的值 hiy(i) = yData(as(i)); end highlightColor = ‘r’; % 突出显示的颜色 line(hix, hiy, ‘Color’, highlightColor, ‘LineWidth’, 2);</td><td>分析:在函数的开始部分,通过get函数从GUI界面中获取用户输入的节点个数、节点间路径长度、起始节点和终点节点等信息,并将它们保存在相应的变量中。这些变量将用作Dijkstra算法的输入参数。 接下来,调用名为dijkstra的函数,该函数接受节点个数、节点间路径长度和起始节点作为输入,并返回最短路径的一些结果,包括S(起始节点到其他节点的最短路径和距离)、nodes_all(所有节点的路径)和str_all(路径的字符串表示)。这些结果将用于更新GUI界面上的文本显示。 然后,根据节点间路径长度的信息创建一个图对象G,并使用plot函数绘制图形。然后,通过获取图形句柄的坐标数据,从nodes_all中找到终点节点的路径,并提取对应的坐标数据。最后,使用line函数绘制突出显示终点节点路径的线段。</td></tr></tbody></table><ol><li><p><strong>仿真结果及分析</strong></p><p>设计的UI面板如下:</p><p><img src="/media/2f02dd1b52dbd2bec4d62740e3459f78.png"></p></li></ol><ul><li><p>左上角为输入面板,用于输入节点个数,距离矩阵,起点与终点等参数。</p></li><li><p>左下角为控制面板,有开始运行和清除输出两个功能。</p></li><li><p>右边为输出面板,可以可视化有权无向图并将程序的输出结果用红色标注于图上,并且可以输出起点到每个点每个距离的信息。</p><p>程序的仿真结果如下:</p><p>对于测试用例:</p><p>我们将相关参数输入UI,设置1为起点,运行程序。</p></li></ul><p><img src="/media/7b6b0c18d2dc2ba561f9ba8e6da249e6.png"></p><p>可以观察到,程序准确的输出了起点到每个点的最小距离与最短路径。</p><p>可以观察UI界面的输出面板:</p><p><img src="/media/9601b16a8903c4dfbaa80d4987bbffe2.png"></p><p>UI的输出面板准确的可视化出起点到终点的最短路径,并用红色高亮,并且输出了起点到所有点最小距离。</p><p><img src="/media/9e5ec332f8d84c93ad82209f237332c5.png"></p><p>将终点换为节点7,可以看出可视化结果精准且美观,仿真结果较为满意。</p><ol><li><strong>心得体会</strong></li></ol><p>作为通信工程专业的学生,在进行上述课程设计时,我认为这是一个非常有意义且实用的设计任务。通过实现Dijkstra算法并将其应用于图形化界面,我们可以学习到以下几个方面的知识和技能:</p><p>1. 数据结构和算法:Dijkstra算法是一种用于求解最短路径的经典算法,通过实现它,我们加深了对图论中图和节点的理解,以及掌握了一个重要的图算法。</p><p>2. 编程能力:实现Dijkstra算法涉及到数组、循环、递归、条件判断等编程概念的运用,通过编写代码,我们锻炼了自己的编程能力。</p><p>3. GUI设计:将算法应用于图形化界面,使得用户可以直观地输入参数、观察最短路径的结果,这要求我们掌握MATLAB GUI的基本操作和界面设计。</p><p>4. 问题分析和解决能力:在实现算法的过程中,可能会遇到一些问题和bug,需要我们仔细分析和排查错误,提高了问题解决能力。</p><p>5. 数据传递与可视化:通过将计算得到的结果传递到MATLAB工作空间,并进行图形化展示,我们学会了如何将程序计算结果进行可视化和展示。</p><p>6. 在计算机网络中,此算法是很经典且重要的最短路由算法,实现此算法,让自己在计网课程中学习的理论以代码的方式得以实践,并且加深了我对路由算法的理解。</p><p>总的来说,这样的课程设计既锻炼了我们的编程能力,又提高了对通信网络中最短路径问题的理解和解决能力。同时,实现图形化界面让算法更加直观和易于使用,这样的项目不仅有学术价值,还有一定的实际应用价值,能够培养我们综合运用所学知识解决实际问题的能力。因此,这样的课程设计对我来说是一次非常有意义的学习和实践机会。</p><p><strong>题目2:基于STK的卫星星座仿真</strong></p><ol><li><strong>课程设计目的</strong></li></ol><p>上述课程设计的目的是为通信工程专业的学生提供一个实践性的项目,旨在培养实际操作能力和解决问题的能力,以及加深对卫星通信系统和STK仿真软件的理解。</p><p>具体目的包括:</p><ol><li>熟悉卫星通信系统:通过设计卫星星座和地面站的布局,学生可以深入了解卫星通信系统的基本原理、组成要素以及卫星与地面站之间的通信链路。</li><li>掌握STK软件的使用:STK是一款常用于卫星和航天器轨道分析、链路仿真等工具。通过本课程设计,学生可以学会使用STK软件进行卫星星座建模、轨道仿真、链路分析等操作,提高对该软件的熟练程度。</li><li>理解链路几何参数的计算和可视化:通过对星地链路和星间链路的几何参数进行仿真计算和可视化展示,学生可以深入理解链路几何特性对通信质量和可靠性的影响,并掌握相关计算和分析方法。</li><li>培养解决实际问题的能力:本课程设计要求学生根据具体要求和限制条件,设计合理的卫星星座布局和地面站设置,并通过仿真展示星座运行和链路变化过程。通过解决实际问题的过程,培养学生的问题分析能力和创新思维。</li></ol><p>综上所述,这个课程设计旨在通过实际操作和仿真分析,加深对卫星通信系统和STK软件的理解,培养实践能力和问题解决能力,为其未来从事通信工程相关工作打下坚实基础。</p><ol><li><strong>课程设计要求</strong></li></ol><p>要求:</p><ol><li>利用STK产生任意非同步轨道的卫星星座(可参考铱星等实际卫星系统或自己设计卫星星座);</li><li>设置哈尔滨、威海、深圳三个地面站;</li><li>仿真展示星座运行及链路变化过程;</li><li>仿真计算星地链路、星间链路的几何参数变化规律及可视性关系,主要包括:俯仰角、方位角、链路长度。</li><li><strong>基本原理</strong></li></ol><p>1. 卫星轨道类型:了解不同类型的卫星轨道,例如地球同步轨道、非同步轨道、极地轨道等。理解这些轨道的特点和应用场景,选择适合的轨道类型进行卫星星座建模。</p><p>2. 卫星星座布局:研究卫星星座的布局方式,包括卫星数量、分布形式和相对位置等。了解不同布局方式的优缺点,例如全球覆盖、区域覆盖等,可以参考实际卫星系统的设计经验。</p><p>3. 卫星通信链路:理解卫星与地面站之间建立的通信链路,包括星地链路和星间链路。了解链路的几何参数,如俯仰角、方位角、链路长度等。掌握计算和分析链路参数的方法,以及链路质量和可视性的影响因素。</p><p>4. STK软件的使用:熟悉STK软件的基本功能和操作方法。学习如何创建卫星轨道、设置地面站、进行仿真运行和链路分析。了解STK的数据处理和可视化功能,以及相关的计算工具和分析工具。</p><ul><li><strong>Delta walker星座</strong></li></ul><p>Delta Walker星座是一种非同步的卫星星座,具有以下基本原理:</p><p>1. 轨道布局:Delta Walker星座采用多个不同的轨道平面,每个平面上分布有多颗卫星。这些卫星之间的相对位置和轨道参数被精心设计,以实现全球范围的覆盖和高可靠性的通信服务。</p><p>2. 卫星分布:在每个轨道平面上,卫星被均匀地分布,通常采用环形或其他分布模式。每个平面上的卫星数量可以根据需求进行调整,以达到所需的通信容量和覆盖要求。</p><p>3. 非同步运行:Delta Walker星座中的卫星采用非同步的轨道,即卫星在轨道上的运行速度和位置不同。这样可以确保在不同时间和地点都能获得良好的卫星覆盖,提供持续的通信服务。</p><p>4. 信号传输:卫星之间通过无线通信链路传输信号。每颗卫星上都搭载有天线和通信设备,用于接收和发送信号。通过卫星之间的跳频或其他调度方式,实现信号的传输和转发,从而实现地面站之间或地面站与移动终端之间的通信。</p><p>5. 链路管理:Delta Walker星座需要进行链路管理,以确保通信链路的质量和可靠性。这包括链路功率控制、干扰管理、频率规划等。通过动态调整卫星之间的链路参数和资源分配,最大程度地优化系统性能和服务质量。</p><p>总体而言,Delta Walker星座的基本原理是通过合理的轨道布局和卫星分布,以非同步的方式运行,利用卫星之间的无线链路实现全球范围的通信覆盖。通过链路管理和资源优化,提供高质量和可靠性的通信服务。这种星座设计可根据具体需求进行定制,以满足不同应用场景的通信需求。</p><p>Walker星座指的是具有相同轨道高度和轨道倾角的多颗圆轨道卫星,以地球为球心均匀分布的卫星星座。Walker星座构型常用的描述方式为。</p><p>为星座中卫星的总数量,为星座的轨道面数,为星座中卫星的轨道倾角,为星座中卫星的轨道高度,为相位因子,是之间的一个整数,代表的含义为Walker星座中相邻两个轨道面对应卫星之间的相位关系。相位因子用来确定相邻两个轨道平面上对应卫星之间的相位差为:</p><ol><li><strong>仿真结果及分析</strong></li></ol><p>1. 利用STK产生delta_walker的卫星星座。</p><p><img src="/media/0843b49dc26165384dcccd2ac7bd91bd.png"></p><p>我们插入倾角为45°,轨道高度为10000km的轨道卫星为母星,接着以此按walker星座参数为(36/4/1)来设计,插入其余23颗卫星如下:</p><p><img src="/media/d47a5ec765c14a5269e7b20cec90bd1e.png"></p><p><img src="/media/db30fe9ef0ff384fde2da8f62222a5b7.png"></p><p>2. 设置哈尔滨、威海、深圳三个地面站;</p><p>插入place,按城市数据库分别harbin,weihai,shenzhen三个站,位置如下:</p><p><img src="/media/33014449f1f88a20c445a29a6b5fcd94.png"></p><p><img src="/media/7732081e4d14a06642aff95400173e21.png"></p><p>3. 仿真展示星座运行及链路变化过程;</p><p>仿真从3 Jul 2023 4:00开始,时间步长为10 sec,在4 Jul 2023 4:00结束。在3 Jul 2023 4:50时刻的卫星仿真图如下。</p><p><img src="/media/fbee8cccb26e999ddc8967d9794044e0.png"></p><p>4. 仿真计算星地链路、星间链路的几何参数变化规律及可视性关系,主要包括:俯仰角、方位角、链路长度。</p><p><strong>1)星地链路</strong></p><p>Harbin到整个星座每颗卫星的几何参数变化规律如下:</p><p><img src="/media/7edcb516632d59b026719de43dae8e1a.png"></p><p>Harbin-方位角随时间的变化关系</p><p><img src="/media/8575b57718280d0bbd8726f21f3f7c23.png"></p><p>Harbin-俯仰角随时间的变化关系</p><p><img src="/media/e3c7fb35cde50aaa70449407c5d89f81.png"></p><p>Harbin-链路长度随时间的变化关系</p><p><img src="/media/9c9cfb3bd246ac56d533136473bcf913.png"></p><p>Harbin-星座覆盖时间分析</p><p>Shenzhen到整个星座每颗卫星的几何参数变化规律如下:</p><p><img src="/media/5c4eeae30e6fb8146e56bd4ea0bbd4f5.png"></p><p>Shenzhen-方位角随时间的变化关系</p><p><img src="/media/68087e69763b85e9c9cb4dc883d507ed.png"></p><p>Shenzhen-俯仰角随时间的变化关系</p><p><img src="/media/3c889450bdd1f59bdfc6646512adf5a2.png"></p><p>Shenzhen-链路长度随时间的变化关系</p><p><img src="/media/b8840f94f9252e72083342e3e072ed3f.png"></p><p>Shenzhen-星座覆盖时间分析</p><p>Weihai到整个星座每颗卫星的几何参数变化规律如下:</p><p><img src="/media/a6ac1b0447e587212ed3c4fdd0348908.png"></p><p>Weihai-方位角随时间的变化关系</p><p><img src="/media/3e42ff71e917c253d4b3061ed6063a96.png"></p><p>Weihai-俯仰角随时间的变化关系</p><p><img src="/media/9f387282f08836be15f4b0484353c354.png"></p><p>Weihai-链路长度随时间的变化关系</p><p><img src="/media/f34ba2a4e4ba6c83f18e04d3a68b3813.png"></p><p>Weihai-星座覆盖时间分析</p><p><strong>2)面内星间链路</strong></p><p>面内星间链路是指一颗卫星到同一轨道面上的其余卫星的几何参数变化关系,MEO111卫星到同轨道卫星的几何参数如下:</p><p><img src="/media/0605ccf1ccb6b65285424415d57c2f8b.png"></p><p>面内方位角随时间的变化关系</p><p><img src="/media/2b62a5169fe97ba7a7d4fae22886d1a8.png"></p><p>面内俯仰角随时间的变化关系</p><p><img src="/media/32fb618e425b01c12f2a3cf61996d4b0.png"></p><p>面内链路长度随时间的变化关系</p><p><strong>3)面间星间链路</strong></p><p>面间星间链路是指一颗卫星到相邻轨道面上的其余卫星的几何参数变化关系,MEO121卫星到相邻轨道卫星的几何参数如下:</p><p><img src="/media/49bc23af7f7d9dcd392d4f9f1edeb90c.png"></p><p>面间方位角随时间的变化关系</p><p><img src="/media/4288d962298a697fb93d1ed67d72781c.png"></p><p>面间俯仰角随时间的变化关系</p><p><img src="/media/76b5041e7272d1f844bb8efb4ba019ca.png"></p><p>面间链路长度随时间的变化关系</p><ol><li><strong>心得体会</strong></li></ol><p>在进行STK设计星座仿真课设的过程中,我有以下心得体会:</p><p>1. 系统理解与应用:这个课设使我更深入地理解了卫星通信系统的运行原理和相关技术。通过使用STK软件进行星座设计和仿真,我能够将理论知识应用到实际操作中,加深了对卫星通信系统的整体认识。</p><p>2. STK软件操作技能:通过这个课设,我学习并掌握了STK软件的基本操作和功能。包括创建场景、插入卫星对象、设置属性参数、进行仿真运行等。这对我未来在通信工程领域的实际工作和研究具有很大帮助。</p><p>3. 系统性思维与分析能力:设计星座仿真涉及到多个参数和因素的综合考虑,如卫星数量、轨道参数、覆盖范围等。通过分析和调整这些参数,我能够思考系统的整体优化和性能改进,培养了系统性思维和分析能力。</p><p>4. 实践能力的培养:在课设过程中,我需要独立进行卫星星座的设计和仿真,解决遇到的问题和调试错误。这锻炼了我的实践能力和问题解决能力,提高了我的自主学习和独立工作的能力。</p><p>总的来说,这个STK设计星座仿真的课设对我来说是一次非常有意义的学习和实践经历。通过实际操作和仿真分析,我加深了对卫星通信系统的理解,提高了我的技术和应用能力。这也为我今后在通信工程领域的学习和工作打下了坚实的基础。</p>]]></content>
</entry>
<entry>
<title>communication system simulate</title>
<link href="/2023/07/14/%E9%80%9A%E4%BF%A1%E5%B7%A5%E7%A8%8B-%E8%AF%BE%E7%A8%8B%E8%AE%BE%E8%AE%A1%E6%8A%A5%E5%91%8Ahzrlinux/"/>
<url>/2023/07/14/%E9%80%9A%E4%BF%A1%E5%B7%A5%E7%A8%8B-%E8%AF%BE%E7%A8%8B%E8%AE%BE%E8%AE%A1%E6%8A%A5%E5%91%8Ahzrlinux/</url>
<content type="html"><![CDATA[<h2 id="1-课程设计目的"><a href="#1-课程设计目的" class="headerlink" title="1. 课程设计目的"></a>1. 课程设计目的</h2><p>1. 深入理解通信系统原理:通过设计和仿真一个<strong>完整的通信系统</strong>,可以深入理解通信系统各个模块的功能、工作原理和相互关系,包括信源、信道编码、调制、信道传输、解调、信道译码和信宿等。这将加深对通信系统原理的理解,提高专业知识的掌握程度。</p><p>2. 掌握通信系统的<strong>关键技术</strong>:在设计和实现通信系统的过程中,将学习并掌握<strong>8QAM调制、汉明码编码、高斯噪声信道模型</strong>等关键技术,加深对这些技术的理解和应用能力。</p><p>3. 提高<strong>编程和算法设计</strong>能力:在实现各个模块的过程中,需要编写代码来实现汉明码编码、调制解调等功能。这将提高的编程能力和算法设计能力,培养在通信系统领域的技术实践能力。</p><p>4. 分析和评估系统性能:通过仿真和分析系统的时域波形和误码率性能,可以学习如何评估和分析<strong>通信系统的性能</strong>。这将培养的数据分析和性能评估能力,在实际工程项目中具备更好的能力。</p><p>5. 培养问题解决和<strong>创新思维能力</strong>:在设计和实现过程中,可能会遇到各种问题和挑战。通过解决这些问题,将培养解决问题和创新思维的能力,提升在实际工作中面对复杂问题时的应对能力。</p><p>6. 增强综合能力:通信系统仿真的课程设计要求<strong>综合运用多个学科领域</strong>的知识,如通信原理、数字信号处理、编程等。这将增强的综合能力,培养将理论知识应用于实际问题解决的能力。</p><p>7. 报告撰写和结果分析:需要撰写课程设计报告,详细描述系统设计的过程、各个模块的功能实现、仿真结果和性能分析。通过分析结果,能够<strong>总结和归纳</strong>设计中的问题、改进的空间以及对系统性能的理解。</p><p>总的来说,上述要求的课程设计的目的是<strong>通过实践</strong>,将理论知识应用到实际通信系统的设计和性能评估中,提高技能和能力。同时,培养分析和解决问题的能力,以及编程和报告撰写的能力。</p><h2 id="2-课程设计要求"><a href="#2-课程设计要求" class="headerlink" title="2. 课程设计要求"></a>2. 课程设计要求</h2><p>一、 仿真实现如下图所示的通信系统并分析其性能,要求:</p><p>a)采用8QAM调制。</p><p>b)信道编码采用汉明码。</p><p><img src="/media/932c043cd32e4062be971b4258909e8c.png"></p><p>二、 在上述系统的基础下添加相关其它模块,例如码分多址、除汉明码外的其他信道编码等。</p><p>具体要求为:</p><ul><li>首先要完成系统基本原理学习,画出系统框图(viso 画图),搞清楚每个模块的原理及其公式描述,在课设报告中写出。</li><li>在之上基础上,对各模块功能实现: 不能直接调用matlab中的现成函数,只能自己编写代码实现(虚线框内必须编程实现)。</li><li>画出各点处的时域波形,分析仿真的正确性。</li><li>分析系统的误码性能,对比不同编码长度下的误码率性能。</li><li>对比无信道编码和有信道编码的误码率性能,若添加扩展模块,对比不同信道编码下的误码率性能。</li><li>若选做了多用户,对比不同用户数下的误码性能。</li><li>其它可以验证系统性能的仿真图。</li><li>对报告中的仿真结果进行分析。</li></ul><h2 id="3-基本原理"><a href="#3-基本原理" class="headerlink" title="3. 基本原理"></a>3. 基本原理</h2><h4 id="3-1-信源产生"><a href="#3-1-信源产生" class="headerlink" title="3.1 信源产生"></a>3.1 信源产生</h4><p>二进制贝努利序列产生器产生一个二进制序列,并且这个二进制序列中的0和1 服从贝努利分布。本系统使用了二进制贝努利信号发生器,以子系统形式封装于输入信号中。产生器的产生是由一个随机信号器与一个常数进行判决,输出的二进制再进行抽样整形,从而输出符合参数设置的二进制。输入信号抽样时间均设为1kHz,,选择产生一维向量。</p><h4 id="3-2-汉明编码与译码"><a href="#3-2-汉明编码与译码" class="headerlink" title="3.2 汉明编码与译码"></a>3.2 汉明编码与译码</h4><p>汉明码是1950年由汉明提出的一种能纠正单个错误的线性分组码。它不仅性能好,而且编译码电路非常简单,易于实现。与其他的错误校验码类似,汉明码也利用了奇偶校验位的概念,通过在数据位后面增加一些比特,可以验证数据的有效性。利用一个以上的校验位,汉明码不仅可以验证数据是否有效,还能在数据出错的情况下指明错误位置。因此是数字通信系统中常用的一种纠错码。本文采用的就是( 7,4) 汉明码。</p><p>设将要进行检测的二进制源码为n位,为使其具有纠错能力,需要再加上k位的检测位,组成n+k=m位的二进制。那么,新增加的检测位数k应满足:</p><p>这就是汉明码不等式,规定所得到的m位编码位上插入特殊的校验码,其余位把源码按顺序放置。</p><p>( 7,4) 汉明码是一种常见的信道编码,其性能参数如下:</p><p>生成矩阵 G:</p><p><img src="/media/972a931e353b137fad36248e5e90c2fb.png"></p><p>校验矩阵 H:</p><p><img src="/media/9497a44b37207911cba4b58ace42bb85.png"></p><p>表格 1 (7,4)汉明码可纠错图样</p><table><thead><tr><th><strong>伴随式</strong> <strong>S={S0,S1,S2}</strong></th><th><strong>陪集首</strong> <strong>e={e0,e1,e2,e3,e4,e5,e6}</strong></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th><th></th></tr></thead><tbody><tr><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td></tr><tr><td>1</td><td>0</td><td>0</td><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td></tr><tr><td>0</td><td>1</td><td>0</td><td>0</td><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td></tr><tr><td>0</td><td>0</td><td>1</td><td>0</td><td>0</td><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td></tr><tr><td>1</td><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td>0</td><td>0</td><td>0</td></tr><tr><td>0</td><td>1</td><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td>0</td><td>0</td></tr><tr><td>1</td><td>1</td><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td><td>0</td></tr><tr><td>1</td><td>0</td><td>1</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>0</td><td>1</td></tr></tbody></table><h4 id=""><a href="#" class="headerlink" title=""></a></h4><h4 id="-1"><a href="#-1" class="headerlink" title=""></a></h4><h4 id="-2"><a href="#-2" class="headerlink" title=""></a></h4><h4 id="3-3-8QAM调制与解调"><a href="#3-3-8QAM调制与解调" class="headerlink" title="3.3 8QAM调制与解调"></a>3.3 8QAM调制与解调</h4><p>QAM (Quadrature Amplitude Modulation)是一种振幅和相位联合调制键控,频谱利用率较高的调制方式,它用两路独立的基带数字信号对两个相互正交的同频载波的双边带调制,并利用这种已调信号在同一带宽内频谱正交的性质来实现两路并行的数字信号传输。</p><p>QAM是用两个独立的基带数字信号对两个相互正交的同频载波进行抑制载波的双边带调制。其输出的单频信号是由两个相互正交的I信号和Q信号组成,其幅度和相位均受到了调制,星座图上每个点对应着一个合成矢量在每一瞬间的输出,即将二进制输出序列映射成了空间上不同的振幅,不同相位的信号波形,所以它是一种多进制的相位、振幅混合调制。它具有较高的信息传输率和频带利用率。MQAM的时域表达式为:</p><p><img src="/media/76873381aa40b9e044f7da6a36848c10.png"></p><p>QAM的调制框图如下所示:</p><p><img src="/media/70c6f5dda7ac21fa212cf80a5133d63d.png"></p><p>QAM的解调框图如下所示:</p><p><img src="/media/fc570adc27c0a7432b32457da281500b.png"></p><h4 id="3-4-高斯噪声与瑞利信道"><a href="#3-4-高斯噪声与瑞利信道" class="headerlink" title="3.4 高斯噪声与瑞利信道"></a>3.4 高斯噪声与瑞利信道</h4><p>信道中存在的不需要电信号统称为噪声,通信系统中的噪声是叠加在信号上的,没有输入信号时通信系统中也有噪声,噪声永远存在于通信系统中。噪声可看成是信道中的一种干扰,成为加性干扰,因为他是叠加在信号上的,噪声对于信号的传输时有害的,它能使模拟信号失真,使数字信号发生错码,并限制着信息的传输速率。</p><p>加性高斯白噪声作用下的调制信道(白高斯信道)可由shannon公式计算信道的容量:</p><p>:信道带宽(Hz)</p><p>:信号功率(W)</p><p>:白噪声功率(W)</p><p>瑞利信道是一种无线通信中常见的信道模型,用于描述在自由空间传播距离较远或存在遮挡物的环境中的信号传输。它得名于英国物理学家罗伯特·瑞利(Robert Rice)。</p><p>瑞利信道的原理可以简要概括如下:</p><p>1.多径传播:当无线信号在传播过程中遇到障碍物(如建筑物、山脉等),会经历多条路径的传播,其中一部分路径为直射路径(Line-of-Sight,LOS),另一部分路径经过反射、散射等多次反射后到达接收器,这些路径称为多径。这种多径传播现象导致接收信号同时受到多个信号成分的影响。</p><p>2.多径衰落:由于多径传播,到达接收器的不同信号成分可能会以不同的相位和幅度到达,导致信号的合成受到干涉效应的影响。这种干涉效应导致信号强度在时间和频率上的快速变化,称为多径衰落。</p><p>3.多径衰落模型:瑞利信道常用的模型是瑞利衰落模型,描述了信号在多径传播环境中的衰落情况。瑞利衰落模型假设没有直射路径(LOS),只有通过反射和散射得到的多径成分。这种模型适用于城市环境等没有明显直射路径的场景。</p><p>4.复信道表示:瑞利信道中的信号通常以复数形式表示,包括幅度和相位信息。由于多径传播和干涉效应,接收到的信号可以视为多个复数信号的叠加。复数形式的信道表示使得可以对信号的相位和幅度进行建模和分析。</p><p>5.信号特性:瑞利信道中的信号具有时变性和频率选择性。时变性表示信号的强度和相位在时间上发生变化,频率选择性表示信号的强度和相位在频率上存在衰落。</p><p>对于无线通信系统的设计和性能评估,了解和建模瑞利信道的特性非常重要。这样可以更好地理解信号的传播过程,并采取适当的调制、编码和信号处理技术来克服多径衰落对通信系统的影响。</p><p><img src="/media/075ac76dc56f3f8f892a28146455adad.png"></p><h4 id="3-5-格雷码"><a href="#3-5-格雷码" class="headerlink" title="3.5 格雷码"></a>3.5 格雷码</h4><p>格雷码(Gray code)是一种二进制编码方式,其中相邻的两个码字之间只有一个位数发生改变。它在数字通信、旋转编码器、数字信号处理等领域具有广泛的应用。格雷码的原理可以如下解释:</p><p>1. 基本思想:格雷码的基本思想是通过改变二进制码字的生成方式,使得相邻的码字之间只有一个位数发生变化。这种方式可以减少在码字转换过程中可能发生的错误,提高编码的可靠性。</p><p>2. 二进制码字与格雷码字的转换关系:格雷码中的每个码字与对应的二进制码字之间存在一种转换关系。该转换关系可以通过以下步骤实现:</p><p>对于给定的n位二进制码字,将最高有效位(Most Significant Bit,MSB)作为格雷码的最高有效位,直接复制到格雷码中。</p><p>从第二位开始,将每个二进制位与前一个二进制位进行异或运算,将运算结果作为对应格雷码位的值。</p><p>重复以上步骤,直到转换完成。</p><p>3. 格雷码的优势:相对于普通二进制码字,格雷码具有以下优势:</p><p>避免错误:相邻的格雷码之间只有一个位数不同,这意味着在进行码字转换时,只有一个位需要改变。这可以减少由于错误码字转换引入的错误,提高系统的可靠性。</p><p>降低干扰:格雷码的特性使得在码字转换过程中信号的变化最小化,从而减少了可能引入的干扰。</p><p>适用于旋转编码器:格雷码常用于旋转编码器(如旋转开关、编码器轮等)中,可用于准确地检测旋转方向和步进数目。</p><h4 id="3-6-均衡技术"><a href="#3-6-均衡技术" class="headerlink" title="3.6 均衡技术"></a>3.6 均衡技术</h4><p>在瑞利信道中,由于多径传播和干涉效应的影响,接收到的信号可能会出现时变的多径衰落。这会导致接收信号的失真和频率选择性衰落。为了恢复信号的质量和减少错误,可以使用均衡技术来抵消信道引起的失真和衰落。</p><p>瑞利信道的均衡原理可以简要概括如下:</p><p>1. 信道估计:在均衡之前,首先需要对瑞利信道进行估计。信道估计的目标是获得对信道响应的估计,即了解信道的多径传播特性。常见的信道估计方法包括最小均方误差(MMSE)估计、最大似然(ML)估计等。</p><p>2. 均衡器设计:在信道估计得到的信息基础上,设计合适的均衡器来抵消信道引起的失真和衰落。均衡器可以通过改变接收信号的加权系数和延迟来调整信号的幅度和相位,以补偿信道的影响。</p><p>3. 线性均衡器:线性均衡器是一种常用的均衡器类型,它通过滤波器来抵消信道引起的失真。常见的线性均衡器包括零延迟线性均衡器(Zero-Forcing Equalizer,ZF)和最小均方误差线性均衡器(Minimum Mean Square Error Equalizer,MMSE)。</p><p><img src="/media/2327ac32e60c7c9ebb34653ba92202db.png"></p><p>图2 常见的ZF迫零均衡</p><h2 id="4-模块实现及分析"><a href="#4-模块实现及分析" class="headerlink" title="4. 模块实现及分析"></a>4. 模块实现及分析</h2><p>系统的整体流程框图如下:</p><p><img src="/media/61b2f36953793d6000def94cfde69dc5.png"></p><p>图3 通信系统整体流程框图</p><table><thead><tr><th><strong>模块一:信源产生</strong></th><th></th></tr></thead><tbody><tr><td>实验程序: classdef Sender properties (SetAccess = private) dataBoardHandle_ end methods function obj = Sender(DataBoard) obj.dataBoardHandle_ = DataBoard; end function out = sequenceGenerate(obj) out=double(rand(obj.dataBoardHandle_.sourceSequenceLength, 1) > 0.5); obj.dataBoardHandle_.signalOriginal = out; end</td><td>实验结果与分析: <img src="/media/88a1537e76595fbbf35b2ec1921b4ab5.png"> 分析:rand函数是matlab中符合均匀分布的随机序列生成器,配合已定义好的数据管理句柄databoard和if条件,系统可以取任意长度的信源输入</td></tr><tr><td><strong>模块二:汉明编码</strong></td><td></td></tr><tr><td>实验程序: %偶校验 function hamming_code = hamming_encode(data) % 信息位长度 data_len = length(data); % 求监督位个数flag_len flag_len = 0; while 2^flag_len - flag_len - 1 < data_len flag_len = flag_len + 1; flag_index(flag_len) = 2^(flag_len - 1); end % 总码长 code_len = data_len + flag_len; % 初始化码元数组 hamming_code = zeros(1, code_len); % 填入源码元 index = 1; i = 1; while index <= code_len if ismember(index, flag_index) index = index + 1; else hamming_code(index) = data(i); index = index + 1; i = i + 1; end end % 判断监督位的值 for i = 1:flag_len this_flag_pos = 2^(i - 1); temp = 0; for j = this_flag_pos:2^i:code_len for index = j:min(j+2^(i-1)-1, code_len) temp=xor(temp,hamming_code(index)); end end if temp == 1 hamming_code(this_flag_pos) = 1; end end end</td><td>实验结果与分析: <img src="/media/88a8b2d28918079f5742f952ee0e4abc.png"> <img src="/media/6346eb9fbdd791b87f16b044227f939f.png"> 分析:汉明编码可采取奇校验码和偶校验码。本系统中采取偶校验,由于信源序列的长度可随机变化,而我们采取(7,4)汉明编码能大大降低误码率,所以我们将信源序列的长度分成四个序列一组,并对每一组进行汉明编码,最后进行连接成新的编码序列。由结果可分析设计正确。</td></tr><tr><td><strong>模块三:8QAM调制</strong></td><td></td></tr><tr><td>实验程序: function out = modulate(obj, in) if obj.dataBoardHandle_.modulationType == “BPSK” out = (in .* 2 - 1) * obj.dataBoardHandle_.A; obj.dataBoardHandle_.signalModulated = out; elseifobj.dataBoardHandle_.modulationType==”ASK” out=in.*obj.dataBoardHandle_.A; obj.dataBoardHandle_.signalModulated=out; elseifobj.dataBoardHandle_.modulationType==”8QAM” mid=reshape(in,[3,length(in)/3]); mid_de=mid(1,:)*4+mid(2,:)*2+mid(3,:)+1; out=obj.dataBoardHandle_.QAM8_Map(mid_de).’; obj.dataBoardHandle_.signalModulated=out; elseifobj.dataBoardHandle_.modulationType==”16QAM” mid=reshape(in,[4,obj.dataBoardHandle_.encodeSequenceLength/4]); mid_de=mid(1,:)*8+mid(2,:)*4+mid(3,:)*2+mid(4,:)+1; out=obj.dataBoardHandle_.QAM16_Map(mid_de).’; obj.dataBoardHandle_.signalModulated=out;</td><td>实验结果与分析: <img src="/media/9f8cc222acf6d56aee6f645cb8f0419f.emf"> <img src="/media/30b842ec341a63092cf64a1d2f230a99.png"> 分析:本系统采取8QAM调制,调制的信源序列通过QAM_Map映射至星座图上,目前主流的8QAM星座图有米型和长方型的,本系统采取长方型的映射方案,星座图上每个点对应着一个合成矢量在每一瞬间的输出,即将二进制输出序列映射成了空间上不同的振幅,不同相位的信号波形,所以它是一种多进制的相位、振幅混合调制。这种调制方法具有较高的信息传输率和频带利用率。</td></tr><tr><td><strong>模块四:瑞利信道加高斯噪声</strong></td><td></td></tr><tr><td>实验程序: %% 信道传输+高斯白噪声 ts = 1e-3; % 抽样时间间隔 fd = 1; % 最大多普勒频移 chan = rayleighchan(ts, fd); % 创建瑞利衰落信道对象 outputSignal = filter(chan, signal_modulated); outputSignal_Noise = awgn(outputSignal,10); signal_received = outputSignal_Noise;</td><td>实验结果与分析: <img src="/media/3f7d54744ec20afe26f1c37550ed1d48.png"> <img src="/media/cb46443fc4bb131d778c8946b9dd42a7.png"> 分析:经过瑞利信道加噪声后,发现星座图出现了很多杂点,由于经过不同的时延与振幅衰减, 我们可以发现调制的波形的振幅和相位开始不稳定。</td></tr><tr><td><strong>模块五:瑞利信道均衡</strong></td><td></td></tr><tr><td>实验程序: % 创建决策反馈均衡器对象 numFFTaps = 15; % 前馈滤波器抽头数 numFBTaps = 8; % 反馈滤波器抽头数 eqObj = dsp.LMSFilter(numFFTaps, numFBTaps); % 定义训练数据长度 trainLen = 1000; % 循环进行训练和均衡过程 for iter = 1:numIterations % 提取训练数据 trainingSignal = signal_received(iter:iter+trainLen-1); trainingData = modData(iter:iter+trainLen-1); % 对训练数据进行均衡 [eqSig, ~] = eqObj(trainingSignal, trainingData); % 在这里可以根据需要对均衡后的信号进行进一步处理或分析 % 更新均衡器的系数 [~, ~] = eqObj.update(trainingSignal, trainingData); end % 使用适应性均衡器补偿信道的衰落效应 signal_makeup=equalize(eq, outputSignal_Noise, signal_modulated);</td><td>实验结果与分析: <img src="/media/6578b32679eed81a83dd3401ac582ee7.png"> 分析:经过均衡后,红色的点相对于未均衡的绿色杂点更加接近已调制的标准蓝色点,可以发现均衡的效果较为满意。</td></tr><tr><td><strong>模块六:8QAM解调</strong></td><td></td></tr><tr><td>实验程序: functionout=detect(obj,in) ifobj.dataBoardHandle_.modulationType==”BPSK” A=obj.dataBoardHandle_.A; star_points=[-A,A]; [signal_detected,index]=obj.MLDetection(in,star_points); obj.dataBoardHandle_.signalDetected=signal_detected; out=index-1; obj.dataBoardHandle_.signalRecovered=out; elseifobj.dataBoardHandle_.modulationType==”ASK” A=obj.dataBoardHandle_.A; star_points=[0,A]; [signal_detected,index]=obj.MLDetection(in,star_points); obj.dataBoardHandle_.signalDetected=signal_detected; out=index-1; obj.dataBoardHandle_.signalRecovered=out; elseifobj.dataBoardHandle_.modulationType==”8QAM” [signal_detected,index]=obj.MLDetection(in,obj.dataBoardHandle_.QAM8_Map); obj.dataBoardHandle_.signalDetected=signal_detected; new_data=de2bi(index-1,3,’left-msb’).’; out=reshape(new_data,[obj.dataBoardHandle_.encodeSequenceLength,1]); obj.dataBoardHandle_.signalRecovered=out; elseifobj.dataBoardHandle_.modulationType==”16QAM” [signal_detected,index]=obj.MLDetection(in,obj.dataBoardHandle_.QAM16_Map); obj.dataBoardHandle_.signalDetected=signal_detected; out=reshape(de2bi(index-1,4,’left-msb’).’,[obj.dataBoardHandle_.encodeSequenceLength,1]); obj.dataBoardHandle_.signalRecovered=out;</td><td>实验结果与分析: <img src="/media/79fde797e37e9ee4b4328b16fc97fb8a.png"> <img src="/media/7b792ab3305a41abe5973ef59cd071ac.png"> 分析:经解调恢复,本系统采用了极大似然的思想,利用计算最小欧氏距离的方法计算与标准星座图点的最近似映射关系,从而将幅值与相位进行恢复。恢复的结果如上,较为理想的接收到了编码序列。</td></tr><tr><td><strong>模块六:汉明码解码</strong></td><td></td></tr><tr><td>实验程序: functionoutput=hamming_decode(code) code_len=length(code); %求信息位长度和监督位长度 flag_len=0; while2^flag_len<code_len flag_len=flag_len+1; end data_len=code_len-flag_len; %判断奇偶校验位组别的奇偶性并纠错 fori=1:flag_len this_flag_pos=2^(i-1); temp=0; forj=this_flag_pos:2^i:code_len forindex=j:min(j+2^(i-1)-1,code_len) temp=xor(temp,code(index)); end end iftemp==1 wrong(i)=’1’; else wrong(i)=’0’; end end %定位错误码元位置并纠错 wrong=reverse(wrong); wrong_index=bin2dec(wrong); ifwrong_index~=0 code(wrong_index)=~code(wrong_index); end fori=1:flag_len flag_index(i)=2^(i-1); end index=0; i=1; whileindex<code_len index=index+1; ifismember(index,flag_index) continue else output(i)=code(index); i=i+1; end end end</td><td>实验结果与分析: <img src="/media/4ff395714369288e6bd4534f278a2d32.png"> <img src="/media/dc439dbfec20308489f0aebd1c9c5214.emf"> 分析:经过汉明解码后,我们再将序列按四个一组合并,最后输出的序列与信源序列相似,整个系统的仿真结束。</td></tr><tr><td><strong>模块七:格雷编码与解码</strong></td><td></td></tr><tr><td>实验程序: %将二进制表示转换为格雷码表示 graySeq=zeros(size(signal_original)); graySeq(1,:)=signal_original(1,:); fori=2:size(signal_original,1) graySeq(i,:)=bitxor(signal_original(i-1,:),signal_original(i,:)); end signal_original=graySeq; 格雷码译码 binarySeq=zeros(size(signal_decode)); binarySeq(1,:)=signal_decode(1,:); fori=2:size(signal_decode,1) binarySeq(i,:)=bitxor(binarySeq(i-1,:),signal_decode(i,:)); end signal_decode=binarySeq;</td><td>实验结果与分析: <img src="/media/f269483fb081487516bf7850306b8d52.png"> 分析:格雷编码,格雷译码的过程经过检验均正确,利用序列之间的相关性减少了出错的几率。使得在码字转换过程中信号的变化最小化,从而减少了可能引入的干扰。</td></tr></tbody></table><h2 id="5-仿真结果及分析"><a href="#5-仿真结果及分析" class="headerlink" title="5. 仿真结果及分析"></a>5. 仿真结果及分析</h2><ul><li>对于信源长度为100时,对比不同信噪比下的误码率性能。</li></ul><p><img src="/media/1d13457fe5e1f842afd005e2901eaaa4.emf"></p><p>分析:当信噪比低于10时,噪声功率较大,因此使有效的码元淹没于信道传输中,使得本系统的误码率高于0.3。当信噪比高于10时,随着其增加噪声功率降低,直到几乎可以忽略,但瑞利信道带来的干扰使系统的误码率稳定于0.10左右的水平。</p><ul><li>对比不同信源长度下的误码率性能。</li></ul><p><img src="/media/06ac9d4aa6241a509a3777b4f1d48081.png"></p><p>分析:当信源长度低于50时,系统由于不稳定的差错导致误码率增加较快,使得本系统的误码率高于0.1。当信源长度高于50时,随着其长度的增加,系统逐渐趋于稳定,最终稳定于0.03左右的水平。证明系统的解调性能和译码性能较为优秀。</p><ul><li>对比不同信源长度下无信道编码,有信道汉明编码和有信道格雷编码的误码率性能。</li></ul><p><img src="/media/9f7168fc6eac44d3203db250c50c4a66.emf"></p><p>分析:比较了系统在汉明编码,格雷编码和无信道编码下随着信源序列的增加,整个系统的误码率曲线,可以明显的观察出,无信道编码情况下系统极不稳定,且误码率随着信源长度增加最终水平降为0.15。而格雷编码时误码率下降且稳定度增高,随着信源长度增加最终能降至0.075。最终,汉明编码的效果最好,系统加了不少冗余,对于每四位都进行了(7,4)汉明编码,这意味着每四位能纠错一位,随着信源长度的增加最终误码率降至0.02的水平,但也代表着通信系统的有效性会变低,这也是汉明编码的劣势。</p><h2 id="6-心得体会"><a href="#6-心得体会" class="headerlink" title="6. 心得体会"></a>6. 心得体会</h2><p>此次课程设计我的心得体会如下:</p><p>1. 综合应用理论知识:这个课程设计要求综合运用通信系统的基本原理、信道编码和调制技术等多个理论知识。通过实际设计和仿真,我能够将课堂学到的知识应用到实际问题中,加深对这些理论的理解和掌握。</p><p>2. 增强编程能力:课程设计要求自己编写代码实现系统的各个模块功能,不能直接调用现成的函数。这对我的编程能力提出了一定的挑战,但也促使我深入理解算法和原理,并将其转化为可执行的代码。</p><p>3. 系统性能分析能力:通过对系统的时域波形和误码率性能进行分析,我能够评估系统在不同条件下的性能表现。这培养了我的数据分析能力和对系统性能的理解,使我能够对系统进行优化和改进。</p><p>4, 实践应用能力:通过设计和仿真一个完整的通信系统,我能够将理论知识与实际应用相结合。这锻炼了我的实践能力,使我能够将所学知识应用于实际工程项目中,提高解决实际问题的能力。</p><p>总的来说,这个课程设计对我来说是一次综合运用通信专业知识的实践机会。通过设计、实现和分析一个完整的通信系统,我提高了编程能力、数据分析能力和实践应用能力,并且加深了对通信系统原理和技术的理解。这个经历对我的专业成长和未来职业发展都具有重要意义。</p>]]></content>
</entry>
<entry>
<title>FPGA(7 div design && code lock)</title>
<link href="/2023/07/14/FPGA_hzr/"/>
<url>/2023/07/14/FPGA_hzr/</url>
<content type="html"><![CDATA[<h1 id="设计一-7分频时钟产生电路设计"><a href="#设计一-7分频时钟产生电路设计" class="headerlink" title="设计一 7分频时钟产生电路设计"></a>设计一 7分频时钟产生电路设计</h1><h2 id="设计目的"><a href="#设计目的" class="headerlink" title="设计目的"></a>设计目的</h2><p>1. 验证电路功能:通过仿真,可以确认分频电路是否正确地将输入时钟进行7分频,并生成工作时钟和分频信号。您可以检查电路是否按照预期工作,确保其符合设计规范。</p><p>2. 确保时序满足要求:仿真可以帮助您验证电路的时序是否满足要求。您可以检查工作时钟和分频信号的频率是否正确,以及各个计数阶段是否按照预期进行。</p><p>3. 确定功能与显示:通过仿真,您可以验证LED的点亮和数码管的计数显示功能是否正常工作。您可以检查LED是否在分频信号的控制下正确地点亮,以及数码管是否正确地显示从0到7的计数值。</p><p>4. 验证复位功能:仿真可以帮助您验证复位功能是否正常工作。您可以测试在复位信号触发时,分频信号是否停止输出,确保在复位状态下电路不产生无效的计数。</p><p>5. 验证设计的准确性:通过仿真结果,您可以与设计中的要求进行对比,确保设计的准确性和符合要求。</p><p>总体而言,目的是通过验证和测试设计方案,确保电路按照预期工作,同时加深对FPGA设计流程的理解和掌握。</p><h2 id="设计任务"><a href="#设计任务" class="headerlink" title="设计任务"></a>设计任务</h2><p>完成7分频电路。</p><p>1. 将输入时钟进行7分频。</p><p>2. 工作时钟1hz。</p><p>3. 分频信号点亮LED,工作时钟0~7计数显示于数码管。</p><p>4. 复位时分频信号无输出。</p><p>5. 完成全部流程。</p><h2 id="使用的仿真软件"><a href="#使用的仿真软件" class="headerlink" title="使用的仿真软件"></a>使用的仿真软件</h2><p>Vivado2019.1、Modelsim、VsCode。</p><h2 id="设计参数和指标"><a href="#设计参数和指标" class="headerlink" title="设计参数和指标"></a>设计参数和指标</h2><h2 id="设计方法及步骤"><a href="#设计方法及步骤" class="headerlink" title="设计方法及步骤"></a>设计方法及步骤</h2><p>1. 设计规范和功能定义:输入时钟的分频比例1:7、工作时钟频率1hz、LED随着cnt增加显示1~7和数码管显示的逻辑等。</p><p>2. 模块划分和接口定义:由于此设计较为简单,根据设计要求,将电路划分为适当的部分,复位部分、分频逻辑部分、数码管控制部分,并定义模块之间输入、输出信号以及可能的控制信号。</p><p>3. 模块级设计:使用Verilog语言编写三个部分的描述,包括模块的输入、输出端口、内部信号以及逻辑实现。</p><p>4. 时序约束:根据设计要求和目标平台的时序特性,为设计添加时序约束。时序约束可以包括时钟频率、时钟延迟、信号间的最小间隔等。时序约束对于确保电路的正确性和时序满足要求至关重要。</p><p>5. 仿真验证:使用Vivado联合ModelSim仿真等,对设计进行功能仿真和时序仿真。通过提供输入时钟和其他必要的输入信号,观察输出信号的行为和时序,并与预期的结果进行比较。确保电路按照设计要求正确工作。</p><p>6. 代码综合:将Verilog代码进行综合,将其转换为目标平台的门级网表或其他等效表示。</p><p>7. 布局布线:根据综合结果,进行物理设计,包括布局和布线。布局过程将电路中的逻辑元件放置在芯片上的适当位置,布线过程则将逻辑元件之间的连线进行规划和优化。</p><p>8. 时序分析和优化:进行时序分析,评估电路的时序性能,并进行优化以满足设计要求。这可能涉及到时序约束的微调、逻辑优化、时钟树优化等。</p><p>9. 下载验证:将设计编程到目标FPGA芯片上,并进行验证。由于目前缺乏FPGA开发板,此点留待后续完成。</p><h2 id="设计流程"><a href="#设计流程" class="headerlink" title="设计流程"></a><img src="/media/902602e07ea714cf12ecd3dd32734509.png"><img src="/media/56da81127be3f8d5822f22df269b4da0.png">设计流程</h2><h2 id="设计结果和分析"><a href="#设计结果和分析" class="headerlink" title="设计结果和分析"></a>设计结果和分析</h2><h4 id="一、复位部分"><a href="#一、复位部分" class="headerlink" title="一、复位部分"></a>一、复位部分</h4><p>核心代码:</p><p>always @(posedge rst)</p><p>begin</p><p>if(rst == 1’b1)</p><p>begin</p><p>cnt0 <= 4’b0;</p><p>cnt1 <= 4’b0;</p><p>div7 <= 1’b1;</p><p>end</p><p>end</p><h4 id="二、分频逻辑部分"><a href="#二、分频逻辑部分" class="headerlink" title="二、分频逻辑部分"></a>二、分频逻辑部分</h4><p>核心代码:</p><p>always @(posedge clk)</p><p>begin</p><p>if(cnt0 == 4’d6)</p><p>begin</p><p>cnt0 <= 4’b0;</p><p>div7 = 1;</p><p>end</p><p>else</p><p>cnt0 <= cnt0 + 1’b1;</p><p>end</p><p>always @(negedge clk)</p><p>begin</p><p>if(cnt0 == 4’d3)</p><p>div7 = 0;</p><p>end</p><h4 id="三、数码管显示部分"><a href="#三、数码管显示部分" class="headerlink" title="三、数码管显示部分"></a>三、数码管显示部分</h4><p>核心代码:</p><p>always @(cnt0)</p><p>begin</p><p>case(cnt0)</p><p>4’b0000: data_out <= 7’b0111111;</p><p>4’b0001: data_out <= 7’b0000110;</p><p>4’b0010: data_out <= 7’b1011011;</p><p>4’b0011: data_out <= 7’b1001111;</p><p>4’b0100: data_out <= 7’b1100110;</p><p>4’b0101: data_out <= 7’b1101101;</p><p>4’b0110: data_out <= 7’b1111100;</p><p>default: data_out <= 7’b0000000;</p><p>endcase</p><p>end</p><h4 id="四、网表综合"><a href="#四、网表综合" class="headerlink" title="四、网表综合"></a>四、网表综合</h4><p><img src="/media/b6045227b6187168028daf889ad48235.png"></p><h4 id=""><a href="#" class="headerlink" title=""></a></h4><h4 id="五、波形仿真与分析"><a href="#五、波形仿真与分析" class="headerlink" title="五、波形仿真与分析"></a>五、波形仿真与分析</h4><p><strong><img src="/media/a9cda6891adbaadce331c1a61748cde6.png">分析</strong>:如图所示,输入为1hz的时钟信号,当复位后,将其进行了7分频。Div7的周期是7s,变为了原来的7倍。并且随着cnt0的增加输入给了数码管显示模块,显示的二进制电平与仿真结果相一致。</p><h1 id="设计二-多功能密码锁设计"><a href="#设计二-多功能密码锁设计" class="headerlink" title="设计二 多功能密码锁设计"></a>设计二 多功能密码锁设计</h1><h2 id="设计目的-1"><a href="#设计目的-1" class="headerlink" title="设计目的"></a>设计目的</h2><p>1. 验证电路功能:通过仿真,可以确认串行数字锁的功能是否满足设计要求。您可以模拟输入不同的密码组合和开锁程序,观察锁的状态和指示灯的点亮情况。同时,您还可以模拟错误的密码输入,以验证错误状态和报警功能是否正常工作。</p><p>2. 时序分析和优化:通过仿真,可以分析和优化串行数字锁的时序性能。您可以评估锁的响应时间、报警灯的延迟等,并对设计进行调整以满足时序要求。</p><p>3. 验证报警功能:仿真可以帮助您验证报警功能是否正常工作。您可以模拟按下复位开关来停止报警,并观察报警灯的熄灭情况。同时,您还可以测试在复位后,锁是否重新进入等待下一个开锁状态。</p><p>4. 验证密码调整和预置功能:通过仿真,您可以验证密码调整和预置功能的实现。您可以模拟调整密码和预置密码,并观察锁的响应和指示灯的变化。</p><p>5. 确定设计的准确性:通过仿真结果,您可以与设计中的要求进行对比,确保设计的准确性和符合要求。</p><p>总体而言,目的是通过验证和测试设计方案,确保电路按照预期工作,同时加深对FPGA设计流程的理解和掌握。</p><h2 id="设计任务-1"><a href="#设计任务-1" class="headerlink" title="设计任务"></a>设计任务</h2><p>设计一个4位串行数字锁。</p><p>1. 开锁密码为4位二进制,当输入代码的位数与锁内给定的密码一致,且按规定程序开锁时,方可开锁,并点亮一个指示灯。否则进入“错误”状态,并发出报警信号。</p><p>2. 锁内的密码可调,且预置方便,保密性好。</p><p>3. 串行数字锁的报警由点亮一个灯,直到按下复位开关,报警才停下。此时,数字锁又自动等待下一个开锁状态。</p><p>4. 完成全部流程。</p><h2 id="使用的仿真软件-1"><a href="#使用的仿真软件-1" class="headerlink" title="使用的仿真软件"></a>使用的仿真软件</h2><p>Vivado2019.1、Modelsim、VsCode。</p><h2 id="设计参数和指标-1"><a href="#设计参数和指标-1" class="headerlink" title="设计参数和指标"></a>设计参数和指标</h2><table><thead><tr><th>信号名</th><th>I/O</th><th>位宽</th><th>含义</th></tr></thead><tbody><tr><td>clk</td><td>I</td><td>1bit</td><td>系统时钟输入</td></tr><tr><td>rst</td><td>I</td><td>1bit</td><td>系统复位信号</td></tr><tr><td>led</td><td>O</td><td>8bits</td><td>8个LED数码管</td></tr><tr><td>boma</td><td>I</td><td>8bits</td><td>8个拨码开关</td></tr><tr><td>scan</td><td>O</td><td>4bits</td><td>动态显示扫描位选信号</td></tr><tr><td>m</td><td>O</td><td>7bits</td><td>七段数码管的段码控制信号</td></tr><tr><td>keyin0</td><td>I</td><td>1bit</td><td>矩阵键盘输入,2*4矩阵键盘第一行信号</td></tr><tr><td>keyin1</td><td>I</td><td>1bit</td><td>矩阵键盘输入,2*4矩阵键盘第二行信号</td></tr></tbody></table><h2 id="设计方法及步骤-1"><a href="#设计方法及步骤-1" class="headerlink" title="设计方法及步骤"></a>设计方法及步骤</h2><p>1. 设计规范和功能定义:明确设计中<strong>开锁密码的位数、密码调整和预置的方式、开锁程序的规定、报警功能</strong>等。</p><p>2. 模块划分和接口定义:根据设计要求,将电路划分为适当的模块,如<strong>分频器模块</strong>、<strong>核心控制模块</strong>、<strong>按键及数码管控制模块</strong>、<strong>顶层连接模块</strong>等,并定义模块之间的接口,包括输入、输出信号以及可能的控制信号。</p><p>3. 模块级设计:对每个模块进行详细设计,包括逻辑电路设计、状态机设计、时序设计等。使用Verilog语言编写每个模块的描述,包括模块的输入、输出端口、内部信号以及逻辑实现。</p><p>4. 顶层设计:将各个模块组合到<strong>顶层设计</strong>中,并定义模块之间的连接关系。此时,可以编写顶层模块的Verilog描述,将各个子模块实例化并连接。</p><p>5. 仿真验证:使用<strong>vidado联合modelsim</strong>对设计进行功能仿真和时序仿真。通过提供合适的输入序列,观察输出信号的行为和时序,并与预期的结果进行比较。确保电路按照设计要求正确工作。</p><p>6. 代码综合:将Verilog代码进行<strong>综合</strong>,将其转换为目标平台的门级网表或其他等效表示。</p><p>7. 布局布线:根据综合结果,进行物理设计,包括布局和布线。布局过程将电路中的逻辑元件放置在芯片上的适当位置,布线过程则将逻辑元件之间的连线进行规划和优化。</p><p>8. 时序分析和优化:进行时序分析,评估电路的时序性能,并进行优化以满足设计要求。这可能涉及到时序约束的微调、逻辑优化、时钟树优化等。</p><p>9. 下载验证: 将设计编程到目标FPGA芯片上,并进行验证。由于目前缺乏FPGA开发板,此点留待后续完成。</p><h2 id="设计流程-1"><a href="#设计流程-1" class="headerlink" title="设计流程"></a><img src="/media/a9bde59d372e5e03af4b9dd60a31aa65.png"><img src="/media/b596f31ad3edbcd4a2075d425c64bd4c.png">设计流程</h2><p><img src="/media/70c5dd946d3adecf9e5926c1b35806cf.png"></p><p><img src="/media/f00b24e3ab8e58f1ce8b52d7dda36548.png"></p><h2 id="设计结果和分析-1"><a href="#设计结果和分析-1" class="headerlink" title="设计结果和分析"></a>设计结果和分析</h2><h4 id="一、分频器模块部分"><a href="#一、分频器模块部分" class="headerlink" title="一、分频器模块部分"></a>一、分频器模块部分</h4><p>核心代码:</p><p>//5000分频</p><p>module clk_div(</p><p>clk, //输入时钟</p><p>rst_clock,</p><p>clk1 //输出时钟</p><p>);</p><p>input clk,rst_clock;</p><p>output clk1;</p><p>reg clk1;</p><p>reg [13:0] cnt;</p><p>always @(posedge clk or posedge rst_clock)</p><p>begin</p><p>if(rst_clock == 1’b1)</p><p>begin</p><p>cnt <= 2’b00;</p><p>clk1 <= 1’b0;</p><p>end</p><p>else if(cnt == 2499)</p><p>begin</p><p>cnt <= 2’b00;</p><p>clk1 <= ~clk1;</p><p>end</p><p>else</p><p>cnt <= cnt + 1’b1;</p><p>end</p><p>endmodule</p><p>上述程序完成了对clk的5000分频。</p><h4 id="二、核心控制模块部分"><a href="#二、核心控制模块部分" class="headerlink" title="二、核心控制模块部分"></a>二、核心控制模块部分</h4><p>核心代码:</p><p>module state(</p><p>rst,</p><p>clk1,</p><p>led,</p><p>boma,</p><p>display,</p><p>key_s</p><p>);</p><p>input rst; //系统复位信号</p><p>input clk1; //分频后5k时钟输出</p><p>input [3:0] boma; //拨码开关</p><p>output [7:0] led,display; //8个LED输出和七段数码管</p><p>input [7:0] key_s; //键值,使用[0],[1],[2]</p><p>reg [7:0] led; //led状态机的状态编码</p><p>reg [7:0] display;</p><p>reg[3:0] mima;</p><p>always @(posedge clk1)</p><p>begin</p><p>if(rst == 1’b1)</p><p>begin</p><p>display <= 8’b00000000; //七段数码管</p><p>led <= 4’b00000000;</p><p>mima <= 4’b0000;</p><p>end</p><p>else</p><p>begin</p><p>case(led)</p><p>8’b00000000:begin //复位状态,只能接收密码设定</p><p>if(key_s[0] == 1’b1) //如果按键1按下,led4亮,并且确定密码</p><p>begin</p><p>led <= 8’b00010000;</p><p>display <= boma;</p><p>mima <= boma;</p><p>end</p><p>end</p><p>8’b00010000:begin //设密码完毕,等待上锁</p><p>if(key_s[1] == 1’b1) //如果按键2按下,led5亮,密码上锁</p><p>begin</p><p>led <= 8’b00100000;</p><p>display <= 8’b0;</p><p>end</p><p>end</p><p>8’b00100000:begin //处于锁定,等待开锁</p><p>if(key_s[2] == 1’b1) //判断密码是否正确,正确则led6亮</p><p>begin</p><p>if(boma == mima)</p><p>begin</p><p>led <= 8’b01000000;</p><p>display <= boma;</p><p>end</p><p>else</p><p>begin</p><p>led <= 8’b11111111;</p><p>display <= boma;</p><p>end</p><p>end</p><p>end</p><p>default:begin //处于开锁状态,或者其它状态,直接转到锁定状态</p><p>if(key_s[1] == 1’b1)</p><p>begin</p><p>led <= 8’b00100000;</p><p>display <= 8’b0;</p><p>end</p><p>end</p><p>endcase</p><p>end</p><p>end</p><p>endmodule</p><p>按照状态机的标准设计方法,此模块设计为了简化,直接用8位LED信号灯寄存器作为状态寄存器来完成设计。组合逻辑译码的方式有很多种,具体编码设计的方式提供了一种。</p><h4 id="三、按键与数码管控制模块部分"><a href="#三、按键与数码管控制模块部分" class="headerlink" title="三、按键与数码管控制模块部分"></a>三、按键与数码管控制模块部分</h4><p>核心代码:</p><p>module scan_crl(</p><p>display,</p><p>key_s,</p><p>scan,</p><p>m,</p><p>keyin0,</p><p>keyin1,</p><p>clk1</p><p>);</p><p>input[7:0] display; //七段数码管二进制数据</p><p>output[7:0] key_s; //键盘输出信号</p><p>output[3:0] scan; //键盘和数码管扫描信号</p><p>output[6:0] m; //七段数码管段码控制信号</p><p>input keyin0,keyin1,clk1; //矩阵键盘输入信号和分频后的时钟信号</p><p>reg[3:0] scan;</p><p>reg[7:0] key_s;</p><p>reg[6:0] m;</p><p>reg[1:0] st = 2’b00; //产生scan信号</p><p>always @(posedge clk1) begin</p><p>st <= st + 1’b1;</p><p>end</p><p>always @(st)</p><p>begin</p><p>case(st)</p><p>2’b00:scan <= 4’b0001;</p><p>2’b01:scan <= 4’b0010;</p><p>2’b10:scan <= 4’b0100;</p><p>2’b11:scan <= 4’b1000;</p><p>default:scan <= 4’b0000;</p><p>endcase</p><p>end</p><p>always @(posedge clk1) //矩阵按键产生键值</p><p>begin</p><p>if(scan == 4’b0001)</p><p>begin</p><p>if(keyin0 == 1’b1) key_s[0] <= 1’b1;</p><p>else key_s[0] <= 1’b0;</p><p>if(keyin1 == 1’b1) key_s[4] <= 1’b1;</p><p>else key_s[4] <= 1’b0;</p><p>end</p><p>if(scan == 4’b0010)</p><p>begin</p><p>if(keyin0 == 1’b1) key_s[1] <= 1’b1;</p><p>else key_s[1] <= 1’b0;</p><p>if(keyin1 == 1’b1) key_s[5] <= 1’b1;</p><p>else key_s[5] <= 1’b0;</p><p>end</p><p>if(scan == 4’b0100)</p><p>begin</p><p>if(keyin0 == 1’b1) key_s[2] <= 1’b1;</p><p>else key_s[2] <= 1’b0;</p><p>if(keyin1 == 1’b1) key_s[6] <= 1’b1;</p><p>else key_s[6] <= 1’b0;</p><p>end</p><p>if(scan == 4’b1000)</p><p>begin</p><p>if(keyin0 == 1’b1) key_s[3] <= 1’b1;</p><p>else key_s[3] <= 1’b0;</p><p>if(keyin1 == 1’b1) key_s[7] <= 1’b1;</p><p>else key_s[7] <= 1’b0;</p><p>end</p><p>end</p><p>reg[3:0] bai,shi;</p><p>wire[3:0] ge;</p><p>always @(display)</p><p>begin</p><p>if(display > 8’d199)</p><p>bai <= 4’d2;</p><p>else if(display > 7’d99)</p><p>bai <= 4’d1;</p><p>else</p><p>bai <= 4’d0;</p><p>end</p><p>wire[7:0] display_2wei; //十位和个位</p><p>assign display_2wei = display - bai * 7’d100;</p><p>always @(display_2wei)</p><p>begin</p><p>if(display_2wei >= 7’d90)</p><p>shi <= 4’d9;</p><p>else if(display_2wei >= 7’d80)</p><p>shi <= 4’d8;</p><p>else if(display_2wei >= 7’d70)</p><p>shi <= 4’d7;</p><p>else if(display_2wei >= 7’d60)</p><p>shi <= 4’d6;</p><p>else if(display_2wei >= 7’d50)</p><p>shi <= 4’d5;</p><p>else if(display_2wei >= 7’d40)</p><p>shi <= 4’d4;</p><p>else if(display_2wei >= 7’d30)</p><p>shi <= 4’d3;</p><p>else if(display_2wei >= 7’d20)</p><p>shi <= 4’d2;</p><p>else if(display_2wei >= 7’d10)</p><p>shi <= 4’d1;</p><p>else</p><p>shi <= 4’d0;</p><p>end</p><p>assign ge = display_2wei - shi * 4’d10;</p><p>reg[4:0] bin;</p><p>always @(st, ge, shi, bai)</p><p>begin</p><p>case(st)</p><p>2’b00: bin <= 4’b0000;</p><p>2’b01: bin <= bai;</p><p>2’b10: bin <= shi;</p><p>2’b11: bin <= ge;</p><p>default: bin <= 4’b0000;</p><p>endcase</p><p>end</p><p>always @(bin)</p><p>begin</p><p>case(bin)</p><p>4’b0000: m <= 7’b0111111;</p><p>4’b0001: m <= 7’b0000110;</p><p>4’b0010: m <= 7’b1011011;</p><p>4’b0011: m <= 7’b1001111;</p><p>4’b0100: m <= 7’b1100110;</p><p>4’b0101: m <= 7’b1101101;</p><p>4’b0110: m <= 7’b1111101;</p><p>4’b0111: m <= 7’b0000111;</p><p>4’b1000: m <= 7’b1111111;</p><p>4’b1001: m <= 7’b1101111;</p><p>default: m <= 7’b0000000;</p><p>endcase</p><p>end</p><p>endmodule</p><p>此模块比较复杂,按键分为复位键、上锁键、报警键。按键、七段数码管控制模块主要负责把显示的二进制数据转换为BCD码,进而通过动态显示技术在七段数码管上显示出来。此外,还负责外部矩阵键盘的扫描处理。</p><h4 id="四、顶层连接模块部分"><a href="#四、顶层连接模块部分" class="headerlink" title="四、顶层连接模块部分"></a>四、顶层连接模块部分</h4><p>核心代码:</p><p>module mimasuo(</p><p>clk,</p><p>rst_clock,</p><p>rst,</p><p>led,</p><p>boma,</p><p>scan,</p><p>m,</p><p>keyin0,</p><p>keyin1</p><p>);</p><p>input clk,rst_clock,rst;</p><p>output[7:0] led;</p><p>input[3:0] boma;</p><p>output[3:0] scan;</p><p>output[6:0] m;</p><p>input keyin0,keyin1;</p><p>wire clk1;</p><p>wire[7:0] display;</p><p>wire[7:0] key_s;</p><p>clk_div clk_div_inst(</p><p>.clk(clk),</p><p>.rst_clock(rst_clock),</p><p>.clk1(clk1)</p><p>);</p><p>state state_inst(</p><p>.rst(rst),</p><p>.clk1(clk1),</p><p>.led(led),</p><p>.boma(boma),</p><p>.display(display),</p><p>.key_s(key_s)</p><p>);</p><p>scan_crl scan_crl_inst(</p><p>.display(display),</p><p>.key_s(key_s),</p><p>.scan(scan),</p><p>.m(m),</p><p>.keyin0(keyin0),</p><p>.keyin1(keyin1),</p><p>.clk1(clk1)</p><p>);</p><p>endmodule</p><p>此模块按照连接逻辑将上述三个模块与端口之间建立起连接关系。</p><h4 id="五、网表综合"><a href="#五、网表综合" class="headerlink" title="五、网表综合"></a><img src="/media/7e6531da94c4dd34a8852bc44c85ef8b.png">五、网表综合</h4><h4 id="-1"><a href="#-1" class="headerlink" title=""></a></h4><h4 id="六、波形仿真与分析"><a href="#六、波形仿真与分析" class="headerlink" title="六、波形仿真与分析"></a><img src="/media/bd7eb8e188037efe8aad333c5fadeddd.png">六、波形仿真与分析</h4><p><strong>分析</strong>:如图所示,本设计完整的完成了密码锁的系统功能,我们于复位后,led被置为00000000状态,首先,我们拨码设为c即1100,按下按键1,可以观察到此时led为00010000,即定义的设置密码灯亮。之后我们按下按键2,可以观察到此时led为00100000,即锁定状态完成,留待我们输入正确的密码。我们再输入拨码为d即1101,按下按键3,可以观察到此时led为11111111,即全亮表示报警状态,在此状况下按下按键2重新回到了锁定状态。最后,我们输入正确密码1100,按下按键2,可以观察到led为11110000,即最终开锁状态。</p>]]></content>
</entry>
<entry>
<title>Mobile communication</title>
<link href="/2023/05/14/mobile_communication/"/>
<url>/2023/05/14/mobile_communication/</url>
<content type="html"><![CDATA[<h1 id="Mobile-communication"><a href="#Mobile-communication" class="headerlink" title="Mobile communication"></a>Mobile communication</h1><h2 id="1-概述"><a href="#1-概述" class="headerlink" title="1.概述"></a><strong>1.概述</strong></h2><p><img src="https://github.com/Ricky-pluto/mobile_communication/blob/master/AG_pro.zipD40555D1AF4C9821C2ABE8F7DB958F21.jpg?raw=true" alt="avatar"></p><h2 id="2-电波传输与传播模型"><a href="#2-电波传输与传播模型" class="headerlink" title="2.电波传输与传播模型"></a><strong>2.电波传输与传播模型</strong></h2><p><img src="https://github.com/Ricky-pluto/mobile_communication/blob/master/AG_pro.zip2D19088DC2B0BBE168F706C0B29373E6.jpg?raw=true" alt="avatar"><br><img src="https://github.com/Ricky-pluto/mobile_communication/blob/master/AG_pro.zip1071E152D1AACA685DAE7068A1DC442F.jpg?raw=true" alt="avatar"></p><h2 id="3-抗衰落技术"><a href="#3-抗衰落技术" class="headerlink" title="3.抗衰落技术"></a><strong>3.抗衰落技术</strong></h2><p><img src="https://github.com/Ricky-pluto/mobile_communication/blob/master/AG_pro.zip4D57A85CC4B95669ACD36AB1485517A7.jpg?raw=true" alt="avatar"><br><img src="https://github.com/Ricky-pluto/mobile_communication/blob/master/AG_pro.zip0D428D1700FA6FB1DD14A0BA6B07AF1E.jpg?raw=true" alt="avatar"></p><p><img src="https://github.com/Ricky-pluto/mobile_communication/blob/master/AG_pro.zipF82B0F6CB4E8EF214D8B0067D116F2C4.jpg?raw=true" alt="avatar"></p><p><img src="https://github.com/Ricky-pluto/mobile_communication/blob/master/AG_pro.zipE2E84420B4EB3DD6D1C4DD17F01ED1AC.jpg?raw=true" alt="avatar"><br><img src="https://github.com/Ricky-pluto/mobile_communication/blob/master/AG_pro.zipD457C868DDD85264C606E8C5A6736C6C.jpg?raw=true" alt="avatar"><br><img src="https://github.com/Ricky-pluto/mobile_communication/blob/master/AG_pro.zipC1DEDEE91780D88631473AF53FFD6534.jpg?raw=true" alt="avatar"><br><img src="https://github.com/Ricky-pluto/mobile_communication/blob/master/AG_pro.zip3974712C429B75D53E428D61D3F83A51.jpg?raw=true" alt="avatar"></p><h2 id="4-蜂窝组网技术"><a href="#4-蜂窝组网技术" class="headerlink" title="4.蜂窝组网技术"></a><strong>4.蜂窝组网技术</strong></h2><p><img src="https://github.com/Ricky-pluto/mobile_communication/blob/master/AG_pro.zip483D1F2A97D9F47DC8BAFDBAEB593677.jpg?raw=true" alt="avatar"></p><h2 id="5-gsm系统"><a href="#5-gsm系统" class="headerlink" title="5.gsm系统"></a><strong>5.gsm系统</strong></h2><p><img src="https://github.com/Ricky-pluto/reinforce_learning/blob/master/0_0_1.jpg?raw=true" alt="avatar"></p>]]></content>
</entry>
<entry>
<title>Reinforce learning</title>
<link href="/2023/05/10/reinforce/"/>
<url>/2023/05/10/reinforce/</url>
<content type="html"><![CDATA[<h1 id="Reinforce-learning"><a href="#Reinforce-learning" class="headerlink" title="Reinforce learning"></a>Reinforce learning</h1><h2 id="1-概述与基础"><a href="#1-概述与基础" class="headerlink" title="1.概述与基础"></a><strong>1.概述与基础</strong></h2><p><img src="https://github.com/Ricky-pluto/reinforce_learning/blob/master/0_0_2.jpg?raw=true" alt="avatar"></p><h2 id="2-MDP"><a href="#2-MDP" class="headerlink" title="2.MDP"></a><strong>2.MDP</strong></h2><p><img src="https://github.com/Ricky-pluto/reinforce_learning/blob/master/0_0_5.jpg?raw=true" alt="avatar"></p><h2 id="3-无模型预测与控制"><a href="#3-无模型预测与控制" class="headerlink" title="3.无模型预测与控制"></a><strong>3.无模型预测与控制</strong></h2><p><img src="https://github.com/Ricky-pluto/reinforce_learning/blob/master/0_0_3.jpg?raw=true" alt="avatar"></p><h2 id="4-价值函数近似"><a href="#4-价值函数近似" class="headerlink" title="4.价值函数近似"></a><strong>4.价值函数近似</strong></h2><p><img src="https://github.com/Ricky-pluto/reinforce_learning/blob/master/0_0_33.jpg?raw=true" alt="avatar"></p><h2 id="5-基于策略函数"><a href="#5-基于策略函数" class="headerlink" title="5.基于策略函数"></a><strong>5.基于策略函数</strong></h2><p><img src="https://github.com/Ricky-pluto/reinforce_learning/blob/master/0_0_1.jpg?raw=true" alt="avatar"></p>]]></content>
</entry>
<entry>
<title>初涉ROS2</title>
<link href="/2023/05/09/ROS%E5%88%9D%E5%AD%A6/"/>
<url>/2023/05/09/ROS%E5%88%9D%E5%AD%A6/</url>
<content type="html"><![CDATA[<!-- * @Author: pluto * @Date: 2022-06-22 10:21:25 * @LastEditors: error: git config user.name && git config user.email & please set dead value or install git * @LastEditTime: 2022-06-22 16:59:01 * @FilePath: /undefined/home/pluto/桌面/ros2_learn/README.md * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE--><h2 id="ROS2初学"><a href="#ROS2初学" class="headerlink" title="#ROS2初学"></a>#ROS2初学</h2><p>##了解ROS2的版本迭代<br><img src="https://book.guyuehome.com/ROS2/1.%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84/image/1.1_ROS%E5%92%8CROS2%E6%98%AF%E4%BB%80%E4%B9%88/image-20220521163636582.png" alt="ROS历史图标"></p><table><thead><tr><th>Year</th><th>Version</th></tr></thead><tbody><tr><td>2014</td><td>ROSCon</td></tr><tr><td>2015</td><td>Alpha</td></tr><tr><td>2016</td><td>Beta</td></tr><tr><td>2017</td><td>Ardent</td></tr><tr><td>2018</td><td>Bouncy&Crystal</td></tr><tr><td>2019</td><td>Dashing&Eloquent</td></tr><tr><td>2020</td><td>Foxy</td></tr><tr><td>2021</td><td>Galactic</td></tr><tr><td>2022</td><td>Humble</td></tr></tbody></table><hr><p>#ROS2的优点</p><ul><li><p>ROS2可以跨平台运行于Linux、Windows、MacOS、RTOS,甚至是没有任何系统的微控制器(MCU)上</p></li><li><p>无论在怎样的网络环境下,ROS2都可以尽量保障机器人大量数据的完整性和安全性</p></li><li><p>系统架构进行了颠覆性的变化</p></li><li><p>编译系统进行了升级</p></li></ul><hr><h2 id="与ROS的区别-ROS1中所有节点都需要在节点管理器ROS-Master下进行工作,ROS2实现了真正的分布式,借助一种全新的通信框架DDS,为所有节点的通信提供可靠保障。-ROS2结合C-最新标准和Python3语言特性,设计了更具通用性的API。-ROS1中使用的rosbuild和catkin问题诸多,重新优化后的编译系统叫做ament和colcon。"><a href="#与ROS的区别-ROS1中所有节点都需要在节点管理器ROS-Master下进行工作,ROS2实现了真正的分布式,借助一种全新的通信框架DDS,为所有节点的通信提供可靠保障。-ROS2结合C-最新标准和Python3语言特性,设计了更具通用性的API。-ROS1中使用的rosbuild和catkin问题诸多,重新优化后的编译系统叫做ament和colcon。" class="headerlink" title="#与ROS的区别* ROS1中所有节点都需要在节点管理器ROS Master下进行工作,ROS2实现了真正的分布式,借助一种全新的通信框架DDS,为所有节点的通信提供可靠保障。* ROS2结合C++最新标准和Python3语言特性,设计了更具通用性的API。* ROS1中使用的rosbuild和catkin问题诸多,重新优化后的编译系统叫做ament和colcon。"></a>#与ROS的区别<br>* ROS1中所有节点都需要在节点管理器ROS Master下进行工作,ROS2实现了真正的分布式,借助一种全新的通信框架DDS,为所有节点的通信提供可靠保障。<br>* ROS2结合C++最新标准和Python3语言特性,设计了更具通用性的API。<br>* ROS1中使用的rosbuild和catkin问题诸多,重新优化后的编译系统叫做ament和colcon。</h2><p>#工作空间</p><ul><li>工作空间是一个存放项目开发相关文件的文件夹,在ROS1中,工作空间的子文件夹是由src,devel,build,include等,而ROS中简化分类,由src,install,build,log构成。具体如下:</li><li><strong>src</strong>,代码空间,未来编写的代码、脚本,都需要人为的放置到这里;<br> <strong>build</strong>,编译空间,保存编译过程中产生的中间文件;<br> <strong>install</strong>,安装空间,放置编译得到的可执行文件和脚本;<br> <strong>log</strong>,日志空间,编译和运行过程中,保存各种警告、错误、信息等日志。</li></ul><p>##编译工作空间</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ cd ~/dev_ws/</span><br><span class="line">$ colcon build #ROS1中是catkin_make</span><br></pre></td></tr></table></figure><h2 id="设置环境变量"><a href="#设置环境变量" class="headerlink" title="##设置环境变量"></a>##设置环境变量<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ source install/local_setup.sh # 仅在当前终端生效</span><br><span class="line">$ echo " source ~/dev_ws/install/local_setup.sh" >> ~/.bashrc</span><br></pre></td></tr></table></figure></h2><h2 id="功能包-功能包的创建-功能包的必要文件-对于c-其中必然存在两个文件:package-xml和CMakeLists-txt。package-xml文件包含功能包的版权描述,和各种依赖的声明。CmakeLists-比ROS1简化,主要在于find-package可以从package-xml里寻找依赖-对于python,由于不需要编译,含有两个文件-package-xml和setup-py-setup-py文件里边也包含一些版权信息,除此之外,还有“entry-points”配置的程序入口。"><a href="#功能包-功能包的创建-功能包的必要文件-对于c-其中必然存在两个文件:package-xml和CMakeLists-txt。package-xml文件包含功能包的版权描述,和各种依赖的声明。CmakeLists-比ROS1简化,主要在于find-package可以从package-xml里寻找依赖-对于python,由于不需要编译,含有两个文件-package-xml和setup-py-setup-py文件里边也包含一些版权信息,除此之外,还有“entry-points”配置的程序入口。" class="headerlink" title="#功能包##功能包的创建##功能包的必要文件* 对于c++,其中必然存在两个文件:package.xml和CMakeLists.txt。package.xml文件包含功能包的版权描述,和各种依赖的声明。CmakeLists.比ROS1简化,主要在于find_package可以从package.xml里寻找依赖.* 对于python,由于不需要编译,含有两个文件:package.xml和setup.py.setup.py文件里边也包含一些版权信息,除此之外,还有“entry_points”配置的程序入口。"></a>#功能包<br>##功能包的创建<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ cd ~/dev_ws/src</span><br><span class="line">$ ros2 pkg create --build-type ament_cmake learning_pkg_c # C++</span><br><span class="line">$ ros2 pkg create --build-type ament_python learning_pkg_python # Python</span><br></pre></td></tr></table></figure><br>##功能包的必要文件<br>* 对于c++,其中必然存在两个文件:package.xml和CMakeLists.txt。package.xml文件包含功能包的版权描述,和各种依赖的声明。CmakeLists.比ROS1简化,主要在于find_package可以从package.xml里寻找依赖.<br>* 对于python,由于不需要编译,含有两个文件:package.xml和setup.py.<br>setup.py文件里边也包含一些版权信息,除此之外,还有“entry_points”配置的程序入口。</h2><h2 id="ROS2相关指令"><a href="#ROS2相关指令" class="headerlink" title="#ROS2相关指令"></a>#ROS2相关指令<br><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">$ ros2 run learning_node node_helloworld</span><br><span class="line">$ ros2 node list # 查看节点列表</span><br><span class="line">$ ros2 node info <node_name> # 查看节点信息</span><br><span class="line">$ ros2 topic list # 查看话题列表</span><br><span class="line">$ ros2 topic info <topic_name> # 查看话题信息</span><br><span class="line">$ ros2 topic hz <topic_name> # 查看话题发布频率</span><br><span class="line">$ ros2 topic bw <topic_name> # 查看话题传输带宽</span><br><span class="line">$ ros2 topic echo <topic_name> # 查看话题数据</span><br><span class="line">$ ros2 topic pub <topic_name> <msg_type> <msg_data> # 发布话题消息</span><br></pre></td></tr></table></figure></h2><h2 id="ROS2消息结构-话题通信接口的定义使用的是-msg文件-服务通信接口的定义使用的是-srv文件,包含请求和应答两部分定义,通过中间的“—”区分-动作是另外一种通信机制,用来描述机器人的一个运动过程,使用-action文件定义,此时接口的定义分成了三个部分,分别是动作的目标,比如是开始运动,运动的结果,最终旋转的90度是否完成,还有一个周期反馈,比如每隔1s反馈一下当前转到第10度、20度还是30度了,让我们知道运动的进度。-标准接口位于ROS安装路径中的share"><a href="#ROS2消息结构-话题通信接口的定义使用的是-msg文件-服务通信接口的定义使用的是-srv文件,包含请求和应答两部分定义,通过中间的“—”区分-动作是另外一种通信机制,用来描述机器人的一个运动过程,使用-action文件定义,此时接口的定义分成了三个部分,分别是动作的目标,比如是开始运动,运动的结果,最终旋转的90度是否完成,还有一个周期反馈,比如每隔1s反馈一下当前转到第10度、20度还是30度了,让我们知道运动的进度。-标准接口位于ROS安装路径中的share" class="headerlink" title="#ROS2消息结构* 话题通信接口的定义使用的是.msg文件.* 服务通信接口的定义使用的是.srv文件,包含请求和应答两部分定义,通过中间的“—”区分.* 动作是另外一种通信机制,用来描述机器人的一个运动过程,使用.action文件定义,此时接口的定义分成了三个部分,分别是动作的目标,比如是开始运动,运动的结果,最终旋转的90度是否完成,还有一个周期反馈,比如每隔1s反馈一下当前转到第10度、20度还是30度了,让我们知道运动的进度。* 标准接口位于ROS安装路径中的share."></a>#ROS2消息结构<br><img src="https://book.guyuehome.com/ROS2/2.%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5/image/2.6_%E9%80%9A%E4%BF%A1%E6%8E%A5%E5%8F%A3/image-20220528001633925.png" alt="ROS2消息"><br>* 话题通信接口的定义使用的是.msg文件.<br>* 服务通信接口的定义使用的是.srv文件,包含请求和应答两部分定义,通过中间的“—”区分.<br>* 动作是另外一种通信机制,用来描述机器人的一个运动过程,使用.action文件定义,此时接口的定义分成了三个部分,分别是动作的目标,比如是开始运动,运动的结果,最终旋转的90度是否完成,还有一个周期反馈,比如每隔1s反馈一下当前转到第10度、20度还是30度了,让我们知道运动的进度。<br>* 标准接口位于ROS安装路径中的share.</h2><h2 id="对动作的理解-动作的三个通信模块,有两个是服务,一个是话题,当客户端发送运动目标时,使用的是服务的请求调用,服务器端也会反馈一个应带,表示收到命令。动作的反馈过程,其实就是一个话题的周期发布,服务器端是发布者,客户端是订阅者。-通信模型是客户端发送给一个动作目标,服务器控制机器人开始运动,并周期反馈,结束后反馈结束信息。"><a href="#对动作的理解-动作的三个通信模块,有两个是服务,一个是话题,当客户端发送运动目标时,使用的是服务的请求调用,服务器端也会反馈一个应带,表示收到命令。动作的反馈过程,其实就是一个话题的周期发布,服务器端是发布者,客户端是订阅者。-通信模型是客户端发送给一个动作目标,服务器控制机器人开始运动,并周期反馈,结束后反馈结束信息。" class="headerlink" title="#对动作的理解* 动作的三个通信模块,有两个是服务,一个是话题,当客户端发送运动目标时,使用的是服务的请求调用,服务器端也会反馈一个应带,表示收到命令。动作的反馈过程,其实就是一个话题的周期发布,服务器端是发布者,客户端是订阅者。* 通信模型是客户端发送给一个动作目标,服务器控制机器人开始运动,并周期反馈,结束后反馈结束信息。"></a>#对动作的理解<br>* 动作的三个通信模块,有两个是服务,一个是话题,当客户端发送运动目标时,使用的是服务的请求调用,服务器端也会反馈一个应带,表示收到命令。动作的反馈过程,其实就是一个话题的周期发布,服务器端是发布者,客户端是订阅者。<br>* 通信模型是客户端发送给一个动作目标,服务器控制机器人开始运动,并周期反馈,结束后反馈结束信息。</h2><h2 id="数据传输方式——参数-类似C-编程中的全局变量,可以便于在多个程序中共享某些数据-在ROS2中,参数的特性非常丰富,比如某一个节点共享了一个参数,其他节点都可以访问,如果某一个节点对参数进行了修改,其他节点也有办法立刻知道,从而获取最新的数值。-通过yaml文件实现参数传递。"><a href="#数据传输方式——参数-类似C-编程中的全局变量,可以便于在多个程序中共享某些数据-在ROS2中,参数的特性非常丰富,比如某一个节点共享了一个参数,其他节点都可以访问,如果某一个节点对参数进行了修改,其他节点也有办法立刻知道,从而获取最新的数值。-通过yaml文件实现参数传递。" class="headerlink" title="#数据传输方式——参数* 类似C++编程中的全局变量,可以便于在多个程序中共享某些数据* 在ROS2中,参数的特性非常丰富,比如某一个节点共享了一个参数,其他节点都可以访问,如果某一个节点对参数进行了修改,其他节点也有办法立刻知道,从而获取最新的数值。* 通过yaml文件实现参数传递。"></a>#数据传输方式——参数<br>* 类似C++编程中的全局变量,可以便于在多个程序中共享某些数据<br>* 在ROS2中,参数的特性非常丰富,比如某一个节点共享了一个参数,其他节点都可以访问,如果某一个节点对参数进行了修改,其他节点也有办法立刻知道,从而获取最新的数值。<br>* 通过yaml文件实现参数传递。</h2><h2 id="通信模式-ROS1采用的是Broker模型。由Broker集中处理所有人的请求,并进一步找到真正能响应该服务的角色。这样客户端就不用关心服务器的具体地址了,但处理速度受限。-ROS2采用以数据为中心的DDS模型了,这种模型与广播模型有些类似,所有节点都可以在DataBus上发布和订阅消息。但它的先进之处在于,通信中包含了很多并行的通路,每个节点可以只关心自己感兴趣的消息,忽略不感兴趣的消息。"><a href="#通信模式-ROS1采用的是Broker模型。由Broker集中处理所有人的请求,并进一步找到真正能响应该服务的角色。这样客户端就不用关心服务器的具体地址了,但处理速度受限。-ROS2采用以数据为中心的DDS模型了,这种模型与广播模型有些类似,所有节点都可以在DataBus上发布和订阅消息。但它的先进之处在于,通信中包含了很多并行的通路,每个节点可以只关心自己感兴趣的消息,忽略不感兴趣的消息。" class="headerlink" title="#通信模式* ROS1采用的是Broker模型。由Broker集中处理所有人的请求,并进一步找到真正能响应该服务的角色。这样客户端就不用关心服务器的具体地址了,但处理速度受限。* ROS2采用以数据为中心的DDS模型了,这种模型与广播模型有些类似,所有节点都可以在DataBus上发布和订阅消息。但它的先进之处在于,通信中包含了很多并行的通路,每个节点可以只关心自己感兴趣的消息,忽略不感兴趣的消息。"></a>#通信模式<br>* ROS1采用的是Broker模型。由Broker集中处理所有人的请求,并进一步找到真正能响应该服务的角色。这样客户端就不用关心服务器的具体地址了,但处理速度受限。<br>* ROS2采用以数据为中心的DDS模型了,这种模型与广播模型有些类似,所有节点都可以在DataBus上发布和订阅消息。但它的先进之处在于,通信中包含了很多并行的通路,每个节点可以只关心自己感兴趣的消息,忽略不感兴趣的消息。</h2><h2 id="Launch文件-ros2的launch文件上有很大的变化,采取了基于python语法的文件格式,使启动节点方式更为多样。具体语法在具体项目实践中掌握。"><a href="#Launch文件-ros2的launch文件上有很大的变化,采取了基于python语法的文件格式,使启动节点方式更为多样。具体语法在具体项目实践中掌握。" class="headerlink" title="#Launch文件* ros2的launch文件上有很大的变化,采取了基于python语法的文件格式,使启动节点方式更为多样。具体语法在具体项目实践中掌握。"></a>#Launch文件<br>* ros2的launch文件上有很大的变化,采取了基于python语法的文件格式,使启动节点方式更为多样。具体语法在具体项目实践中掌握。</h2><h1 id="TF坐标系"><a href="#TF坐标系" class="headerlink" title="TF坐标系"></a>TF坐标系</h1><ul><li>一个移动机器人的中心点是基坐标系Base Link,雷达所在的位置叫做雷达坐标系laser link,机器人要移动,里程计会累积位置,这个位置的参考系叫做里程计坐标系odom,里程计又会有累积误差和漂移,绝对位置的参考系叫做地图坐标系map。</li></ul><hr><p><strong>有待更新</strong>。。。</p>]]></content>
</entry>
<entry>
<title>PCL库初学指南</title>
<link href="/2023/05/09/PCL%E5%88%9D%E5%AD%A6%E6%8C%87%E5%8D%97/"/>
<url>/2023/05/09/PCL%E5%88%9D%E5%AD%A6%E6%8C%87%E5%8D%97/</url>
<content type="html"><![CDATA[<!-- * @Author: Pluto * @Date: 2022-03-18 19:46:06 * @LastEditTime: 2022-03-19 20:20:16 * @LastEditors: Please set LastEditors * @Description: 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE * @FilePath: /22_胡正睿PCL库初学/README.md--><h1 id="pcl库初学心得"><a href="#pcl库初学心得" class="headerlink" title="pcl库初学心得"></a>pcl库初学心得</h1><hr><p>简介:本指南仅为刚接触pcl库对各个模块粗浅的理解,由于pcl库的库函数丰富,提供的接口众多,函数的调用形式也较为复杂。本指南并不意在解释每种函数和算法的基本原理,为了 尽早上手点云库实战,我把点云的比较重要的模块选择出来,粗略的了解了下算法以及重要的函数,在此记录以便以后仿照调用,也对第一次上传git留下纪念。</p><p>2022疫情寝室无聊至极……</p><h2 id="编译"><a href="#编译" class="headerlink" title="编译"></a>编译</h2><hr><pre><code>cd <模块>/<案例>mkdir build&&cd buildcmake ..make</code></pre><h2 id="运行"><a href="#运行" class="headerlink" title="运行"></a>运行</h2><hr><pre><code>./<target>pcl_viewer ***.pcdpcl_viewer -multiview <1.pcd> <2.pcd> <3.pcd></code></pre><h2 id="base"><a href="#base" class="headerlink" title="base"></a>base</h2><hr><p>base文件夹提供了对点云的最基本的处理,包括pcd文件的写入 ,以及矩阵的变换(以实现旋转和平移).</p><h3 id="重要函数及操作"><a href="#重要函数及操作" class="headerlink" title="重要函数及操作"></a>重要函数及操作</h3><pre><code>pcl::PointCloud<pcl::PointXYZ> cloud;cloud.width = 5;cloud.height = 1;cloud.is_dense = false;cloud.points.resize(cloud.width * cloud.height);</code></pre><hr><pre><code>pcl::io::savePCDFileASCII("test_pcd.pcd", cloud);pcl::io::loadPLYFile(argv[filenames[0]], *source_cloud)</code></pre><hr><pre><code>pcl::PointCloud<pcl::PointXYZ>::Ptr transformed_cloud(new pcl::PointCloud<pcl::PointXYZ>())pcl::transformPointCloud(*source_cloud, *transformed_cloud, transform_2);</code></pre><h4 id="可视化"><a href="#可视化" class="headerlink" title="可视化"></a>可视化</h4><pre><code>pcl::visualization::PCLVisualizer viewer("Matrix transformation example");// Define R,G,B colors for the point cloudpcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> source_cloud_color_handler(source_cloud, 255, 255, 255);// We add the point cloud to the viewer and pass the color handlerviewer.addPointCloud(source_cloud, source_cloud_color_handler, "original_cloud");pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> transformed_cloud_color_handler(transformed_cloud, 230, 20, 20); // Redviewer.addPointCloud(transformed_cloud, transformed_cloud_color_handler, "transformed_cloud");viewer.addCoordinateSystem(1.0, "cloud", 0);viewer.setBackgroundColor(0.05, 0.05, 0.05, 0); // Setting background to a dark greyviewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "original_cloud");viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "transformed_cloud");//viewer.setPosition(800, 400); // Setting visualiser window positionwhile (!viewer.wasStopped()){ // Display the visualiser until 'q' key is pressed viewer.spinOnce();}return 0;</code></pre><h2 id="kdtree"><a href="#kdtree" class="headerlink" title="kdtree"></a>kdtree</h2><hr><p>通过3D相机(雷达、激光扫描、立体相机)获取到的点云,一般数据量较大,分布不均匀,数据主要表征了目标物表面的大量点的集合,这些离散的点如果希望实现基于邻域关系的快速查找比对功能,就必须对这些离散的点之间建立拓扑关系。<br>kdtree是指选定几个特定维度,比如说x-y-z-x-y-z…然后按每个维度的数据的中位数作为当前根节点,将大于小于的分别二叉分割到左子树、右子树。然后,在左右两个子树上都重复此过程,直到要分区的最后一棵树仅由一个元素组成。k-d tree对于范围搜索和最近邻居搜索的适用性强。<br>kdtree搜索可以k邻居搜索,也可指定半径搜索。</p><h3 id="重要函数及操作-1"><a href="#重要函数及操作-1" class="headerlink" title="重要函数及操作"></a>重要函数及操作</h3><pre><code>pcl::KdTreeFLANN<pcl::PointXYZ> kdtree; kdtree.setInputCloud (cloud);kdtree.nearestKSearch (searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance)kdtree.radiusSearch (searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) </code></pre><h2 id="octree"><a href="#octree" class="headerlink" title="octree"></a>octree</h2><hr><p>我们可以想象一个立方体,我们最少可以切成多少个相同等分的小立方体?答案就是8个。<br>每个八叉树节点有八个子节点或没有子节点。根节点描述了一个包围所有点的3维包容盒子。这样就可以对点数据集进行空间分区,下采样和搜索操作。<br>pcl_octree实现提供了有效的最近邻居搜索(邻域搜索)API,例如“ 体素(Voxel)邻居搜索”,“ K最近邻居搜索”和“半径搜索邻居”。叶子节点类也提供其他功能,例如空间“占用率”和“每个体素(Voxel)的点密度”检查;序列化和反序列化功能可将八叉树结构有效地编码为二进制格式;</p><h3 id="重要函数及操作-2"><a href="#重要函数及操作-2" class="headerlink" title="重要函数及操作"></a>重要函数及操作</h3><pre><code>pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> octree(resolution); //初始化Octreeoctree.setInputCloud(cloud); //设置输入点云 这两句是最关键的建立PointCloud和octree之间的联系octree.addPointsFromInputCloud(); //构建octreeoctree.nearestKSearch(searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance)octree.radiusSearch(searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance)octree.getPointIndicesFromNewVoxels(newPointIdxVector);</code></pre><h2 id="随机性采样"><a href="#随机性采样" class="headerlink" title="随机性采样"></a>随机性采样</h2><hr><p>RANSAC算法假定我们要查看的所有数据均由内部值和异常值组成。可以用带有一组特定参数值的模型来解释离群值,而离群值在任何情况下都不适合该模型。</p><p>利用RANSAC可以实现点云分割,目前 PCL 中支持的几何模型分割有 空间平面、直线、二维或三维圆、圆球、锥体等 。 RANSAC的另一应用就是点云的配准对的剔除。</p><p>RANSAC从样本中随机抽选出一个样本子集,使用最小方差估计算法对这个子集计算模型参数,然后计算所有样本与该模型的偏差,再使用一个预先设定好的阈值与偏差比较,当偏差小于阈值时,该样本点属于模型内样本点.否则为外样本点。</p><h3 id="重要函数及操作-3"><a href="#重要函数及操作-3" class="headerlink" title="重要函数及操作"></a>重要函数及操作</h3><pre><code>//创建随机采样一致性对象pcl::SampleConsensusModelSphere<pcl::PointXYZ>::Ptrmodel_s(new pcl::SampleConsensusModelSphere<pcl::PointXYZ> (cloud)); //针对球模型的对象pcl::SampleConsensusModelPlane<pcl::PointXYZ>::Ptrmodel_p (new pcl::SampleConsensusModelPlane<pcl::PointXYZ> (cloud)); //针对平面模型的对象if(pcl::console::find_argument (argc, argv, "-f") >= 0){ //根据命令行参数,来随机估算对应平面模型,并存储估计的局内点pcl::RandomSampleConsensus<pcl::PointXYZ> ransac (model_p);ransac.setDistanceThreshold (.01); //与平面距离小于0.01 的点称为局内点考虑,注意局内点设置参数ransac.computeModel(); //执行随机参数估计ransac.getInliers(inliers); //存储估计所得的局内点}</code></pre><h2 id="深度图"><a href="#深度图" class="headerlink" title="深度图"></a>深度图</h2><hr><p>在PCL 中深度图像与点云最主要的区别在于其近邻的检索方式的不同,并且可以互相转换。<br>深度图像(Depth Images)也被称为距离影像(Range Image),是指将从图像采集器到场景中各点的距离值作为像素值的图像,它直接反应了景物可见表面的几何形状,利用它可以很方便的解决3D目标描述中的许多问题,深度图像经过点云变换可以计算为点云数据,有规则及有必要信息的点云数据可以反算为深度图像数据。</p><h3 id="重要函数及操作-4"><a href="#重要函数及操作-4" class="headerlink" title="重要函数及操作"></a>重要函数及操作</h3><pre><code>createFromPointCloud(pointCloud, angularResolution, maxAngleWidth, maxAngleHeight,sensorPose, coordinate_frame, noiseLevel, minRange, borderSize)range_image.integrateFarRanges (far_ranges);if (setUnseenToMaxRange){range_image.setUnseenToMaxRange ();}pcl::RangeImageBorderExtractor border_extractor (&range_image);pcl::PointCloud<pcl::BorderDescription> border_descriptions;border_extractor.compute (border_descriptions); //提取边界计算描述子</code></pre><h2 id="IO输入输出"><a href="#IO输入输出" class="headerlink" title="IO输入输出"></a>IO输入输出</h2><hr><p>顾名思义,实现读写pcd文件,点云pcd的合并,以及OPENNI数据流读取点云。</p><h3 id="重要函数及操作-5"><a href="#重要函数及操作-5" class="headerlink" title="重要函数及操作"></a>重要函数及操作</h3><pre><code>pcl::io::savePCDFileASCII("../test_pcd.pcd", cloud);pcl::io::loadPCDFile<pcl::PointXYZ>("../test_pcd.pcd", *cloud) ;</code></pre><h2 id="滤波"><a href="#滤波" class="headerlink" title="滤波"></a>滤波</h2><p>在获取点云数据时,由于设备精度、操作者经验、环境因素等影响,点云数据中将不可避免地出现一些噪声点。由于外界干扰如视线遮挡、障碍物等,往往也会存在一些离主体数据较远的离群点。而滤波可以将噪声点、离群点、数据压缩等按照后续要求处理,更好地进行配准、特征提取、曲面重建、可视化,所以常作为点云处理的第一步。</p><p>PCL点云滤波模块提供了很多灵活的滤波算法,如直通滤波,双边滤波,体素法滤波,高斯滤波,条件滤波,基于随机采样一致性滤波等。</p><p>如果是线结构光的采集方式得到的点云,则沿z向的分布较广,但沿x、y方向的分布则处于有限的范围内。此时,可采用直通滤波,确定x或者y方向的范围,快速裁剪离群点。</p><p>如果使用高分辨率相机等设备对点云进行采集,则点云往往较为密集。过多的点云数据对后续的分割工作带来困难。体素法滤波可以达到下采样的同时不破坏点云本身几何结构的功能,可以提高配准、曲面重建、形状识别等算法的速度,并保证准确性。</p><p>统计滤波器用于去除明显的离群点(离群点往往由噪声引入)。噪声信息属于无用信息,信息量较小。所以离群点表达的信息可以忽略不计。考虑到离群点的特征,则可以定义某处点云小于某个密度,既点云无效。计算每个点到其最近的k个点平均距离。则点云中所有点的距离应构成高斯分布。给定均值与方差,可剔除3∑之外的点。<strong>对离群点的处理可以提高对局部点云特征提取的准确性,从而提高点云配准的正确率。</strong></p><h3 id="重要函数及其操作"><a href="#重要函数及其操作" class="headerlink" title="重要函数及其操作"></a>重要函数及其操作</h3><pre><code>对一个点云进行降采样:输入input.pcd,输出output.pdfpcl_voxel_grid input.pcd output.pcd -leaf 0.03,0.03,0.03</code></pre><hr><pre><code>pcl::PassThrough<pcl::PointXYZ> pass;pass.setInputCloud (cloud); //设置输入点云pass.setFilterFieldName ("z"); //设置过滤时所需要点云类型的Z字段pass.setFilterLimits (0.0, 1.0); //设置在过滤字段的范围pass.setFilterLimitsNegative (true); //设置保留范围内还是过滤掉范围内pass.filter (*cloud_filtered); //执行滤波,保存过滤结果在cloud_filtered//从一个点云提取索引 pcl::ExtractIndices<pcl::PointXYZ> extract; //创建点云提取对象 //为了处理点云包含的多个模型,在一个循环中执行该过程并在每次模型被提取后,保存剩余的点进行迭代 //通过分割得到内点inliers// Extract the inliersextract.setInputCloud (cloud_filtered);extract.setIndices (inliers); // extract.setNegative (false);extract.filter (*cloud_p);</code></pre><h2 id="特征提取"><a href="#特征提取" class="headerlink" title="特征提取"></a>特征提取</h2><hr><p>3D 点云特征描述与提取是点云信息处理中的最基础也是最关键的部分,点云的识别、分割、重采样、配准、曲面重建等大部分算法,都十分依赖特征描述与提取的结果。</p><p>输入方式:</p><ol><li><p>通过setInputCloud(PointCloudConstPtr&)给出的整个点云数据集, 任何试图在给定输入云中的每个点上进行特征估计。 </p></li><li><p>通过setInputCloud(PointCloudConstPtr&)和setIndices(IndicesConstPtr&)(可选)给出的点云数据集的子集, 所有特征估计方式都将用来尝试估计输入云中每个在indices索引列表中点的特征。默认情况下,如果未给出索引集,则将考虑云中的所有点。</p></li><li><p>额外的调用setSearchSurface(PointCloudConstPtr&)来指定要搜索使用的点邻居集。</p></li></ol><p>使用setSearchSurface的最有用的情况是:当我们有一个非常密集的输入数据集,但我们不想估计其中所有点的特征,而是要估计使用pcl_keypoints中的方法发现的某些关键点,或者在点云的降采样版本上(例如,使用pcl::VoxelGrid <T>过滤器获得的降采样点云)。在这种情况下,我们通过setInputCloud传递降采样/关键点输入,并将原始数据作为setSearchSurface传递,这样可以大幅提高效率。</p><p>点云特征包括法线的计算、PFH点特征直方图描述子、FPFH快速点特征直方图描述子、VFH视点特征直方图描述子、NARF (Normal Aligned Radial Feature)法线对齐径向特征。</p><p>PFH通过参数化查询点与邻域点之间的空间差异信息,形成一个多维直方图对点的k邻域的几何特征进行描述。使点云对应的6DOF(degree of freedom自由度)姿态来说具有不变性。通过建立uvw坐标系,减少与法向量有关参数至四元组。</p><p>VFH源于FPFH描述子,为了使构造的特征保持缩放不变性的同时,还要区分不同的位姿,因而计算时,需要加入视点信息。</p><h3 id="重要函数及操作-6"><a href="#重要函数及操作-6" class="headerlink" title="重要函数及操作"></a>重要函数及操作</h3><pre><code>pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;ne.setInputCloud(cloud);//创建一个空的KdTree对象,并把它传递给法线估计向量//基于给出的输入数据集,KdTree将被建立pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());ne.setSearchMethod(tree);//存储输出数据pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);//使用半径在查询点周围3厘米范围内的所有临近元素ne.setRadiusSearch(0.03);//计算特征值ne.compute(*cloud_normals);// cloud_normals->points.size ()应该与input cloud_downsampled->points.size ()有相同的尺寸</code></pre><h2 id="表面"><a href="#表面" class="headerlink" title="表面"></a>表面</h2><hr><p>使用统计分析很难消除某些数据不规则性(由较小的距离测量误差引起)。要创建完整的模型,必须考虑光滑的表面以及数据中的遮挡。重采样算法尝试通过周围数据点之间的高阶多项式插值来重新创建表面的缺失部分.</p><h3 id="相关函数及操作"><a href="#相关函数及操作" class="headerlink" title="相关函数及操作"></a>相关函数及操作</h3><pre><code>pcl::MovingLeastSquares<pcl::PointXYZ, pcl::PointNormal> mls;mls.setComputeNormals(true);// Set parametersmls.setInputCloud(cloud);mls.setPolynomialOrder(2);mls.setSearchMethod(tree);mls.setSearchRadius(0.03);// Reconstructmls.process(mls_points);</code></pre><h2 id="点云分割"><a href="#点云分割" class="headerlink" title="点云分割"></a>点云分割</h2><hr><p>点云分割是根据空间、几何和纹理等特征对点云进行划分,使得同一划分区域内的点云拥有相似的特征 。<br>现有实现的分割算法是鲁棒性比较好的Cluster聚类分割和RANSAC基于随机采样一致性的分割。<br>简而言之就是分而治之,将物体分开处理。</p><h3 id="相关函数及操作-1"><a href="#相关函数及操作-1" class="headerlink" title="相关函数及操作"></a>相关函数及操作</h3><pre><code>/** * 创建分割时所需要的模型系数对象 coefficients 及存储内点的点索引集合对象 inliers . * 这也是我们指定“阈值距离DistanceThreshold”的地方,该距离阈值确定点必须与模型有多远才能被视为离群点。 * 这里距离阔值是 0.01m ,即只要点到 z=1 平面距离小于该阈值的点都作为内部点看待,而大于该阁值的则看做离群点。 * 我们将使用RANSAC方法(`pcl::SAC_RANSAC`)作为可靠的估计器。因为RANSAC比较简单(其他强大的估算工具也以此为基础,并添加了其他更复杂的概念)。 */ pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);pcl::PointIndices::Ptr inliers(new pcl::PointIndices);// Create the segmentation objectpcl::SACSegmentation<pcl::PointXYZ> seg;// 可选配置:是否优化模型系数seg.setOptimizeCoefficients(true);// 必选配置:设置分割的模型类型、分割算法、距离阈值、输入点云seg.setModelType(pcl::SACMODEL_PLANE);seg.setMethodType(pcl::SAC_RANSAC);seg.setDistanceThreshold(0.01);seg.setInputCloud(cloud);// 执行分割操作,并存储分割结果保存到点集合 inliers 及存储平面模型系数 coefficientsseg.segment(*inliers, *coefficients);// Extract the planar inliers from the input cloudextract.setInputCloud(cloud_filtered);extract.setIndices(inliers_plane);extract.setNegative(false);</code></pre><hr><pre><code>pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;因为点云是PointXYZ类型的,所以这里用PointXYZ创建一个欧氏聚类对象,并设置提取的参数和变量。ec.setClusterTolerance(0.02); // 设置临近搜索的搜索半径(搜索容差)为2cm设置一个合适的聚类搜索半径 ClusterTolerance,如果搜索半径取一个非常小的值,那么一个实际独立的对象就会被分割为多个聚类;如果将值设置得太高,那么多个对象就会被分割为一个聚类,所以需要进行测试找出最合适的ClusterTolerance.ec.setMinClusterSize(100); // 每个簇(集群)的最小大小ec.setMaxClusterSize(25000); // 每个簇(集群)的最大大小</code></pre><h2 id="点云配准"><a href="#点云配准" class="headerlink" title="点云配准"></a>点云配准</h2><hr><p>由于三维扫描仪设备受到测量方式和被测物体形状的条件限制,一次扫描往往只能获取到局部的点云信息,进而需要进行多次扫描,然后每次扫描时得到的点云都有独立的坐标系,不可以直接进行拼接。</p><p>为了得到被测物体的完整数据模型,需要确定一个合适的坐标变换 ,将从各个视角得到的点集合并到一个统一的坐标系下形成一个完整的数据点云,然后就可以方便地进行可视化等操作,这就是点云数据的配准。</p><p>粗配准是指在点云相对位姿完全未知的情况下对点云进行配准,找到一个可以让两块点云相对近似的旋转平移变换矩阵,进而将待配准点云数据转换到统一的坐标系内,可以为精配准提供良好的初始值。</p><p>精配准是指在粗配准的基础上,让点云之间的空间位置差异最小化,得到一个更加精准的旋转平移变换矩阵。该算法的运行速度以及向全局最优化的收敛性却在很大程度上依赖于给定的初始变换估计以及在迭代过程中对应关系的确立。</p><p>依赖平台设备:将被测物体放在平台上,利用控制器对平台进行控制,使之按照指定角度转动,通过多次测量可以得到不同视角下的点云,由于提前获知了距离及角度信息,则可以直接对所有点云进行配准。</p><p>辅助标志点:通过在被测物体表面粘贴标签,将这些标签作为标志点,对多次测量得到的点云数据进行配准时,对这些有显著特征的标签进行识别配准,代替了对整体点云的配准,提高效率,精确度。</p><p>pcl的自动配准:</p><p>两两配准(pairwise registration):我们称一对点云数据集的配准问题为两两配准(pairwise registration)。通常通过应用一个估算得到的表示平移和旋转的 4 × 4 刚体变换矩阵来使一个点云数据集精确地与另一个点云数据集(目标数据集)进行完美配准。<br>具体操作为:提取关键点特征描述子,去除噪声点,得到对应关系矩阵。</p><p>配准算法有迭代最近点算法(ICP)、正态分布变换配准(NDT)、刚性物体的鲁棒姿态估计等。</p><h3 id="具体函数及操作"><a href="#具体函数及操作" class="headerlink" title="具体函数及操作"></a>具体函数及操作</h3><pre><code>pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;icp.setInputSource(cloud_in);icp.setInputTarget(cloud_out);</code></pre><hr><pre><code>pcl::NormalDistributionsTransform<pcl::PointXYZ, pcl::PointXYZ> ndt;// Setting scale dependent NDT parameters// Setting minimum transformation difference for termination condition.ndt.setTransformationEpsilon(0.01);// Setting maximum step size for More-Thuente line search.ndt.setStepSize(0.1);//Setting Resolution of NDT grid structure (VoxelGridCovariance).ndt.setResolution(1.0); // Setting max number of registration iterations.ndt.setMaximumIterations(35);// Setting point cloud to be aligned.ndt.setInputSource(filtered_cloud);// Setting point cloud to be aligned to.ndt.setInputTarget(target_cloud);// Set initial alignment estimate found using robot odometry.Eigen::AngleAxisf init_rotation(0.6931, Eigen::Vector3f::UnitZ());Eigen::Translation3f init_translation(1.79387, 0, 0);Eigen::Matrix4f init_guess = (init_translation * init_rotation).matrix();// Calculating required rigid transform to align the input cloud to the target cloud.pcl::PointCloud<pcl::PointXYZ>::Ptr output_cloud(new pcl::PointCloud<pcl::PointXYZ>);ndt.align(*output_cloud, init_guess);</code></pre><h2 id="可视化-1"><a href="#可视化-1" class="headerlink" title="可视化"></a>可视化</h2><hr><p>可视化能够把科学数据(包括测量获得的数值、图像或者计算中设计、产生的数字信息)变为直观的、可以用以图形图像信息表示的、随时间和空间变化的物理现象或物理量。进而呈现在研究者面前,使他们可以方便的观察、模拟和计算。</p><h3 id="重要函数及操作-7"><a href="#重要函数及操作-7" class="headerlink" title="重要函数及操作"></a>重要函数及操作</h3><pre><code> // 定义对象 pcl::visualization::PCLVisualizer viewer; //设置背景颜色,默认黑色 viewer.setBackgroundColor(100, 100, 100); // rgb // --- 显示点云数据 ---- // "cloud1" 为显示id,默认cloud,显示多个点云时用默认会报警告。 viewer.addPointCloud(cloud1, "cloud1"); pcl::visualization::PointCloudColorHandlerCustom<PointT> red(cloud2, 255, 0, 0); // rgb // 将点云设置颜色,默认白色 viewer.addPointCloud(cloud2, red, "cloud2"); // 将两个点连线 PointT temp1 = cloud1->points[0]; PointT temp2 = cloud1->points[1]; viewer.addLine(temp1, temp2, "line0");while (!viewer.wasStopped()) { viewer.spinOnce(100); boost::this_thread::sleep(boost::posix_time::microseconds(100000)); // 可添加其他操作,注意Cmakelists链接boost. } system("pause"); return 0;</code></pre><h2 id="关键点"><a href="#关键点" class="headerlink" title="关键点"></a>关键点</h2><hr><p>关键点是 可以通过检测标准来获取的具有稳定性、区别性的点集。从技术上来说,关键点的数量比原始点云或图像的数据量少很多,其与<strong>局部特征描述子</strong>结合组成关键点描述子。常用来构成原始数据的紧凑表示 ,具有代表性与描述性,从而加快后续识别、追踪等对数据的处理速度 。<br>关键点提取过程有以下要求:</p><ul><li>提取的过程必须考虑边缘以及物体表面变化信息</li><li>即使换了不同的视角,关键点的位置必须稳定的可以被重复探测</li><li>关键点所在的位置必须有稳定的支持区域,可以计算描述子和估计唯一的法向量。</li></ul><h3 id="重要函数及操作-8"><a href="#重要函数及操作-8" class="headerlink" title="重要函数及操作"></a>重要函数及操作</h3><pre><code>pcl::NarfKeypoint narf_keypoint_detector(&range_image_border_extractor);narf_keypoint_detector.setRangeImage(&range_image);narf_keypoint_detector.getParameters().support_size = support_size;//narf_keypoint_detector.getParameters ().add_points_on_straight_edges = true;//narf_keypoint_detector.getParameters ().distance_for_additional_points = 0.5;pcl::PointCloud<int> keypoint_indices;narf_keypoint_detector.compute(keypoint_indices);std::cout << "Found " << keypoint_indices.points.size() << " key points.\n";// ----------------------------------------------// -----Show keypoints in range image widget-----// ----------------------------------------------//for (size_t i=0; i<keypoint_indices.points.size (); ++i)//range_image_widget.markPoint (keypoint_indices.points[i]%range_image.width,//keypoint_indices.points[i]/range_image.width);// -------------------------------------// -----Show keypoints in 3D viewer-----// -------------------------------------pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints_ptr(new pcl::PointCloud<pcl::PointXYZ>);pcl::PointCloud<pcl::PointXYZ> &keypoints = *keypoints_ptr;keypoints.points.resize(keypoint_indices.points.size());</code></pre><hr>]]></content>
</entry>
</search>