Triangulation offers a way to locate yourself in space. Cartographers in the 1600s originally used the technique to measure things like the height of the cliff, which would be too impractical to measure directly. Later, triangulation evolved into an early navigation system when Dutch mathematician Willebrord Snell discovered three points can be used to locate a point on a map.

While triangulation uses angles to locate points, trilateration uses lateral distances. If we know the positions of three points *P1*, *P2*, and *P3*, as well as our distance from each of the points, *r1*, *r2*, and *r3*; we can look at the overlapping circles formed to estimate where we are relative to the three points. We can even extend the technique to 3D, finding the intersecting region of spheres surrounding the points.

In this project, I’d like to show how we can use the Wifi signal strength, in dB, to approximate distance from a wireless access point (AP) or router. Once we have this distance, we can create a circle surrounding an AP to show possible locations we might occupy. In the next part of the project, I plan to show how we can use three APs to estimate our position in a plane using concepts of trilateration. (Note: I haven’t had time to implement this, but you can use this Wiki article to implement it yourself).

### Determining distance from decibel level

There’s a useful concept in physics that lets us mathematically relate the signal level in dB to a real-world distance. Free-space path loss (FSPL) characterizes how the wireless signal degrades over distance (following an inverse square law):

The constant there, 92.45, varies depending on the units you’re using for other measurements (right now it’s using GHz for frequency and km for distance). For my application I used the recommended constant -27.55, which treats frequency in MHz and distance in meters (m). We can re-arrange the equation to solve for d, in Java:

1 2 3 4 |
public double calculateDistance(double levelInDb, double freqInMHz) { double exp = (27.55 - (20 * Math.log10(freqInMHz)) + Math.abs(levelInDb)) / 20.0; return Math.pow(10.0, exp); } |

Now, there are few drawbacks to this rough approximation:

- FSPL explicitly requires “free space” for calculation, while most Wifi signals are obstructed by walls and other materials.
- Ideally, we will want to sample the signal strength many times (10+) to account for varying interference.

Problem (1) will be resolved in the future by using the signal-to-noise ratio to more accurately estimate (that sounds like an oxymoron) obstructions to the wifi signal. Problem (2) can be implemented in code by sampling many times and computing the average signal level.

Using the above code along with Android’s WifiManager and ScanResult classes, I can print out our final measurements:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE); registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context c, Intent intent) { results = wifi.getScanResults(); for (ScanResult s : results) { DecimalFormat df = new DecimalFormat("#.##"); Log.d(TAG, s.BSSID + ": " + s.level + ", d: " + df.format(calculateDistance((double)s.level, s.frequency)) + "m"); } } }, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); wifi.startScan(); |

And we can get back data that appears to be correct when moving further away from my test router (MAC address: 84:1b:5e:2c:76:f2):

[Image lost during host transition, but basically just showed how the distance increased]