Soundscape 背后的技术

本页面旨在让您对 Soundscape 应用在底层是如何工作的有一个大致的了解。您无需阅读本页面即可使用该应用,但编写它有以下几个原因:

  1. 帮助任何对该应用感兴趣的新用户了解其局限性所在
  2. 让用户了解通过新功能还能实现哪些可能
  3. 为开发者提供该应用功能的概览

有两项技术使该应用成为可能:GPS 和 OpenStreetMap 数据。GPS 能让我们很好地了解手机所在的位置以及它去过的地方。然后可以利用 OpenStreetMap 数据来查找附近有什么,并将其描述给用户。

音频信标

在大多数方面,从技术角度来看,这些是最简单实现的东西。假设我们已知手机位置和手机的方向,我们就可以改变信标的音频,使其听起来像是来自那个方向。我们使用来自 Steam Audio 的一个库来执行音频定位,它利用头部相关传递函数(HRTF)来提供尽可能好的定位音效。我们做的唯一另一件事,就是改变信标音频,使得根据用户方向与信标位置之间的角度播放不同的声音。这些角度因所选信标(Tactile、Flare、Ping 等)而异,有些信标的声音数量比其他的更多。这就是最简单层面上的音频信标。

唯一额外的复杂性在于对手机位置和用户所朝方向的假设。让我们依次来看这两点。

位置

GPS 返回的位置可能存在相当大的误差,这取决于手机 GPS 能看到多少天空,以及在信号传到手机的过程中有多少树木和高楼在反射 GPS 信号。

我们对位置进行过滤所采用的方法被称为地图匹配。它假设用户最有可能沿着已绘制在地图上的路径或道路行进——我们使用术语“路径(Way)”来涵盖所有道路、小道和路径。地图匹配会查看用户去过的地方,并结合移动方向和本地地图数据,挑选出用户在某条路径上最可能所处的位置。这种方法不仅能消除 GPS 的误差,还能消除地图数据中的误差。并非所有路径都被精确绘制,因此它们也存在误差。为了确定用户最可能所在的路径,该算法会考虑:

  • 某条路径与 GPS 位置以及之前 GPS 位置的接近程度
  • 行进方向——他们是否朝着与该路径相同的方向移动
  • 是否有可能通过路径网络从上一个地图匹配的位置到达新位置。这是为了排除在实际并不相连的路径之间切换的情况,例如一条路通过桥梁从另一条路上方经过,或通过隧道从其下方经过。 地图匹配可能会判断附近没有路径,或者它无法确定用户在哪条路径上,在这种情况下,它会直接等待下一个 GPS 位置并再次尝试,直到它有把握为止。

方向

我们在软件中跟踪几种方向:

  1. 手机所指向的方向。当手机解锁且应用正在使用时,我们会使用这个方向;此外,只要手机平放且屏幕朝向天空,即使手机锁定时也会使用它。在把手机放进包里时记住这一点很有用。如果手机平放在直立放置的包的底部,那么应用会使用您的包所朝向的随机方向。
  2. 手机正在行进的方向。
  3. 来自带头部跟踪功能耳机的方向。我们目前尚未使用它,尽管 iOS 应用确实支持过。我们已经具备相应的技术,可以在未来添加它。

当手机锁定并放在包里时,应用将使用行进方向。然而,如果用户没有移动,则无法获得任何方向。当这种情况发生时,音频信标会变得更安静,以表明无法得知信标当前的方向——用户可能在原地转身而位置没有改变。

对于应用中某些方向的用途,方向会被“吸附”到地图匹配路径的方向上,因此如果用户大致沿着该路径的方向行走,那么就会假定该路径的实际方向是正确的,并在这些计算中加以使用。

结论

尽管表面上看音频信标很简单,但使用地图匹配来尝试消除位置和方向误差却带来了相当大的复杂性。

地图数据

应用使用的地图数据几乎全部来源于 OpenStreetMap 项目。我们运行着一台服务器,其中包含一份多种缩放级别的全球地图。每个缩放级别都被分割成多个瓦片。缩放级别 0 包含 1 个瓦片,级别 1 包含 4 个瓦片,级别 2 包含 16 个瓦片,依此类推,直到级别 14,它包含约 2.68 亿个瓦片以覆盖整个地球。每个瓦片包含多个图层,每个图层都有点、线和多边形,可以绘制出一张图形地图。这张图形地图就是在应用 GUI 中向用户展示的内容。每个点、线和多边形都有描述其是什么的元数据。这大多直接来自 OpenStreetMap 数据,因此一条线可能是属于 sidewalk(人行道)的 footway(人行步道),或者是属于 minor(次要)的 road(道路)。

数据通过一种“样式”转换成图形地图,该样式包含如何绘制每个图层中不同的点、线和多边形的规则,例如如何绘制一条路径、如何绘制一片森林、如何绘制一个公交站。这些规则可以因缩放级别而异,这就是为什么当您放大时,会有越来越多在缩小时看不到的点和线变得可见,例如公交站和路径。

通过改变样式,我们可以改变 GUI 地图的外观,这就是我们正在试验的“无障碍地图”的由来。它旨在拥有更高的对比度以及更粗的线条和文字。这种样式内置于应用中,所以我们无需更改服务器上的地图就能改变它的外观。

但我们是如何将地图数据用于音频的呢?

将地图数据用于音频

我们目前只使用相对少量的地图数据来生成音频用户界面。几乎所有的音频 UI 都只使用最大缩放级别的瓦片。应用会将用户周围的 2×2 瓦片网格拼接在一起,然后只查看其中的几个图层:

  • transportation - 用于所有类型的路径,包括道路、路径、铁路和有轨电车线路。
  • poi - 兴趣点,例如商店、运动中心、长椅、邮筒、公交站等。
  • building - 用于那些不仅仅被绘制为一个点的 poi,例如大型超市或市政厅。

它会跨越瓦片边界连接线和多边形,并将所有路径转化为相互连接的路径段和路口。这一点很重要,因为它使我们能够沿着一条路径进行搜索,从而了解我们能到达哪里。

所有解析后的数据也被放入一种易于搜索的格式中,以便应用能够轻松找到地图上附近有哪些要素。此时,数据被分类为不同的类别。当前的类别包括:

  • 道路
  • 道路和路径(所有路径)
  • 路口 - 路径相交的点
  • 入口 - 这些是建筑物上被标记为入口的点。
  • 人行横道 - 道路上的过街通道
  • 兴趣点 - 所有兴趣点
  • 公交站点 - 公交站、火车站、有轨电车站等等。
  • 兴趣点的子类别:
    • 信息
    • 物体
    • 场所
    • 地标
    • 出行
    • 安全
  • 聚居地及其子类别(见下一节)
    • 城市
    • 城镇
    • 村庄
    • 小村落

有了这些之后,对于任何位置,应用都可以轻松找到

  • “50 米内的所有公交站点”,或者
  • “我前方最近的路口”,或者
  • “最近的小村落、村庄、城镇或城市”

有了这些之后,创建音频播报就只是根据当前位置和方向查询数据的问题了。当用户在瓦片网格中移动时,应用会更新网格,使其以当前位置为中心。

更多数据

我们这种非常本地化的地图数据网格的问题之一在于,它意味着我们在任何方向上最多只能“看到”大约 1 公里。当我们描述前方有什么时,这没问题,但有时我们希望提供更多背景信息。这方面的主要例子是当应用被使用而用户并未步行时。

当应用检测到用户的行进速度超过每秒 5 米时,它会切换描述世界的方式。它不再播报每一个路口和兴趣点,而是减少播报频率,且只播报附近的道路。这样做的问题在于,如果您不知道某条道路在哪个城镇,那么知道道路名称也不太有用。

为了解决这个问题,我们现在也会在较低的缩放级别解析地图数据,并从 place 图层提取数据。该图层包含城镇、城市、街区、村庄等的名称。绘制这些事物的一个问题是,这些地点之间并不总有明显的边界。OpenStreetMap 的数据库中有时会有城市边界,但即便如此,当这些信息进入我们的瓦片地图时,往往也会丢失。我们所拥有的是这些地名在地图上被绘制的位置。这些位置会被分类,然后应用会找到离用户最近的小村落、村庄、城镇或城市并予以报告。

对于许多城市,实际的城市名称永远不会被播报,因为大多数城市被划分为更小的区域,比如街区,但那些区域确实提供了非常有用的额外背景信息。只需记住,因为应用报告您靠近某个特定街区的一条街道,这仅仅意味着该街区的标签是最近的点,它可能不正确,甚至可能在一条河的对岸。

更多背景信息

在描述中能添加的背景信息越多越好,只要保持简洁且可预测。我们在描述路口时遇到的一个问题是,常常会涉及“未命名”的路径。这些路径没有名称。在地图数据中,它们可能只是一条小道、一条路径或一条服务道路,但若没有更多背景信息,它在文字描述中就不太有用。幸运的是,我们可以做得更好,所以应用所做的就是:每当它即将播报一条未命名路径时,它会看看能否为它推断出更多背景信息。

  • 它是人行道吗? 现在 OpenStreetMap 中很多区域都将人行道与道路分开绘制了。这些通常被标记为 sidewalk,但它们通常不会说明它们是哪条道路的人行道。

    当应用遇到一条未命名的人行道时,它会搜索一条它认为与之并行的道路,并用它来为该人行道命名。事实证明这对我们的播报非常重要。我们不再播报每一个人行道路口,而是当我们沿着人行道行进时,播报内容就如同我们沿着相关联的道路行进一样。我们不会说“沿路径向西行进”,而是说“沿 Moor Road 向西行进”。用户走在已绘制的人行道上,但这样的描述更合理。

  • 它的终点是一条已命名的路径吗? 很多时候有连接两条道路的人行路径。通过查看路径的两端,我们可以轻松地添加该背景信息,因此在一个方向上它可能是“通往 Moor Road 的路径”,而从另一端接近时它可能是“通往 Roselea Drive 的路径”。只有在路径不分岔的情况下才会这样做,如果它分岔成两条未命名的路径,那么我们就不会尝试添加此背景信息。

  • 它的终点靠近一个标记点吗? 如果一条未命名路径的起点或终点靠近某个标记点,则会用它来描述该路径,例如“通往大树路口的路径”。用户可以随心所欲地添加标记点,通过沿着路径网络添加标记点,他们可以为整条路线增添背景信息。

  • 它进入或离开一个兴趣点吗? 如果一条未命名路径起始于一个兴趣点之外并终止于其内部(或反之),那么我们就可以添加该背景信息,例如“通往 Lennox Park 的小道”。

  • 它的终点靠近一个入口吗? 如果一条未命名路径的起点或终点更靠近某个入口,那么我们就可以添加该背景信息,例如“通往 Best Buy 的服务道路”。

  • 它的终点靠近一个地标或场所吗? 如果一条未命名路径的起点或终点更靠近某个地标,那么我们也可以添加该背景信息,例如“通往 St. Giles Cathedral 的服务道路”。

  • 它是死胡同吗? 应用会将任何不通往任何地方的未命名路径标记为死胡同。

  • 它经过任何台阶吗? 如果未命名路径经过一座桥、穿过一条隧道或上/下台阶,那么这一点会被记录下来并添加到背景信息中。这与目的地标记是分开的,因此可以有诸如“经桥通往 Lennox Park 的路径”这样的背景信息。

这些背景信息是按顺序添加的,因此一个方向上可能是“经台阶通往 Park Lane 的路径”,而另一个方向上是“经台阶通往 Lennox Park 的路径”。离开公园时已命名的街道获得优先权,而进入公园时则使用公园名称。

未来的背景信息

我们希望在未来添加各种额外的背景信息,包括:

  • 为沿着线性水体特征延伸的路径添加背景信息,例如“River Dee 旁的路径”
  • 为沿着水体边缘延伸的路径添加背景信息,例如“Milngavie 水库旁的路径”
  • 为沿着铁路延伸的路径添加背景信息,例如“铁路旁的路径”。这甚至可以包括铁路线的名称
  • 为桥梁和隧道添加额外内容,说明它们跨越或穿过什么,例如“经跨铁路桥通往 Moor Road 的路径”

音频播报

既然我们已经有了易于使用的格式的地图数据,那么生成播报实际上就相当简单了。

步行时的播报

步行时,可能发生的音频播报有(按优先级排序):

  1. 描述当前目的地有多远
  2. 描述即将到来的路口
  3. 描述最近的 5 个兴趣点

所有播报都进行了频率限制,以免它们重复得太频繁。如果用户停止移动,播报就会停止,即使在移动时,播报也不会在每个新的 GPS 位置上都重复。与 iOS 应用一致的频率为:

  • 当前目的地每 60 秒一次
  • 即将到来的路口每 30 秒一次
  • 兴趣点每 60 秒一次

播报可以通过设置菜单进行筛选,而且这一行为肯定还有扩展的空间。

行进速度较快时的播报

当行进速度超过每秒 5 米时,对当前目的地的播报仍会进行,但路口和兴趣点的播报会被一条大致描述用户所在位置的播报所取代。这会给出一个附近的公交站点、一个将我们包含在内的兴趣点(例如在一个大型公园内部),或者一条附近的道路和聚居地。这些都使用了前面描述过的数据,而且未来显然有允许对此进行自定义的空间。

标记点与路线

在很大程度上,标记点和路线只是一项既不依赖 GPS 也不真正依赖地图数据的用户界面功能。标记点是用户想要存储的已命名位置,而路线是这些标记点的有序列表。创建两者的用户界面都直接取自 iOS 版本。

路线播放

路线播放是路线真正发挥作用的地方。当播放一条路线时,会在路线中的第一个标记点处创建一个音频信标。一旦用户靠近该标记点,路线就会自动将音频信标移动到路线中的下一个标记点。如果没有更多标记点了,那么路线播放就结束。

结论

希望这能让您对应用如何运作有所了解。该应用始终在根据用户反馈不断发展,所以如果您认为有任何可以添加的内容,请与我们联系。


This site uses Just the Docs, a documentation theme for Jekyll.