这很容易。这只是一些基本的数学。把它分成两部分:
- 找到你的水平位置(没有高度)。
要找到您的位置,您需要三点,但只需关注两点一秒钟。通过使用两点,您可以与自己创建一个三角形,并根据您在两点之间的信号强度找到您的位置。这将找出您在两个路由器之间的位置。例如,如果您在路由器 3 和 4 之间,与 3 相比,您的信号强度为 -89,与 4 相比,您的信号强度为 -54,您知道您与 3 相比,与 4 相比更接近。如果您对距离与信号强度进行近似,您可以得出一个非常准确的读数,即您在路由器 3 和 4 之间的位置。剩下的问题是确定您在 3 和 4 之间的哪一侧,因为您可以在路由器上方或下方具有相同的信号强度值(-89、-54)(看图表)
6
You could be here
3--------------------------4
You could also be here
5
然后只需找到另一个路由器,并注意您的信号强度。只需查看 5 和 6 个路由器之间的信号强度关系(在图中),您应该能够很容易地确定您在哪一边。
- 你可以对高度做同样的事情。
要完成上述所有操作,您实际上只需要距离与信号强度的近似值,以及路由器之间的距离。根据我的测试(我编写了自己的 Wi-Fi 三角测量代码),移动设备之间的信号强度非常一致,因此一台设备应该与旁边的设备具有相同的结果。
我认为Skyhook要么通过 GPS 定位(可能是硬编码),要么与此原理基本相同。Skyhook 是 Apple 批准的唯一服务,因此 Apple 基本上做了同样的事情,然后确保其他应用程序无法使用它(任何使用包含这些功能的受限802.11库的 iPhone 应用程序都将被App Store拒绝)。
如何找到距离:
你需要做一些简单的近似。根据您的环境,这些近似值并不完全相同,因此 -89 英尺 (27 m) 可能意味着您距离路由器 3 15 英尺 (4.5 m),但距离路由器 4 -89 英尺 (27 m) 可能意味着您在 13 英尺 (4 m) 之外。无论您做什么,这都不会 100% 准确,但这没关系,因为您肯定可以在 5 英尺 (1.5 m) 以内。
所以你要做的就是找到一堆点,你从路由器 3 获得 -89 的读数,然后记下你的距离。然后,你取一个平均值,然后用这个平均值记入你的数据库(当你从路由器 3 到 -89 时,你是 15 英尺(4.5 m))。然后,您对其他值执行此操作,例如 -50 或其他值,然后记下您的值并找到平均值。现在,如果 -89 表示您在 15 英尺 (4.5 m) 之外,而 -50 表示您在 25 英尺 (4.5 m) 之外(只是一个示例),那么当您距离 -75 时,您必须估算您的距离路由器 3 除非您想手动获得 -75 的近似值。这对于大量的值来说会很麻烦,但是您必须进行试验以查看使用尽可能少的数据点可以获得的准确度。
通过意识到信号强度是对数的,您可以在两个信号强度平均值之间进行近似,因此您可以估计由于 -89 是 15 英尺(4.5 m),那么 -75 将是对数(以 10 为底或以 2 为底,我不记得了,但我倾向于以 10) 为底,比 -89 远 14/100。
求代码
我在某处有代码,但那是几年前的事了,所以我必须翻阅很多东西才能找到它。我认为从概念上讲,它应该很容易在没有代码的情况下复制。对于我正在测试的安卓设备,我花了大约 50 行 Java 代码。
基本上我拿了一部安卓手机并创建了一个应用程序,它允许我随时显示连接的 Wi-Fi 设备的当前 ID、其信号强度、其他附近的 Wi-Fi ID 及其信号强度,然后是 GPS 位置。这一切都可以通过 Android 的 API 访问。我认为您需要 API 4 或更高版本的 Android 设备。这就像三四年前的事,所以我只是把它从我记得的东西中扔掉。
GPS定位部分是为了使物理强度和Wi-Fi强度之间的映射更容易,而不是必须以其他方式创建我的设施的蓝图,我可以让谷歌地图同时为我做这件事,因为我在创建距离图的同时,基本上可以覆盖他们的地图和 GPS 坐标。不过,您仍然需要一个深度图来绘制楼层平面图,我们可以通过查找您是否在两个路由器中间轻松地手动完成。
我们知道同一楼层的 Wi-Fi 集线器的信号强度最强,然后可以通过确保不同楼层的 Wi-Fi 集线器的信号较弱来仔细检查。此深度图本质上是 Wi-Fi 集线器及其各自楼层的列表。
我们不需要他们的位置,因为我们可以将信号强度与我们在设施周围走动并抓取某些集线器的信号强度时抓取的 GPS 位置进行最佳匹配。这是一些简单的数学运算。所以对于 2D 平面位置,从顶部向下看,我们有一堆像这样的对象:
BestFitObject{
Tuple<long, long> GPSLocation;
List<Tuple<WifiDevice, signedInt>> WifiReadings; //WifiDeviceName(through UUID or some other way), tupled with the signalStrength when that bestFit reading was taken
}
WifiDevice{
UUID ID; // Think a string should work fine, might be an internal type that encompasses UUID which would be better.
int floorNumber;
Tuple<long, long> GPSLocation; // Not entirely necessary, could provide better accuracy though
}
然后,当我们 ping 客户端设备并希望最适合它时,它会返回一个像这样的对象:
ClientPosition{
List<Tuple<UUID, signedIt> NearbySignals; // Tuple of the UUID of the Wi-Fi device and the signal strength taken during the time of the ping.
}
然后,我们可以轻松地将 ClientPosition 最适合我们使用上述两个对象创建的 2D 地图。
以上很简单,我认为深度图更简单。
理想情况下,您应该尝试使用包含几种不同无线技术(一些 a 设备、一些 b 设备、n、g 等)的几个不同设备,以获得更准确的结果。但我发现,准确度并不是什么大不了的事,你会在 5 英尺(1.5 m)左右的范围内。这对我的需要来说已经足够准确了。理想情况下,所有 Wi-Fi 集线器都是同一型号,它们通常位于大型设施/公司中,但即便如此,也没什么大不了的。可变性是如此之小,如果您不需要疯狂的准确性,那也没关系。