
說到定位算法,一般我們第一個想到的方案就是三邊測量法(Trilateration),通過三個信號點(Beacons)和分別對應(yīng)的距離,形成三個圓并相交于一點。但是實際情況并沒有那么理想化,有可能會出現(xiàn)兩圓不相交、圓包含圓、只有兩個信號點或者多個信號點排成一列的情況(過道里),這都是一些比較常見的場景。所以我們需要一個能同時解決上面這些問題的計算方法——分步定位法。
分步定位法
在iOS開發(fā)中,使用CLLocationManager的startRangingBeaconsInRegion:方法監(jiān)聽Beacons,并通過代理回調(diào)中獲得Beacons列表。取出rssi信號值最強的三個點,取accuracy值作為圓半徑(需要減去高度差),用major、minor值從后臺返回的數(shù)據(jù)中取出對應(yīng)的坐標(biāo)點數(shù)據(jù)即為三個圓的圓心。

該算法比較簡單,如圖1-1,不相交時,按比例取中點(和
)。當(dāng)兩圓相交時,就是拆分成幾個三角形,通過一系列三級函數(shù)計算出未知的兩個交點。最后將三點連成三角形,此三角形的重心(即點M)就是最終定位點,步驟如下:
- 通過勾股定律用a、b長度計算出線段AB長度(即點A到點B距離),使用 ra + rb 與AB對比即可得知兩圓的對應(yīng)情況,一共有三種情況:兩圓相離
ra + rb < AB、兩圓相切ra + rb == AB、兩圓相交ra + rb > AB。 - 兩圓相離:按照兩圓半徑的比例在線段AZ上求
點,即
;因為“兩圓相切
ra + rb == AB”在實際程序中出現(xiàn)的幾率太小,所以直接使用“兩圓相離”相同的求法。 - 兩圓相交:求出相交點C的坐標(biāo) {Cx, Cy},可通過
得出Q1,通過
得出Q2,最后計算出點C的坐標(biāo):
同理可求出點D的坐標(biāo)。得到C、D兩交點后取距離圓心Z點近的交點作為最后三個參考點中的一點。 - 將最后求得的三個參考點連接成一個三角形,該三角形的重心即為最后的定位點M:
采用分步定位法測量一個移動節(jié)點的位置,只需要3個參考節(jié)點。該定位法還避免了采用三邊測量法可能無解的情況,使得該方法的適應(yīng)性更強。
相關(guān)代碼
CGPoint pointA = [self sidePointCalculationWith:x1 :y1 :r1
:x2 :y2 :r2
:x3 :y3 ];
CGPoint pointB = [self sidePointCalculationWith:x2 :y2 :r2
:x3 :y3 :r3
:x1 :y1 ];
CGPoint pointC = [self sidePointCalculationWith:x1 :y1 :r1
:x3 :y3 :r3
:x2 :y2 ];
double Mx = (pointA.x + pointB.x + pointC.x) / 3;
double My = (pointA.y + pointB.y + pointC.y) / 3;
-(CGPoint)sidePointCalculationWith:(double)x1 :(double)y1 :(double)r1
:(double)x2 :(double)y2 :(double)r2
:(double)x3 :(double)y3{
//勾股定理 sqrt(X)是X開根號 pow(X,n)是X的n次方
//取beacon1圓心A 與 beacon2圓心B的距離
double AB = sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
double rAB = (r1 + r2);
if (rAB > AB && (r1 < AB && r2 < AB)) {
//兩圓有相交點,兩圓相交點為C、D。兩圓與AB的相交點為E、F。o是EF的中點。
double EF = rAB - AB;
double Eo = EF * 0.5;
double AE = r1 - EF;
double Ao = AE + Eo;
double AQ1 = acos((x2 - x1) / AB);
double AQ2 = acos(Ao / r1);
double BF = r2 - EF;
double Bo = BF + Eo;
// double BQ1 = acos(fabs(x1 - x2) / AB);
double BQ2 = acos(Bo / r2);
//原點{0,0}在左上角的情況下
double Cx = x1 + (r1 * cos(AQ1 + AQ2));
double Cy = 0.0;
double Dx = x2 - (r2 * cos(AQ1 + BQ2));
double Dy = 0.0;
if (x1 < x2) {
Dx = x2 - (r2 * cos(AQ1 + BQ2));
if (y1 < y2) {
Cy = y1 + (r1 * sin(AQ1 + AQ2));
Dy = y2 - (r2 * sin(AQ1 + BQ2));
}else{
Cy = y1 - (r1 * sin(AQ1 + AQ2));
Dy = y2 + (r2 * sin(AQ1 + BQ2));
}
}else{
Cy = y1 + (r1 * sin(AQ1 + AQ2));
if (y1 < y2) {
Dy = y2 - (r2 * sin(AQ1 + BQ2));
}else{
Dy = y2 + (r2 * sin(AQ1 + BQ2));
}
}
double Cc = sqrt(pow(Cx - x3, 2) + pow(Cy - y3, 2));
double Dc = sqrt(pow(Dx - x3, 2) + pow(Dy - y3, 2));
return Cc < Dc ? CGPointMake(Cx, Cy) : CGPointMake(Dx, Dy);
}else{
//兩圓無相交點
return [self midpointCalculationWith:x1 :y1 :r1
:x2 :y2 :r2];
}
}
-(CGPoint)midpointCalculationWith:(double)x1 :(double)y1 :(double)r1
:(double)x2 :(double)y2 :(double)r2{
double a = y1 - y2;//豎邊
double b = x1 - x2;//橫邊
double rr = r1 + r2;
double s = r1 / rr;
double x = fabs(x1 - (b * s)) ;
double y = fabs(y1 - (a * s)) ;
return CGPointMake(x, y);
}
參考資料
三邊測量法,分步定位法比較
蘋果核 - iOS端近場圍欄檢測(一) ——iBeacon
iOS藍牙開發(fā)之iBeacon篇(二)
---END---
原文地址:https://www.hlzhy.com/?p=161
最后,如果此文章對你有幫助,希望給個??。有什么問題歡迎在評論區(qū)探討