I'm using "AT+CNETSCAN" to get a list of all the cell towers within range. I've downloaded the 4gig decompressed file from OpenCellId with all the cell tower locations, and I have reduced it to about 800 megabytes by discarding 3G towers and 4G towers and converting ASCII to binary. I have copied this file onto an SDcard, and it contains the coordinates of 10 million towers, all sorted ascendingly.
When my microcontroller wants to get the location of a cell tower, it does a binary search through the ten million towers. Log base 2 of ten million is 24. So I shouldn't have to load more than 24 entries from the SDcard. I have hardcoded some of the towers into my program, bringing the search down from 24 to around about 12. I haven't quite got it finished yet but I reckon I'll have it done today. I'm hoping it will only take a second or two to convert a cell tower to longitude and latitude.
What field is in ascending order so you can do a binary search?
MCC, MNC, Ltac and CellId are all 16-bit numbers. Combine those four 16-bit numbers together and you get a 64-bit number. I'm doing the binary search on that 64-bit number. I have it working on my desktop PC simulator so I just need to tweak it for Arduino now.
Fine, but where did they get sorted into ascending sequence? And when the file is on an sd card, how will you know which 512 byte sector your next entry is located?
To sort them, on a desktop PC you can read in the ASCII text file, add all the cell towers to an std::vector and then just call std::sort. Or as a shortcut, you can use std::set which automatically sorts. Then write each 64-Bit number, along with two 32-Bit number for longitude and latitude, to a file in binary mode, so that each cell tower occupies 16 bytes.
On the microcontroller, open up the file on the SDcard and use file.seek() to navigate to the entry you want. Each entry is 16 bytes so I just do:
myfile.seek( index * 16u );
myfile.read(mybuffer, 16u);
There will be at most 24 of these read operations. But I aim to get it way lower than 24. It would be fantastic if I could find the tower within 1 second.
What do you do with the tower location?
As I read the documentation, SEEK is "Seek to a new position in the file, which must be between 0 and the size of the file (inclusive).". I do not see where it is looking for particular data value.
The data file on the SDcard contains the data for each tower. Each tower is:
64-Bit number for MCC,MNC,Ltac,Cellid
32-Bit number for longitude
32-Bit number for latitude
So altogether, each Tower is 128 bits, which is 16 bytes.
So if I navigate to position 0 in the file and read 16 bytes, then I'll get the first tower. If I seek to 16 and read 16 bytes, I'll get the second tower. If I seek to 32 and read 16 bytes, I'll get the 3rd tower.
Why bother with a binary search when you can seek to the exact tower number you want?
Because the 64-Bit numbers aren't sequential. They are sorted, but they're not sequential.
If the numbers were smaller, say 32-Bit, I could possibly create a file with sequential values, and then just seek to the 32-Bit number. I'd need about 64 gigabytes of space to do that.
But with ten million 64-Bit numbers that aren't sequential, the best I can do is a binary search.
Ok. But I see you are using a binary search based on the position of a record in the file. The number of positions you are working with, when divided by two for each iteration will skip over the actual record you are looking for. I think you need a 1 for 1 correspondence to make the binary search work.
I got it working just now. The binary search takes about 3.9 seconds running on an ESP32 clocked at 240 MHz. I reckon I can get it quicker though, I'm aiming for less than a second.
And to answer jremington's question, I haven't decided yet what I'm gonna do with the longitude and latitude. In fact I haven't even decided yet what kind of device I'm gonna make.
I'm putting together a bullet-proof circuit with a bullet-proof firmware that I'm gonna torture-test for weeks, checking the statistics for how long the superloop takes to iterate, and counting how many times I had to reset modules like the SIM800L and SDcard reader.
Once I've satisfied that I've got rock-solid hardware and a very robust firmware, I'll have a little think about what I want it to do.
I now have it down to 1.360 - 1.784 seconds per search. So that's less than seconds.
I'll get it less than a second though.
Also I'll write it so that the superloop jumps in and out of it, so that the superloop isn't stalled for an entire second while we're trying to find the longitude and latitude.
Would you be able to share your code please? There are 2 weeks since I am trying to do the exact same thing but can't get the sim800l to work as described ![]()
I'm going to go step by step through how to get this working.
Step 1: Download the file from 'https://www.opencellid.org/' that has the locations of all the cell towers around the world
Step 2: If you don't have Linux as your operating system, or if you don't have Linux in a virtual machine, download this VMware image of Debian and start it up: https://dlconusc1.linuxvmimages.com/046389e06777452db2ccf9a32efa3760:dlhz157/VMware/D/12/Debian_12.0.0_VMG.7z
We will be doing some stuff at the command line in Linux.
Copy the cell tower file into the virtual machine. Use sha256sum on it at the command line.
I have w11 on main wich allows me to sha256sum on files, also with Debian 12 on VMbox. Result: dd2d2cdb6c493a3d3d459577fe785bcf6fa4aaca7735f8ef4ff4a9ac11469d50
Is that the hash for a '.tar.gz' file? If so then unzip the tar archive:
tar xf filename.tar.gz
There should be a file in the archive ending with ".csv" (it stands for Comma-Separated Values).
5fbea0f9ca995ca14d9f16977cb8202548ee74b7ed9187848a3a63b1f0d022c8
This is the one for the 4gb csv file
Okay if we want only the 2G cell towers, then we can make a smaller CSV file as follows:
head -1 old.csv > new.csv
cat old.csv | grep "^GSM," >> new.csv
The first line takes the first line from the old file and writes it to the new file.
The second line takes the lines beginning with "GSM," and appends them to the new file.