Showing posts with label gnuradio. Show all posts
Showing posts with label gnuradio. Show all posts

Tuesday, December 27, 2016

RTL-SDR to Orbit with LimeSDR!

As promised, I'd like to show you how the LimeSDR can be used as a GPS simulator to fake out a RTL-SDR device using a rocket trajectory and gps-sdr-sim.

First, I need to thank Dr. Takuji Ebinuma - the author of gps-sdr-sim, who provided me with the rocket trajectory. Takuji designed and built the GPS/GLONASS receiver for the satellite TRICOM 1, scheduled to be launched early next year on the Japanese SS-520-4 rocket. The satellite weighs 3kg and will be spin-stabilizied and contains an earth imaging camera. Here's a picture of the satellite, the GPS/GLONASS receiver is the yellow box:


The rocket is pretty cool too - a 3 stage to orbit vehicle just under 32' long and 2' in diameter which can put a few kilograms into orbit. The launch vehicle is tiny compared to conventional launch vehicles like Altas, Delta or Falcon. Its relative size and scale are encouraging to ambitious amateurs who would like to tackle the project of putting something small into orbit.



More information on the satellite and rocket can be found in this article. Takuji also blogged about it on his blog.

On to the simulation. Takuji provided the trajectory file which is included with his bladeGPS real-time simulator. The trajectory is generated using OpenTsiolkovsky, an open-source rocket trajectory simulator. The trajectory goes from T-60 seconds through the first orbital period but I will only be investigating the first 6 minutes of the trajectory. SoftGNSS only acquires satellites once, at the beginning of processing, so by 6 minutes in several satellites are starting to fall out of view and the GPS fix starts to wander and ultimately fail. However the first 6 minutes are sufficiently interesting as the vehicle accelerates from standing still in the ECEF (Earth Centered Earth Fixed) frame to orbital velocity.

Using gps-sdr-sim (with one tweak - in gpssim.h, change USER_MOTION_SIZE to 3600 or higher to allow for 360+ seconds of simulation, then recompile) the baseband RF can be generated by executing the following:


./gps-sdr-sim -e brdc3540.14n -u ss520-4.csv -d 900 -o trajectory_10M.s8 -s 10000000 -b 8

Then I took the flowgraph I used last time, disabled the receive chain and updated the source file on the transmit chain. I connected the output from my LimeSDR directly to the 1PPM RTL-SDR with bias tee I've been using for testing over the past year. I started the transmission in GNU Radio and then captured the RF using rtl_sdr on the command line like so:


Here is the setup. The USB cable sends samples from GNU Radio to the lime colored LimeSDR. The output from transmitter 1 is sent via SMA cable to the RTL-SDR stick plugged directly in the computer. The samples from the RTL-SDR stick are then captured by rtl_sdr on the command line:


Feeding the output from the RTL-SDR into SoftGNSS, we can see the RTL-SDR captures the trajectory of the rocket from launchpad to low earth orbit. Green satellites are sufficiently strong to track, I use the seven strongest satellites in my navigation solution below.



We can clearly see all three motor burns in the velocity profile. These align well with the values given in the input deck.


Finally, a map showing the ascending trajectory of the rocket as it flies from Uchinoura Space Center in Japan. The three red segments are the three stage burns. Yellow denotes coast phases. 



Now, while this is very exciting, there are a few important caveats
  1. The signal generated is perfect: there is no thermal noise or other RF interference
  2. The trajectory is idealized: acceleration is smooth and there is no jerk
  3. There is no occlusion of satellites due to the location and orientation of the antenna on the vehicle
  4. There is no structural vibration or other environmental factors
As such there is no guarantee a RTL-SDR would perform as admirably on an actual rocket.

Next: will be focusing my attention on working with the FPGA.

Tuesday, December 20, 2016

GPS Fake-out with the LimeSDR

I've been privileged to receive an early LimeSDR unit to perform some testing and demonstration! Today I'd like to show you the LimeSDR, the 3d printed case I designed for it, and a demonstration of using the LimeSDR to simulate GPS signals.

First, here's the LimeSDR. It was funded via Crowd Supply and features dual TX/RX with operating frequencies of 100kHz to 3.8GHz at 12 bits, full duplex! You can find more information at the Crowd Supply link and at the MyriadRF discourse.


First thing I did was to design a case to be 3D printed to protect the board. I am always paranoid about using bare circuit board. (Part of the reason I've been negligent in posting the past few months is because I caught the 3D printed bug. My kids and I have been busy building and fighting plastic antweight robots at Robot Roundabout) You can download the STL models of the case from Thingiverse. Here's the case in action:


I used a sharpie to mark the channels and TX/RX. I have a CAD model which has those engraved, but my printer is not quite that precise. I'm pretty happy with the case it has served me well. The only thing I might add is a clip to hang it from my laptop monitor like I did with my HackRF. If you decide to use it and have any feedback I'd be happy to take it! 

So once you get your LimeSDR, it is pretty straightforward to set up. Under Linux, follow the instructions on the wiki, with one minor alteration: during step 2.1 do not apt-get limesuite or limesuite-udev. Instead, continue with the instructions as you will be installing LimeSuite from source in Step 4.1. On my machine, anyways, the presence of the lms7 driver from the ppa and the lms driver installed from source confused SoapySDR. If you are using Windows, download the drivers from here, plug it in to your USB port and tell Windows where the drivers reside. You can then download Pothos to run GNURadio and other supported applications in Windows.

So once I was set up under Linux, I did the canonical SDR test of tuning in the FM band in gqrx. And behold, there was spectrum! Next, to probe the features of the device, use the command "SoapySDR --probe". Study the output closely and you will see there are multiple transmit and receive antennas for each channel. Cross-check the names with the LimeSDR Schematic (page 5/6) and you can see the appropriate frequency ranges for each antenna. You will need to know which antenna port your antenna is connected to so you can tell GNURadio which antenna to tune.

On to GNU Radio. If you have your own installation, make sure that gr-osmosdr is installed with SoapySDR enabled. If you use pybombs, you can uninstall gr-osmosdr and then reinstall gr-osmosdr and it should work since you installed SoapySDR two paragraphs ago. Alternately if you don't have GNU Radio installed you can get them from the MyraidRF GNU Radio PPA.

In order to fake out GPS, I needed to either record and replay acquired GPS signals, or generate the GPS signals from software. I opted for the latter, as eventually I want to simulate high speed and high altitude trajectories to test software receivers on the bench. I used gps-sdr-sim by Takuji Ebinuma. An open-source code, it uses a GPS broadcast ephemeris file (one is provided) to orient the satellite constellation, and then based on a user specified location or path you can generate a baseband signal of the GPS constellation. For this first example, I picked a fixed location, 5 degrees latitude, 10 degrees longitude, 15 feet altitude - nice, round numbers that happen to lie outside Nkongsamba in Cameroon. I used 10Msps and 8 bits of I/Q resolution. The command line is thus:

./gps-sdr-sim -e brdc3540.14n -l 5,10,15 -d 60 -s 10000000 -b 8
Now to build the GNURadio flowgraph. On the transmit chain, we need to read in the file generated by gps-sdr sim, convert it from 8 bit interleaved samples (I,Q,I,Q,I,Q...) into 32 bit Complex values for the osmocom sink. For the file source, grab the full file path and set repeat to false. This is what I consider to be best practice because if you repeat, you won't see a change in the statistics of the transmission, but the satellites jump places in the sky and this will cause errant results on the decoding. If you don't repeat, the void will be filled in with null values and this, statistically, is visible to the naked eye in a waterfall. For the osmocom sink, specify the device string and the antenna. 





On the receive chain, our source is the LimeSDR using the same device arguments but specifying the LNAW output antenna. We use the Complex to IChar block to reduce from 32 bit integer to 8 and interleave the samples, and write to file.



The complete flowgraph looks like this:



If you are having trouble setting up your flowgraph, you can download my grc file. 

On the hardware side you need to connect the transmit antenna (BAND1) to the receive antennal (LNAW). To do this I used a direct connection via SMA cables and an attenuator. Once connected I ran the flowgraph. I then took the recorded file and ran it through my fork of SoftGNSS.




What's next? I want to fake out the flight RTLSDR stack with a rocket-type trajectory with velocity/altitude which violates the so-called COCOM limits. After that, I am going to play with the FPGA on board the LimeSDR. 

Tuesday, April 12, 2016

GNURadio XMLRPC hints

If you are like me with a Windows computer using GNURadio in a VMware virtual machine, here's what you need to know to XMLRPC from a remote computer into your VMware instance on your local machine.

First, you need to make sure your VMWare instance is using a bridged connection. A bridged connection will present your VMware instance as a separate computer to your router giving it a unique IP address on the LAN (note: it is possible to use NAT, where the VMware instance appears on a private LAN to your PC, but the configuration gets messy for port forwarding)


Now, you should be able to use XMLRPC on your LAN. Download the example scripts from the GNURadio repository. In your virtual machine open up 'xmlrpc_server.grc' in grc. Open up the XMLRPC server block and change the IP address from 'localhost' to '0.0.0.0' and the port to whatever port you want to use.


If you use 'localhost' you will default to the local loopback device and will not be able to reach it from outside the VM instance. Execute the diagram and start the server - you should see a window pop up with a scope and FFT. 

You will need to get your VMware instances' IP address using ifconfig or some other tool. In my case it is 192.168.1.10.

On your client machine, download the example scripts and open up 'xmlrpc_client.grc' and edit the XMLRPC client blocks to use the IP address of your VMware instance and the same port


Execute the diagram and move the slider - you should see it update on the server.

Now, if you want remote access from outside your LAN we need to configure the router. First off for convenience' sake give the VMware instance a static or reserved IP address so that the MAC address of the VMware instance will always get the same IP address on the local network. Now, we can configure port forwarding, in which your router will take incoming traffic on a certain port and forward it to your virtual machine. My configuration looks like this:


Now you need to determine your routers' IP address or - better yet - set up a dynamic DNS address so that you can use a URL to always hit your router. I'm not telling you mine :) but I use a free one from freedns.afraid.org. Now go to your off-the-lan computer and update the XMLRPC client as above, but with your router IP address or dynamic DNS. If you did everything right it will work!





Friday, April 8, 2016

Paul Breed Rocket Test Flight Data #3: MOAR RESULTS!


I got a little help on Reddit. Thanks to PE1NUT for identify a way to visualize the crystal drift in the data and jddes for doing some sleuthing: he identified some On Off Keying (OOK) right at ignition. Sure enough; I loadded the data up in Inspectrum (which I should have done in the first place!):


Turns out Paul is using a 900 MHz wireless transmitter to ignite the rocket which sends OOK for about 1.5 seconds, which leave its mark at 1.5 GHz! There are peaks at ~ -300kHz and ~ +650kHz.

So I played around with filtering the data with mixed success initially. When you look at the data, the intermediate frequency (IF) is 110 Hz, or damn near zero, so half the spectrum is negative in frequency and the other half is positive. In order to filter just one half of the spectrum you need to have complex taps on your FIR filter. Now, the problem is most of the GNURadio filter blocks don't expose complex taps! The generic FIR filter and the band pass filter do but you have to provide the taps. Fair enough... but the gui to firdes (Finite Impulse Response Design tool) doesn't expose complex taps either! Ideally we'd want two band reject or notch filter. But since the band pass filter does work with complex taps we can add (n+1) band pass filters together to do the same thing - we just band pass two chunks instead of band rejecting one. Ultimately the flowgraph looks like this:


I also put in an automatic gain control block to try and deal with the jumps in the spectrum (horizontal lines). You can download the flowgraph if you like.

The easiest way to just filter a chunk of time is to split up the data file into three - the first part, the noisy part, and the last part. A combination of "split -b" and "head -c" are used on the command line, then the files are re-merged with CAT.

Here's the cleaned-up spectrum. There's still some jumps in the spectrum but the peaks are nulled out. We lose data, but the hope is that the data lost is outweighed by the interference removed.


I still don't get a valid fix during engine firing but I do reacquire satellites a bit quicker... meaning more data in flight!  Updated trendline in black. Tracking from ~ 3500m to 5000m, covering 12 seconds of flight. There are 30 seconds from ignition to apogee, gnss-sdr loses lock during motor firing (~6 seconds) assuming that is insurmountable there is a maximum of 18 seconds of valid GPS data. Assuming perfection, you could start tracking on the next subframe and have a maximum of 20 seconds of flight data, (if you miss that subframe, 15 seconds) so we're over halfway there. Of course, not losing it during the motor firing would be ideal!

Money shot

Saturday, April 2, 2016

Paul Breed Rocket Flight Test Data!

This post is long overdue as I've been quite busy with my day job that I've been remiss in updating the blog with the progress happening with the rocket GPS.

On February 6th, 2016 Paul Breed flew an RTL-SDR on a high power rocket to capture GPS RF data for post-processing. This was the second test flight and the first one to get good data.

Hardware Configuration

Paul shows off the payload. The blue box outlines a 6DOF IMU, the orange box is a LNA4ALL low noise amplifier. On the reverse the orange box outlines a 2S LiPo battery, the green box a Nooelec 0.5PPM TXCO in aluminum case and the blue box an Intel Compute Stick running Ubuntu, and the yellow trapezoid a quadrifilar antenna GPS antenna from antennas.us.


Backside of RF capture unit.


Frontside of RF capture unit.


Hardware Configuration

They payload is packaged inside the nosecone fairing of the rocket. Here, the rocket is mounted on the launch rail in a horizontal configuration. Before launch the rail is elevated to near vertical, but this orientation allows for easy handling of the rocket.

Rocket mounted on the launch rail

At T-2 minutes (2 minutes prior to launch) the rocket begins aquiring data - Paul SSH's over wifi into the Intel Compute Stick to trigger a script which calls rtl_sdr centered on the L1 frequency with a bandwidth of 2048000 Hz. Two minutes is sufficient time to get multiple GPS fixes of the launch site.

And at T-0, smoke and flames!

Liftoff!



Post-flight analysis

I took the output from rtl_sdr and converted it to complex for gnss-sdr. I was able to get a fix on the pad but not much after that. The last fix was at about 145 seconds - liftoff was likely between 145 and 150 seconds. I attempted to make a few tweaks to the tracking loop configuration gnss-sdr file with little success - it changed the results but not the actual character, that is not a whole lot after liftoff. I did find I was able to get a few subframes well after launch - 3 with the final configuration file - but not enough to get a fix. But there are other codes to be investigated which can get an approximate fix without a full 4 satellite solution.

One of the productive changes was decreasing the step size of the doppler search - this performs a more refined search and reveal more post-launch subframes. Initially I had one subframe and through tweaking the search step size (to 100 hz) I was able to get three. It is tempting to increase the doppler window but the max doppler shift of a GPS satellite to a stationary receiver is ~ 5kHz and the default search window is +/- 10 kHz - unless you are going orbital velocity at the satellite while it is coming at you, you are well within 10 kHz.

Here's the KML file in Google Earth. Don't get too excited about the altitude jumps! There are two of them in the file one occurs during the first few fixes and the last ones are of similar magnitude. I've seen the same thing happen with fixes at home. We know for the early jumps the rocket is sitting soundly on the pad and the latter jump is of the same magnitude.



I took the GPS time from gnss-sdr and used an online tool to back out the orientation of the satellite constellation during the rocket flight. The arrows point to the satellites which were used to get position fixes as output in the RINEX files. It is interesting to see some satellites which appear farther away on the map are useful to getting a fix where closer ones are not - however that's only half the story.


If we look at altitude (the earth is crudely pointed so the launch site is oriented up towards the top of your monitor) we see the satellites it uses are largely overhead and the "closer" satellites are on the horizon.



I also looked at the two satellites which gave valid subframes after T-0, they are PRN 3 and PRN 11, shown here.



So why didn't we get a good fix in flight? There are two likely culprits - the vibration / acclereation environment and the loop dynamics. Both vibration and acceleration affect the crystal which effects the frequency being captured. If the tracking loops are off then we'd anticipate losing satellite  directly overhead (in the direction of acceleration) and not laterally where the acceleration of the rocket doesn't effect things much. I tweaked the tracking loops as far as I could without making results worse and they didn't seem to get any better. Based on the fact that one of the satellites is fairly high in the sky my gut suspects the acceleration/vibe environment.

UPDATE: Got a brief in-flight nav solution; see this post!

But there's still work to be done to try fft-based approaches like fastgps, dig into the intermediate outputs and see if some smart people out there have ideas!

Thanks to Paul for providing the data, test hardware and ideas on how to look at and understand the data. Follow his blog or twitter!
Files
  1. Feb6.bin - raw RTLSDR binary file (interleaved shorts) you will need to convert to complex.
  2. flight.conf - gnss-sdr configuration file
  3. output.log - Console output from "gnss-sdr --config_file=flight.conf"
  4. PVT.kml - Position fixes in Google Earth format
  5. GSDR086x11.16N - Navigation data in RINEX format 
  6. GSDR086x11.16O - Observation data in RINEX format

Next Actions
  1. Investigate gnss-sdr telemetry and tracking outputs
  2. Try running through fastgps code 
  3. Get help from smart gps/sdr folk!

Saturday, February 27, 2016

Find the signal in the noise




 GPS signals are very weak, coming in at about 120 dBm ... which is below the thermal noise floor of ~ 100 dBm! If you try plotting an FFT 2 MHz wide about the L1 frequency you won't be able to distinguish the signal from the noise.



But it is there, and we can find it! 

First, we need data. I used data collected with an RTL-SDR stick converted to complex output. The output from the RTL-SDR is interleaved unsigned short, whereas the input block expects signed complex numbers. I talked about this in a prior post; I use the gcc code myself. 

So when we have data we can build a very simple flow diagram in GNURadio to play back the file and visualize it using the Fast Autocorrelation Sink. As noted in a previous post, there is a bug in GNURadio which breaks the Fast Autocorrelation Sink, but it is an easy fix!


The Fast Autcorrelation Sink is documented on Balint Seeber's blog and provides links to why the fast autcorrelation sink is indeed so fast! If you aren't familiar with autocorrelation, it is the correlation of a signal with itself. At any given time the correlation of a signal with itself is perfect, but if you insert a time delay and look at a later signal compared to a previous signal we can see just how similar the later signal. 

For example let's visualize a triangle wave with a frequency of 1000 Hz - that is, 1000 peaks per second, or 1 peak per millisecond. Since each repetition of the triangle is exactly 1 millisecond apart and since there is no noise in the system we would expect that every millisecond we'd have a perfect correlation of the shifted signal to the current signal. In between those milliseconds the correlation would get worse until we were half a millisecond apart where the peaks from the original signal would line up with the troughs of the shifted signal, resulting in a negative correlation.

Here's a simple flowgraph in GNURadio to visualize the autocorrelation using the Fast Autocorrelation Block from gr-baz. First, we create a signal source of a triangle wave with a frequency of 1000 Hz. Then we insert a throttle - this throttles the rate at which the diagram runs so we can visualize the signal. Left to its own devices GNURadio would simply pump triangle waves as quickly as it could with the given CPU resources. Then we can visualize the waveform using a WX GUI signal sink and the autocorrelation using the Fast Autocorrelation Sink:



Note the color of the block interfaces: Orange. This means floating point. Most of the blocks will default to complex, which is what you'd want for a lot of radio work but in this case it just makes things confusing as you will be plotting the triangle waves in both the Re and Im space. You can double click on each block and change the types to floating point or POWERUSER TIP: Click on the block and use up/down arrows to change the type. Once the flowgraph is complete (or download it here) hit play and you should see something like this:


We see our triangle waves with a period of 1 Hz and the Fast Autocorrelation Sink showing peaks at 1 Hz, and negative peak at a rate of 1 Hz shifted by half a Hz. 

So now let's do it with a real signal. You can use the same flowgraph, we just need to substitute the signal source block for a file source and specify our complex file. And since the file is complex, we need to change the data types. Finally, the throttle should be set to the sample rate of your input source - in my case, 2048000 Hz for the RTL-SDR. For the fast autocorrelation sink you will likely want to tweak the size to make the number of milliseconds a reasonable number. For my use I did (2**18)/2. Here's the updated diagram, running with the Fast Autocorrelation Sink, which you can download from github.


We see nice peaks every millisecond. Why every millisecond?

The coarse/acquisition code for GPS (C/A) has a period of 1023 chips which are transmitted at a rate of 1.023 MBit/s. This results in period of 1 millisecond. BAM! You can read more about the encoding on wikipedia. The L1 carrier at 1575.42 MHz has two codes, the C/A code and the navigation message. The navigation message varies with time as the satellites move through space but the C/A code does not change.  The C/A code is used for locking onto the satellites: Each satellite has a different unique C/A code. Earthside a receiver generates a particular C/A code and then shifts it in time and frequency to correlate the known C/A code with the C/A code of the satellite. Since we don't have a perfect clock we have to shift in time to line up our signal with the GPS signal timing and since the satellites are moving rapidly they frequency we receive is subject to a doppler shift of up to 5kHz (10kHz if we are moving very quickly, say, on a rocket or missile)

But that's a story for another day.

Wednesday, January 13, 2016

GNURadio: Getting audio to work in a VM

I've been going through a number of GNURadio tutorials and the waveform generator (signal sources) and display sinks have worked just fine. But then I hit a tutorial using the RTL-SDR stick as input and a flowgraph to process FM radio and an audio sink... and I get choppy audio! I started googling and most people blame the VM, but YouTube audio works just fine.

Then I stumbled across this post which contained the answer:

Ok, here are the contents of my ~/.gnuradio/config.conf:

[audio_alsa]
default_input_device = default
default_output_device = default
#period_time = 0.010                      # in seconds (default)
period_time = 0.100                      # in seconds
nperiods = 4                 # total buffering = period_time * nperiods
#verbose = false
verbose = true

The actual change I made was to increase audio_alsa/period_time from
0.010
to 0.100.  Play around with it until it works on your system.  My only
guess is that perhaps the default ALSA buffer sizes are small enough
that
they are often consumed by ALSA before GnuRadio will fill them.

Cheers,
-Remington

By default (at least in my Kali Linux VM) config.conf does not exist. Copy and paste the block of code to ~/gnuradio/config.conf.

For me, the above settings didn't work, but increasing period_time to 0.400 and nperiods to 16 and audio is crystal clear! Try the above settings, then mine, then something in between... hopefully this works!

Thursday, December 24, 2015

Acquire GPS signals from rtl_sdr recording

This one took a few evenings of head-scratching to finally resolve.

I want to be able to record I/Q off an RTL-SDR stick and then post-process it with gnss-sdr. The rtl_sdr software by default dumps interleaved unsigned shorts - that is an (uchar)i_sample, then a (uchar)q_sample, then an (uchar)i_sample, so on and so forth.

gnss-sdr has a couple of different SignalSources and a couple of different item_types and I initially tried varying combinations of those hoping something would work out of the box. Part of my confusion was the existence of an Osmosdr_Signal_Source which uses the RTL-SDR stick and outputs gr_complex without any intermediate conversion. I figured there would be a way to use this SignalSource with raw RTL-SDR dumps but this is not the case. In any case, with the current gnss-sdr infrastructure one must convert the rtl_sdr dump into a file format that gnss-sdr will read.

There are two components to getting an rtl_sdr dump into gnss-sdr. The first is converting the input file from interleaved uchars to gr_complex. The second is properly configuring your input file.

Converting rtl_sdr interleaved uchar into gr_complex

This is fairly well documented in this post at the Amateur Radio stackexchange. There are two methods proposed, one is writing up a flowgraph in GNURadio to convert the file. The second is a short C program posted by Dr. Paul Brewer which performs the exact same operation in 45 lines of code (with comments!) I opted for the C code. Once you compile the program, the process looks like this:
  1. Acquire dump using "rtl_sdr /path/to/mydump.bin -s 2.048e6 -f 1575.420e6 &"
  2. Convert file using "rtlsdr-to-gqrx /path/to/mydump.bin /path/to/complex.bin"
A third option is to write a radio receiver in GNURadio which uses the RTL-SDR stick to directly write a file in the appropriate format. I will go through this in a future post, as it is a good introduction into gnuradio using only two blocks.

Creating an input file

You can use the "gnss-sdr_GPS_L1_rtlsdr_realtime.conf" as a template and make the following changes:

  1. SignalSource.implementation=File_Signal_Source
  2. SignalSource.filename=/path/to/complex.bin
  3. Change every sampling_frequency to the sampling frequency used in the initial acquisition
  4. Change the InputFilter.IF to your IF
Once you make these changes you should be able to decode the file.

Bonus: Have your cake and eat it too!

You can skip the whole mess by modifying two line of code in gnss-sdr_GPS_L1_rtlsdr_realtime.conf which will let you dump the raw I/Q in complex format to file while in parallel running the tracking loop and getting a GPS solution.

To enable this,
  1. Set SignalSource.dump=true
  2. Set SignalSource.dump_filename=/path/to/dump.bin
Now you can track in realtime and generate a data file to post-process simultaneously!

As always any questions, comments or suggestions please leave a message.

Wednesday, December 16, 2015

Acquiring GPS signals with an RTLSDR dongle using gnss-sdr

Once you've installed gnss-sdr and tested your installation with prerecorded data, the next step is to try and get a live GPS solution. The following is based off this node at gnss-sdr.org and this paper. The paper is a really good mix of theory and implementation and I strongly recommend reading it.

The first thing you need to do is calibrate the front end of your RTL-SDR device. The calibration procedure will do the following
  1. Download an ephemeris via SUPL. This provides your computer with advance knowledge of the GPS satellite locations, allowing you to get a quick fix.
  2. Search for GPS satellites
  3. Calculate the doppler shift assuming your RTL-SDR stick is perfect (trust me, it's not!)
  4. Using the predicted doppler shift and some fancy math (see the paper, section 5), calculate
    1. The actual sampling frequency
    2. The actual IF bias

Before running the calibration you need to update the front-end-cal.conf. Make a copy of the version installed (typically to /usr/local/share/gnss-sdr/conf/front-end-cal.conf). On the first couple of lines you will see a number of GPS lat/lon/alt locations commented out using a semicolon. You need to provide your best estimate at lat/lon/alt, bearing in mind altitude is in meters. The easiest way to do this is use a tool like the aptly named mapcoordinates.net. The other change I had to make was to change both SUPL servers to supl.google.com in place of supl.nokia.com - for some reason the nokia servers were not working. Once complete, you can run the front end calibration like so 

sudo front-end-cal --config_file=/path/to/my/front-end-cal.conf

Your output should look something like this
linux; GNU C++ version 4.9.1; Boost_105500; UHD_003.007.003-0-unknown
Initializing... Please wait.
Logging will be done at /tmp
Use front-end-cal --log_dir=/path/to/log to change that.
Trying to read ephemeris from SUPL server...
SUPL: Trying to read GPS ephemeris from SUPL server...
SUPL: Received Ephemeris for GPS SV 1
SUPL: Received Ephemeris for GPS SV 2
SUPL: Received Ephemeris for GPS SV 3
SUPL: Received Ephemeris for GPS SV 5
SUPL: Received Ephemeris for GPS SV 6
SUPL: Received Ephemeris for GPS SV 7
SUPL: Received Ephemeris for GPS SV 8
SUPL: Received Ephemeris for GPS SV 9
SUPL: Received Ephemeris for GPS SV 10
SUPL: Received Ephemeris for GPS SV 11
SUPL: Received Ephemeris for GPS SV 12
SUPL: Received Ephemeris for GPS SV 13
SUPL: Received Ephemeris for GPS SV 14
SUPL: Received Ephemeris for GPS SV 15
SUPL: Received Ephemeris for GPS SV 16
SUPL: Received Ephemeris for GPS SV 17
SUPL: Received Ephemeris for GPS SV 18
SUPL: Received Ephemeris for GPS SV 19
SUPL: Received Ephemeris for GPS SV 20
SUPL: Received Ephemeris for GPS SV 21
SUPL: Received Ephemeris for GPS SV 23
SUPL: Received Ephemeris for GPS SV 24
SUPL: Received Ephemeris for GPS SV 25
SUPL: Received Ephemeris for GPS SV 26
SUPL: Received Ephemeris for GPS SV 27
SUPL: Received Ephemeris for GPS SV 28
SUPL: Received Ephemeris for GPS SV 29
SUPL: Received Ephemeris for GPS SV 30
SUPL: Received Ephemeris for GPS SV 31
SUPL: Received Ephemeris for GPS SV 32
SUPL: Trying to read Acquisition assistance from SUPL server...
Actual RX Rate: 2000000.000000 [SPS]...
Actual RX Freq: 1575420000.000000 [Hz]...
PLL Frequency tune error 0.000000 [Hz]...Actual RX Gain: 40.200000 dB...
Front-end RAW samples captured
Using Volk machine: sse4_2_64_orc
Searching for GPS Satellites in L1 band...
[ . . . . 5 . 7 8 9 . . . . . . . . . 19 . . . 23 . . . 27 28 . 30 . . ]
Total signal acquisition run time 2.73478 [seconds]
Reference Time:
GPS Week: 851
GPS TOW: 276680 22134.400000
~ UTC: Tue Dec 15 20:51:21 2015
Current TOW obtained from SUPL assistance = 276680
Doppler analysis results:
SV ID Measured [Hz] Predicted [Hz]
5 3000.00 871.77
7 2875.00 524.39
8 2500.00 170.24
9 1125.00 -1220.17
19 6000.00 3734.82
23 -750.00 -3032.99
27 687.50 -1703.53
28 4375.00 2306.86
30 3750.00 1621.38
Parameters estimation for Elonics E4000 Front-End:
Sampling frequency =1999997.27 [Hz]
IF bias present in baseband=2151.87 [Hz]
Reference oscillator error =-1.37 [ppm]
Corrected Doppler vs. Predicted
SV ID Corrected [Hz] Predicted [Hz]
5 848.13 871.77
7 723.13 524.39
8 348.13 170.24
9 -1026.87 -1220.17
19 3848.13 3734.82
23 -2901.87 -3032.99
27 -1464.37 -1703.53
28 2223.13 2306.86
30 1598.13 1621.38GNSS-SDR Front-end calibration program ended.

The important outputs are highlighted above, the sampling frequency and the IF bias. The sampling frequency is nominally 2 MHz but deviation of a few Hz are normal. Baseband is defined as 0 Hz, so when the signal is shifted to baseband if the signal is not exactly centered at 0 Hz this bias is calculated as an IF bias. 

To receive GPS, then, we can copy the gnss-sdr_GPS_L1_rtlsdr_realtime.conf file (typically located in /usr/local/share/gnss-sdr/conf) to another directory and make a few edits. Handily enough there are comments in the file like this

NSS-SDR WITH RTLSDR DONGLES USER MUST SET THE CALIBRATED SAMPLE RATE HERE
; i.e. using front-end-cal as reported here:http://www.cttc.es/publication/turning-a-television-into-a-gnss-receiver/


at each place we need to make an edit. The four edits you need to make are

GNSS-SDR.internal_fs_hz=(your sampling frequency)
SignalSource.sampling_frequency=(your sampling frequency)
InputFilter.sampling_frequency=(your sampling frequency)
InputFilter.IF=(your IF bias)

Once complete, you can run the receiver 

gnss-sdr ---config_file=/path/to/your/gnss-sdr_GPS_L1_rtlsdr_realtime.conf

It will likely take a minute or two to get a fix as a certain amount of ephemeris and almanac data must be downloaded from the satellites. You also must have at least four satellites in view. Here is example output once a fix was found:


Using the KML file generated by gnss-sdr I was able to plot the locations generated in Google Earth


The red dots are individual position fixes. The blue arrow points to the skylight where my GPS antenna is mounted. The road is a two-lane road with no shoulder and the boat in the backyard is 20' long. There is a bias which may be due to the fact that the roof occludes satellites to the east (the four satellites I picked up were, at the time, overhead and eastward). I want to move the antenna up to a (plastic) roof vent in the attic to get a better view of the sky.


Testing gnss-sdr with prerecorded data

Under the documentation section of gnss-sdr.org there is a post entitled "First positioning fix using Galileo" where they document getting a position fix using (at the time) all four Galileo satellites (there are now ten in orbit). They provide not only the position fix but the raw I/Q data which can be fed into gnss-sdr to replicate the fix. This makes a good first test of a gnss-sdr installation.

The page is not incredibly verbose so I will add some verbosity here. First off download and decompress the data from the link provided on the page. Inside the folder you will find the raw data file (.dat) along with a configuration file (.conf) USRP recording output log (.log) and output from their gnss-sdr run (.txt), Google Earth output (.kml) and NMEA messages (.nmea) 

Unfortunately the provided configuration file doesn't work with the current gnss-sdr. However the default configuration file provided with gnss-sdr works just fine. So do the following

  1. Copy gnss-sdr.conf from the installation location (typically /usr/local/share/gnss-sdr/conf/gnss-sdr.conf) to the directory containing the raw data file you downloaded
  2. Update the line SignalSource.filename to the full path filename of the data file
  3. Set GNSS-SDR.SUPL_read_gps_assistance_xml=false

Once you made those two tweaks you can execute the example by running
gnss-sdr --config_file=/path/to/my/gnss-sdr.conf

You should see similar but not identical output to the output provided with the data file. Once the run completes you should have a number of new files. The KML and NMEA files were already described, but you will also see some files named GSDR350w40.15N and GSDR350w40.15O. The file ending in "N" is the navigation solution and the file ending in "O" is the observables. Basically, the navigation solution is your 'fix' and the observables are what information you received from the satellite to generate that fix. Lastly, the gps_ephemeris.xml is an ephemeris which is a description of the satellites' orbit in space.

Setting up gnss-sdr in Kali Linux


Here's instructions on how to set up gnss-sdr in Kali Linux virtual machine. Kali Linux is

... an open source project that is maintained and funded by Offensive Security, a provider of world-class information security training and penetration testing services. In addition to Kali Linux, Offensive Security also maintains the Exploit Database and the free online course, Metasploit Unleashed.

Most importantly, it comes with a modern version of GNURadio and up to date versions of nearly all the dependencies, making getting gnss-sdr installed quite easy.

Installation Instructions

1. Download the Kali Linux VM, or install Kali Linux from ISO.

2. Create a user account and home directory

3. Update apt-get
sudo apt-get update
4. Install cmake
sudo apt-get install cmake
5. Install gnss-sdr dependancies
sudo apt-get install libboost-all-dev gnuradio-dev liblapack-dev libgnutls-openssl-dev libgoogle-glog-dev liblog4cpp5 liblog4cpp5-dev liblog4cpp-doc
6. Install Doxygen
sudo apt-get install doxygen doxygen-gui graphviz
7. Install gnss-sdr (instructions derived from http://gnss-sdr.org/node/45)
git clone https://github.com/gnss-sdr/gnss-sdr
cd gnss-sdr/build $ cmake -DENABLE_OSMOSDR=ON ../
make
sudo make install
make doc
make pdfmanual
make doc-clean
The -DENABLE_OSMOSDR=ON is required to build the rtlsdr drivers!

You should now have a working copy of gnss-sdr; to test it out type gnss-sdr into your console and you should see something like this:


There is an error message because no configuration file was specified, and the default configuration file doesn't point to a valid signal source on my file system (and likely yours, either). No worries we'll fix that later. The message generated here indicates a good installation.