複数のiBeaconsを使用して「大まかな」屋内位置を特定する可能性を検討しています。アプリケーションは一種の「博物館」設定であり、異なるオブジェクトの位置と個々のビーコンの位置を備えたグリッドを形成する方が簡単です(ただし、それも不可能ではないかもしれません)。
複数のビーコンを使用して特定の場所に三角測量する例、経験、またはそれを自分で書く方法を支援するロジックがありますか?
3つのビーコンを使用して正確な位置を取得するために、いくつかの実験を行ってきました。
三辺測量の結果
残念なことに、結果は品質の点で非常に残念でした。主に2つの問題がありました。
可能な解決策
このように積極的に私を落胆させた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);
}
以下は、三辺測量/多辺測量を実行するオープンソース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 のような学術的な例のほとんどは、正確に3つの円を扱い、完全に正確な情報を想定しています。これらの状況は、正確な答えを伴うはるかに単純な問題の定式化を可能にし、実際の状況では通常満足のいくものではありません。
Rの問題2 またはR3 測定誤差を含む距離を持つユークリッド空間、関心のあるエリア(楕円)またはボリューム(楕円)は通常、ポイントの代わりに取得されます。領域の代わりにポイント推定が必要な場合は、面積重心または体積重心を使用する必要があります。 R2 固有の領域を取得するには、空間に少なくとも3つの非縮退点と距離が必要です。同様にR3 スペースには、一意の領域を取得するために、少なくとも4つの非縮退点と距離が必要です。
これを調べました。三辺測量が必要な用語。 (三角測量では、3つの既知の点からの角度があります。三辺測量では、3つの既知の点からの距離があります)Googleを使用する場合、Wikiに1つを含むいくつかの記事があります。 3つの連立方程式のセットを解くことになります。私が見たドキュメントは3D三辺測量用でした-Zタームを削除するだけで2Dが簡単になりました。
私が見つけたのは抽象的な数学でした。一般的なアルゴリズムを特定のコードにマップするのにまだ時間をかけていませんが、ある時点でそれに取り組む予定です。
あなたが得る結果は、特に空の部屋以外では非常に粗雑なものになることに注意してください。信号は十分に弱いので、人、像、または視線を遮る何かがあなたの距離の測定値をかなり大きく増加させます。建物内に建設的な干渉(主に壁からの干渉)がある場所があり、実際の場所よりも近くの場所を読み取ることができます。
IBeaconを使用した正確な屋内測位は、次の理由により困難です。
一方、iBeaconの周波数を10Hzより大きい値に上げることができた場合(これは疑わしい)、適切な処理方法を使用して5m以上の精度を得ることができます。第一に、 逆二乗法 に基づく自明な解決策は、三辺測量のように、実際にはさまざまなビーコンの距離/ RSSI関係が逆二乗法からしばしば外れているため、うまく機能しないことがよくあります。上記1。ただし、RSSIが特定の場所の特定のビーコンに対して比較的安定している限り(通常はそうです)、fingerprintingと呼ばれるアプローチを使用して、より高い精度を実現できます。フィンガープリンティングに使用される一般的な方法はkNN( k-Nearest Neighbor )です。
Estimoteがデフォルトとして5Hzを使用するように、一部のiBeaconsは1Hz以上をブロードキャストできます。ただし、これによると link : "これはAppleの制限です。IOSはビーコンの更新を毎秒返します。デバイスは広告しています。」。 「私たちのビーコンははるかに速くブロードキャストすることができ、それはmay結果を改善する」という別のコメントがあります(おそらくEstimoteベンダーから)および測定」。したがって、より高いiBeacon周波数が有益であるかどうかは明確ではありません。
あなたが私のようなもので、数学が好きではない場合は、「屋内測位SDK」をすばやく検索することをお勧めします。サービスとして屋内測位を提供している企業はたくさんあります。
恥知らずのプラグ: indoo.rs で働いており、このサービスを推奨できます。また、「ジャスト」屋内ポジショニングに加えて、ルーティングなども含まれます。
次のアルゴリズムを書いた私の建築家/マネージャー、
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;
}
テストした後、5メートルまで正確であることがわかりました。
改善できる場合は、テストをコメントしてください。
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;
}
私は非常に単純なFingerprintアルゴリズムをAndroid 4.4に実装し、比較的「悪い」環境でテストしました。
正確な距離は5〜8メートルで、3つのIbeacon放送局をどのように配置したかによって異なります。アルゴリズムは非常に単純であり、自分で実装できると思います。手順は次のとおりです。
したがって、ポジショニングを開始するときは、手順を逆にしただけです。
また、iBeaconsを使用して、部屋に誰かを正確に見つける最適な方法を見つけようとしています。問題は、ビーコン信号の電力が一定ではなく、他の2.4 Ghz信号、金属オブジェクトなどの影響を受けるため、最大精度を達成するには、各ビーコンを個別にキャリブレーションする必要があり、一度希望の位置に設定すると。 (および他のBluetoothデバイスが存在する場合に信号の変動を確認するために、いくつかのフィールドテストを行います)。 EstimoteのiBeaconsもいくつかあり(Konrad Dzwinelのビデオと同じ)、彼らはすでにiBeaconsでできることの技術デモを開発しています。アプリ内では、iBeaconsが表示されるレーダーを見ることができます。かなり正確な場合もありますが、そうでない場合もあります(そして、位置の計算には電話の動きは考慮されていないようです)。ここで作成したビデオのデモを確認してください: http://goo.gl/98hiza
理論的にはiBeaconsは十分な精度を達成するのに十分なはずですが、実際の状況では、探している精度を確保するためにより多くのビーコンが必要になる可能性があります。
私を本当に助けたのはCode.Google.comのこのプロジェクトでした: https://code.google.com/p/wsnlocalizationscala/ 大量のコード、いくつかの三辺測量アルゴリズム、すべてC#で記述されています。これは大きなライブラリですが、実際には「そのまま」使用することを意図したものではありません。
参照を確認してください https://proximi.io/accurate-indoor-positioning-bluetooth-beacons/
Proximi SDKが三角形分割を処理します。このSDKは、ビーコンの位置決め、三角測量、フィルタリングのすべてのロジックをバックグラウンドで自動的に処理するためのライブラリを提供します。ビーコンに加えて、IndoorAtlas、Wi-Fi、GPS、セルラーポジショニングを組み合わせることができます。
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;
}
代替方程式
- (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);
}