CoreBluetooth: txPowerLevel + rssi = distance?

Using CoreBluetooth I am getting these values from CBCentralManagerDelegate's didDiscover peripheral delegate method:

kCBAdvDataTxPowerLevel: 12 (could be other number like 7, 0 or a small negative number)

This one is taken from advertisementData parameter. This key might be absent.

rssi: -68 (or -60, -100, etc)

this is taken from the "rssi" parameter (always present).

I am looking for a formula to calculate approximate distance based on these two numbers. Is that possible?

I know that ideally I need to know rssi0 (rssi at 1 meter), but I don't see how I can get that via CoreBluetooth API or other means (without actually measuring rssi at one meter distance which is not good for me). How could I approximate rssi0 value with "kCBAdvDataTxPowerLevel"?

Assuming signal propagating in "vacuum" approximation:

FSPL = ((4*pi*d*f) / c)^2   // Free-space path loss
rssi = txPowerLevel - FSPL
rssi0 = txPowerLevel - FSPL0 = 12 - 40 = -28 // rssi at 1 meter distance
// pi = 3.14, d = 1, f = 2.4E9, c = 3e8

Is this correct calculation? (given the approximate nature of it of course, plus I'd need to apply some high frequency filter to get rid of noise).

Your equation for FSPL is not in dB. You need either 10 log_10 or 20 log_10 of that value. Whether it's 10 or 20 depends on whether it's in mV or mW.

Also, I think the f term should disappear. I think it's because there is some sort of assumption about the antenna size being related to the wavelength, or something. I guess you've already looked at the Wikipedia page, but if not: https://en.wikipedia.org/wiki/Link_budget

Please let us know if you get anything like useful numbers from this. My experience has been that it really doesn't work in the "real world". I have a simple weather station in my garden which sends data to a receiver in a cupboard the house and I log the RSSI. It's in the same frequency band as bluetooth. It varies dramatically depending on, for example, whether blinds are open or closed in other rooms, whether the ironing board is in that cupboard, where the metal gardening tools are in the garden, and so on.

This is the current formula I'm using:

    let n = 2.0
    let distance = pow(10, Double(txPowerLevel - 12 - 62 - rssi) / (10 * n))

Here 12 was the txPowerLevel reported from one test device of mine, and -62 was approximate averaged rssi level at 1 meter distance from that test device. Will give this a test in a field to see how well it goes.

This works reasonably well. However, is there a better approach? The two different devices with the same txPowerLevel could have different RSSI at 1 meter values (besides txPowerLevel is optional).

CoreBluetooth: txPowerLevel + rssi = distance?
 
 
Q