GNSS-SDR operation with a Realtek RTL2832U USB dongle DVB-T receiver

Introduction

This article describes what is probably one of the cheapest ways for
experimenting with real-life signals and GNSS-SDR. This is a product from a
combined effort of many people, so let us only mention (to our knowledge) the
very original source, the V4L/DVB kernel developer Antti Palosaari, who
discovered
an undocumented operation mode for some USB DVB-T dongles based on the Realtek
RTL2832U
chipset,
enabling them to be used as a cheap Software Defined Radio (SDR) front-end. The
key feature is that the chip allows transferring raw I/Q samples to the host,
which in principle is responsible for DAB/DVB+/FM demodulation. This is great
news for a GNSS software receiver since it covers the targeted frequency bands.

The RTL2832U outputs 8-bit I/Q-samples with a baseband sample rate up to 3.2
MSPS, according to the specifications. However, the highest sample rate that has
been tested so far without losing samples is 2.8 MSPS. The frequency range is
highly dependent on the used tuner. Dongles that use Elonics E4000 offer the
widest possible range (64 – 1700 MHz with a gap from approx. 1100 – 1250 MHz).
When used out-of-spec, a tuning range of approx. 50 MHz – 2.2 GHz is possible
(with gap). More information about device compatibility is available at the
Osmocom rtl-sdr Wiki.

The GNSS Galileo E1 and GPS L1 links are centered at 1575.42 MHz, and this band
is covered by the E4000 tuner IC. The GNSS-SDR software receiver can be
configured to use the RTL2832U as a real-time signal source, thus providing a
low-cost option (about 20 € or $25) to build a real-time software-defined GPS L1
receiver. This article introduces the operation details and some performance
measurements regarding this GNSS-SDR feature.

OsmoSDR driver support

The GNSS-SDR support for Realtek RTL2832U dongles makes use of the OsmoSDR GNU
Radio source block and driver. We implemented a new GNSS-SDR Signal Source
adapter that instantiates OsmoSDR’s gr_hier_block2, which associated GNSS-SDR
Signal Source name is Osmosdr_Signal_Source. The adapter’s source code is
located at:

It makes use of the gr-osmosdr library,
including the following header:

#include <osmosdr/source.h>

Important:
The compilation of the RTL2832U support in GNSS-SDR is optional and it requires
the installation of the
gr-osmoSDR library.
See GNSS-SDR’s
README.md file for
step-by-step building instructions with the optional OsmoSDR
driver.

Configuring GNSS-SDR for GPS L1 real-time operation

In order to use a compatible USB DVB-T device, it is necessary to select the
Osmosdr_Signal_Source implementation in the GNSS-SDR configuration file
(gnss-sdr.conf)
for the SignalSource block. In addition, the following parameters should be
configured:

  • the baseband sampling frequency,
  • the RF center frequency,
  • the RF gain, and
  • the AGC operation.

Hereafter can be found a working configuration for the reception of a GPS L1 C/A
signal:

[GNSS-SDR]

;######### GLOBAL OPTIONS ##################

GNSS-SDR.internal_fs_sps

=

2000000

;######### SIGNAL_SOURCE CONFIG ############

SignalSource.implementation

=

Osmosdr_Signal_Source

SignalSource.item_type

=

gr_complex

SignalSource.sampling_frequency

=

2000000

SignalSource.freq

=

1575420000

SignalSource.gain

=

50

SignalSource.rf_gain

=

40

SignalSource.if_gain

=

30

SignalSource.AGC_enabled

=

true

SignalSource.samples

=

0

SignalSource.repeat

=

false

SignalSource.dump

=

false

SignalSource.dump_filename

=

../data/signal_source.dat

SignalSource.enable_throttle_control

=

false

The recommended sampling frequency is 2 MSPS. This configuration enables the
real-time receiver operation with 8 satellite channels in an Intel Core 2 quad
Q9400 @ 2.66 GHz with 4 GB of RAM. In addition, we obtained the best results
enabling the Automatic Gain Control (AGC) of the E4000 front-end.

RTL2832U oscillator accuracy and stability issues

It is known, as reported in Michele Bavaro’s GNSS
blog, that the crystal oscillator used by
the RTL2832U dongles has very low accuracy. Our experiments with two different
devices (EzCap 666 and Generic P160) confirm this issue. We used a high accuracy
signal generator to generate an unmodulated carrier at the GPS L1 link and we
measured the carrier frequency error in the captured signal. The resulting
deviations were in the order of 80 kHz for the EzCap and 14.8 kHz for the P160.

The local oscillator frequency inaccuracies cause two different effects in the
GNSS receiver:

  1. The baseband signal is shifted to an Intermediate Frequency (IF), equal to
    the VCO deviation. It can be seen as an apparent Doppler shift. If the
    superposed Doppler shift (real signal Doppler + the parasitic IF) is beyond the
    acquisition Doppler search margins, the acquisition will fail.

  2. A deviation in the sample clock since the local oscillator is used also for
    the Analog-to-Digital Converter (ADC) sample clock reference. This issue
    affects the tracking Delay Locked Loop (DLL) as there is a deviation in the
    theoretical sample clock frequency set in the receiver configuration file and
    the real sample frequency. If the deviation is high enough, the tracking DLL
    will lose the lock.

Thanks to the GNSS-SDR flexibility, the software receiver can be configured to
overcome both effects. On the one hand, the parasitic IF frequency can be
canceled using the Signal Conditioner block by enabling the frequency
translating FIR filter as follows:

;######### SIGNAL_CONDITIONER CONFIG ############

SignalConditioner.implementation

=

Signal_Conditioner

DataTypeAdapter.implementation

=

Pass_Through

;######### INPUT_FILTER CONFIG ############

InputFilter.implementation

=

Freq_Xlating_Fir_Filter

InputFilter.input_item_type

=

gr_complex

InputFilter.output_item_type

=

gr_complex

InputFilter.taps_item_type

=

float

InputFilter.number_of_taps

=

5

InputFilter.number_of_bands

=

2

InputFilter.band1_begin

=

0.0

InputFilter.band1_end

=

0.85

InputFilter.band2_begin

=

0.90

InputFilter.band2_end

=

1.0

InputFilter.ampl1_begin

=

1.0

InputFilter.ampl1_end

=

1.0

InputFilter.ampl2_begin

=

0.0

InputFilter.ampl2_end

=

0.0

InputFilter.band1_error

=

1.0

InputFilter.band2_error

=

1.0

InputFilter.filter_type

=

bandpass

InputFilter.grid_density

=

16

InputFilter.sampling_frequency

=

2000000

InputFilter.IF

=

14821

;######### RESAMPLER CONFIG ############

Resampler.implementation

=

Pass_Through

Resampler.dump

=

false

Resampler.item_type

=

gr_complex

On the other hand, the sample frequency error can be measured and taken into
account by setting the estimated sample clock frequency value in the internal
GNSS-SDR sampling frequency parameters as follows:

GNSS-SDR.internal_fs_sps

=

corrected_value

InputFilter.sampling_frequency

=

corrected_value

GPS active antenna

We used a ceramic patch antenna equipped with an internal Low Noise Amplifier
(LNA) to reduce the overall noise figure. The picture below shows a picture of
such Garmin GA27C GPS antenna exposing the ceramic patch over the LNA PCB.

Garmin's GA27C antenna
Garmin GA-27 active antenna without the plastic cover.

In order to connect the antenna to a DVB-T dongle it is necessary some hardware
hacking:

  1. Assuming that the GPS antenna is equipped with an SMA M connector, it is
    required to build an RF cable to convert the SMA M connector to the MCX M
    connector in order to plug the GPS antenna into the DVB-T dongle.

  2. We must feed the LNA using a Bias-T network.

Some performance measurements and conclusions

Two different setups were assessed to receive and process GPS signals in
real-time:

  • In the first one, we connected the DVB dongle to an active patch antenna
    using a custom 20 dB amplification and filtering circuit. The gain block
    provides also the +5 DC voltage required to power the active antenna internal
    LNA. More information on this circuit can be found at Arribas’ PhD
    Thesis.

The following picture shows the DVB dongle (generic P160) + LNA + Active
antenna setup.

Dongle
Generic P160 DVB-T dongle connected to a GA-27 antenna using an external LNA circuit.

  • On the other hand, we also tested the direct connection of an active GPS
    antenna to the DVB dongle as well, using a standard bias-T network. This setup
    is shown in the following picture:

Dongle2
Generic P160 DVB-T dongle connected to a GA-27 antenna using a bias-T network.

In those experiments, we used a Dell XPS M1530 laptop equipped with an Intel
Core 2 Duo T9300 CPU with 4 GB of RAM. The operating system was Linux Ubuntu
12.04 and the GNU Radio version was 3.6.0.

GNSS-SDR was able to acquire, track, and obtain a position fix in both front-end
setups. The antenna was placed on the roof of the CTTC building and remained
static during the experiments.

The following pictures show some tracking data analysis using the GNSS-SDR
intermediate data extraction and dump feature:

Tracking.dump

=

true

Tracking.dump_filename

=

./tracking_ch_

As a sanity check, we did some post-processing analysis using the Matlab script
based on the ones on Key Borre’s book and available at

The figure clearly shows the GPS C/A navigation symbols, The PLL and DLL
discriminator outputs are quite noisy, tough:

Output1
Tracking data analysis.

Output2
Tracking data analysis.

Finally, the obtained KML position file can be displayed by Google Earth as
shown in the following picture. The yellow line represents the position
evolution for a 10 seconds time-lapse. The red arrow represents the true antenna
position. In addition, we plotted also the height evolution. Considering that
the Position Velocity and Time (PVT) solutions were estimated using 4 satellites
and a really low sampling frequency of 1.2 MSPS, the estimated position error
was in the order of 200 m.

Google Earth
GNSS-SDR estimated position analysis using Google Earth.

Summarizing this preliminary experiment, we can conclude that the GNSS
positioning using low cost Realtek-based DVB-T dongles is feasible, and to the
best of our knowledge, this is the first time that a GNSS software receiver
supports the real-time operation with RTLSDR-based devices. This milestone
enables access to the full potential of GNSS services using a standard laptop
and extremely low-cost hardware. Further measurements and improved support for
RTLSDR devices are planned.

Update: Those experiments and the results were finally published in a
paper presented at ION GNSS+ 2013.

Update 2: New RTL-SDR Blog
V3
dongles ship a < 1 PPM temperature compensated oscillator (TCXO), which is well
suited for GNSS signal processing, and a 4.5 V powered bias-tee to feed an
active antenna that can be enabled by software. Check out the
Osmosdr_Signal_Source documentation for more details.

Full configuration file (updated for the current GNSS-SDR version):

[GNSS-SDR]

;######### GLOBAL OPTIONS ##################

GNSS-SDR.internal_fs_sps

=

2000000

;######### SIGNAL_SOURCE CONFIG ############

SignalSource.implementation

=

Osmosdr_Signal_Source

SignalSource.item_type

=

gr_complex

SignalSource.sampling_frequency

=

2000000

SignalSource.freq

=

1575420000

SignalSource.gain

=

50

SignalSource.rf_gain

=

40

SignalSource.if_gain

=

30

SignalSource.AGC_enabled

=

true

SignalSource.samples

=

0

SignalSource.repeat

=

false

SignalSource.dump

=

false

SignalSource.dump_filename

=

../data/signal_source.dat

SignalSource.enable_throttle_control

=

false

;# Please note that the new RTL-SDR Blog V3 dongles ship a < 1 PPM ;# temperature compensated oscillator (TCXO), which is well suited for GNSS ;# signal processing, and a 4.5 V powered bias-tee to feed an active antenna. ;# Whether the bias-tee is turned off before reception depends on which version ;# of gr-osmosdr was used when compiling GNSS-SDR. With an old version ;# (for example, v0.1.4-8), the utility rtl_biast may be used to switch the ;# bias-tee, and then call gnss-sdr. ;# See https://github.com/rtlsdrblog/rtl_biast ;# After reception the bias-tee is switched off automatically by the program. ;# With newer versions of gr-osmosdr (>= 0.1.4-13), the bias-tee can be ;# activated by uncommenting the following line: ;SignalSource.osmosdr_args=rtl,bias=1

;######### SIGNAL_CONDITIONER CONFIG ############

SignalConditioner.implementation

=

Pass_Through

;######### CHANNELS GLOBAL CONFIG ############

Channels_1C.count

=

8

Channels_1B.count

=

0

Channels.in_acquisition

=

1

Channel.signal

=

1C

;######### ACQUISITION GLOBAL CONFIG ############

Acquisition_1C.implementation

=

GPS_L1_CA_PCPS_Acquisition

Acquisition_1C.item_type

=

gr_complex

Acquisition_1C.coherent_integration_time_ms

=

1

Acquisition_1C.pfa

=

0.01

Acquisition_1C.doppler_max

=

5000

Acquisition_1C.doppler_step

=

250

Acquisition_1C.dump

=

false

Acquisition_1C.dump_filename

=

./acq_dump.dat

;######### TRACKING GPS CONFIG ############

Tracking_1C.implementation

=

GPS_L1_CA_DLL_PLL_Tracking

Tracking_1C.item_type

=

gr_complex

Tracking_1C.dump

=

false

Tracking_1C.dump_filename

=

./tracking_ch_

Tracking_1C.pll_bw_hz

=

35.0;

Tracking_1C.dll_bw_hz

=

1.5;

Tracking_1C.pll_bw_narrow_hz

=

2.5;

Tracking_1C.dll_bw_narrow_hz

=

0.5;

Tracking_1C.extend_correlation_symbols

=

1;

Tracking_1C.dll_filter_order

=

2;

Tracking_1C.pll_filter_order

=

3;

Tracking_1C.early_late_space_chips

=

0.5;

Tracking_1C.early_late_space_narrow_chips

=

0.25

;######### TELEMETRY DECODER GPS CONFIG ############

TelemetryDecoder_1C.implementation

=

GPS_L1_CA_Telemetry_Decoder

TelemetryDecoder_1C.dump

=

false

;######### OBSERVABLES CONFIG ############

Observables.implementation

=

Hybrid_Observables

Observables.dump

=

false

Observables.dump_filename

=

./observables.dat

Observables.enable_carrier_smoothing

=

false

Observables.smoothing_factor

=

200

;######### PVT CONFIG ############

PVT.implementation

=

RTKLIB_PVT

PVT.positioning_mode

=

PPP_Static ; options: Single, Static, Kinematic, PPP_Static, PPP_Kinematic

PVT.iono_model

=

Broadcast ; options: OFF, Broadcast, SBAS, Iono-Free-LC, Estimate_STEC, IONEX

PVT.trop_model

=

Saastamoinen ; options: OFF, Saastamoinen, SBAS, Estimate_ZTD, Estimate_ZTD_Grad

PVT.enable_rx_clock_correction

=

false

PVT.output_rate_ms

=

100

PVT.rinexobs_rate_ms

=

100

PVT.display_rate_ms

=

500

PVT.dump_filename

=

./PVT

PVT.nmea_dump_filename

=

./gnss_sdr_pvt.nmea;

PVT.flag_nmea_tty_port

=

false;

PVT.nmea_dump_devname

=

/dev/pts/4

PVT.dump

=

false

PVT.flag_rtcm_server

=

true

PVT.flag_rtcm_tty_port

=

false

PVT.rtcm_dump_devname

=

/dev/pts/1

References