iBeacons的三角剖分示例


75

我正在研究使用多个iBeacon进行“粗略”室内位置定位的可能性。该应用程序是一种“博物馆”设置,并且能够形成一个网格,该网格具有用于放置不同对象的位置的网格,而不是形成单个信标的网格(尽管这可能也不是不可能的)。

是否存在使用多个信标将其划分为某种位置的示例或经验,或者有一些逻辑可以帮助我自行编写代码?


5
查看我的演示:youtube.com/watch?v=dMWEl6GBGqk。在评论中,您会找到Jakub Krzych的回复,他的公司生产了我正在使用的信标。
Konrad Dzwinel 2013年

谢谢,这非常有用。如果Estimote打算发布API,那么我可能会等着看它是如何工作的,而不是亲自研究数学,而是尝试找到一种方法来动态地校正和纠正注释中建议的信标。
Luuk D. Jansen 2013年

@ LuukD.Jansen我也在看这个...有什么消息吗?
莱昂纳多·

我一直无法进一步调查。我认为三角剖分将无法在我需要的比例尺(地板空间)上足够精确。它会更容易/便宜,对所有重要场所的灯塔
Luuk D.扬森

Answers:


74

我一直在做一些实验,以使用三个信标获得精确的位置。

三边测量结果

不幸的是,结果在质量方面令人非常失望。主要有两个问题:

  1. 在不受控制的环境中,您会发现金属和其他会影响信号的物体,信标的接收信号强度经常变化,因此似乎无法获得5米以下的误差范围。
  2. 根据用户处理接收器设备的方式,读数也会发生很大变化。如果用户将他/她的手放在蓝牙天线上,则该算法将以低信号作为输入,因此信标将被认为距离设备很远。请参阅此图像以查看蓝牙天线的精确位置。

可能的解决方案

与一位积极劝阻我采用这种方式的苹果工程师交谈后,我现在更倾向于使用的选择是蛮力。尝试每隔X米设置一个信标(X是系统中允许的最大误差),因此我们可以通过计算网格上哪个信标最接近该设备并假设该信标在该信标网格上跟踪给定设备的位置。设备在同一位置。

三边测量算法

但是,出于完整性考虑,我在下面介绍了三边测量算法的核心功能。它基于的第3款(“三个距离称为”)这篇文章

- (CGPoint)getCoordinateWithBeaconA:(CGPoint)a beaconB:(CGPoint)b beaconC:(CGPoint)c distanceA:(CGFloat)dA distanceB:(CGFloat)dB distanceC:(CGFloat)dC {
    CGFloat W, Z, x, y, y2;
    W = dA*dA - dB*dB - a.x*a.x - a.y*a.y + b.x*b.x + b.y*b.y;
    Z = dB*dB - dC*dC - b.x*b.x - b.y*b.y + c.x*c.x + c.y*c.y;

    x = (W*(c.y-b.y) - Z*(b.y-a.y)) / (2 * ((b.x-a.x)*(c.y-b.y) - (c.x-b.x)*(b.y-a.y)));
    y = (W - 2*x*(b.x-a.x)) / (2*(b.y-a.y));
    //y2 is a second measure of y to mitigate errors
    y2 = (Z - 2*x*(c.x-b.x)) / (2*(c.y-b.y));

    y = (y + y2) / 2;
    return CGPointMake(x, y);
}

2
对于我的y值,我似乎总是会得到NaN或Inf +。您在开发算法时遇到过这种情况吗?
Yazid 2014年

不,我没有这个问题。确保所有输入参数都已缩放到您的UIView坐标系中。例如,如果您正在跟踪一个10×10米的空间,并绘制成一个500x500像素的UIView,那么你需要乘以标由50测试的实际位置和距离
哈维尔Chávarri

8
我发现y的公式有时会中断,特别是当点a和b具有相同的y坐标时。它是/ (2*(b.y-a.y))产生0,然后除以零误差的部分。
Yazid 2014年

1
这确实帮助了我很多。我将此方法转换为Java,效果很好。正如我们所说的那样使用它。
丹尼斯·安德森

1
我同意这个等式不起作用。信标设置为1.5mx2.5m,我的uiview为300x500。根据您的乘数,我的xy出现在4k像素区域中
jdog

22

这是一个将执行trilateration / multilateration的开源Java库:https : //github.com/lemmingapex/Trilateration

例

它使用来自Apache Commons Math的流行的非线性最小二乘法优化器Levenberg-Marquardt算法。

double[][] positions = new double[][] { { 5.0, -6.0 }, { 13.0, -15.0 }, { 21.0, -3.0 }, { 12.42, -21.2 } };
double[] distances = new double[] { 8.06, 13.97, 23.32, 15.31 };

NonLinearLeastSquaresSolver solver = new NonLinearLeastSquaresSolver(new TrilaterationFunction(positions, distances), new LevenbergMarquardtOptimizer());
Optimum optimum = solver.solve();

// the answer
double[] calculatedPosition = optimum.getPoint().toArray();

// error and geometry information
RealVector standardDeviation = optimum.getSigma(0);
RealMatrix covarianceMatrix = optimum.getCovariances(0);

大多数学术示例,例如Wikipedia上的示例,都恰好处理了三个圆圈并假定了完全准确的信息。这些情况允许使用更简单的问题公式来给出准确的答案,并且通常对于实际情况并不令人满意。

R 2或R 3中的问题欧氏空间中的距离问题包含测量误差,通常会获得感兴趣的面积(椭圆)或体积(椭圆体)而不是点的问题。如果需要点估计而不是区域估计,则应使用面积质心或体积质心。R 2空间至少需要3个简并点和距离才能获得唯一区域;R 3空间至少需要4个简并点和距离才能获得唯一区域。


15

我看着这个。您想要的术语三边测量。(在三角测量中,您与3个已知点之间存在角度。在三角测量中,您与3个已知点之间存在距离)。如果您使用Google,则应该在Wiki上找到几篇文章,其中一篇。它涉及求解3个联立方程组。我看到的文档用于3D三边测量-2D更加容易,因为您可以删除Z项。

我发现的是抽象数学。我还没有花时间将通用算法映射到特定代码中,但是我计划在某个时候解决它。

请注意,您得到的结果将非常粗糙,尤其是在空房间之外的任何地方。信号微弱到足以使人,雕像或任何阻挡视线的东西都会明显增加您的距离读数。您甚至可能在建筑物中的某些地方,存在建设性的干扰(大部分来自墙壁)使某些地方的阅读距离比实际距离近得多。


谢谢邓肯,我来看看。我知道缺点,但是无论如何都想对其进行测试。如果省去了在每个点上放置信标的距离,那么几米内的精度就足够了。即使那是要走的路,我也想测试一下。
卢克·詹森

7

由于以下原因,使用iBeacon进行准确的室内定位将具有挑战性:

  1. 正如前面的评论中指出的那样,iBeacon信号往往波动很大。原因包括多径效应,人在移动时电话与iBeacon之间的动态物体障碍,其他2.4GHz干扰等等。因此,理想情况下,您不想信任1个单个数据包的数据,而是对来自同一信标的多个数据包进行平均。这将要求电话/信标之间的距离在这几个数据包之间的变化不会太大。对于一般的BLE数据包(如StickNFind的信标),可以轻松将其设置为10Hz信标速率。但是,对于iBeacon而言,这将非常困难,因为
  2. iBeacon的信标频率可能不能高于1Hz。如果有人能指出相反的说法,我将感到很高兴,但是到目前为止,我所看到的所有信息都证实了这一主张。这实际上是有道理的,因为大多数iBeacon将由电池供电,而高频会严重影响电池寿命。考虑到人们的平均步行速度为5.3km(〜1.5m / s),因此,即使仅使用适度的3个信标数据包进行平均,您也很难获得约5m的精度。

另一方面,如果您可以将iBeacon频率增加到大于10Hz(我怀疑这是可能的),那么使用适当的处理方法就可以达到5m或更高的精度。首先,基于反平方定律的琐碎解决方案(例如三边测量)通常效果不佳,因为在实践中,由于上述原因1,不同信标的距离/ RSSI关系通常与平方反比定律相去甚远。但是,只要RSSI对于任何特定位置的特定信标相对稳定(通常是这种情况),就可以使用称为指纹识别的方法来获得更高的准确性。用于指纹识别的常用方法是kNN(k最近邻居)。

更新2014-04-24

某些iBeacon可以广播超过1Hz的频率,例如Estimote使用5Hz作为默认值。但是,根据此链接:“这是Apple的限制。无论设备发布的频率如何,IOS每秒都会返回信标更新。 ”。那里还有另一条评论(可能来自Estimote供应商)说:“我们的信标可以更快地广播,并且可以改善结果和度量”。因此,尚不清楚较高的iBeacon频率是否有益。


1
在不进行过多研究的情况下,我有一组Estimote信标,默认情况下该间隔设置为200 ms。但是,可以将其设置为50毫秒(但这自然会影响电池寿命)
Luuk D. Jansen 2014年

在这种情况下,您可以在iOS应用中看到> 1Hz范围更新吗?
Penghe Geng

我不知道,我目前没有适当的代码要测试,老实说,我还没有时间编写它。我刚刚看到该选项,并添加了评论,但答案的更新似乎表明没有。
Luuk D. Jansen 2014年

6

如果您像我一样不喜欢数学,则可以快速搜索“室内定位sdk”。有很多公司提供室内定位服务。

无耻的插件:我为indoo.rs工作,可以推荐此服务。它还包括“仅”室内定位之上的路由等。


6

对于那些需要设备@Javier Chávarri三边测量功能的用户Android(以节省时间):

public static Location getLocationWithTrilateration(Location beaconA, Location beaconB, Location beaconC, double distanceA, double distanceB, double distanceC){

    double bAlat = beaconA.getLatitude();
    double bAlong = beaconA.getLongitude();
    double bBlat = beaconB.getLatitude();
    double bBlong = beaconB.getLongitude();
    double bClat = beaconC.getLatitude();
    double bClong = beaconC.getLongitude();

    double W, Z, foundBeaconLat, foundBeaconLong, foundBeaconLongFilter;
    W = distanceA * distanceA - distanceB * distanceB - bAlat * bAlat - bAlong * bAlong + bBlat * bBlat + bBlong * bBlong;
    Z = distanceB * distanceB - distanceC * distanceC - bBlat * bBlat - bBlong * bBlong + bClat * bClat + bClong * bClong;

    foundBeaconLat = (W * (bClong - bBlong) - Z * (bBlong - bAlong)) / (2 * ((bBlat - bAlat) * (bClong - bBlong) - (bClat - bBlat) * (bBlong - bAlong)));
    foundBeaconLong = (W - 2 * foundBeaconLat * (bBlat - bAlat)) / (2 * (bBlong - bAlong));
    //`foundBeaconLongFilter` is a second measure of `foundBeaconLong` to mitigate errors
    foundBeaconLongFilter = (Z - 2 * foundBeaconLat * (bClat - bBlat)) / (2 * (bClong - bBlong));

    foundBeaconLong = (foundBeaconLong + foundBeaconLongFilter) / 2;

    Location foundLocation = new Location("Location");
        foundLocation.setLatitude(foundBeaconLat);
        foundLocation.setLongitude(foundBeaconLong);

    return foundLocation;
}

嗨,我正在尝试您的代码,但是不明白它给我的结果吗?我的3点是:49.348657、6.173041、3.126m-49.348658、6.172981、5.452m-49.348588、6.173028、4.065m结果我在我的位置:纬度始终为-90,0,经度根据距离而变化?任何想法 ?
圣约翰勋爵

1
检查您的三个位置点是否创建三角形,并且它们没有形成线。我从电话接听。一旦我在PC病中测试您的位置
hrskrs 2015年

@LordStJohn您是否尝试过其他要点?我的意思是你总是得到那个结果吗?
hrskrs

是的,我尝试其他问题,总是在同一座建筑物中。始终获得相同的结果,“纬度”始终为-90.0,经度随距离而变化。
圣约翰勋爵

1
@LordStJohn我刚刚尝试使用以下统计数据:49.348657、6.173041、3.126m-49.348658、6.17291、5.452m-49.348588、6.173028、4.065,但不给出-90。尝试Debugging确保您使用的是这些位置。
hrskrs

5

我的架构师/经理,他编写了以下算法,

public static Location getLocationWithCenterOfGravity(Location beaconA, Location beaconB, Location beaconC, double distanceA, double distanceB, double distanceC) {

    //Every meter there are approx 4.5 points
    double METERS_IN_COORDINATE_UNITS_RATIO = 4.5;

    //http://stackoverflow.com/a/524770/663941
    //Find Center of Gravity
    double cogX = (beaconA.getLatitude() + beaconB.getLatitude() + beaconC.getLatitude()) / 3;
    double cogY = (beaconA.getLongitude() + beaconB.getLongitude() + beaconC.getLongitude()) / 3;
    Location cog = new Location("Cog");
    cog.setLatitude(cogX);
    cog.setLongitude(cogY);


    //Nearest Beacon
    Location nearestBeacon;
    double shortestDistanceInMeters;
    if (distanceA < distanceB && distanceA < distanceC) {
        nearestBeacon = beaconA;
        shortestDistanceInMeters = distanceA;
    } else if (distanceB < distanceC) {
        nearestBeacon = beaconB;
        shortestDistanceInMeters = distanceB;
    } else {
        nearestBeacon = beaconC;
        shortestDistanceInMeters = distanceC;
    }

    //http://www.mathplanet.com/education/algebra-2/conic-sections/distance-between-two-points-and-the-midpoint
    //Distance between nearest beacon and COG
    double distanceToCog = Math.sqrt(Math.pow(cog.getLatitude() - nearestBeacon.getLatitude(),2)
            + Math.pow(cog.getLongitude() - nearestBeacon.getLongitude(),2));

    //Convert shortest distance in meters into coordinates units.
    double shortestDistanceInCoordinationUnits = shortestDistanceInMeters * METERS_IN_COORDINATE_UNITS_RATIO;

    //http://math.stackexchange.com/questions/46527/coordinates-of-point-on-a-line-defined-by-two-other-points-with-a-known-distance?rq=1
    //On the line between Nearest Beacon and COG find shortestDistance point apart from Nearest Beacon

    double t = shortestDistanceInCoordinationUnits/distanceToCog;

    Location pointsDiff = new Location("PointsDiff");
    pointsDiff.setLatitude(cog.getLatitude() - nearestBeacon.getLatitude());
    pointsDiff.setLongitude(cog.getLongitude() - nearestBeacon.getLongitude());

    Location tTimesDiff = new Location("tTimesDiff");
    tTimesDiff.setLatitude( pointsDiff.getLatitude() * t );
    tTimesDiff.setLongitude(pointsDiff.getLongitude() * t);

    //Add t times diff with nearestBeacon to find coordinates at a distance from nearest beacon in line to COG.

    Location userLocation = new Location("UserLocation");
    userLocation.setLatitude(nearestBeacon.getLatitude() + tTimesDiff.getLatitude());
    userLocation.setLongitude(nearestBeacon.getLongitude() + tTimesDiff.getLongitude());

    return userLocation;
}
  1. 计算三角形的重心(3个信标)
  2. 计算最短距离/最近的信标
  3. 计算信标与重心之间的距离
  4. 他将最短距离转换为只是一个常数的坐标单位,他用来预测精度。您可以使用常量进行测试
  5. 计算距离增量
  6. 将delta与最近的信标x,y相加。

经过测试,我发现它精确到5米。

如果可以改进,请评论我您的测试。


您如何将RSSI值转换为距离?您如何获得参考信标的距离?
Mahamutha M

4

我已经为android 4.4实现了一个非常简单的指纹算法,并在相对“糟糕”的环境中进行了测试:

  • 附近有将近10个wifi AP。
  • 附近还有其他几个蓝牙信号。

精确度似乎在5-8米之内,这取决于我如何放置3个Ibeacon广播机。该算法非常简单,我认为您可以自己实现一个,步骤如下:

  1. 载入室内地图。
  2. 使用地图对所有待处理的定位点进行采样。
  3. 记录所有采样数据,数据应包括:地图坐标,位置信号及其RSSI。

因此,当您开始定位时,它只是步骤相反。


您的指纹算法使用了三边测量法或其他技术?
andrea.spot。

3

我们还试图找到使用iBeacons将某人精确定位到房间中的最佳方法。问题是,信标信号功率不是恒定的,并且会受到其他2.4 GHz信号,金属物体等的影响,因此要获得最大的精度,有必要分别校准每个信标,并将其设置在所需位置。(并进行一些现场测试以查看存在其他蓝牙设备时的信号波动)。我们还有Estimote的一些iBeacon(与Konrad Dzwinel的视频相同),他们已经开发了一些iBeacons的技术演示。在他们的应用程序中,可以看到其中显示iBeacon的雷达。有时很准确,但有时却不准确(而且似乎没有考虑移动电话来计算位置)。http://goo.gl/98hiza

尽管从理论上讲3个iBeacon应该足以实现良好的精度,但也许在现实世界中,需要更多的beacon来确保您正在寻找的精度。




1

我发现Vishnu Prahbu的解决方案非常有用。如果有人需要,我将其移植到C#。

public static PointF GetLocationWithCenterOfGravity(PointF a, PointF b, PointF c, float dA, float dB, float dC)
    {
        //http://stackoverflow.com/questions/20332856/triangulate-example-for-ibeacons
        var METERS_IN_COORDINATE_UNITS_RATIO = 1.0f;

        //http://stackoverflow.com/a/524770/663941
        //Find Center of Gravity
        var cogX = (a.X + b.X + c.X) / 3;
        var cogY = (a.Y + b.Y + c.Y) / 3;
        var cog = new PointF(cogX,cogY);

        //Nearest Beacon
        PointF nearestBeacon;
        float shortestDistanceInMeters;
        if (dA < dB && dA < dC)
        {
            nearestBeacon = a;
            shortestDistanceInMeters = dA;
        }
        else if (dB < dC)
        {
            nearestBeacon = b;
            shortestDistanceInMeters = dB;
        }
        else
        {
            nearestBeacon = c;
            shortestDistanceInMeters = dC;
        }

        //http://www.mathplanet.com/education/algebra-2/conic-sections/distance-between-two-points-and-the-midpoint
        //Distance between nearest beacon and COG
        var distanceToCog =  (float)(Math.Sqrt(Math.Pow(cog.X - nearestBeacon.X, 2)
                + Math.Pow(cog.Y - nearestBeacon.Y, 2)));

        //Convert shortest distance in meters into coordinates units.
        var shortestDistanceInCoordinationUnits = shortestDistanceInMeters * METERS_IN_COORDINATE_UNITS_RATIO;

        //http://math.stackexchange.com/questions/46527/coordinates-of-point-on-a-line-defined-by-two-other-points-with-a-known-distance?rq=1
        //On the line between Nearest Beacon and COG find shortestDistance point apart from Nearest Beacon
        var t = shortestDistanceInCoordinationUnits / distanceToCog;
        var pointsDiff = new PointF(cog.X - nearestBeacon.X, cog.Y - nearestBeacon.Y);
        var tTimesDiff = new PointF(pointsDiff.X * t, pointsDiff.Y * t);

        //Add t times diff with nearestBeacon to find coordinates at a distance from nearest beacon in line to COG.
        var userLocation = new PointF(nearestBeacon.X + tTimesDiff.X, nearestBeacon.Y + tTimesDiff.Y);

        return userLocation;
    }

0

替代方程

- (CGPoint)getCoordinateWithBeaconA:(CGPoint)a beaconB:(CGPoint)b beaconC:(CGPoint)c distanceA:(CGFloat)dA distanceB:(CGFloat)dB distanceC:(CGFloat)dC {


CGFloat x, y;
x = ( ( (pow(dA,2)-pow(dB,2)) + (pow(c.x,2)-pow(a.x,2)) + (pow(b.y,2)-pow(a.y,2)) ) * (2*c.y-2*b.y) - ( (pow(dB,2)-pow(dC,2)) + (pow(c.x,2)-pow(c.x,2)) + (pow(c.y,2)-pow(b.y,2)) ) *(2*b.y-2*a.y) ) / ( (2*b.x-2*c.x)*(2*b.y-2*a.y)-(2*a.x-2*b.x)*(2*c.y-2*b.y) );

y = ( (pow(dA,2)-pow(dB,2)) + (pow(c.x,2)-pow(a.x,2)) + (pow(b.y,2)-pow(a.y,2)) + x*(2*a.x-2*b.x)) / (2*b.y-2*a.y);



return CGPointMake(x, y);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.