iBeacon の受発信が Android/iOS で出来上がったので、具体的に iBeacon の受信確率を実測していきます。
BLE 物理層の詳細とスキャン頻度 | Moonmile Solutions Blog https://www.moonmile.net/blog/archives/11968
問題を簡単に解決するには、
- 発信機の発信頻度を高くする
- 受信機のスキャン頻度を高くする
という形にすれば問題はないのですが、バッテリーの問題や、省電力のために、できるだけ発信頻度やスキャン頻度は低く抑えておきたいところです。iOS の場合は、これらの頻度を変えることができないので調節が不可能なのですが、Android の場合は、ADVERTISE_MODE_LOW_POWER を設定することで発信/受信タイミングを調節することができます。
が、この発信頻度と受信頻度の両方とも ADVERTISE_MODE_LOW_POWER にしてしまうとなかなか iBeacon を受信しないという現象が起きます。これは GATT サービスのデバイスの発見のときにも発生します。
受信確率を計算する
変数としては以下の3つを使います。
- 発信間隔 Advertising Interval
- 受信ウィンドウ Scan Window
- 受信間隔 Scan Interval
例えば、以下のように設定をします。
Scan Window: 100 ms
Scan Interval: 1000 ms
Advertising Interval: 100 ms ~ 200 ms

図 受発信の関係
発信する BLE 電文は、Advertising Interval の間隔で発信されます。受信機は Scan Window の間だけスキャンをして、Scan Interval の間隔でスキャンを繰り返します。うまく、Scan Window に当たれば iBeacon が受信できるという訳です。
完全に同期が取れれば、受信確率を高めることができるのですが、実際はそうはいきません。BLE デバイスはそれぞれ独立したタイミングで動いているので、ある程度の幅をもって受信する必要があります。また、発信するタイミングも Advertising Interval を固定してしまうと全て外してしまう可能性がでてくるので、ある程度の幅をもってランダムに Advertising Interval を変えていきます。
iBeacon は発信機で出力した電文を全て受信する必要はありません。どれか1つでも受信できればいいのです。できれば、早めに受け取りたいところです。ここで、受信確率を計算します。

p = Scan Window / Scan Interval: 1秒間に iBeacon を受信する確率
n = 1000 / Advertising Interval: 1秒間に iBeacon が発信される回数
受信側は 1秒間で 0.1 の確率で受信することができ、発信側は1秒間に 6.67 回発信されている訳。受信できない確率が3つめの式になって、(1-p)^λ で計算できるので、0.513 という確率になります。これを1から引けば、受信できる確率 0.487 になります。
これだと、2秒間に1回は受信できそうなので、問題なさそうですね。
これを受信確率 p は変えずに、発信間隔 Advertising Interval だけを変えます。
Scan Window: 100 ms
Scan Interval: 1000 ms
Advertising Interval: 500 ms ~ 2000 ms
発信間隔を少し間延びさせて平均 1250 ms にします。

同じ計算をすると、1秒間に受信できる確率が 0.081 と激減します。この確率だと到底、1秒間に受信できる確率は無理ですね。
ポアソン近似を使う
ポアソン近似を使うと、受信できる確率は以下の式で計算できます。

99% の確率で受信できる秒数を計算
t 秒間で受信できる確率が 99% になるような t を計算します。

99%になる t を求める。

というわけで、約58秒ほど経たないと 99% の確率で受信ができません。つまり、最悪 1 分近く iBeacon の受信が遅延することになります。
つまり、省電力にしようとして発信側で Advertising Interval: 500 ms ~ 2000 ms 程度の間延びした iBeacon を発信してしまうと、最悪 1 分近く受信が遅れる可能性があるということです。
50% 確率の場合は、8.7 秒程度なのでだいたい半分は10秒ぐらい遅れるということになります。このあたりを実測したいところです。実際、Android を使って両方とも ADVERTISE_MODE_LOW_POWER にしてみると、iBeacon の受信がかなり遅れます。
この部分、接触確認アプリ FolkBears を作成したときに、接触時刻がこれだけずれる(確定範囲がある)ということになります。
ADVERTISE_MODE_LOW_POWER の問題
このため、発信と受信の間隔を ADVERTISE_MODE_LOW_POWER にすると、iBeacon やデバイス発見の遅延が 10 秒から 60 秒ぐらいまで遅延するので、接触確認アプリでこれを使ったときには 10 秒から 1分程度のすれ違いを検出できない可能性が高いです。
これは COCOA/EN API の発信/受信間隔にも適用される筈で、iOS の場合は結構頻繁に受発信をしているのですが、Android の場合は省電力設定にされていると、接触を検知しにくい状態であった、という仮説が立てられます。
これを m5stack などを使って実測してみたいところです。
