Mobile Network Geolocation: Obtaining the Cell IDs & the Signal Strength of Surrounding Towers From a GSM Modem & Triangulating Device Location

Mobile Network GeolocationTo perform basic triangulation of the client GSM device’s location, the GSM modem can be queried to return information about the towers in the area, including their unique Cell Ids, and the signal strength obtained from each.

Using this information, a circle can be drawn around each cell, with the circle size relative to the signal strength of each tower. The point where these circles intersect can be considered the client’s probable location.

Here we explore methods of communication with an internal GSM modem over a serial interface, some of the applicable Hayes or AT commands used to communicate with the hardware and how the information provided to us buy the modem can be used to determine the device’s location by triangulating it’s position against known cell tower locations.

Contents

Setting up your test environment

Verifying Modem Configuration

The first order of business is to verify our serial port configuration using the stty command. In my case, the gsm modem is available on /dev/ttyS1

root@ion:~# stty -F /dev/ttyS1
speed 9600 baud; line = 0;
susp = <undef>; min = 1; time = 0;
-brkint -icrnl -imaxbel -opost -isig -icanon -iexten -echo -echoe -echok noflsh -echoctl -echoke

To verify that the GSM modem is functioning correctly, the gsmctl command can be used. If your sim requires a pin, the folowing message may be displayed:

root@ion:~# gsmctl all
gsmctl[ERROR]: ME/TA error 'SIM PIN required' (code 311)

If that is the case, you can provide the pin using gsmctl -I as follows: (the same can be achieved via the use of the +CPIN Hayes command)

root@ion:~# gsmctl -I "+cpin=NNNN"

If all is well the result of calling gsmctl all should look something like this:

root@ion:~# gsmctl all
<ME0> Manufacturer: Telit
<ME1> Model: GC864-QUAD
<ME2> Revision: 10.00.063
<ME3> Serial Number: 359294031006030
<FUN> Functionality Level: 1
...

gsmctl requires a symlink at /dev/mobilephone that points to your GSM modem’s serial interface. If the symlink does not exist on your system you can create it by issuing the command:
ln -s /dev/ttyS<#> /dev/mobilephone

Listening on Your Modem’s Serial Interface

Next we need to establish a method of communication with the modem. In a Linux terminal, listening on a serial interface is as simple as issuing the following command:
cat /dev/mobilephone &

This prints any communication received from the device at /dev/mobilephone to our terminal in real time.

If like me you find yourself accessing a device via ssh or creating a serial terminal from a remote device this solution for listening on the modem’s serial interface may not always be appropriate as you will need to be able to use the same terminal for issuing commands to the modem and viewing these responses.

In this case, the best method for separating the responses from the modem out while testing is to redirect the output from the modem’s serial interface into a text file in a background process:
cat /dev/mobilephone > modem.log &

Now your terminal will be left free for you to issue commands to the modem and the responses will be stored in the modem.log file for you to view when required.

Communicating with your Modem

A set of commands, known as Hayes or AT commands have been established as a standard for issuing commands to modems. Commands begin with the character sequence AT for “Attention” indicating to the modem that a command follows, the command, and are then terminated by a carriage return (‘\r’ or 0x0D).

root@ion:~# echo -e "ATZ\r" > /dev/mobilephone
root@ion:~# cat modem.log
ATZ

OK


The Hayes command, ATZ instructs the modem to perform a soft reset. The echo command is used with the -e option to enable interpretation of backslash escaped characters. The modem.log file contains our command, and the modem’s response, “OK”.

+CREG? – Obtaining Network Registration Information

By querying the modems current network registration status we can determine whether or not the modem is registered on the network, whether or not the sim is registered as roaming or on it’s home network and on which specific cell (tower) the sim is registered.

To get this information, one must first issue the command AT+CREG=2 to enable unsolicited network registration information with network Cell identification data. With this option set, the new network registration status and network Cell identification data will be sent by the modem every time it changes. It also allows us to query the information as necessary. the options are:

  1. Disable network registration unsolicited result code (factory default)
  2. Enable network registration unsolicited result code
  3. Enable network registration unsolicited result code with network cell identification data
root@ion:~# echo -e "AT+CREG=2\r" > /dev/mobilephone
root@ion:~# echo -e "AT+CREG?\r" > /dev/mobilephone
root@ion:~# cat modem.log
AT+CREG=2

OK
AT+CREG?

+CREG: 2,1,"02D0","CB9B"

OK

Understanding the Network Registration Report Results

After issuing the AT+CREG=2 command, we can use AT+CREG? to query the Network Registration Report. The modem returned +CREG to identify the report, 2 indicating the current Network Registration Report Mode and 1 indicating the current network registration status as registered on the “home” network. This is followed by the Local Area Code and Cell Id for the Cell on which the sim is currently registered in hex.

+CREG: <stat>[<Lac>,<Ci>]
<stat>

  1. Not registered, not currently searching for a new operator to register to
  2. Registered, home network
  3. Not registered, but currently searching for a new operator to register to
  4. Registration denied
  5. Unknown
  6. Registered, roaming

<Lac> – Local Area Code for the current cell (hex)
<Ci> – Cell Id for the current cell (hex)

As we have enabled unsolicited network registration information, this information will continue to be provided over the serial interface when it changes until the Network Registration Report mode is set back to 0.

#MONI – Obtaining GSM information for neighboring cells using Cell Monitor

If we’re going to triangulate our position, we’re going to need more information about the cells in our area. In order to get the location of a cell from OpenCellID for example, we’ll need:

  • Mobile Country Code
  • Mobile Network Code
  • Location Area Code
  • Cell ID

To get an accurate location using the Google Maps Geolocation API, or to calculate it yourself using your own database of cell coordinates you will also likely need:

  • Age
  • Signal Strength
  • Timing Advance

To obtain this information, I have made use of the #MONI (Cell Monitor) AT command. This is not a command that was specified in the Hayes or 3GPP standards documents and may not be available on your modem.

Obtaining the modem manufacturer name (+GMI) and model number (+GMM)

The #MONI command is however available for most modern Telit devices. If it is not available on your device I would recommend determining the manufacturer and model of your device and consulting the manufacturer’s AT command reference guide for an equivalent command. the following standard Hayes commands can be used to obtain manufacturer and model information:

root@ion:~# cat /dev/null > modem.log
root@ion:~# echo -e "AT+GMI\r" > /dev/mobilephone
root@ion:~# echo -e "AT+GMM\r" > /dev/mobilephone
root@ion:~# cat modem.log
AT+GMI

Telit

OK
AT+GMM

GC864-QUAD-V2

OK

Obtaining neighbor cell GSM information

The #MONI command can be used to extract GSM related information from the serving cell, and up to six neighbouring cells. The set command can be used to select the cell from which to request information: echo -e "AT#MONI=0\r" > /dev/mobilephone

The parameter in this command can be the cell number identified by the ordinal number 0 (the serving cell) to 6 (the neighbouring cells). Below, I have cleared my log file, selected the serving cell and requested the information:

root@ion:~# cat /dev/null > modem.log
root@ion:~# echo -e "AT#MONI=0\r" > /dev/mobilephone
root@ion:~# echo -e "AT#MONI?\r" > /dev/mobilephone
root@ion:~# cat modem.log
AT#MONI=0

OK
AT#MONI

#MONI: VodaCom-SA BSIC:73 RxQual:0 LAC:02D0 Id:CB9B ARFCN:31 PWR:-83dbm TA:1

OK

When extracting data for the serving cell and the network name is known the format is:#MONI: <netname> BSIC:<bsic> RxQual:<qual> LAC:<lac> Id:<id> ARFCN:<arfcn> PWR:<dBm> dBm TA: <timadv>

When the network name is unknown, the format is:#MONI: <cc> <nc> BSIC:<bsic> RxQual:<qual> LAC:<lac> Id:<id> ARFCN:<arfcn> PWR:<dBm> dBm TA: <timadv>

  • <netname> – name of network operator
  • <cc> – country code
  • <nc> – network operator code
  • <n> – progressive number of adjacent cell
  • <bsic> – base station identification code
  • <qual> – quality of reception 0..7
  • <lac> – localization area code
  • <id> – cell identifier
  • <arfcn> – assigned radio channel
  • <dBm> – received signal strength in dBm
  • <timadv> – timing advance

In the next example, I have cleared my log file, selected the first neighbouring cell and requested the gsm information:

root@ion:~# cat /dev/null > modem.log
root@ion:~# echo -e "AT#MONI=1\r" > /dev/mobilephone
root@ion:~# echo -e "AT#MONI\r" > /dev/mobilephone
root@ion:~# cat modem.log
AT#MONI=1

OK
AT#MONI

#MONI: Adj Cell 1 LAC:02D0 Id:CC61 ARFCN:39 PWR:-82dbm

OK

When extracting data for an adjacent cell, the format is:#MONI: Adj Cell<n> [LAC:<lac> Id:<id>] ARFCN:<arfcn> PWR:<dBm> dBm

Finally, if the Cell Monitor mode is set to 7, GSM-related information from the whole set of seven cells, including the serving cell and it’s neighbour list is returned in tabular format.

root@ion:~# cat /dev/null > modem.log
root@ion:~# echo -e "AT#MONI=7\r" > /dev/mobilephone
root@ion:~# echo -e "AT#MONI\r" > /dev/mobilephone
root@ion:~# cat modem.log
AT#MONI=7

OK
AT#MONI

#MONI: Cell  BSIC  LAC  CellId  ARFCN    Power  C1  C2  TA  RxQual  PLMN
#MONI:  S    73  02D0   CB9B      31   -82dbm  20  20   1     0    VodaCom-SA
#MONI: N1    03  02D0   CC61      39   -85dbm  17  13
#MONI: N2    53  02D0   CB99      50   -90dbm  12   8
#MONI: N3    13  02D0   CC63      37   -91dbm  11   7
#MONI: N4    16  02D0   CB9A      38   -93dbm   9   5
#MONI: N5    22  02D0   D23C      41   -94dbm   8   4
#MONI: N6    35  02D0   0000      44   -99dbm   3  -1

OK
  • <C1value> – C1 reselection parameter
  • <C2value> – C2 reselection parameter

Triangulating your position using GSM Cell Tower Locations

Cell LocationsWith this information in hand, and provided that you have access to a database of coordinates for the Cell IDs, triangulation of the our is now possible. The exact location’s of these cells is not generally freely available, however, if a deal cannot be struck with the network operators in your region and you cannot afford to make use of the Google Maps Geolocation API, a number of services exist for obtaining coordinates for cell towers using this information including OpenCellID.

The following coordinates for our towers were obtained from OpenCellID.

These open databases are often generated by grabbing the current GPS location of a mobile device and then allocating that location to all cells in range, and so are wildly inaccurate. In fact 3 of these towers appear to have been placed on top of each other in the middle of a shopping mall.

However this will have to suffice if you do not have the resources to obtain access to database of actual cell positions.

Cell Latitude Longitude
CB9B -25.868423 28.189260450000006
CC61 -25.8616442888889 28.195777477777824
CB99 -25.8663650111111 28.19577164444445
CB9A -25.8583868203475 28.189013391625167
CC62 -25.8583868203475 28.1890133916252
D23C -25.8583868203475 28.1890133916252
CC63 -25.87912 28.18255

Triangulation Algorithm

I have used JavaScript while experimenting with this for ease of use when plotting the results on Google Maps.

To perform basic triangulation of the client devices location, a circle is drawn around each cell, with the circle size relative to the signal strength of each tower.
The point where these circles intersect can be considered the client’s probable location. Obviously dBm is not a measure of distance and so determining the actual circle radius is an exercise in calculating the signal strength’s relative weights, and growing the circles around their point of origin according to that ratio until the circles intersect.

So, where our cell tower’s x & y coordinates are represented as:

(function () {
    var tx1 = 28.189260450000006;
    var tx2 = 28.195777477777824;
    var tx3 = 28.19577164444445;
    var tx4 = 28.189013391625167;
    var tx5 = 28.1890133916252;
    var tx6 = 28.1890133916252;
    var tx7 = 28.18255;

    var ty1 = -25.868423;
    var ty2 = -25.8616442888889;
    var ty3 = -25.8663650111111;
    var ty4 = -25.8583868203475;
    var ty5 = -25.8583868203475;
    var ty6 = -25.8583868203475;
    var ty7 = -25.87912;

    ...

…and the signal strength for each tower is expressed as:

    ...

    var s1 = -82;
    var s2 = -85;
    var s3 = -90;
    var s4 = -91;
    var s5 = -93;
    var s6 = -94;
    var s7 = -99;

    ...

The signal strength ratio for each tower can be calculated as ratio = signal strength/(total, combined signal strength):

    ...

    var sr1 = s1 / (s1 + s2 + s3 + s4 + s5 + s6 + s7);
    var sr2 = s2 / (s1 + s2 + s3 + s4 + s5 + s6 + s7);
    var sr3 = s3 / (s1 + s2 + s3 + s4 + s5 + s6 + s7);
    var sr4 = s4 / (s1 + s2 + s3 + s4 + s5 + s6 + s7);
    var sr5 = s5 / (s1 + s2 + s3 + s4 + s5 + s6 + s7);
    var sr6 = s6 / (s1 + s2 + s3 + s4 + s5 + s6 + s7);
    var sr7 = s7 / (s1 + s2 + s3 + s4 + s5 + s6 + s7);

    ...

Finally, the client device’s x & y coordinates can be calculated individually by multiplying each tower’s coordinate by it’s signal strength ratio and adding them together as follows:

    ...

    var longitude = ((tx1 * sr1) + (tx2 * sr2) + (tx3 * sr3) + (tx4 * sr4) + (tx5 * sr5) + (tx6 * sr6) + (tx7 * sr7));
    var latitude = ((ty1 * sr1) + (ty2 * sr2) + (ty3 * sr3) + (ty4 * sr4) + (ty5 * sr5) + (ty6 * sr6) + (ty7 * sr7));
   
    console.log("longitude: " + longitude);
    console.log("latitude: " + latitude);
})();

Triangulation result

Triangulated Location

Full Triangulation Algorithm (JavaScript)

(function () {
    var tx1 = 28.189260450000006;
    var tx2 = 28.195777477777824;
    var tx3 = 28.19577164444445;
    var tx4 = 28.189013391625167;
    var tx5 = 28.1890133916252;
    var tx6 = 28.1890133916252;
    var tx7 = 28.18255;

    var ty1 = -25.868423;
    var ty2 = -25.8616442888889;
    var ty3 = -25.8663650111111;
    var ty4 = -25.8583868203475;
    var ty5 = -25.8583868203475;
    var ty6 = -25.8583868203475;
    var ty7 = -25.87912;

    var s1 = -82;
    var s2 = -85;
    var s3 = -90;
    var s4 = -91;
    var s5 = -93;
    var s6 = -94;
    var s7 = -99;

    var sr1 = s1 / (s1 + s2 + s3 + s4 + s5 + s6 + s7);
    var sr2 = s2 / (s1 + s2 + s3 + s4 + s5 + s6 + s7);
    var sr3 = s3 / (s1 + s2 + s3 + s4 + s5 + s6 + s7);
    var sr4 = s4 / (s1 + s2 + s3 + s4 + s5 + s6 + s7);
    var sr5 = s5 / (s1 + s2 + s3 + s4 + s5 + s6 + s7);
    var sr6 = s6 / (s1 + s2 + s3 + s4 + s5 + s6 + s7);
    var sr7 = s7 / (s1 + s2 + s3 + s4 + s5 + s6 + s7);

    var longitude = ((tx1 * sr1) + (tx2 * sr2) + (tx3 * sr3) + (tx4 * sr4) + (tx5 * sr5) + (tx6 * sr6) + (tx7 * sr7));
    var latitude = ((ty1 * sr1) + (ty2 * sr2) + (ty3 * sr3) + (ty4 * sr4) + (ty5 * sr5) + (ty6 * sr6) + (ty7 * sr7));
   
    console.log("longitude: " + longitude);
    console.log("latitude: " + latitude);
})();

Or rather:

(function () {

    var towers = [
        {
            latitude: -25.868423,
            longitude: 28.189260450000006,
            signalStrength: -82,
            signalStrengthRatio: 1
        },
        {
            latitude: -25.8616442888889,
            longitude: 28.195777477777824,
            signalStrength: -85,
            signalStrengthRatio: 1
        },
        {
            latitude: -25.8663650111111,
            longitude: 28.19577164444445,
            signalStrength: -90,
            signalStrengthRatio: 1
        },
        {
            latitude: -25.8583868203475,
            longitude: 28.189013391625167,
            signalStrength: -91,
            signalStrengthRatio: 1
        },
        {
            latitude: -25.8583868203475,
            longitude: 28.1890133916252,
            signalStrength: -93,
            signalStrengthRatio: 1
        },
        {
            latitude: -25.8583868203475,
            longitude: 28.1890133916252,
            signalStrength: -94,
            signalStrengthRatio: 1
        },
        {
            latitude: -25.87912,
            longitude: 28.18255,
            signalStrength: -99,
            signalStrengthRatio: 1
        }
    ];

    var totalSignalStrength = 0;
    for (var i = 0; i < towers.length; i++)
        totalSignalStrength += towers[i].signalStrength;

    for (var i = 0; i < towers.length; i++)
        towers[i].signalStrengthRatio = towers[i].signalStrength / totalSignalStrength;

    var clientLongitude = 0;
    for (var i = 0; i < towers.length; i++)
        clientLongitude += towers[i].longitude * towers[i].signalStrengthRatio;

    var clientLatitude = 0;
    for (var i = 0; i < towers.length; i++)
        clientLatitude += towers[i].latitude * towers[i].signalStrengthRatio;

    console.log("longitude: " + clientLongitude);
    console.log("latitude: " + clientLatitude);
})();
  • Soumya

    Can you help me to implement the Google Maps Geolocation API that you have mentioned in your article. I have no idea on how ti use JSON. Please Help

    • SheldonNeilson

      I can.. is there a particular aspect of it that you’re struggling with? You’ll definitely need a good understanding of javascript/json in general if you don’t already.

  • camacazi

    What model modem did you use that was compatible with the AT commands above. What is a good modem manufacturer model to try to monitor and 3g and 4g [and grps]

    • faustus

      +1. i have been testing all my GSM devices (dongle and phone) and none of them support the AT#MONI command. aside from telit, i’m unable to find any other manufacturers.

  • Tejas

    Hey I am able to run AT commands like +CLAC, +CREG, +GMI,+GMM. But I ma not able to run AT#MONI command. I am using Samsung Chat device as modem.

  • Dinakaran K

    Hi.. Its nice tutorial its really helpful for me hence I am trying to use google geolocation api but I didn’t understand.. I know how json file formatted and working. But how to sent request to the google geo location API with MNC(Mobile Networke Code), MCC(Mobile Country Code), cell id and LAC(Local Area Code).. Please help me to get a better clarity. If you give me a sample request with my requirement in it. It will be grateful. I am struggling a lot. Thanks in Advance.

    • SheldonNeilson

      Hi. You can look at this basic sample that I dd for someone else. http://www.neilson.co.za/demos/google-geolocation-api.html Just go to the page and view source to see how you can query Google’s geolocation API using mobile network information.

      • Dinakaran K

        Hi.. Thank you so much for the help.. I am getting a daily useage limit exceeded error while using my API key. But I didn’t even sent a request in past 3days.. Is there any code to be changed or fixed?

        • SheldonNeilson

          Just read through the information provided by google there. You have to enable billing. They won’t actually bill you yet but you have to enable it.

  • Sanjay Goel

    I want a solution in which I issue a mobile number and return get followings :

    MCC
    NC
    LAC
    CELLID
    CURRENT STATUS : ON / OFF
    IN CASE OFF, DATE AND TIME OF SWITCH OFF.

  • Andy Crofts

    Hmmm… Rather than signal strength, why not use the TA (Timing Advance) numbers? It’s a range from 0-63, and IIRC corresponds to 0-35(31.5?) Km. As the base stations MUST be accurately synch’d to absolute time, that should get you to a few metres

  • Dmitry Remer

    To get coordinates of cell tower is really easy with the free service of public cell positions https://www.mylnikov.org/archives/1059. Also I found that it can do triangulation as well

    • Rama

      Hi, is there any link/document where i can go through to get the coordinates of cell tower based on triangulation. Is it possible to to get the lat/long of Cell tower based on Mobile device’s lat/long

  • Matthew Ortiz

    Is this technology still working today, Aug 2016

  • Akshay jogani

    9408682232 thavhr lagana ka Ha to call

  • ARNIKA PATEL

    I am trying to retrieve location coordinates using Google’s geolocation API but every time got the same lat-lng pair…. & Can’t understand what is timing advance field?.. can anybody help me about this?

  • Duy(vietnam)

    probleme is: in my country, we can’t find any Cell-ID for data.

  • rama

    Hi, is there any link/document where i can go through to get the coordinates of cell tower based on triangulation. other option which i am looking is to get the lat/long of Cell tower based on Mobile device’s lat/long