# 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"; //如果minor4量測到的距離小於特徵距離 } 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"; //如果minor4量測到的距離小於特徵距離 } else { area = "A"; } } else if ((nearest == 3 && second == 4)||(nearest == 4 && second == 3)) { if (R4 < charR4) { area = "A"; //如果minor4量測到的距離小於特徵距離 } 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 |