Making your own GPS receiver from scratch? It’s certainly possible. All you need is a radio receiver, some software to decode the signals sent down from space, a bit of technical know-how, and perhaps some guidance from an expert – and you’re good to go.
Indeed, GPS is a fascinating piece of modern technology we often take for granted (how did people ever manage to find their way around with just paper maps???), allowing us to locate objects wherever on the planet they might be and take us from point A to point B with no issues.
As with most of the really cool tech, it was originally made for the military and, at the beginning, its ‘coarse’ positioning was only capable of accuracy within a few hundred meters. This legacy code was the first thing that programmer Chris Doble tackled to create his own GPS receiver from scratch.
Running it is possible from pre-recorded sample files or a connected RTL-SDR (a super-cheap USB dongle that can be used as a computer-based radio scanner for receiving live radio signals in your area without internet) and estimates are usually within a few hundred meters of the true location.
Specifically, Doble wrote the code for it in Python with no runtime dependencies other than aiohttp (for the accompanying dashboard), NumPy, Pydantic (for data sterilization), and pyrtlsdr, and shared the process on his YouTube channel, as well as his GitHub account.
Upon testing it with the accompanying web-based dashboard that shows location estimates and satellite information, the receiver managed to resolve a location rather quickly – in 24 seconds from a cold start – and then display its information in a browser window.
What you’ll need to make a GPS receiver from scratch
According to the GitHub repository of Doble’s GPS receiver project, which contains a Python package that processes samples of GPS signals from a file or SDR dongle to estimate a clock bias and location, you’ll also need to run the dashboard.
This is because the gpsreceiver package provided by Doble only logs information to stdout, e.g. when satellites are acquired or a solution is computed, but doesn’t have a graphical interface.
In terms of setup – first, you’re going to need proper hardware. If you want to record your own samples or run the receiver in real-time from an RTL-SDR, you’ll need a GPS antenna and (optionally) a ground plate. As for the software, you’ll use the following code:
python -m venv .env source .env/bin/activate pip install -r requirements.txt |
Running the GPS receiver setup from a file
If running the setup from a file, it will need to have a series of I/Q samples recorded at a rate matching SAMPLES_PER_MILLISECOND in config.py (the default rate is 2.046 MHz). The samples’ I and Q components must be represented by 32-bit floats and be interleaved, i.e:
[32-bit float][32-bit float][32-bit float][32-bit float]… ^ ^ ^ ^ Sample 0 I Sample 0 Q Sample 1 I Sample 1 Q |
You can pass the file to the GPS receiver by running the following from within the gpsreceiver directory:
python -m gpsreceiver -f $FILE_PATH -t $START_TIMESTAMP |
Here, $FILE_PATH is the path to the file and $START_TIMESTAMP is the Unix time when the samples began being recorded.
As Doble explained, Phillip Tennen made such a file available as part of his Gypsum project. It contains about 13 minutes of samples recorded from St Ives in the UK. To use it:
- Download nov_3_time_18_48_st_ives.zip from here
- Unzip it.
- Run python -m gpsreceiver -f nov_3_time_18_48_st_ives -t 1699037280.
If you want to record your own file:
- Connect your antenna to your RTL-SDR and your RTL-SDR to your computer.
- Install GNU Radio.
- Open the GNU Radio Companion (GNURC) by running gnuradio-companion.
- Open rtl_srd_gps_sampler.grc in GNURC.
- Click play in GNURC. A window will open.
- Record data for as long as you’d like.
- Close the window that opened in step 5.
- There will be a new file called samples-TIMESTAMP.
- Run python -m gpsreceiver -f samples-TIMESTAMP -t TIMESTAMP.
Running the GPS receiver from an RTL-SDR
If you’re running your setup from an RTL-SDR, then you should use the code:
python -m gpsreceiver –rtl-sdr |
Development
# Autoformat make format # Type check make type_check |
Dashboard
Referring to the dashboard, Doble pointed out that it takes information from the receiver’s HTTP server and renders it in a web-based interface, as well as that the receiver only exposes an HTTP server when running from a file, whereas “doing so when running from real-time RTL-SDR data causes the receiver to miss data and lose lock on satellites.”
Setup
pnpm install # A Google Maps API key is required to show location estimates on a map. Replace # the ellipses (…) with your API key. See here[1] for more instructions. # # 1: https://developers.google.com/maps/documentation/javascript/cloud-setup echo “VITE_GOOGLE_MAPS_API_KEY=…” >> .env.local # If you know the receiver’s actual location and want to show it on the map to # compare it with the estimated location, set this environment variable. Replace # LAT and LNG with the receiver’s actual latitude and longitude. echo “VITE_ACTUAL_LOCATION=LAT,LNG” >> .env.local |
Running
pnpm start |
Here, Doble noted that the GPS receiver must be running in order for data to be available to the dashboard.
Development
# Autoformat pnpm format # Generate dashboard/src/http_types.ts from gpsreceiver/gpsreceiver/http_types.py. # # Run from the root of the repository. ./bin/generate_dashboard_types.sh # Lint pnpm lint # Type check pnpm type_check |
For Doble’s detailed walkthrough and resources for the entire process of making your own GPS receiver from scratch, visit the project’s GitHub repository and its developer’s YouTube playlist, and you’ll be ready in no time.
Meanwhile, NASA has managed to acquire and track GPS navigation signals on the surface of the Moon with its Lunar GNSS Receiver Experiment, making it the first technology demonstration to get Earth-based navigation signals on our planet’s only natural satellite.