Showing posts with label rtlsdr. Show all posts
Showing posts with label rtlsdr. 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, July 5, 2016

Paul Breed Rocket Test Flight Data #4: SoftGNSS

So where we last left off, I had successfully tracked the last 15 seconds of coast before apogee using GNSS-SDR. We discovered thanks to a little help from jddes on reddit that there was a loud burst of RF noise (confirmed by Paul to be due to a 900 MHz wireless igniter) which caused GNSS-SDR to lose lock on the GPS signal. It had to reacquire and could not do so for ~ 15 seconds

To quote myself:
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.

The assumption, in bold, is incorrect! There is no need to wait for a valid subframe of data to resume calculating pseudoranges, rather, the only thing required is that we are locked onto the signal, ie, that our DLL and PLL are actively and correctly tracking the signals. I am still investigating, but this appears to be due to the way gnss-sdr performs the acquisition and tracking: re-acquisition occurs shortly after the noise source goes away, but tracking doesn't occur until after the next subframe is acquired. I believe this is an implicit assumption in the code which doesn't perform a tracking check until that subframe comes in but I am still investigating and will update this post when I determine the exact culprit.

Earlier this year I read the book A Software-Defined GPS and Galileo Receiver: A Single-Frequency Approach. With the book came an accompanying CD with a Matlab-based GPS receiver (GPLv2 licensed) and there are several updates available online. I was unable to run the example data provided with the book and felt gnss-sdr was a far more mature solution. I cached the code for later. After a few months it was gnawing at me that the code wasn't working and I wanted to try and get Paul's data working in another code. It took a week of evenings to get the code up and running, primarily due to Matlab language changes to legacy functions and several bugs in the code. I will document this in an upcoming post along with a link to my repository of the updated code.

It took another evening or two to get Paul's data fed in, as the data type was different (8 bit I/Q instead of 8 bit real) and there were a number of hardcoded assumptions in the code (including file seek operations and FFT bin sizes) that had to be exposed as parameters to get the data working...





...But work it did! The code tracks through the entire ascent until the nose cone jettisons to deploy drogues at apogee, and a few seconds beyond that although it becomes very noisy as the receiver suffers from multipath and the GPS constellation coming in and out of view as the cone tumbles. You will notice the signal is pretty noisy in the east and up components with up to 200 meters of error - this is due to the GPS constellation orientation (bottom right). All of the satellites are in the east quadrant and thus we get excellent resolution in the north direction but poor (ambiguous, one-sided) resolution in the east and up directions. There is a satellite to the west (PRN13) which gnss-sdr picks up. SoftGNSS will acquire it but not successfully track it - if I can get that tracking, the noise in the E/U channels will go away.

Coplotted with the GNSS-SDR data and the Big Red Bee GPS tracker, things fit nicely.



The BRB, gnss-sdr and SoftGNSS all agree on the location of the launch site. gnss-sdr (yellow) loses it at ignition but reacquires near apogee. SoftGNSS tracks all the way past apogee into reentry when the nose cone is swinging under drogue and the BRB reacquires satellites all the way to the ground. Between SoftGNSS and the BRB tracker we have end-to-end GPS coverage for the flight, with gnss-sdr confirmation at liftoff and apogee. The max speed according to SoftGNSS (with generous filtering) is 350 m/s... right about Mach 1. Still below the CoCOM limit for velocity, but as we see the COTS GPS solution loses lock where we are able to tease out a PVT solution.

So why did this work where gnss-sdr failed? Basically, the naivete of the SoftGNSS program design alowed it happen. SoftGNSS only acquires satellites at the start of file (plus specified offset). It then processes the data, tracking the signals with DLL/PLL for the duration of the file. Once all the file is processed it looks for the first subframe and decodes the next 30 seconds of transmission (five subframes at 6 seconds/subframe) to propagate the ephemeris for each satellite. It then takes the timing information from signal that was tracked to calculate pseudoranges. So long as the DLL/PLL retains a lock we get valid pseudoranges and there's no signal saying "We lost lock, stop calculating pseudoranges." More or less. The figure below shows tracking for PRN22. On the bottom left you see the filtered PLL discriminator which stays tight until liftoff where there's notable jump due to doppler (and likely RTLSDR cystal drift due to acceleration).






    Files
    1. Big Red Bee GPS tracker KML file
    2. GNSS-SDR KML file
    3. SoftGNSS KML file


    Action Item List
    1. Update post on cause of gnss-sdr delay in tracking after losing acquisition
    2. Post on SoftGNSS with links to my github repo

    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

    Tuesday, April 5, 2016

    Paul Breed Rocket Flight Test Data #2: PROGRESS!

    I GOT A gnss-sdr PVT SOLUTION IN FLIGHT!

    Success kid is successful.

    So I managed to get a valid navigation solution for ~ 7 seconds in flight close to what I presume is apogee, absent additional information. Paul flew an IMU but lost the SD card and a Big Red Bee GPS tracker which is, of course, subject to CoCom limits. Below I plotted both the RTLSDR (in red) and the Big Red Bee (in yellow... in retrospect this should have been red!)




    I removed spurious readings from the GPS tracker: these are easy to identify because the GPS time is out of sync. The long red and yellow lines connect the dots from the last good reading on the pad to the first good reading in flight, and are not representative paths per see. If we assume data to be correct it appears the RTLSDR acquires a navigation solution at a higher altitude than the BRB, which based on the speed and drift is operating under chutes. Next up I extracted the the lat/lon/alt from the PVT solution generated by GNSS-SDR (again, the blue line is just connecting the last good fix on the pad with  the first good fix in flight). The data is aligned with the last good fixes for both the RTLSDR and BRB. 










    Now we get confirmation that the RTLSDR does indeed acquire before the BRB, and a little mental extrapolation can connect the dots between the last RTLSDR sample and the first BRB sample post-launch if we presume the rocket is drifting steadily under a drogue parachute. (The inflection in the BRB is likely going from drogues to main chute - awaiting confirmation.)

    The rocket pops the nosecone at apogee to deploy a drogue chute, at which time the nosecone is swinging in the breeze and we don't anticipate getting any data from the RTLSDR because the directional antenna is no longer pointed up. However the BRB is expected to get a fix under chutes, when within the CoCom limits. My thesis is that we get a valid GPS solution about 7 seconds before popping the nosecone and deploying the drogue, which then causes us to lose track on most of the satellites and thus lose our navigation solution. Indeed, the rest of the flight is filled with messages of acquiring and subsequently losing acquisition of satellites.

    Here's an excerpt of the output from just before liftoff to just after apogee:
    Current input signal time = 145 [s]
    NAV Message: received subframe 3 from satellite GPS PRN 22 (Block IIR)
    NAV Message: received subframe 3 from satellite GPS PRN 31 (Block IIR-M)
    NAV Message: received subframe 3 from satellite GPS PRN 1 (Block IIF)
    NAV Message: received subframe 3 from satellite GPS PRN 14 (Block IIR)
    NAV Message: received subframe 3 from satellite GPS PRN 3 (Block IIF)
    NAV Message: received subframe 3 from satellite GPS PRN 10 (Block IIA)
    NAV Message: received subframe 3 from satellite GPS PRN 25 (Block IIF)
    Position at 2016-Feb-06 18:45:47 UTC is Lat = 35.34828164793844 [deg], Long = -117.8089714500355 [deg], Height= 646.4366382388398 [m]
    Current input signal time = 146 [s]
    Position at 2016-Feb-06 18:45:48 UTC is Lat = 35.34792485975112 [deg], Long = -117.8090110485498 [deg], Height= 653.1580742103979 [m]
    Current input signal time = 147 [s]
    Position at 2016-Feb-06 18:45:49 UTC is Lat = 35.34836233536886 [deg], Long = -117.8087743892498 [deg], Height= 622.0710280425847 [m]
    Current input signal time = 148 [s]
    Position at 2016-Feb-06 18:45:50 UTC is Lat = 35.34776621261069 [deg], Long = -117.8090573844694 [deg], Height= 649.063727453351 [m]
    Current input signal time = 149 [s]
    Position at 2016-Feb-06 18:45:51 UTC is Lat = 35.34842555835016 [deg], Long = -117.8087875236563 [deg], Height= 634.0006730658934 [m]
    Current input signal time = 150 [s]
    Position at 2016-Feb-06 18:45:52 UTC is Lat = 35.34802741910629 [deg], Long = -117.808877076439 [deg], Height= 641.1753705441952 [m]
    Current input signal time = 151 [s]
    NAV Message: received subframe 4 from satellite GPS PRN 22 (Block IIR)
    NAV Message: received subframe 4 from satellite GPS PRN 10 (Block IIA)
    Loss of lock in channel 5!
    Tracking start on channel 5 for satellite GPS PRN 11 (Block IIR)
    Current input signal time = 152 [s]
    Loss of lock in channel 6!
    Loss of lock in channel 3!
    Tracking start on channel 6 for satellite GPS PRN 31 (Block IIR-M)
    Tracking start on channel 3 for satellite GPS PRN 14 (Block IIR)
    Loss of lock in channel 0!
    Tracking start on channel 0 for satellite GPS PRN 1 (Block IIF)
    Loss of lock in channel 4!
    Tracking start on channel 4 for satellite GPS PRN 22 (Block IIR)
    Current input signal time = 153 [s]
    Loss of lock in channel 5!
    Tracking start on channel 5 for satellite GPS PRN 11 (Block IIR)
    Loss of lock in channel 6!
    Tracking start on channel 6 for satellite GPS PRN 31 (Block IIR-M)
    Loss of lock in channel 3!
    Tracking start on channel 3 for satellite GPS PRN 14 (Block IIR)
    Loss of lock in channel 0!
    Tracking start on channel 0 for satellite GPS PRN 1 (Block IIF)
    Loss of lock in channel 4!
    Tracking start on channel 4 for satellite GPS PRN 22 (Block IIR)
    Current input signal time = 154 [s]
    Current input signal time = 155 [s]
    Loss of lock in channel 4!
    Tracking start on channel 4 for satellite GPS PRN 22 (Block IIR)
    Current input signal time = 156 [s]
    Current input signal time = 157 [s]
    Loss of lock in channel 4!
    Tracking start on channel 4 for satellite GPS PRN 22 (Block IIR)
    Current input signal time = 158 [s]
    Current input signal time = 159 [s]
    Current input signal time = 160 [s]
    Current input signal time = 161 [s]
    Current input signal time = 162 [s]
    Current input signal time = 163 [s]
    NAV Message: received subframe 1 from satellite GPS PRN 11 (Block IIR)
    NAV Message: received subframe 1 from satellite GPS PRN 14 (Block IIR)
    Current input signal time = 164 [s]
    Current input signal time = 165 [s]
    Current input signal time = 166 [s]
    Current input signal time = 167 [s]
    Current input signal time = 168 [s]
    Current input signal time = 169 [s]
    NAV Message: received subframe 2 from satellite GPS PRN 11 (Block IIR)
    Current input signal time = 170 [s]
    Current input signal time = 171 [s]
    Current input signal time = 172 [s]
    Current input signal time = 173 [s]
    Current input signal time = 174 [s]
    Current input signal time = 175 [s]
    NAV Message: received subframe 3 from satellite GPS PRN 1 (Block IIF)
    NAV Message: received subframe 3 from satellite GPS PRN 11 (Block IIR)
    NAV Message: received subframe 3 from satellite GPS PRN 14 (Block IIR)
    NAV Message: received subframe 3 from satellite GPS PRN 3 (Block IIF)
    Current input signal time = 176 [s]
    Position at 2016-Feb-06 18:46:18 UTC is Lat = 35.3536423978743 [deg], Long = -117.8154004936006 [deg], Height= 4891.649443297647 [m]
    Current input signal time = 177 [s]
    Position at 2016-Feb-06 18:46:19 UTC is Lat = 35.35313826705141 [deg], Long = -117.8151172574466 [deg], Height= 4786.770911485888 [m]
    Current input signal time = 178 [s]
    Position at 2016-Feb-06 18:46:20 UTC is Lat = 35.35361800624526 [deg], Long = -117.8156283909009 [deg], Height= 4907.156536793336 [m]
    Current input signal time = 179 [s]
    Position at 2016-Feb-06 18:46:21 UTC is Lat = 35.35351364315449 [deg], Long = -117.815566988265 [deg], Height= 4801.439769400284 [m]
    Current input signal time = 180 [s]
    Position at 2016-Feb-06 18:46:22 UTC is Lat = 35.35325156470748 [deg], Long = -117.8156706709576 [deg], Height= 4741.917847431265 [m]
    Current input signal time = 181 [s]
    NAV Message: received subframe 4 from satellite GPS PRN 22 (Block IIR)
    NAV Message: received subframe 4 from satellite GPS PRN 1 (Block IIF)
    NAV Message: received subframe 4 from satellite GPS PRN 31 (Block IIR-M)
    NAV Message: received subframe 4 from satellite GPS PRN 11 (Block IIR)
    NAV Message: received subframe 4 from satellite GPS PRN 3 (Block IIF)
    Loss of lock in channel 7!
    Current input signal time = 182 [s]
    Tracking start on channel 7 for satellite GPS PRN 23 (Block IIR)
    Loss of lock in channel 3!
    Tracking start on channel 3 for satellite GPS PRN 26 (Block IIF)
    Current input signal time = 183 [s]


    Therefore, based on the output and plots, I believe liftoff takes place at 151 seconds, engine burns for ~ 5-6 seconds (highlighted in yellow), with apogee occurring at 182 seconds, or roughly 30 seconds on ascent. Apogee of ~ 4850 meters ASL.

    The numerous subframes from 163-182 seconds show we are still getting some meaningful data which could be interpreted by a fft-based approach like fastpgs.


    So what did you change?

    I lowered the bandwidth of all 3 tracking loops by roughly half. Previously I had increased the bandwidth on the loops figuring more bandwidth = ability to deal with rapid shifts in phase/frequency but my intuition was incorrect. I'm still a DSP newbie but I am learning.

    To Do
    1. Continue playing with tracking loops 
    2. Investigate fastgps fft-based solutions

    Files
    1. BRB.kml - Big Red Bee GPS Logger
    2. RTLSDR.kml - RTLSDR tracking

    Sunday, March 6, 2016

    An RTL-SDR dataset for gnss-sdr

    I've had several requests for a dataset for users to play with. I've been recalcitrant simply because every dataset I've taken has been from my house! So this week I went to a park and took a two-minute acquisition using GNSS-SDR. My setup is a RTL-SDR stick with a 0.5PPM TXCO and aluminum case with the bias tee mod, a LNA4ALL, and a cheap active GPS antenna. (By no means are 0.5PPM TXCO, aluminum care or LNA4ALL requirements, I've gotten a good fix with a cheap dongle in a plastic case with no LNA.)

    The dataset lives on my Google Drive. The .conf file is the file I used for acquisition. If you want to use it for playback with gnss-sdr, you need to make the following changes

    Line 29: Change the SignalSource.implementation from Osmosdr_Signal_Source to File_Signal_Source
    Line 30: Uncomment the SignalSource.filename and provide the correct path to the data file
    Line 42: Change SignalSource.dump to false

    gnss_sdr_pvt.nmea contains position/velocity/time (PVT) in NMEA format. The GSDR063p40.16N contains the raw navigational information and the GSDR063p40.16O contains the observables. PVT.kml is a Google Earth file with coordinates.

    You might be interested in recovering the chip rate.

    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.

    First proof-of-concept: A GPS Fix in Windows using an RTL-SDR stick

    Using a $20 RTL-SDR stick with 1ppm TXCO and a simple mod to power an active GPS antenna, it is possible to download and decode GPS signals in real time.

    Software

    Both packages are Open Source, with a default build target is Windows.

    Both packages are Open Source (GPL2 and BSD 2-clause, respectively). The default build target for both packages is Windows, although RTKLIB has been compiled under Linux.

    Please note that GNSS-SDRLIB is not to be confused with GNSS-SDR!

    Resources
    Useful presentation by the author of GNSS-SDRGUI for a summer school course. Also check the manuals included with GNSS-SDRLIB and RTKLIB.

    Step-By-Step Implementation
    1. Ensure RTL-SDR stick is working in Windows. If your driver is not working, try using the Zadig driver installation method outlined here.
    2. Install GNSS-SDRLIB and RTKLIB to any convenient directory
    3. Open GNSS-SDRGUI and select the following options
      1. Input Type: RTL-SDR
      2. [x] RTCM MSM, Port 9999
      3. Change "output interval" dropdown to 10 hz
      4. [x] Plot Tracking
      5. [x] All GPS, GLOSNASS, Galileo satellites 
      6. (optional) enter approximate lat/lon into MISC and click the "..." button to get  current satellite locations in relation to your location.
    4. Click "Start", a number of command consoles will open then close for each satellite being tracked.
    5. Click "M" for log
    6. Now, open RTKNAVI
      1. Click on the "I" button
        1. check "rover", type TCP Client, format RTCM3
        2. click OPT button and set address to "localhost" and port to "9999"
        3. click OK
        4. Click OK
      2. Click on the "start" button
      3. Within a few seconds you should see satellites in the Rover:Base SNR pane
      4. Once a solution exists it will update lat/lon in the left pane
      5. Click "Plot" to generate a plot of the random walk of lat/lon over time

    This is what your GNSS-SDRGUI should look like:



    This is what your RTKNAVI input should look like:


    If everything is working you should get a GPS solution, as shown in this video



    Next Actions
    Try using GNSS-SDR and/or GNURadio to decode the GNSS signal; this would provide native, Linux compatible headless execution and a cursory Google suggests this has been done successfully with the RTL-SDR stick.