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 27, 2016

Fast Autocorrlelation Sink broke? Here's the fix

If this diagram doesn't work for you:


There's a very easy fix, outlined here. The issue is that GNURadio is asking wxGUI for the window size before the window is created. The fix is to edit top_block_gui.py. This file is likely located in ./usr/lib/python2.7/dist-packages/grc_gnuradio/wxgui/top_block_gui.py assuming your build prefix is /usr.


This defers creation of the GUI element and removes the error. And as you'd expect the autcorrelation of random noise is not very interesting :)




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.

Monday, December 21, 2015

Project Background

A few months ago Paul Breed of Unreasonable Rocket posted on Twitter asking for help from getting GNSS-SDR running on an Intel Compute stick...



I responded and Paul provided an Intel Compute Stick, RTL-SDR stick with a 1PPM TXCO and the bias tee mod and an active antenna. It was my job, then, to make it work in parallel with Paul's investigateions.

The initial concept is simply to record the GPS L1 frequency through flight and post-process position-velocity-altitude after the fact. This would let Paul work out kinks in the hardware ad give us data to play with to tune GNSS-SDR's tracking loops to work in the high acceleration environment. 

Eventually, it would be useful to do this in real time on the rocket. 

So the path forward looks something like this:



Dark blue steps are complete. 

Help is welcome - I'm learning GNSS-SDR but if you know GNSS-SDR and can provide a few answers via email I'd love to hear from you!

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.