Doppler correction tool for SDR

Doppler is the last tool that is missing for receiving data from satellites using software defined radio (SDR) in a UNIX fashion:

Write programs that do one thing and do it well. Write programs to work together. Write programs to handle text streams, because that is a universal interface.

– Doug McIlroy

As I mentioned in my earlier post there exists many GUI based SDR tools for doing doppler correction and demodulation. However there aren’t tools available for doing this:

rtl_sdr | doppler | demod | multimon-ng

Some readers might already know that rtl_sdr is used for getting IQ data out of simple SDR dongles and multimon-ng is a tool that decodes actual packets from demodulated audio. Demod is a new tool that I wrote for demodulating IQ stream. Currently it supports only FM modulation, however it is quite easy to add more demodulators that are supported by liquid-dsp library.
Doppler was the last missing piece from the pipeline.


Doppler uses the same library for calculating satellite position and other parameters as Gpredict. Bill Shupp has extracted core functions from Gpredict source and released them as standalone library called libgpredict. This is the library that does heavy lifting for calculating doppler shift.
Baseband signal is shifted by doppler frequency in the following way:

float complex c_sample;
float complex c_corrector;
int n = 0;

for (k=0; k<len; k+=2) {
    // convert int16_t IQ to complex float
    c_sample = iqbuffer[k] / 32768.0 + 
               iqbuffer[k+1] / 32768.0 * I;

    c_corrector = cexpf(0.0 -2*M_PI*doppler_hz/samplerate*n*I);
    c_sample = c_sample * c_corrector;

    // convert float back to int16_t IQ
    iqbuffer[k] = crealf(c_sample) * 32767.0; // I part
    iqbuffer[k+1] = cimagf(c_sample) * 32767.0; // Q part

Thats it - basically this is the only thing what it does. Computes doppler shift and centers baseband signal according to this value.


 Working in realtime

Suppose you have RTL-SDR dongle and you would like to decode AX.25 packets from cube satellite ESTCube-1 that transmits last days on 437.505 MHz. Lets set rtl_sdr center frequency off by 5 kHz to mitigate DC offset that is occurring with some of the dongles. That is why here rtl_sdr uses 437.500 MHz as center frequency and doppler uses -o 5000 (offset) parameter. Here multimon-ng fork that supports 48 kHz input is used because it decodes more reliably than original 22.050 kHz. TLE file cubesat.txt can be downloaded from here.

rtl_sdr -f 437500000 -s 1024000 -g 20 - | doppler -s 1024000 -i i16 -d -t cubesat.txt -n 'ESTCUBE 1' --location lat=58.26541,lon=26.46667,alt=76.1 -f 437505000 -o 5000 | demod -s 1024000 -r 48000 -b 4500 -m fm d=3500 | multimon-ng -t raw -a FSK9600 /dev/stdin

 Working with recordings

Suppose we have recorded a satellite overpass to a file and now we want to decode packets from that file. Here --log doppler.log is used to write doppler information to the file instead of stderr. Also offset parameter -o 5000 is used because recording was taken with center frequency of 437.500 MHz. If dealing with old recordings use TLE parameters from the same time, otherwise doppler correction might be wrong.

cat | doppler -s 256000 -i i16 -d -t cubesat.txt -n 'ESTCUBE 1' --location lat=58.26541,lon=26.46667,alt=76.1 -f 437505000 -o 5000 --time 2015-02-19T20:53:56 --log doppler.log | demod -s 256000 -r 48000 -b 4500 -m fm d=3500 | multimon-ng -t raw -a FSK9600 /dev/stdin


I have not yet used it in real environment, so there might be some quirks. Doppler correction was also little bit off when I tried it with old recordings. It was especially off in the end of a the overpass. I am planning to add automatic frequency correction (AFC) support to this tool to correct those mismatches. It should improve packet decoding quite a lot because it is very important to feed demodulator with zero offset baseband signal.


Now read this

Liquid-dsp based command line FM demodulator

In my last post I wrote about how I hacked Google radioreceiver into command line based FM demodulator that can be used to pipe demodulated audio into multimon-ng for AX.25 packet decoding. However it had some significant flaws. For... Continue →