web-dev-qa-db-ja.com

iBeaconsの三角測量の例

複数のiBeaconsを使用して「大まかな」屋内位置を特定する可能性を検討しています。アプリケーションは一種の「博物館」設定であり、異なるオブジェクトの位置と個々のビーコンの位置を備えたグリッドを形成する方が簡単です(ただし、それも不可能ではないかもしれません)。

複数のビーコンを使用して特定の場所に三角測量する例、経験、またはそれを自分で書く方法を支援するロジックがありますか?

73
Luuk D. Jansen

3つのビーコンを使用して正確な位置を取得するために、いくつかの実験を行ってきました。

三辺測量の結果

残念なことに、結果は品質の点で非常に残念でした。主に2つの問題がありました。

  1. 金属や信号に影響する他のオブジェクトを見つけることができる非制御環境では、ビーコンの受信信号強度が頻繁に変化するため、5メートル未満のエラー範囲を取得することは不可能に思えます。
  2. ユーザーが受信デバイスを処理する方法に応じて、測定値も大きく変化する可能性があります。ユーザーがBluetoothアンテナに手をかざすと、アルゴリズムの入力としての信号が低くなり、ビーコンはデバイスから非常に遠くなるはずです。 この画像 を参照して、Bluetoothアンテナの正確な位置を確認してください。

可能な解決策

このように積極的に私を落胆させたAppleエンジニアと話した後、私が今より使いたいと思うオプションはブルートフォースです。 Xメートルごとにビーコンを設定してみてください(Xはシステムで許容される最大エラーです)。グリッド上のどのビーコンがデバイスに最も近いかを計算して特定のデバイスの位置を追跡し、デバイスは同じ位置にあります。

三辺測量アルゴリズム

ただし、完全を期すために、以下では三辺測量アルゴリズムのコア機能について説明します。 この記事 のパラグラフ3(「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);
}
73

以下は、三辺測量/多辺測量を実行するオープンソースJavaライブラリです。 https://github.com/lemmingapex/Trilateration

example

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 のような学術的な例のほとんどは、正確に3つの円を扱い、完全に正確な情報を想定しています。これらの状況は、正確な答えを伴うはるかに単純な問題の定式化を可能にし、実際の状況では通常満足のいくものではありません。

Rの問題2 またはR3 測定誤差を含む距離を持つユークリッド空間、関心のあるエリア(楕円)またはボリューム(楕円)は通常、ポイントの代わりに取得されます。領域の代わりにポイント推定が必要な場合は、面積重心または体積重心を使用する必要があります。 R2 固有の領域を取得するには、空間に少なくとも3つの非縮退点と距離が必要です。同様にR3 スペースには、一意の領域を取得するために、少なくとも4つの非縮退点と距離が必要です。

22
Scott Wiedemann

これを調べました。三辺測量が必要な用語。 (三角測量では、3つの既知の点からの角度があります。三辺測量では、3つの既知の点からの距離があります)Googleを使用する場合、Wikiに1つを含むいくつかの記事があります。 3つの連立方程式のセットを解くことになります。私が見たドキュメントは3D三辺測量用でした-Zタームを削除するだけで2Dが簡単になりました。

私が見つけたのは抽象的な数学でした。一般的なアルゴリズムを特定のコードにマップするのにまだ時間をかけていませんが、ある時点でそれに取り組む予定です。

あなたが得る結果は、特に空の部屋以外では非常に粗雑なものになることに注意してください。信号は十分に弱いので、人、像、または視線を遮る何かがあなたの距離の測定値をかなり大きく増加させます。建物内に建設的な干渉(主に壁からの干渉)がある場所があり、実際の場所よりも近くの場所を読み取ることができます。

15
Duncan C

IBeaconを使用した正確な屋内測位は、次の理由により困難です。

  1. 以前のコメントで指摘したように、iBeaconのシグナルは大きく変動する傾向があります。その理由には、 マルチパス 効果、人が動いているときの電話とiBeacon間の動的なオブジェクトの妨害、その他の2.4GHz干渉などが含まれます。したがって、理想的には、1つの単一パケットのデータを信頼するのではなく、同じビーコンからの複数のパケットに対して平均化を行います。それには、これらのいくつかのパケット間で電話/ビーコンの距離があまり変化しないことが必要です。一般的なBLEパケット(StickNFindのビーコンなど)は、10Hzのビーコンレートに簡単に設定できます。ただし、iBeaconの場合、それは難しいでしょう。なぜなら、
  2. iBeaconのビーコン周波数は、おそらく1Hzを超えることはできません。誰かがそうでないと言うソースを指すことができればうれしいですが、私がこれまでに見たすべての情報はこの主張を確認します。ほとんどのiBeaconsはバッテリー駆動であり、高周波はバッテリー寿命に大きな影響を与えるため、これは実際に理にかなっています。人々の平均歩行速度は 5.3km (〜1.5m/s)であるため、平均化を行うために控えめな3つのビーコンパケットを使用しただけでも、〜5mの精度を得るのは困難です。

一方、iBeaconの周波数を10Hzより大きい値に上げることができた場合(これは疑わしい)、適切な処理方法を使用して5m以上の精度を得ることができます。第一に、 逆二乗法 に基づく自明な解決策は、三辺測量のように、実際にはさまざまなビーコンの距離/ RSSI関係が逆二乗法からしばしば外れているため、うまく機能しないことがよくあります。上記1。ただし、RSSIが特定の場所の特定のビーコンに対して比較的安定している限り(通常はそうです)、fingerprintingと呼ばれるアプローチを使用して、より高い精度を実現できます。フィンガープリンティングに使用される一般的な方法はkNN( k-Nearest Neighbor )です。

更新2014-04-24

Estimoteがデフォルトとして5Hzを使用するように、一部のiBeaconsは1Hz以上をブロードキャストできます。ただし、これによると link : "これはAppleの制限です。IOSはビーコンの更新を毎秒返します。デバイスは広告しています。」。 「私たちのビーコンははるかに速くブロードキャストすることができ、それはmay結果を改善する」という別のコメントがあります(おそらくEstimoteベンダーから)および測定」。したがって、より高いiBeacon周波数が有益であるかどうかは明確ではありません。

7
Penghe Geng

あなたが私のようなもので、数学が好きではない場合は、「屋内測位SDK」をすばやく検索することをお勧めします。サービスとして屋内測位を提供している企業はたくさんあります。

恥知らずのプラグ: indoo.rs で働いており、このサービスを推奨できます。また、「ジャスト」屋内ポジショニングに加えて、ルーティングなども含まれます。

6
TomTasche

次のアルゴリズムを書いた私の建築家/マネージャー、

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. 最も近いビーコンx、yを持つデルタを追加します。

テストした後、5メートルまで正確であることがわかりました。

改善できる場合は、テストをコメントしてください。

5
Vishnu Prabhu

Androidデバイスの@Javier Chávarri三辺測量関数が必要な場合(時間を節約するため):

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;
}
5
hrskrs

私は非常に単純なFingerprintアルゴリズムをAndroid 4.4に実装し、比較的「悪い」環境でテストしました。

  • 近くに約10のwifi AP。
  • 他のいくつかのBluetooth信号が近くにあります。

正確な距離は5〜8メートルで、3つのIbeacon放送局をどのように配置したかによって異なります。アルゴリズムは非常に単純であり、自分で実装できると思います。手順は次のとおりです。

  1. インドアマップを読み込みます。
  2. すべての保留中の位置決めポイントのマップを使用したサンプリング。
  3. すべてのサンプリングデータを記録します。データには、マップ座標、位置信号、およびRSSIが含まれている必要があります。

したがって、ポジショニングを開始するときは、手順を逆にしただけです。

4
Shawn

また、iBeaconsを使用して、部屋に誰かを正確に見つける最適な方法を見つけようとしています。問題は、ビーコン信号の電力が一定ではなく、他の2.4 Ghz信号、金属オブジェクトなどの影響を受けるため、最大精度を達成するには、各ビーコンを個別にキャリブレーションする必要があり、一度希望の位置に設定すると。 (および他のBluetoothデバイスが存在する場合に信号の変動を確認するために、いくつかのフィールドテストを行います)。 EstimoteのiBeaconsもいくつかあり(Konrad Dzwinelのビデオと同じ)、彼らはすでにiBeaconsでできることの技術デモを開発しています。アプリ内では、iBeaconsが表示されるレーダーを見ることができます。かなり正確な場合もありますが、そうでない場合もあります(そして、位置の計算には電話の動きは考慮されていないようです)。ここで作成したビデオのデモを確認してください: http://goo.gl/98hiza

理論的にはiBeaconsは十分な精度を達成するのに十分なはずですが、実際の状況では、探している精度を確保するためにより多くのビーコンが必要になる可能性があります。

3
tomacco

私を本当に助けたのはCode.Google.comのこのプロジェクトでした: https://code.google.com/p/wsnlocalizationscala/ 大量のコード、いくつかの三辺測量アルゴリズム、すべてC#で記述されています。これは大きなライブラリですが、実際には「そのまま」使用することを意図したものではありません。

3
woutercx

参照を確認してください https://proximi.io/accurate-indoor-positioning-bluetooth-beacons/

Proximi SDKが三角形分割を処理します。このSDKは、ビーコンの位置決め、三角測量、フィルタリングのすべてのロジックをバックグラウンドで自動的に処理するためのライブラリを提供します。ビーコンに加えて、IndoorAtlas、Wi-Fi、GPS、セルラーポジショニングを組み合わせることができます。

2
Ambi

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;
    }
1
Tom

代替方程式

- (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);
}
0
jdog