本教程展示了图形化差异对比(graphical diff)、personFlow、绘图工具、分析重复运行等内容!
文件#
视频#
文字记录#
简介#
好的,那么简单介绍一下我们要讲的内容。虽然列表不长,但我们试图涵盖很多东西。和往常一样,我们将讨论如何快速入门。这次,我们将通过生成的网络快速入门。我们还将看看如何以图形方式比较不同的网络。然后,任何 SUMO 教程都不可或缺的一部分就是看看 OSMWebWizard。因此,我们将通过几次点击生成一个场景。然后我们将在这个场景上进行模拟。这次,我们将更深入地研究自行车模拟。然后我们将看到如何分析场景并从中提取一些漂亮的图形来总结场景的运行情况。而且我们不仅会运行场景一次,还会运行多次并进行分析。非常期待这一点。
使用 netgenerate 生成网络#
好的,首先是 netgenerate。这是一个生成合成网络的工具。例如,你可以在这里看到一个简单的曼哈顿网格。但也有其他变体,直到非常随机的东西或试图看起来像真实城市的东西。这个工具已经存在了差不多 20 年了。我稍微查了一下。在 2003 年,Daniel Krajzewicz,SUMO 之父,你完全可以这样称呼他,他开始了网络生成器的第一个提交。但现在,我们有了带 UI 的版本,带图形用户界面。那么,让我们看看效果如何。 启动 netedit。我们这里有一个新菜单。“生成网络”菜单。这里有一个对话框。我说过三次点击。所以,不要太纠结于计数。那么,假设一次点击打开对话框。假设另一次点击选择输出文件。我们把它放在这里。还有一个短名称。当然,我们必须选择我们要生成的网络类型。我要去 grid(网格)并运行这个。对话框告诉我们一切顺利。我们在这里有了我们的网络。非常好。 那么,这是默认设置的网络。让我们做点更高级的。让我们再次打开对话框。这次,我要给它一个新名字。然后进入高级对话框。这里,对于你拥有的所有不同类型的网络,都有设置。既然我们要生成一个网格,我们将在这里自定义值。所以,X 数字,这是 X 方向的网格。Y 数字是这个。哦,顺便说一句,你在这里看到的值,即默认值,实际上并不是正确的默认值。这在下一个版本中已经修复了。尽管如此,这只是视觉上的问题。所以,当你运行它时,你仍然需要全部纠正它。请注意,目前它不显示。好的。那么,我们还设置什么?让我们在这里加一点随机性。让我们随机化每一行得到的车道数量。所以,你可能想知道,我们在哪个范围内随机化?嗯,是车道的数量。这可以在构建默认值中设置。所以,在这附近是默认车道数。我们要把它设为 2。然后,每条边将有一条或两条车道。让我们运行这个。工作正常。我们有了我们的网络。正如你所料,它变宽了一点。高度没那么高。如果你放大,你会看到车道数量到处都在变化。好的。这就是 netgenerate。希望你喜欢它。
使用 netdiff 比较网络#
现在,我们将看看这两个网络之间的差异。嗯,我们怎么做呢?我们可以,我会非常快速地谈论它们。要看到它们的区别,嗯,很好。实际上,当我处理网络时,我有时会这样做。眼睛非常擅长发现微小的差异。所以,这可能管用。当然,还有更好的方法。所以,让我们谈谈另一个工具。我们谈到了 netgenerate。现在,让我们谈谈 netdiff。这是一个用于计算网络之间差异的 Python 工具。你可以把它想象成数学。你有两个网络,A 和 B。它们之间的差异,嗯,也是某种文件。就像真正的数学一样,你可以撤销减法。你可以做加法。所以,如果你使用这个 netdiff 工具来计算两个网络文件之间的差异,那么以后,你可以基于这个差异重建网络。假设你从网络 A 开始,在右边做一些更改,然后得到网络 B。这些更改被保存在这个差异文件中,或者更确切地说是一组文件。现在在以后,你可以将这些差异应用到网络 A 并得到网络 B。那么,你为什么要这样做呢?你实际上可以对你的网络做一些语义版本控制,或者记录手动更改。假设你从一个 OpenStreetMap 导出的网络开始。像往常一样,你必须在上面做一些手动修复。然后在以后某个时候,你想升级。你想更新你的 OSM 数据。而你不想重做所有的修复。那么,你该怎么办?你获取原始的 OSM 网络和带有修复的网络,并计算差异。然后在以后,你更新 OSM,得到一个新的原始网络,并再次应用你的差异。在大多数情况下,你的大部分差异仍然适用。我的意思是,和往常一样,如果你做补丁,而你打补丁的部分发生了变化,那么你就必须做一些手动修正。但它可以节省大量的工作。很多你已经做过的手动工作,你不必重做。好的。所以,这实际上并不是新功能。它已经可用相当长一段时间了。但新的是,你现在可以对两个网络之间的差异有一个视觉印象,因为 netdiff 工具现在已集成在 netedit 中。所以,让我们从这个开始。这是原始网络。它被称为网络 A。我要开始,打开新的“工具”菜单。我们今天已经看到了不少这个。这是 1.17.0 中的新功能之一,这里我们有 netdiff 工具。现在,我们必须在这里输入我们要比较的网络的路径。有一个方便的小按钮,“使用当前网络”,当前项目。所以,A 将是我们首先看到的网络。然后,让我们打开另一个东西。第二次运行。现在,我选择所有我想看到的差异。修改、添加和删除内容的形状。让我们开始。那么,我们在这里看到了什么?与原始网络相比,添加了一些东西。我们看到这个是绿色的。移除了一些东西。我们看到这个是红色的。修改了一些东西,我们看到这个是橙色的重叠。你还记得高级网络有一些随机的车道数量吗?所以,车道数量被改变了。边仍然在那里。嗯,它们既不是红色也不是绿色。所以,这让你对两个网络之间的变化有了印象。如果你的同事对你的网络做了什么,现在你将确切地发现他们做了什么。所以,我希望你能好好利用这个。
使用 osmWebWizard 生成场景#
进入下一个话题。我希望在座的各位都已经知道这个工具了。它是一个 Python 工具,帮助你开始 SUMO 模拟。同样,只需大约三次点击。你可以在 SUMO 安装的“工具”菜单中找到这个工具。它会打开网络浏览器。它会让你根据 OpenStreetMap 数据的渲染来选择地图的一部分。你可以选择要导入的道路类型和要看到的交通模式。请注意,尽管数据是真实的,如 OpenStreetMap 提供的那样,但交通将是品牌化的(branded)。但你可以配置你想看到哪些模式。以及交通量。还有多少交通来自外部,多少是在网络内部生成的。例如,如果你有一个小网络,那么大部分将是引导交通(boot traffic)。假设它比已经有的要大一点。你还可以导入公共交通。这是真实数据和生成内容的混合。所以,它是真实的路线和真实的站点,正如它们在 OpenStreetMap 中找到的那样。但因为 OpenStreetMap 没有详细的时刻表,最多只有时段,场景将有一个合成的时刻表,遵循所有已知的事件。然后,当然,你可以配置场景应该运行多长时间。所以,交通应该进来多久。你还会获得背景形状、建筑物,甚至卫星背景图像。所有文件都会自动下载,以便你重建场景并重新运行。所以,正如我所说,你可以在 SUMO 的 Tools 文件夹中找到这个。只需启动 osmWebWizard.py,这里就会出现带有选择的网络浏览器,然后最后,你点击“生成场景”。所以,今天,我准备了一些没有汽车的东西,只有自行车。所以,也许这是明天我们要听的主题演讲的一个小预告。在 Web Wizard 中,你选择的模式有一些微妙的副作用。所以,一旦你选择了自行车,导入网络的方式就会生成额外的信息。它将导入所有自行车基础设施。如果你做一个纯汽车模拟,也许你不需要所有这些自行车道。它们只会锁死网络,挡路,分散你感兴趣内容的注意力。但在这里,一旦你选择了这个,你将在网络中拥有所有额外的自行车道。我现在不打算运行这个,因为这里的连接速度出名地慢。相反,我要切换到我已经准备好的文件。你可以在 Wizard 文件夹中找到它。所有场景文件都可以在教程页面上下载。那么,也许让我们快速回去看看我的意思。在 SUMO 文档中,有一个教程子页面。这里你可以找到所有过去的会议教程,附有幻灯片和示例的下载链接。好的。所以,当你运行 Web Wizard 时,它会为你打开一个模拟。它会像这样。让我们运行它看看。 正如我提到的,这是一个我只激活了自行车的模拟。所有自行车都很小。也许我们需要让它们更显眼一点。让我们看看。嗯,它们仍然很小。让我们把它们变得更大。当然,有一些控制。但是,你知道,它们不是很大。这里你有随机的自行车交通。那么,谁能发现这个位置?谁能弄清楚这是哪里?是的。就是这里。我们在“Rotunde”,也就是这个圆形的东西。这里是火车站,你们很多人可能都是在那里到达的。正如我所说,这是随机交通。这不太现实。而且,缺乏汽车并不能反映 Adlershof 当前的交通状况。当你启动场景时,你还会得到别的东西。也许你在自己的 Web Wizard 场景中见过这样的事情。这里有一个关于一些交通灯的警告信息,所以我们快速谈谈这个。 但在我们这样做之前,让我们简要看看 Web Wizard 生成的所有文件。所以你会得到一整目录的东西,别被吓到,这些文件中的大多数只是场景的输入,你有你的 SUMO 配置文件,它加载所有东西,把所有东西绑定在一起,你当然有网络文件,这些现在默认是 gzip 格式,你可能不知道 SUMO 可以处理所有以 xml.gz 结尾的文件,这些是 gzip 文件,如果你把这些作为输入,它会自动解压,如果你把这些路径作为输出文件,它会自动写入 gzip 文件,这对节省空间非常有用,所以 Web Wizard 现在以 zip 格式保存网络。我们有我们生成的自行车,我们有我们在背景中看到的多边形(例如我们所在的建筑物),然后你有一些设置,关于视图应该如何显示,以及为了重建场景,你有原始的 OSM 数据和构建形状的配置部分,还有一个用于重建随机交通的文件。 如果你对这些细节感兴趣,可以看看最后两个教程,我在那里花了更多时间。所以我们看了模拟,有这些警告,所以让我们简要讨论一下这些是关于什么的。默认情况下,Web Wizard 对现实世界中的交通灯一无所知,除了它们的存在,它们就在那里。构建模拟网络的过程(netconvert 是用于此的应用程序)会采取一些自由来生成合理的信号计划,它还会采取自由假设所有这些交通灯都是交通感应式的(traffic actuating),这意味着道路配备了检测设备,交通灯默认会对它们检测到的交通做出反应,基本上是在有大量排队时延长相位,在没有更多交通时缩短绿灯相位,这使得流量效率大大提高,嗯,这是我们不知道交通灯情况时能做的最好的事情,我们不要让它效率更低。 所以这个警告告诉我们,这种交通感应由于某种原因不起作用,所以相位的布局方式与检测器在车道上的放置方式不太匹配,因此它只是告诉我们这个自动感应将不起作用,实际上 SUMO 中有一个选项可以让交通灯更智能一些,处理这些情况,有一个选项可以设置,然后交通灯会检测拥堵并自动切换到下一个相位以避免一些糟糕的情况。所以,如果你想摆脱这个警告,可以设置这个,记住这一点,我们稍后会回到这一点。但现在我们有了基本场景,让我们做一个更详细的自行车模拟。为什么是自行车?嗯,因为它对环境有益,而且将来我们可能希望城市里有更多的自行车,所以让我们把它作为一个前瞻性的模拟,我们想看到的细节是自行车在自行车道上互相超车。如你所知,SUMO 中的汽车,嗯,当有更多车道时它们会超车,但在单车道上它们通常不会超车。自行车应该能够在自行车道上这样做,如果它足够宽可以超车的话。所以我们应该确保自行车道实际上足够宽,1 米可不行,我们必须在 SUMO 中激活子车道模型(sublane model),它在车道内进行这些动态调整,例如允许这种超车。我们必须增加更多的自行车,现在在这个模拟中,我们看到没有足够的交通量来看到这种情况。然后我们还必须给自行车一个超车的理由。所以其中一些,嗯,它们应该有比其他一些自行车开得更快的愿望。那么我们就可以看到这些超车动作了。好消息是,在过去的几个版本中,我们改进了自行车模拟,现在这种速度分布是开箱即用的。回到 SUMO v1.14.0,你必须做一些非常详细的步骤才能让它们真正超车,因为默认情况下它们都希望以完全相同的速度行驶。好的。当我们处理好所有这些事情后,我们就可以做一些漂亮的图表,甚至多次运行场景。
准备网络#
好的,那么从加宽自行车道开始。有两种方法可以解决这个问题。一种方法,我只会简单提一下,是在从 OpenStreetMap 导入场景的阶段处理它。并非 OpenStreetMap 中的每条车道都附带宽度信息。所以有一个过程会在某处放入默认值。当然,这些值可以由用户自定义。所以在你的 SUMO 安装中,你会找到一些与这些默认值相关的文件。它们都在幻灯片上记录了。所以你可以看看那个,你可以从这些文件中改变值,然后你的网络就会有不同的变量。但我们现在不打算这样做。相反,我们将看看如何在 netedit 中高效地做到这一点。所以我们想加宽自行车道。让我们进入 02_netedit 文件夹。这就是模拟的样子。我可以直接从这里用 Ctrl + T 启动 netedit,这可以是在特定网络上启动 netedit 的一种便捷方式。现在我可以点击一个自行车道,找到宽度属性并更改它。但网络中有大量的自行车道,这效率不高,而且我可能会忘记一些。所以让我们使用选择模式。我按字母 S,但也按这个给出快捷键的小按钮。然后我将根据属性在对象中选择网络。我想根据属性 allow 选择车道。我希望那些 allow 的值正好是 "bicycle" 的车道。等号强制精确匹配。现在我选择了 172 条自行车道。接下来我想做的是更改属性,一次性更改所有这些。现在这里要小心。如果我只是点击这里的这条路,我将选中这个边对象,也就是检查它,这不是我想要的。我想要的是这些车道。所以。我在这个车道上按住 Shift 点击。这是一种方法。另一种方法是设置这里的复选框,这使得每次点击都与车道而不是边交互。现在,我实际上是在检查所有这 172 条车道的集合。我可以看到它们甚至有不同的属性。其中一些的值是 1。其中一些的值是 1.5。我要把它们都改成 1.6,就这样。现在我可以更改网络,它们都有了我想要的宽度。
但我要再做一件事。如前所述,我想激活子车道模型。所以现在这是一个在运行模拟时设置的选项。它不是网络的一部分。所以你可以用不同的细节值运行同一个网络而不改变网络,但你也可以使用 netedit 来设置这个选项,因为现在我们有一种方式来配置、定义 SUMO 配置文件。这是这里的新菜单项,Shift + F10 SUMO 选项。在那里我们可以在处理选项卡中定义。这个值,lateral-resolution,设为 0.8。如果你注意到,这只是自行车道宽度的一半。所以我们将把它分成子车道,自行车可以在那里超车,也正好将默认道路宽度 3.2 米整除。作为一个额外的好处,我会设置这个关于拥堵阈值的选项,我之前提到过,以使那个警告消失。现在我可以保存 SUMO 配置,随便哪里。好的。嗯,这就是那个部分。那是为自行车模拟做准备的一部分,加宽车道,定义一些 SUMO 配置。接下来,当然,我们必须定义更多的自行车。在上一个教程中,我已经讨论了如何定义汽车流。这很无聊。相反,我们将定义人的流,这些人碰巧骑自行车。
在我们开始之前,让我们去掉这里的选区。我只需回到选择模式,按 Esc。所以现在什么都没选中。我想定义人,或者更确切地说是人的整个流。为此,我必须进入另一个模式,就在这里。这些是你看到的所有用于修改网络的模式。然后我们有这些超级模式,网络、需求和数据。我进入这个需求超级模式。快捷键是 F3。它回到网络,这里是需求。然后我进入人模式,按快捷键 P。否则就是这个小人按钮。好的。所以我们已经对网络进行了一些颜色编码。我们看到一些人不能去的地方。这里是冲突,青色。实际上是洋红色。然后在深绿色中,我们有所有可以开始的地方。所以让我们让人从火车站开始,然后去 DLR,参加会议,然后返回火车站。这就是想法。但我们不想要一个人。相反,我们想要一个完整的流,这里的一个 person flow。但就像车辆流一样,对于每个流,我们必须定义它将运行多长时间以及间距是多少。所以让我们为 1000 秒设置一个流。我们可以有均匀的间距,只需设置我们每小时想要多少个对象,或者固定周期,但我们将选择泊松分布(Poisson distribution),平均而言,每两秒一个人应该开始。现在,我们从这个人可以做的事情列表中挑选,personTrip 从一个边到另一个边实际上是默认的。默认情况下,这些人可以直接走。这是默认行为,但在这里的模式字段中,我们也可以选择他们有自己的车或可以使用公共交通。我们说,他们应该骑自行车。这就是我们在这里输入的,modes bicycle。然后当然,如果可以的话,他们会选择这个而不是步行,除非我们碰巧定义了一个包含自行车的网络。所以我们必须在某处选择一个起点。所以让我们从火车站的这条边开始,然后让我们去 DLR。那将是这里。好的。所以让我们去这里的 DLR。这是旅程的第一段,对吧?我们用 Enter 确认,然后 person flow 就创建了。
现在我们想在这个计划中添加更多的阶段或更多的行程。为此,我们需要一个不同的模式。我们选择我们想要处理的 person flow。我们刚刚创建的那个。现在这里的区别在于,在第一种模式中,我们必须选择一个起点和一个终点。现在我们只需要选择终点,因为所有这些东西都隐式地改变了。所以让我们输入一个停靠点。让我们停在 DLR 并参加会议。那将是边上的一个停靠点。当然,会议是漫长的事情。假设我们在这里总共花了八个小时。所以我输入 8:0:0 来使用八个小时。让我们停在这里。让我们说这些人正在做什么,他们正在参加 2023 年 SUMO 会议。好的。我只需点击“撤销”来完成这个。现在是最后阶段,让我们回到火车站。同样,我们有从边到边的 personTrip,模式是自行车,现在我们只需在火车站点击最终目的地。就这样。我们定义了我们的人流,他们骑自行车去,骑自行车回来。我们可以进入检查模式。所以在检查模式。在左下角,我们看到计划中的这三个元素。Person flow,停靠点,以及 flow(再次)。好的,让我们运行这个模拟。我要回到我准备好的东西。所以让我们运行这个。自行车,它们从这里进来。你可以看到它们。它们已经成对地并排骑行,这是它们在交通灯前排队的方式。然后它们去 DLR。它们已经在这里排队了。让我们停止这个。所以如果我右键单击,我看到实际上有成吨的人堆在这个地方。现在如果我继续运行模拟,加快一点速度,那么在某个时候,会议将结束,遗憾的是,每个人都会开始回家。这就是我们的场景。让我们做一些分析。
分析和绘制结果#
首先,所有这些事情。如果你回到幻灯片,你可以找到所有这些东西。你想看看我们是怎么做的。现在,要评估场景,仅仅看是不够的。模拟的全部目的是生成所有这些漂亮的输出文件。所以让我们这样做。所以,当然,在过去,你必须把所有的输出定义在 sumo 配置文件中,或者至少在命令行上写这些选项,让 sumo 为你生成配置文件,你不再需要这样做了。在我已经提到的 sumo 配置设置对话框中,你也有这个输出部分。所以我们可以在那里选择所有我们想要的输出。现在这仍然涉及一些输入,但这将是,嗯,已经计划好让这个对话框更好。所以让我们在这里输出一些 trip info。另一个相当新的功能是,你可以把所有属于人的东西拆分到一个单独的输出文件中。所以让我们把 person input 放在另一个文件里。然后让我们做一些统计。这非常有用。统计输出基本上给你一个关于模拟中所有行程的摘要。所以平均花了多长时间,平均速度是多少,所有这些事情。我们还要输出一些边数据。定义为一个文件。所以。就是它。好的,所以边数据。你们中的一些人可能知道它。这是空间聚合值的输出之一。所以对于每个模拟边,我们聚合有多少辆车经过该边,它们开得有多快,在该边上损失了多少时间。当然,你可以设置各种属性,比如这应该每五分钟聚合一次,或每小时,或整个模拟期间。因为有这么多属性,我们通常必须在 XML 文件中定义这个。把所有属性都写下来。但如果你想要一些快速的东西,你只需将选项 edgedata-output 设置为某个文件。它会给你一个在整个模拟期间运行的聚合。使用默认周期。好的。然后当然你保存 sumo 配置。并运行模拟。我已经做了所有这些。结果就在这个最终文件夹里。这是文件的一部分。嗯,那么让我们看看一些数据。让我们看看,例如,stats.xml 文件。好的。所以。这有点难读。而且。让我们看看。好吧。好多了,对吧?是的。好的。所以我们有各种各样的统计数据。我们有性能,模拟运行了多久。加载了多少辆车,我们有多少人。所以如你所见,我们有这个泊松分布。运行了 1000 秒,每秒生成 1.5 个人的期望值。如果你做随机的事情,嗯,那么你不会得到它的一半。所以我们这里生成了 470 个人。他们每个人都有两次自行车行程:一次从车站出发,一次返回车站。所以这里我们有两倍的车辆行程记录在模拟中。我们还可以看到,为了方便起见,自行车实际上在输出中有它们自己的部分。
通常你有一个自行车的部分,然后是所有其他车辆的部分,因为它们往往与其他模式有很大不同。所以我们看到平均路线长度,大约 1 公里。你可以走路,但有自行车很方便。平均速度,以及这里的 waitingTime(等待时间)。所以 waitingTime 是自行车停止的时间,主要是在交通灯前。这是整体 timeLoss(时间损失)的一部分。TimeLoss 意思是,嗯,他们本想过去,但由于某种原因不能,所以 timeLoss 包括他们只是静止不动的部分。但也包括他们被其他较慢的自行车或其他东西减速的部分。
所以。时间应该总是至少和等待时间一样长。然后,我们这里有另一个统计数据。这是关于人所做行程的统计数据。所以显然,这与车辆的数量相同,因为我们只有这些自行车。但如你所见,我们有另一个 waitingTime 值。路线长度匹配,它和这里的值相同,但我们有另一个 waitingTime 值。那么这是什么?嗯,从自行车的角度来看,waitingTime 是它们不能行驶的时间。但从人的角度来看,waitingTime 是他们开始行驶之前的时间。所以你主要会在公共交通中遇到这个。你在公交车站等车,车没来。所以这是你在行程实际开始前的等待时间。在这种情况下,自行车没有运行在任何公共交通时刻表上。而是它们不能同时都坐在路上的事实。所以你可以说它们都在某个想象的自行车停车区,无法进入自行车道。这就是 waitingTime。好的。所以这些是我们从总结整个模拟的单个文件中得到的值,但也许它有点太浓缩了。也许我们没有看到足够多关于真正发生了什么的信息。所以让我们使用另一个工具来更好地掌握这些统计数据。回到幻灯片。好的。所以我们可以做的一件事是,我们可以直接从 tripinfo 文件获取统计数据。我们计算我们在这里看到的所有这些属性的平均值,但也计算标准差和不同的模式,也许还能找出最小值和最大值是多少。这总是一个好主意。一个好的总结性统计数据,除了平均值之外,还有更多的东西。为此,我们使用工具 attributeStats.py。这是一个 Python 工具,作为 SUMO 的一部分已经很长时间了。呃,但可能没有很多人知道它。现在这个工具有一个更容易被发现的形式,你可以通过 netedit 中的新工具对话框使用它。让我们回到 netedit 并使用工具对话框。所以在输出部分 attributeStats.py。我们选择我们要做摘要的数据文件。所以这是运行后生成的任何文件。我们选择 tripinfo 文件,就这样。当我们按下运行时,它就会给我们所有这些统计数据。当然,在屏幕上,在大屏幕上,这有点难看清。所以我把它放在幻灯片上,让你们详细查看。所以现在对于在这个 tripinfo 文件中找到的每个元素的每个属性,我们有更多的统计数据。所以我们有关于自行车的 tripinfo 的统计数据,也有关于行程(rides)的统计数据。我们可以看到我们在统计输出的背景下已经讨论过的值,traveltime(行程时间)、timeLoss、waitingTime。再次,自行车和行程的 waitingTime 值不同。不同的视角。我们在这里看到的还有最小值和最大值,你甚至可以得到对象的 ID。嗯,在这种情况下,是那些负责最小和最大值的自行车的 ID。然后我们可以回到模拟中,看看这辆自行车到底做了什么才达到这个最大的 waitingTime。也许这辆自行车有什么有趣的地方。但我在这里高亮了一些东西。我们看到 waitingTime 有巨大的偏差。所以在行程的 waitingTime 中,也就是行程开始所花的时间。在这一点上,我们真的应该看一张图,而不是所有这些枯燥的数字,所以让我们这样做。我们回到工具菜单。这次我们将使用一个可视化工具。这是 plotXMLAttributes。我们将绘制自行车的等待时间。实际上是行程的等待时间。所以我将选择递归信息文件(recursion info file)。我将选择我想相互对照绘制的属性。所以我们会看到我的想法。让我们在 X 轴上放上出发时间(departure time),在 Y 轴上放上 waitingTime,也就是偏差很大的那个。好的。至少在这个版本中,你仍然需要点击这个复选框,在下一个版本中它将默认选中。现在我们看到的是这个。老实说,这有点难读。我们看到这些线的原因是数据点按 ID 分组,每辆自行车在模拟中出现了两次,一次是在去 DLR 的行程中。另一次是在返回的行程中。默认情况下,这些数据点是用线连接的。所以让我们回去。把它变成散点图(scatterplot)。这样会清晰得多。所以我们现在有这个,我们清楚地看到模拟中的两个不同阶段,现在我们可以开始理解发生了什么。所以在模拟的第一部分,我们有所有这些自行车这个人流。
正如我们所说,我们设置它运行 1000 秒,并以随机间距开始,出发时间随时间分散。所以几乎在它们想开始的时候就开始,它们不需要花太长时间。但在返程中,我们设置会议在固定时间结束,所以不管人什么时候想骑,会议对所有人来说都在同一时间结束。所以他们都想在同一时间回到火车站,但仍然没有足够的道路空间,所以最后一个上路的人,或者女人,他们必须等很长时间才能在路上找到空间,这就是为什么在模拟的这两个阶段之间,行程开始前的等待时间如此不同,我认为这真的需要一张图才能理解,从原始数据中很难看出来。好的,所以这已经得到了令人满意的解释,让我们再看看模拟的运行情况,所以我们再次回去,这次绘制 timeLoss,毕竟这是评估交通场景效率的一个非常常见的统计数据。嗯,我们再次看到模拟中的这两个阶段,但在后半段,我们清楚地看到有比开始时多得多的 timeLoss,为什么会这样?我的意思是,一旦他们上了路,实际上路上有空间,他们应该和另一条路一样快。所以这是无法解释的。用最好的点击诱饵方式,这个问题的答案会让你惊讶。所以请继续关注...
好的。所以接下来我们要做的是,为了更深入地了解这里发生了什么,是看一些空间性能指标。我们要回到边数据。所以在模拟的不同边上损失了多少时间。你可以做的一件事是在模拟完成后,直接将边数据加载到你的模拟中。所以让我们再次启动模拟。这里有个小技巧。我使用 sumo 配置来启动网络并查看它。但我启动的是这个配置文件,而我是用另一个配置运行模拟的。所以看看区别。一个配置定义了所有输出,而另一个配置,恰当地命名为 "no_output",没有所有这些输出文件的定义。否则,仅仅再次启动这个配置,我就会开始重写输出文件,所有我已经记录的数据都会被覆盖。现在,这不是我想要的,所以我准备了另一个配置来方便地启动这个。现在我可以做的是,我可以将边数据加载到我的模拟中。你从这里得到的只是其中所有属性的摘要。它说数据在时间零和时间 30,000 之间。它加载了诸如 ride 和 waiting 之类的属性。字太小你看不清。尽管如此,它会在那里。现在为了利用这个,我们将重新给行(rows)上色。
我们将按边数据(edgeData)重新给它们上色。现在我们将按边数据重新给行上色。然后我们必须选择我们想要上色的属性。我们将选择 timeLoss。然后我们需要一个配色方案。所以一种方法是从加载的数据中自动构建它。抱歉,我知道彩虹对于科学数据来说不是合适的配色比例。已经有很多论文和报告讨论过这个问题。我日程上也明确写着要改变这个。但现在你只能将就使用彩虹。抱歉。所以现在我们有一个图例,告诉我们这些值的含义。红色是低端,紫色是高端,我们可以看这些值,非常清楚地看到这条自行车道有所有的等待时间。如果我们不相信自己的眼睛看颜色,我们当然可以看数字。一种方法是直接在相应的边上右键单击。然后我们在属性框里有颜色值,但这可行,但我们有更好的方法。我们可以勾选这个框“显示边颜色值”。然后我们在这里就有了所有的值。如果颜色和字体重叠,我们还可以设置背景。然后它就更易读了。所以现在你可以绝对确定这里的数字比其他的要大。所以这给了我们一个明确的指示,我们应该在模拟运行时看看那一部分。所以让我们这样做。嗯,实际上,既然我们已经打开了模拟,为什么不现在就做呢?让我们快进到它们再次出发的部分。所以,哦,是的,差不多就是现在。好的。所以当然,另一种看模拟的方法是,例如,按速度给车辆上色。然后我们也可以得到一个印象,即在这个区域有很多红色的车辆。实际上,让我们回到边的陈述,看看我们到底想看哪条边。这是我们想看的路。现在在模拟移动时看它。这是第一部分,所有东西都在往南走,可以这么说。现在第二部分。好的,所以我们在这里看到的是,自行车必须在红灯前等很长时间。为什么会这样?让我们看看那个信号灯。右键单击这里。然后“显示相位”(Show Phases)。这是基本布局。现在时间在横轴上,纵轴上是交通灯切换的所有不同灯。要真正看到哪些灯,这些水平线中我们想看哪条,我们必须显示这些数字。这是链接 TLS 索引(link TLS index)。现在对于每条交通流,我们这里有一个数字。现在有点不幸的是,这些数字太大了。它们本来更小,我们就能看到发生了什么。所以 15、16、17、18 都是这里的链接。15 是右转。16 是直行。17 是左转。18 是掉头。如果你不确定哪个是哪个,你总是可以禁用路口本身的渲染。Ctrl + J。并简单地右键单击这些内部边。所以你看到了。这是末尾带 15 的那个。这是末尾带 16 的那个。这是自行车想去的地方。所以回到这个。15 在这里。16。这是自行车必须使用的那个。现在如果我们看它们一开始的情况,走这条路是数字一。0。1 直行。所以你已经可以看到,总的来说,这个计划有两个绿灯相位。而 16 只有一个绿灯相位。所以无论何时生成信号时间,这里都有一些不对称。确切的原因,如果你想了解,是这里的自行车道是道路的一部分。出去的自行车道也是道路的一部分。
所有进入那里的边都有一些不对称。主要是关于轨道,它打破了这个路口的对称性。所以无论如何,为复杂的多式联运路口生成信号计划有点,嗯,很困难,所以 SUMO 给你的计划会有一些伪影,在这种情况下,它在走这条路和那条路之间有这种不对称,所以这是为什么返回火车站的自行车收集更多等待时间的原因之一,但这里还有更微妙的事情在发生,所以我们必须看一会儿模拟,慢慢看,看看发生了什么。你能看到吗?这里路上有一些绿灯,但自行车没有开动,正如我提到的,17 和 18 是影响左转和掉头的灯,自行车不想用,他们想直行,但直行他们没有绿灯,他们有红灯,而现在交通感应说,嗯,我们在这里检测到交通,可能它想左转,所以让我们保持绿灯相位开放,这实际上就是一开始警告的内容。它是哦,我不确定是否可以使用检测器,我真的不确定如果检测器上有一辆自行车意味着什么。然后我们在 sumo 配置文件中设置了这个选项,说嗯,忽略这个,如果检测器在 30 秒后堵塞,就直接切换到另一个相位。所以好消息是,这个左转相位不会持续最大可能的持续时间,在这种情况下是 50 秒,30 秒后它检测到有问题就切换了,但在这 30 秒内,我们有一个绿灯,但没人开。所以这是一个你在感应式交通灯中可能遇到的问题,这是这里相当高级的东西,但请记住,这可能发生在你的场景中。这就是为什么这两个图看起来如此不同的谜底。嗯,我想这里的寓意是,微观模拟有很多细节,如果你有很多细节,你就有很大的机会把事情搞错。
使用多个种子运行模拟#
好的,但在一个更愉快的基调上,让我们做一些花哨的事情,一些我们在教程中从未讨论过的事情:让我们不仅运行模拟一次,而是多次运行,你当然应该总是这样做,我们一直告诉你要这样做,但我们没有真正给你工具来让这变得舒适,你总是必须自己编写脚本来多次运行模拟。现在对于那些仍然需要一些动力来解释为什么你甚至想多次运行模拟的人,如果你有你的 sumo 配置,你运行它不是一次而是两次,基本上不会有区别,它会给你完全相同的模拟,这是因为有一个随机种子,所谓的随机种子,这是一个初始化随机数生成器的值,如果你使用相同的值,相同的随机数每次都会出现,模拟将以完全相同的方式运行,但通常我们希望使用不同的初始值、不同的随机种子运行,然后看看随机性如何影响场景。这是多次运行的原因之一,第二个原因可能是你有同一场景的不同变体,也许你有一些想要改变的参数,然后你想用该参数的不同版本运行你的场景,我们将同时做这两件事,我们将让刚刚定义的模拟使用不同的种子运行多次,然后我们还要关闭子车道模型,记得那是让自行车并排行驶的东西,我们将关闭这个并也运行这个模型,而且它不会更慢,因为我们会让它们并行运行。
那么这是如何工作的呢?所以让我们进入教程的最终文件夹,现在这里有一个小难点,我必须确保我在这个文件夹中启动 netedit,因为在当前版本中,该工具要求工作目录设置为所有配置文件所在的文件夹,这是初始化工作目录的一种方式。好的,所以我现在要使用工具 runSeeds。我选择我要运行的配置文件,所以现在通过点击这个小锤子按钮,我切换到工作目录,我想要 sumo 配置文件,所以我必须在这里切换到“所有文件”(下一个版本将为文件文件夹有一个更智能的预选),所以我将选择这两个配置文件,我选择种子的数量,我们不要 10 个,而是 0, 1, 2, 3,让我们按一下运行这个,就这样。所以现在这在后台运行八个模拟,大概使用了我所有的核心,现在你还会看到,如果你改变随机性,有时也许模拟会有不同的行为,实际上今年发现了一个在特定种子下自行车行为的问题,模拟中有一个碰撞,这当然是我在教程后会研究的事情,但现在我可以关闭这个,我得到了什么?runSeeds 工具生成了两个文件夹,每个配置文件一个,在每个文件夹中我有多个版本的输出文件,它们都以随机种子为前缀,记得我使用了随机种子 0 到 4,所以它们以 0、1、2 和 3 为前缀,也就是四次运行。嗯,这很快,不是吗?所以一个简单的方法来拥有所有这些不同的运行,现在当然我们需要做一些分析,所以让我们绘制 timeLoss,我们已经看过了绘图工具,这次我们将使用一些花哨的属性。再次,我们希望 timeLoss 在 Y 轴上,但现在在 X 轴上我们做一个排名,所以基本上每个 timeLoss 数据点,在这些 tripinfo 输出文件中的每一个,都将是图中的一个点,我们将按它们的 timeLoss 值沿 X 轴排序。让我们看看效果如何。而且我们也不关心车辆的 ID,相反,我们想按文件名分组,我们想比较不同的运行。所以这就是为什么我们有这个特殊的值 @RANK 和前缀魔法属性。好的。那么,一次选择所有这些文件的好方法是什么?你可以做 Ctrl+点击来找到它们全部。或者我可以按大小排序。这样它们就会靠在一起。我可以做 Shift+点击。现在 UI 中不幸的是,我们目前无法轻松地从多个文件夹中收集文件。runSeeds 工具的下一个版本实际上有一个选项,可以把所有东西放在一个文件夹里,以使这更方便。现在我要做一些复制粘贴。所以我将从第一个文件夹复制所有文件。然后我选择第二个文件夹中的所有文件。然后我粘贴我刚刚复制的内容。这不太好,但不会一直这样。现在排名,timeLoss,没有 ID。让我们开始。啊,是的。我忘了这个复选框。别担心,下一个版本不需要复选框。现在就这样。我们加载的每个文件都给我们一条线,我们看到场景变化很大。我们还看到有两组线。现在,我会回来的。你已经可以猜到哪组线对应哪个配置文件,我猜。那么,谁想猜猜?好的,所以 timeLoss 低的那组,是带子车道模型的那个。另一组 timeLoss 高的,是我们关掉子车道模型的那组。因为那时道路上的容量甚至更低,当然就没有 timeLoss 了。但如果我们想确认,我们可以回去打开图例。现在,看到带 2 的线来自第二个配置文件,这些是上面的那组。排名图只是对它们排序,给你一个更好的视觉印象。你能看到的是,线离 x 轴的距离不同。这意味着什么?每个数据点来自一辆自行车。我们只是把它们全部放在一起,沿着 X 轴排序。所以不同的线意味着不同的场景有不同数量的自行车,这是可以预料的,因为我们以非常随机的方式定义了交通,我们使用了这个泊松流,它随机化了从一辆自行车到下一辆的时间。所以在 1000 秒的范围内,我们将有不同的间距,这可能导致场景中不同数量的交通,在范围内,也许不是很高,但增加了一些分布。现在,当然,这对场景有很大的影响,因为它们会相互作用,如果你有更多,那么很可能会经历更多的 timeLoss。所以我认为这是一个查看多次运行的绝妙方式。这个绘图工具给你很多选项,可以从 sumo 文件中得到各种各样的图。你可以在文档中找到更多关于这个工具能做什么的例子。条形图,直方图,仅举几例。而且对于 sumo 给出的每个输出文件,现在在文档中都有一个绘图示例,激励你以新的方式看待这些枯燥的 XML 文件。所以这就是我今天想展示给你们的。就此,我结束我的教程。
所以使用 netedit,不仅是为了编辑你的网络,也是为了发现 sumo 拥有的所有这些 Python 工具。我认为现在有 60 个工具可以从那个菜单中获得。我们甚至还没有链接我们拥有的所有工具。所以还有更多即将到来。当然,每个教程都需要以承认使用 osmWebWizard 来结束。所以去吧。和往常一样,在你提问之前,阅读文档。但如果你在文档中找不到任何东西,那就给我们发个邮件,在邮件列表上和我们交流。我们一直在寻找项目合作伙伴。我的部分就到这里。谢谢大家的关注。
其他会议教程#
看看我们的其他会议教程,这里。
