|
This project was started for an Open Source class at Portland State University. It is meant to help tie together the different componenets available to make a completely open hardware/software GPS solution using the Universal Software Radio Peripheral (USRP). LicenseAll code I've created for this project is released under the GNU General Public License. Most (if not all) other code I reference is also under the GPL, but please see their respective pages for the most up to date information. A full copy of the GPL can be found here: GNU Licenses Source CodeThe full source code repository for all original work can be found here:
The entire revision history is included in the above repository. I Moved from a local to a public repo, and when doing so got lazy and just imported the latest working scripts. This also hides the embarrasing early bugs. :) Parts of this code are dependant on the GNU-Radio framework, which can be found at the link below. I also tie into the GPS Correlator created by Isaac Carroll, and I've included that link for reference as well.
DocumentationI'll briefly break down the various components for the Global Positioning System and how they apply to this project. For a more thorough introduction, check out the Wikipedia entry. For all the details, I found the book "Fundamentals of Global Positioning System Receivers: A Software Approach" by James Bao-Yen Tsui very useful. Satellite & Signal The GPS constellation consists of at least 24 satellites (exact count varies since new ones are launched and old ones are decommissioned), all of which broadcast their information on the same frequency, 1575.42 MHz. The base GPS message (C/A code) starts off as a 50 Hz signal, and this includes precise time, satellite position, and other navigation data. This signal is encoded with a pseudo-random code (using CDMA, like some cell phones) unique to each satellite so that they are able to be transmitted on the same frequency. The encoding produces a signal at 1.023 MHz, which then gets modulated onto the carrier frequency of 1575.42 MHz. Antenna & ADC The receiver needs a device (hardware) to accept this signal, and here we will focus on the open hardware Universal Software Radio Peripheral. This is a great little device which allows you to both transmit and receive on a wide range of frequencies (depending on the daughterboards you have). It also includes a FPGA chip so you can push some of your application code down into hardware for better performance. For a GPS receiver, you would want to purchase the DBSRX daughterboard which can receive directly at the 1575.42 MHz frequency. I'm using a Basic RX daughterboard on the USRP which ties into another board which holds a Zarlink GP2015 chip. I'm only using the first stage of the Zarlink chip which downconverts the 1575.42 MHz signal to a 4.309 MHz signal (which is in the range of a Basic RX board). The USRP has a 64M sample/sec ADC (analog to digital converter), which is more than enough for our GPS signal at this frequency. We can sample at the 4.309 MHz frequency and use a decimation rate of 4, giving 64M / 4 = 16M samples/sec, which is enough to pickup the signal without aliasing. At this point the signal gets sent over USB to the host computer for processing (until we can push of the software into the FPGA). GNU Radio The GNU Radio platform is the primary development environment for the USRP. It provides a modular framework with many software signal processing modules ready to use. Once getting the software installed and verifying the USRP was working, I wrote the following python script to capture the raw GPS data (or any other signal): To capture the signal from the Zarlink/Basic RX setup, I run the command: python usrp_to_file.py -d 4 -f 4309000 -o gps.float -F This writes the signal data in floating point format to 'gps.float'. From here, we need to feed the signal into correlator software. Eventually that software will be written to be run on the FPGA, but for now I'm doing this as a multi-step process just as a proof of concept. This currently is not working on my test machine since the USB bus cannot keep up with the required bandwidth. I'm looking into ways of getting around this currently (8 bit samples, disabling channels, ...). This may work for you if you have a fast enough USB chip. If you happen to capture the data in complex format, but need it in floating point format, you can use the following script to convert between the two: You would use this in the following way, given 'gps.complex' is a complex data file from usrp_to_file.py: python complex_to_float.py -i gps.complex -o gps.float Correlator Software This project originally started to bridge the gap between the hardware and a previous project done at PSU, Software Defined Radio (SDR) GPS Correlator by Isaac Carroll. I'm currently using the software he wrote to handle the correlation. This piece is responsible for acquiring and tracking the pseudo-random code for each satellite. This allows you to obtain the ephemeris and pseudorange information from the C/A signal, and thus be able to calculate satellite and user position. In order to use the captured signal file we made with the correlator software, we'll need to tweak the options in acquire.py file. First, you'll want to change the SAMPRATE to your sampling rate (I used 16e6 for the 16M samples/sec from USRP), and then CENTERFREQ to whatever frequency you captured the data at (I used 4.309e6 to match the Zarlink chip output). This script (along with the other scripts in the correlator package) assume a little-endian format. You'll need to search through and replace some file packing formats from '<' to '>' if you have big endian. The next step is to convert the floating point output file from usrp_to_file.py (or complex_to_float.py) to a format the correlator software can use. I wrote another script to do this conversion, and can be found here: This reads the usrp data file and outputs another floating point file, but with some spacing in between the samples. I run it as so: python convert_file.py gps.float gps.corr Finally, we can run the correlator against this data file with: python acquire.py gps.corr With a little luck, a signal will be found. One other script I wrote and found useful for sanity checking the data files was: This takes a data file as an argument and just prints the unpacked floating point values. For the correlator file format, you should see a '0' for every other entry. The other non-zero values will be the actual signal. These last two scritps also assume little-endian format. Position Calculation & User Applications The final steps for a full application are calculating the satellite positions, and from this, the user position. There are already a few open source projects that can handle this, and the hope is to integrate the correlator software into the GPL-GPS project. This would complete the end-to-end open hardware/software solution. TestingIn order to verify the USRP was functioning as I expected, I went ahead and setup the USRP with a Basic TX and a Basic RX board. I connected a cable between the TX antenna and RX antenna to create a loop. With this, I generated a signal using the script in the correlator package, broadcast this with the Basic TX, and then setup another script to capture the data on the Basic RX board for processing. Below is a log of this test with some explantions.
First, modify the makefile.py in the correlator package to make a strong enough signal for raw data (and drop the code to generate lower for faster detection). % diff makesignal.py ../trunk.orig/makesignal.py 35c35 < CODE = 3 # which C/A code --- > CODE = 19 # which C/A code 51c51 < signal = [1000 * siggen.next() for _ in range(N)] --- > signal = [siggen.next() for _ in range(N)] % ./makesignal.py ../gps.mksig.2 2000000 1000 Now with our signal data file, modify and test the aquire script to be sure it works. % diff acquire.py ../trunk.orig/acquire.py 26,27c26 < #from scipy.fftpack import fft, ifft < from numpy.dual import fft, ifft --- > from scipy.fftpack import fft, ifft 39c38 < CENTERFREQ = 2e6 # center frequency in Hz --- > CENTERFREQ = 3.125e3 # center frequency in Hz % ./acquire.py ../gps.mksig.2 code freq offset numchunks 1 False 2 False 3 2000000.0 1564 1 4 False ... Now that the test data works, blast it over the TX board with the following script: % sudo ./usrp_from_file.py -f 2000000 -I 32 -i ../gps.mksig.2 fpga_master_clock_freq 64000000 dac_freq 128000000 tx_freq 2000000.0 interp_rate 32 In another terminal, grab the data off the RX board (make sure your cable is connecting the two antenna ports!): % sudo ./usrp_to_file.py -f 2000000 -d 16 -o ../gps.usrp.2 converter_rate 64000000 fpga_master_clock_freq 64000000 adc_freq 64000000 rx_freq -2000000.0 decim_rate 16 Now, run the captured data through the acquire.py script to make sure we still have the data: % ./acquire.py ../gps.usrp.2 code freq offset numchunks 1 False 2 False 3 2000000.0 750 1 4 False ... These scripts could be expanded to broadcast simulated GPS data and satellites for different types of receiver testing. Possibly another side project once the receiver is working... :) |