---
# System prepended metadata

title: iBeacon indoor localization
tags: [Course Project]

---

# iBeacon indoor localization
###### tags: `Course Project`
## Calibrate
 (distance/RSSI/accuracy): 
 * near:
     * 1m/-51/1.68
     * 1.5m/-54/1.7
 * immediate:
 * far: 
     * 2m/-60/3.5-4.9
     * 3m/-61-64/5.9
 
 ipad 頭對 ibeacon頭 收訊最佳
 * [RSSI -> meters](https://iotandelectronics.wordpress.com/2016/10/07/how-to-calculate-distance-from-the-rssi-value-of-the-ble-beacon/)
                
 
## 定位方式
* http://bbs.brtbeacon.com/post/initTopic/237.html
* https://www.jianshu.com/p/2df3a6bc7f54?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
* tri:
import Glibc
import Foundation
var px1: Double = 0.0
var py1: Double = 0.0
var px2: Double = 0.5
var py2: Double = 0.0
var px3: Double = 0.25
var py3: Double = 1.0 //known
var thelta: Double = 0.0
let r1: Double = 1.0
let r2: Double = 1.0
let r3: Double = 1.0
//let pi: Double = Double.pi
thelta = atan((py2 - py1)/(px2 - px1)) //radian

var px1N: Double = cos(thelta) * px1 + sin(thelta) * py1
var py1N: Double = -sin(thelta) * px1 + cos(thelta) * py1

var px2N: Double = cos(thelta) * px2 + sin(thelta) * py2
var py2N: Double = -sin(thelta) * px2 + cos(thelta) * py2

var px3N: Double = cos(thelta) * px3 + sin(thelta) * py3
var py3N: Double = -sin(thelta) * px3 + cos(thelta) * py3
//rotate
px2N = px2N - px1N
py2N = 0

px3N = px3N - px1N
py3N = py3N - py1N

px1N = 0
py1N = 0
//translate
let p3Square: Double = pow(px3N ,2) + pow(py3N ,2)

let x: Double = (pow(r1 , 2) - pow(r2 , 2) + pow(px2N ,2)) / (2 * px2N)
let y: Double = (pow(r1 , 2) - pow(r3 , 2) + p3Square - 2 * px3N) / (2 * px2N)
//solve
var xt: Double = x + px1N
var yt: Double = y + py1N

var xr: Double = cos(thelta) * xt - sin(thelta) * yt
var yr: Double = sin(thelta) * xt + cos(thelta) * yt


print("%f , %f",xr,yr) //find user’s position


```swift=
//
//  ViewController.swift
//  iBeacon
//
//  Created by ESD 03 on 2019/4/23.
//  Copyright © 2019年 nctu.esd.0751907. All rights reserved.
//
import CoreLocation
import UIKit

class ViewController: UIViewController,CLLocationManagerDelegate {
    @IBOutlet weak var monitorResultTextView: UITextView!
    @IBOutlet weak var rangingResultTextView: UITextView!
    var locationManager: CLLocationManager = CLLocationManager()
    let uuid = "8C38EF3C-32D9-4DFD-A86B-865E2C5A192C"    //Lab
    //let uuid = "8803602F-369E-45C7-AE38-0925B409E584"  //ncrl
    let identfier = "NCRL"
    var dataArray_rssi = [Int]()
    var dataArray_acc = [Double]()
    let ref = -50.0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        if CLLocationManager.isMonitoringAvailable(for: CLBeaconRegion.self){
            if CLLocationManager.authorizationStatus() !=
                CLAuthorizationStatus.authorizedAlways
            {
            locationManager.requestAlwaysAuthorization()
            }
        }
        let region = CLBeaconRegion(proximityUUID: UUID.init(uuidString:
            uuid)!, identifier: identfier)
        locationManager.delegate = self
        region.notifyEntryStateOnDisplay = true
        region.notifyOnEntry = true
        region.notifyOnExit = true
        locationManager.startMonitoring(for: region)
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region:
        CLRegion) {
        monitorResultTextView.text = "did start monitoring \(region.identifier)\n" +
            monitorResultTextView.text
    }
    func locationManager(_ manager: CLLocationManager, didEnterRegion region:
        CLRegion) {
        monitorResultTextView.text = "did enter\n" + monitorResultTextView.text
    }
    func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
        monitorResultTextView.text = "did exit\n" + monitorResultTextView.text
    }
    func locationManager(_ manager: CLLocationManager, didDetermineState state:
    CLRegionState, for region: CLRegion) {
        switch state {
        case .inside:
            monitorResultTextView.text = "state inside\n" + monitorResultTextView.text
        if CLLocationManager.isRangingAvailable(){
            manager.startRangingBeacons(in: region as! CLBeaconRegion)
        }
            
        case .outside:
        monitorResultTextView.text = "state outside\n" + monitorResultTextView.text
        manager.stopMonitoring(for: region)
            
        default:
        break
        }
    }
    func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons:
        [CLBeacon], in region: CLBeaconRegion) {
        rangingResultTextView.text = ""
        let orderedBeaconArray = beacons.sorted(by: { (b1, b2) -> Bool in
            //print(b1,b2)
            return b1.rssi > b2.rssi
        })
        print(beacons)
        var x: Double = 0
        var y: Double = 0
        var xr: Double = 0
        var yr: Double = 0
        var r1I: Double = 0.0
        var r2I: Double = 0.0
        var r3I: Double = 0.0
        var r4I: Double = 0.0
        var measured_rssi: Double = 0.0
        var first_minor:Int = 0
        var second_minor:Int = 0
        var dataArray_minor = [Int]()
        let first: Int?
        let second:Int?
        for beacon in beacons {
            var proximityString = ""
            switch beacon.proximity {
            case .far:
                proximityString = "far"
            case .near:
                proximityString = "near"
            case .immediate:
                proximityString = "immediate"
            default :
                proximityString = "unknow"
            }
            
            if (beacon.major == 1){
                dataArray_minor.append(Int(beacon.minor))  //if major == 1,minor 值大到小丟入
            }
            measured_rssi = Double(beacon.rssi);

            if (beacon.major == 1 && beacon.minor == 1){
                r1I = measured_rssi;
            } else if (beacon.major == 1 && beacon.minor == 2){
                r2I = measured_rssi;
            } else if (beacon.major == 1 && beacon.minor == 3){
                r3I = measured_rssi;
            } else if (beacon.major == 1 && beacon.minor == 4){
                r4I = measured_rssi;
            }
        }
        for i in 0..<dataArray_minor.count{
            if(i == 0){
                first_minor = dataArray_minor[0]
            }
            else if(i == 1){
                second_minor = dataArray_minor[1]
            }
        }
        first = first_minor;
        second = second_minor;
        var area: String = "Non";
        
        if let near = first{
            print("near stores a value");
            let Value:Int = first!;
            print(Value);				
            
        } else {
            //rangingResultTextView.text = rangingResultTextView.text + "Fail to detect" + "\n";
            print("near: no value");    //一個都沒有
            return
        }        
        if let near = first, let sec = second {
            print("ok");
        } else {
            //rangingResultTextView.text = rangingResultTextView.text + "Fail to detect" + "\n";
            print("sec:no value");		//只有一個iBeacon
            return
        }                                 // nil list???????
        
        let Near:Int = first!;
        let Sec:Int = second!;           //optional turn to Int
        let charR1: Double = -62.0;
        let charR4: Double = -65.0;
        
        if ((Near == 1 && Sec == 2)||(Near == 2 && Sec == 1)) {
            if (r1I > charR1) {
                area = "C";  //如果minor1量測到的距離小於特徵距離
            } else {
                area = "B";
            }
        } else if ((Near == 2 && Sec == 3)||(Near == 3 && Sec == 2)) {
            
            if (r4I == 0) {                         //r4 not in range
                area = "B";
            } else {
                if (r4I < charR4) {
                    area = "B";                     //如果minor４量測到的距離小於特徵距離
                } else {
                    area = "A";
                }
            }
        } else if ((Near == 3 && Sec == 4)||(Near == 4 && Sec == 3)) {
            area = "A";
        } else {
            area = "fussy area";
        }
        
        //print("%f , %f",xr,yr) //find user’s position
        rangingResultTextView.text = rangingResultTextView.text + "Minor: \(first_minor)" + "RSSI1:\(r1I)" + "\n";
        rangingResultTextView.text = rangingResultTextView.text + "Minor: \(second_minor)" + "RSSI4:\(r4I)" + "\n";
        //rangingResultTextView.text = rangingResultTextView.text + "Minor: \(beacons[0].minor)" + "RSSI:\(beacons[2].rssi)" + "\n";
        rangingResultTextView.text = rangingResultTextView.text + "area: \(area)" + "\n";
        
    }  //function
        
}//class
```
```swift=
import Foundation

    var measured_rssi: Double = 1.0
    measured_rssi = Double(beacon.rssi);
        var dis: Double = 0
	if (measured_rssi > -55){
        dis = 0.6         //(最小值)
    }
    else if (-58 < measured_rssi && measured_rssi <= -55){
        if (-55 - measured_rssi) <= (measured_rssi + 58){
            //-56
        //                        (measured_rssi + 55)%(dis - 0.6)=(-58+55)%0.6
                dis = 1.2 + 0.6*(58 - measured_rssi)/(-58+55)
        }
        else{
            //-57
                dis = 0.6 + 0.6*(55 + measured_rssi)/(-58+55)
        }
    }

    else if(-59 < measured_rssi && measured_rssi  <= -58){
        if (-58 - measured_rssi) < (measured_rssi + 59){
            dis = 1.8 + 0.6*(59 - measured_rssi)/(-59+58)
        }
        else{

            dis = 1.2 + 0.6*(58 + measured_rssi)/(-59+58)
        }
    }
    else if (-62 < measured_rssi && measured_rssi  <= -59){
        if (-59 - measured_rssi) < (measured_rssi + 62){
            dis = 2.4 + 0.6*(62 - measured_rssi)/(-62+59)
        }
        else{

            dis = 1.8 + 0.6*(59 + measured_rssi)/(-62+59)
        }
    }
    else if(-68 < measured_rssi && measured_rssi <= -62){
        if (-62 - measured_rssi) < (measured_rssi + 68){
            dis = 3.6 + 0.6*(68 - measured_rssi)/(-68+62)
        }
        else{

            dis = 2.4 + 0.6*(62 + measured_rssi)/(-68+62)
        }
    }
    else if (-70 < measured_rssi && measured_rssi <= -68){
        if (-68 - measured_rssi) < (measured_rssi + 70){
        
            dis = 6 + 2.4*(70 - measured_rssi)/(-70+68)
        }
        else{
           dis = 3.6 + 2.4*(68 + measured_rssi)/(-70+68)
        }
    }
    else{
        dis = 7.2 //最大值
    }

    
    
    
    if (beacon.minor == 1){
        R1 = dis;
    } else if (beacon.minor == 2){
        R2 = dis;
    } else if (beacon.minor == 3){
        R3 = dis;
    } else if (beacon.minor == 4){
        R4 = dis;
    }
    
        dataArray_rssi.append(measured_rssi)
        //disArray.append(dis)

//-----------outside for 
        var nearest: Double = 1.0
        var second: Double = 1.0
        var third: Double = 1.0
         nearest = beacon[0].minor
         second = beacon[1].minor
         third = beacon[2].minor
         var area: String = "Non";
         //let charR1: Int = 5;
         //let charR4: Int = 4;
         if ((nearest == 1 && second == 2)||(nearest == 2 && second == 1)) {
            if (R1 < charR1) {
                area = "C";  //如果minor1量測到的距離小於特徵距離
            } else {
                area = "B";
            }
        } else if ((nearest == 2 && second == 3)||(nearest == 3 && second == 2)) {
            if (R4 > charR4) {
                area = "B"; //如果minor４量測到的距離小於特徵距離
            } else {
                area = "A";
            }
        } else if ((nearest == 3 && second == 4)||(nearest == 4 && second == 3)) {
            if (R4 < charR4) {
                area = "A"; //如果minor４量測到的距離小於特徵距離
            } else {
                area = "B"; 
            }
        } else {
           print("fussy area");
           //print("rssi = ",rssi);
        }
    print(area);//特徵距離去樓下量
```
## KF swift
https://www.youtube.com/watch?v=vOVRt-PMl8M  add lib
https://github.com/Hypercubesoft/HCKalmanFilter  (map)
https://github.com/wearereasonablepeople/KalmanFilter (1D)


### cocoapods:
https://www.youtube.com/watch?v=MuMZZtQpB6Y
## PF (2019/6/3) objective C
* 說明:https://www.xzbu.com/8/view-11623514.htm
* 演算法:
http://codeswell.com/downloads/ios-particle-filter/
https://bitbucket.org/codeswell/cdsparticlefilter/src/master/

----------------------------
https://www.cnblogs.com/21207-iHome/p/5237701.html
https://blog.csdn.net/zhangquan2015/article/details/79166537
https://blog.csdn.net/piaoxuezhong/article/details/78619150

## KNN
* https://zhuanlan.zhihu.com/p/61684583
## SVM
* https://kknews.cc/zh-tw/tech/kz4ejmr.html
## deep learning
* https://www.tensorflow.org/swift

## 區域定位
* minor = 1

| 半徑(m) | RSSI |
|:------:|:-----------:|
| 0   | -40 |
| 1 | -50 |
| 2 | -57 |
| 2.96 | -58~-62 |
| 4 | -65 |

* minor = 4

| 半徑(m) | RSSI |
|:------:|:-----------:|
| 0   | -42 |
| 1 | -53~-57 |
| 2 | -55~-57 |
| 3 | -58~-60 |
| 4 | -60~-62 |
|4.5| -64 |