先日、Eddystone の使いどころについて書いた記事で、iBeaconと比較した場合の利点のうちのひとつは「カスタマイズ性」(=自前実装が可能)であると書きました。 *1
この場合、Core Bluetooth を使って、
- Eddystone ビーコンをスキャン
- 発見時に得られるアドバタイズメントデータを解析
という処理を実装することになるわけですが、
その際に Core Location の iBeacon 実装と同等のことをしたければ、つまり「近接度(Proximity)」を知りたければ、 didDiscoverPeripheral〜 メソッドの引数に渡されてくる RSSI と、ビーコンの TxPower から推定距離を算出する 必要があります。 *2
TxPower と RSSI について
TxPower とは?
ビーコンが発する信号の強さを示していて、単位は dBm (デシベルメートル)です。iBeacon の場合は 1m 離れた地点での受信信号強度を利用しますが、Eddystone の場合は 0m 地点での強度を利用する、という違いがあります。
Note that this is different from other beacon protocol specifications that require the Tx power to be measured at 1 m.
1m 地点の受信信号強度に 41dBm を足すと 0m 地点での受信信号強度に なります。
Note to developers: the best way to determine the precise value to put into this field is to measure the actual output of your beacon from 1 meter away and then add 41dBm to that. 41dBm is the signal loss that occurs over 1 meter.
iBeacon の場合はこの値は Proximity UUID や Major, Minor が入っている Manufacturer Data の領域の最後に入っています。
Eddystone の場合は、この値は Eddystone-UID フレーム や、Eddystone-URL フレーム より取得できます。
ちなみに iBeacon の場合は Core Location 内部で Proximity を計算するので、この値を Core Location の API から直接取得することはできません。が、iOS をペリフェラル(ビーコン側)としてふるまわせたい場合に利用する `peripheralDataWithMeasuredPower:` メソッドの引数に `nil` を指定するとデフォルト値が設定されるのですが、その値は -59dBm となります。
RSSI とは?
Received Signal Strength Indication の略で、ここでは iOS デバイスが受信した電波の強度を示します。単位は同じく dBm です。
RSSI と TxPower から推定距離を計算する
自由空間では受信信号強度は距離の二乗に反比例して減衰していく(フリスの伝達公式)ので、RSSI と TxPower と距離(d)の関係は次のようになります。
RSSI = TxPower - 20 * lg(d)
(lg は底を 10 とする常用対数)
というわけで、距離 d の計算式は以下のようになります。
d = 10 ^ ((TxPower - RSSI) / 20)
Swift のコードだとこんな感じです。
let d = pow(10.0, (TxPower - RSSI) / 20.0)
ちなみに上で「自由空間」と書きましたが、自由空間というのは「障害物のない理想空間」を意味していて、実際には障害物の有無などで電波の受信強度というのは変わってきます。
これを考慮したい場合には次のように距離に係る部分を変数にします。
RSSI = TxPower - 10 * n * lg(d)
この係数は
- n = 2.0 : 障害物のない理想空間
- n < 2.0 : 電波が反射しながら伝搬する空間
- n > 2.0 : 障害物に吸収され減衰しながら伝搬する空間
という意味になります。
(参考書籍、ページ)
- iBeacon ハンドブック 2.3 「ビーコンまでの距離推定」
- 無線 LAN と通信距離について(1)|Wireless・のおと|サイレックス・テクノロジー株式会社
- Estimating beacon proximity/distance based on RSSI - Bluetooth LE - Stack Overflow
近接度(Proximity)への変換
Core Location の実装ではビーコンとの距離を、CLBeacon の `proximity` プロパティから、以下の3段階で得られるようになっています。
- CLProximityImmediate (非常に近い)
- CLProximityNear (近い)
- CLProximityFar (遠い)
上に載せた『ビーコンハンドブック』によると、それぞれ 〜20cm、1〜2m、それ以上、とされています。 *3
単純な閾値による判定が行われているのか、その閾値はいくつなのか、というのはわかりませんが、上記を目安に近づけることは可能です。
またレンジングの間隔は1秒であること、CLBeacon の `accuracy` プロパティは "one sigma horizontal accuracy in meters" を示していることから、何回分かのRSSIから計算した推定距離を平均化して近接度の判定に用いていると推測されます。
accuracy(精度)の計算
CLBeacon の accuracy について散見される誤解
ちょっと話はずれるのですが、CLBeacon の `accuracy` プロパティについて、「ビーコンとの推定距離をメートル単位で示したもの」という記述 を結構みかけます。(日本語記事だけじゃなくて、StackOverflowとかでも見かける)
ただAppleのリファレンス によるとこの accuracy は
one sigma horizontal accuracy in meters
とあり、この "one sigma" は
標準偏差によって定義される範囲は測定の68.3%(1σ)の信頼区間である。標準偏差を正確に求めるために十分な回数の測定が行われ、測定の誤差に偏りがなければ、測定のうち68.3%は 1σ の範囲にあり、95.4%は 2σの範囲にあり、99.7%は 3σ の範囲にあることになる。(正確度と精度 - Wikipedia)
の意味での "1σ"(シグマ)です。
なので、`accuracy` は 推定距離ということではなく、推定距離のばらつきを示す値です。
というわけでリファレンスでも、
Use this property to differentiate between beacons with the same proximity value. Do not use it to identify a precise location for the beacon.
と、「同じ proximity であるビーコン同士の比較に使いましょう」としているわけですね。
accuracy の計算
というわけで CLBeacon の accuracy 相当の値が欲しい場合には、推定距離の標準偏差を計算します。
まとめ
RSSI と TxPower から距離を推定する方法について書きました。個人的には Eddystone を iBeacon の代替として用いる際にこの実装が必要になりましたが、iBeacon を使う場合でも、(ラップされているとはいえ、)このあたりを理解しておくとトラブルシューティングの際などにも見通しがよくなるのではないかと思います。