說到定位算法聘鳞,一般我們第一個(gè)想到的方案就是三邊測(cè)量法(Trilateration)悟狱,通過三個(gè)信號(hào)點(diǎn)(Beacons)和分別對(duì)應(yīng)的距離玄糟,形成三個(gè)圓并相交于一點(diǎn)此蜈。但是實(shí)際情況并沒有那么理想化即横,有可能會(huì)出現(xiàn)兩圓不相交、圓包含圓裆赵、只有兩個(gè)信號(hào)點(diǎn)或者多個(gè)信號(hào)點(diǎn)排成一列的情況(過道里)东囚,這都是一些比較常見的場(chǎng)景。所以我們需要一個(gè)能同時(shí)解決上面這些問題的計(jì)算方法——分步定位法战授。
分步定位法
在iOS開發(fā)中页藻,使用CLLocationManager
的startRangingBeaconsInRegion:
方法監(jiān)聽Beacons,并通過代理回調(diào)中獲得Beacons列表植兰。取出rssi
信號(hào)值最強(qiáng)的三個(gè)點(diǎn)份帐,取accuracy
值作為圓半徑(需要減去高度差),用major
楣导、minor
值從后臺(tái)返回的數(shù)據(jù)中取出對(duì)應(yīng)的坐標(biāo)點(diǎn)數(shù)據(jù)即為三個(gè)圓的圓心废境。
該算法比較簡單,如圖1-1噩凹,不相交時(shí)巴元,按比例取中點(diǎn)(和
)。當(dāng)兩圓相交時(shí)驮宴,就是拆分成幾個(gè)三角形逮刨,通過一系列三級(jí)函數(shù)計(jì)算出未知的兩個(gè)交點(diǎn)。最后將三點(diǎn)連成三角形堵泽,此三角形的重心(即點(diǎn)M)就是最終定位點(diǎn)禀忆,步驟如下:
- 通過勾股定律用a、b長度計(jì)算出線段AB長度(即點(diǎn)A到點(diǎn)B距離)落恼,使用 ra + rb 與AB對(duì)比即可得知兩圓的對(duì)應(yīng)情況箩退,一共有三種情況:兩圓相離
ra + rb < AB
、兩圓相切ra + rb == AB
佳谦、兩圓相交ra + rb > AB
戴涝。 - 兩圓相離:按照兩圓半徑的比例在線段AZ上求
點(diǎn),即
钻蔑;因?yàn)椤皟蓤A相切
ra + rb == AB
”在實(shí)際程序中出現(xiàn)的幾率太小啥刻,所以直接使用“兩圓相離”相同的求法。 - 兩圓相交:求出相交點(diǎn)C的坐標(biāo) {Cx, Cy}咪笑,可通過
得出Q1可帽,通過
得出Q2,最后計(jì)算出點(diǎn)C的坐標(biāo):
同理可求出點(diǎn)D的坐標(biāo)窗怒。得到C映跟、D兩交點(diǎn)后取距離圓心Z點(diǎn)近的交點(diǎn)作為最后三個(gè)參考點(diǎn)中的一點(diǎn)。 - 將最后求得的三個(gè)參考點(diǎn)連接成一個(gè)三角形扬虚,該三角形的重心即為最后的定位點(diǎn)M:
采用分步定位法測(cè)量一個(gè)移動(dòng)節(jié)點(diǎn)的位置努隙,只需要3個(gè)參考節(jié)點(diǎn)。該定位法還避免了采用三邊測(cè)量法可能無解的情況辜昵,使得該方法的適應(yīng)性更強(qiá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開根號(hào) 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)) {
//兩圓有相交點(diǎn),兩圓相交點(diǎn)為C、D堪置。兩圓與AB的相交點(diǎn)為E躬存、F。o是EF的中點(diǎn)舀锨。
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);
//原點(diǎn){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{
//兩圓無相交點(diǎn)
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);
}
參考資料
三邊測(cè)量法,分步定位法比較
蘋果核 - iOS端近場(chǎng)圍欄檢測(cè)(一) ——iBeacon
iOS藍(lán)牙開發(fā)之iBeacon篇(二)
---END---
原文地址:https://www.hlzhy.com/?p=161
最后岭洲,如果此文章對(duì)你有幫助,希望給個(gè)??雁竞。有什么問題歡迎在評(píng)論區(qū)探討