# 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 |