iOS iBeacon室內(nèi)定位的簡單實現(xiàn)之分步定位法

說到定位算法,一般我們第一個想到的方案就是三邊測量法(Trilateration),通過三個信號點(Beacons)和分別對應(yīng)的距離,形成三個圓并相交于一點。但是實際情況并沒有那么理想化,有可能會出現(xiàn)兩圓不相交、圓包含圓、只有兩個信號點或者多個信號點排成一列的情況(過道里),這都是一些比較常見的場景。所以我們需要一個能同時解決上面這些問題的計算方法——分步定位法。

分步定位法

在iOS開發(fā)中,使用CLLocationManagerstartRangingBeaconsInRegion:方法監(jiān)聽Beacons,并通過代理回調(diào)中獲得Beacons列表。取出rssi信號值最強的三個點,取accuracy值作為圓半徑(需要減去高度差),用major、minor值從后臺返回的數(shù)據(jù)中取出對應(yīng)的坐標(biāo)點數(shù)據(jù)即為三個圓的圓心。

圖1-1,分步定位法.png

該算法比較簡單,如圖1-1,不相交時,按比例取中點(O_{AZ}O_{BZ})。當(dāng)兩圓相交時,就是拆分成幾個三角形,通過一系列三級函數(shù)計算出未知的兩個交點。最后將三點連成三角形,此三角形的重心(即點M)就是最終定位點,步驟如下:

  1. 通過勾股定律用a、b長度計算出線段AB長度(即點A到點B距離),使用 ra + rb 與AB對比即可得知兩圓的對應(yīng)情況,一共有三種情況:兩圓相離ra + rb < AB、兩圓相切ra + rb == AB、兩圓相交ra + rb > AB
  2. 兩圓相離:按照兩圓半徑的比例在線段AZ上求O_{AZ}點,即ra : rz = |AO_{AZ}| : |O_{AZ}Z|;因為“兩圓相切ra + rb == AB”在實際程序中出現(xiàn)的幾率太小,所以直接使用“兩圓相離”相同的求法。
  3. 兩圓相交:求出相交點C的坐標(biāo) {Cx, Cy},可通過\arccos( \frac {a} {AB} )得出Q1,通過\arccos( \frac {AO_{AB}} {ra} )得出Q2,最后計算出點C的坐標(biāo):
    Cx=Ax + (ra + \cos(Q1+Q2))
    Cy=Ay + (ra + \sin(Q1+Q2))
    同理可求出點D的坐標(biāo)。得到C、D兩交點后取距離圓心Z點近的交點作為最后三個參考點中的一點。
  4. 將最后求得的三個參考點連接成一個三角形,該三角形的重心即為最后的定位點M:
    Mx = \frac{Dx + O_{AZ}x + O_{BZ}x}{3}
    My = \frac{Dy + O_{AZ}y + O_{BZ}y}{3}

采用分步定位法測量一個移動節(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ū)探討

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容