Skip to content

Instantly share code, notes, and snippets.

Last active December 2, 2023 02:27
Show Gist options
  • Save darksidelemm/861cef5e35d5679684932666d4de8ad2 to your computer and use it in GitHub Desktop.
Save darksidelemm/861cef5e35d5679684932666d4de8ad2 to your computer and use it in GitHub Desktop.
Setting up STRF Capture & Processing

Setting up STRF Data Capture & Processing

Author: Mark Jessop (VK5QI)

This guide provides information on how to capture FFT data using the strf toolset, process it to look for satellite signals, and finally compare their doppler shift against TLEs from the SpaceTrack database. This can help with resolving the 'TLE lottery' after new launches, or cataloguing transmissions from spacecraft already in orbit.

It should be noted that the analysis described in this document is but a small subset of what the strf tools are capable of! Scott Tilley has a post describing some of the history behind strf and giving a crash course on the relationship between orbital dynamics and the doppler effect here:

The target platform is Debian-based distributions (e.g. Debian, Raspbian, Ubuntu), but should be applicable to other Linux-based platforms. The data processing software (rfplot and rffit) is also known to work fine under OSX (using Macports to supply the required dependencies).


Capturing STRF data on a RPi

This section assumes you are going to capture RF data using a Raspberry Pi (or some other machine), and an RTLSDR. A Raspberry Pi 3B+ or faster is recommended when capturing 2 MHz bandwidth data from a RTLSDR.

An Airspy R2 or Airspy Mini may be used, but note that you will need to be using a reasonably fast computer (e.g. not a RPi) to be able to process the data from these SDRs.


Install the required dependencies using:

$ sudo apt-get install git build-essential libfftw3-dev screen vim ntp


If you don't have a need to use the internal bias-tee option in some of the new RTLSDRs (i.e. you are using a separately powered preamp), then you can just install rtl-sdr from your system package manager using:

$ sudo apt-get install rtl-sdr

However, if you wish to use the bias-tee option in the newer RTL-SDR Blog v3 dongles, we need to use rtlsdrblog's fork of the rtl-sdr libraries to provide the rtl_biast utility. This is even the case with the latest release of rtl-sdr (v6.x) which while supporting the bias-tee in rtl_fm, still doesn't support it in the rtl_sdr capture utility. Go figure. Until this is fixed, we have to compile our own version.

IMPORTANT NOTE: Make sure to remove any installations of rtl-sdr already on your system before compiling/installing from source. (i.e. sudo apt-get remove rtl-sdr librtlsdr0 librtlsdr-dev

Once you are sure there are no system rtl-sdr libraries installed, run:

$ git clone
$ cd rtl-sdr
$ mkdir build
$ cd build
$ sudo make install
$ sudo ldconfig

Confirm you can communicate with your rtl-sdr by running:

$ rtl_test

STRF Setup

Clone the strf repository:

$ cd ~
$ git clone

Build the rffft utility:

$ cd ~/strf/
$ make rffft

Setup a working directory for data capture:

$ mkdir ~/satobs
$ cd satobs
$ mkdir data
$ mkfifo fifo
$ cp ~/strf/rffft .

Now, grab my script:

$ wget
$ chmod +x

You will then need to edit this script to adjust the GAIN, WORKINGDIR and BIAS variables as appropriate for your configuration. You can check what gain values your RTLSDR supports by running rtl_test.

Capturing data.

From within the ~/satobs directory, you can now start a data capture by running the script:

./ 436e6 30m

The first argument is the centre frequency of the capture, in Hz, with scientific notation accepted. The second argument is the time to capture for. Values can be suffixed with 's' (seconds), 'h' (hours) or 'd' (days). I usually run this script within a screen session, so I can close the terminal window without affecting the running capture.

Data will be saved to files within the ~/satobs/data directory, as files ending in .bin.

Once the capture is finished, you will likely want to copy the data to a faster machine for processing, which can be accomplished using the Secure Copy (scp) utility.

Setting up the STRF GUI Utils

To process the captured data, we will be using two utilities from the strf repository:

  • rfplot - To display the FFT data as a spectrogram, and allow identification of satellite signal doppler curves in the data, and select points from these doppler curves for analysis.
  • rffit - To analyze selected doppler curve data, and fit it to TLE data.

It is recommended that this software not be run on a RPi. I am unsure if it will even work, as Raspbian supplies giza instead of pgplot5, so the GUIs may not work.


Install the required dependencies using:

$ sudo apt-get install git screen vim build-essential libfftw3-dev gfortran gcc libpng-dev libx11-dev libjpeg-dev libexif-dev libgsl-dev pgplot5 dos2unix

Some notes here:

  • pgplot5 does not work when compiled under GCC8 or newer. If installing from the debian repos you should be OK, but on other platforms (e.g. OSX using Macports), you may need to be careful. Using Macports, you have to use the +gcc7 variant of the pgplot port for it to work.

STRF Compilation

Clone the strf repository:

$ cd ~
$ git clone

Build all the strf utilities:

$ cd ~/strf/
$ mkdir tle
$ make
$ sudo make install

Other Setup Tasks - Setting up a COSPAR ID

Edit the ~/strf/data/sites.txt file, and create a new entry for your location. For example, my entry is:

8650 QI  -34.7207  138.6928     80    Mark Jessop

If you are going to be sharing data with other observers, you may wish to submit a pull request to the strf repository adding your entry.

Other Setup Tasks - SpaceTrack Login

To be able to download the SpaceTrack TLE catalog, you will need to create an account at: The password is going to be stored in a plaintext file, so make sure it's unique!

Other Setup Tasks - Environment Variables

You will need to add the following lines to your ~/.bashrc or ~/.profile file:

export ST_DATADIR=$HOME/strf/

Replace the ST_COSPAR ID number with the number you selected above, and add in your SpaceTrack login and password.

Downloading TLE Data

You should now be able to enter the strf directory and download the latest TLE catalog by running:

$ cd ~/strf/
$ ./tleupdate

Remember: You will need to re-download TLE data before processing a new dataset. If you are archiving datasets, or mark data (more on this later), it is advisable to also archive the bulk.tle file along with the data, which is located at ~/strf/tle/bulk.tle.

Plotting Captured Data

Before you start working with captured data, I would suggest setting up a working directory somewhere, perhaps ~/doppler_obs/. Create a subdirectory within, to store the captured data, e.g. ~/doppler_obs/uhf or ~/doppler_obs/vhf. As the data filenames do not have frequency information, this may make it easier to keep your data organised.

Plotting a dataset

The captured data filenames take the form: 2020-03-26T09:28:11_000000.bin, where the first part is a timestamp, and the last is a sequential number. With the default rffft settings, a new file is written every 60 seconds.

To plot a set of data, run:

$ rfplot -p uhf/2020-03-26T09:28:11 -z 0.01

The -p argument is the 'prefix' of the set of captured data. rfplot will automatically find each file from that dataset. the -z option is a color scaling option, which has to be determined somewhat empirically. For RTLSDRs a value of 0.01 appears to be a good starting point. Run rfplot --help for information on other options.

After a while, all the data files will be processed, and a pgplot window will appear. It is recommended that you arrange your screen so that you can see both the pgplot display, and the terminal window from which it was run - you will need to be able to see both!

Navigating within rfplot

Navigation around the dataset is performed with a combination of mouse and keyboard commands. A few notes are as follows:

  • With focus on the pgplot window, press 'h' to list the available commands in the terminal window.
  • Hold down the 'v' or 'b' keys to increase or decrease the dynamic range of the display. (If the display appears too 'bright', use 'v'; if it's too dark, use 'b'. The resultant -z value is written to the terminal window.)
  • If you re-size the display, the spectrogram will not automatically be re-drawn to fit the new window size. You can re-draw by pressing 'r'.
  • You can zoom into a selection by pressing 'z', then selecting an area with the mouse cursor.
  • You can pan through the entire dataset in somewhat useful automatically-defined steps by pressing TAB repeatedly.

Initial STRF Example

The above figure shows an example rfplot window, showing some data captured around 436 MHz. I picked the 'z' setting poorly, so to bring out more detail I hold down 'b' for a while until it looks like this:

Initial STRF Example - Dynamic Range adjusted

We can see from the scales on the plot that this display covers approximately 1 hour of time span, and 3 MHz of frequency span (it was captured using an Airspy Mini).

If we keep pressing the TAB key, we can pan through the dataset in time & frequency steps fairly well suited to looking for LEO objects. After panning through some of the dataset, I come across this signal:

Fairly obvious CW signal.

By pressing 'z' and selecting the area around the signal, we can centre it in the display:

Fairly obvious CW signal, centered.

This is a pretty typical doppler curve from a LEO sat. To start on the process of identifying which satellite it is, we need to get a dataset of time/frequency points to use with the rffit utility. There are a few ways of doing this in rfplot, and I'm going to start with the most manual method, since it's more useful for wider bandwidth signals as we will see later on in this guide.

First of all, open up another terminal in your working directory (wherever you ran rfplot from), and make sure there is no mark.dat file by running: rm mark.dat.

Now, starting at the leftmost point of the doppler curve, hold the mouse cursor as precisely as you can over the signal, and press Shift+D (e.g. capital 'D'). Repeat this for a reasonable set of points over the entire signal. You should see the datapoints appear in the terminal you ran rfplot from as you do this, e.g.:

58934.405147 436844900.000000 0.000143 8650
58934.406270 436844750.000000 0.000205 8650
58934.406791 436844500.000000 0.000983 8650
58934.407288 436844150.000000 0.009969 8650
... and so on

Each point consists of a timestamp (in julian format), a frequency, a power level, and your COSPAR id.

To exit rfplot, press 'q'. Note that the pgplot window will likely hang around will have to be closed manually.

Fitting Time/Frequency Points to TLEs using rffit

Now, open yet another terminal, navigate to the same directory and run:

rffit -c $ST_TLEDIR/catalog.tle -d mark.dat

Time/Frequency Datapoints shown in rffit

You should now be seeing something similar to the above. The red dots are the datapoints we marked out just before. On the right we can see the estimated centre frequency of the transmission. As with rfplot, you can press 'h' to display a list of keyboard commands in the associated terminal.

Now we can attempt to fit these points to the TLEs we have in our local catalog.

With mouse focus on the rffit window, press 's' to highlight all displayed points. Now press 'i'. In the terminal window you will be asked to enter a 'rms limit' in kHz. This is the limit on fit error. To start with, type in '0.5' (0.5 kHz) and press enter.

TLE fit quality

rffit will then attempt to fit the curve against all objects in the local TLE catalog which were visible at the time of the measurement. The results appear in the terminal, showing the object number, the fit quality (rms kHz), and the calculated centre frequency. The doppler curve for the best fitting TLE will be drawn on the rffit window automatically. Press 'f' to fit that TLE to the highlighted points:

TLE fitted to Time/Frequency data

If the fit is < 100 Hz, then that's a very good indication of a match.

If you end up with multiple TLEs which fit closely, it's often worth checking on what those TLEs have been previously identified as, for example using (e.g. ). Use some common sense as to what will be emitting on the frequency you have identified! (e.g. it's unlikely that rocket debris will be transmitting!)

To load a different TLE from the catalog, you can press 'g', and then type the object ID into the terminal. Again, press 'f' to fit the TLE to the highlighted points.

Once you are confident of an identification, press 'l' to log the object ID and the centre frequency to the $ST_TLEDIR/data/frequencies.txt file. The terminal will display something along the lines of:

Logged 10358 at 436.835782 to /Users/darkside/Dev/strf/data/frequencies.txt

If you go back to your rfplot window and press Shift-r (e.g. capital 'R'), you will now see a green trace overlaid on the plot, with the object ID number (you may need to adjust the dynamic range with 'v' and 'b' to better see it):

TLE data overlaid on rfplot

As you add more objects into your frequencies.txt list, you may find that the rfplot window lags a bit when changing dynamic range. You can toggle display of the overlays by press 'p' to speed things up.

Once you are done, you may wish to backup your Time/Frequency datapoints somewhere. Otherwise, make sure to delete mark.dat.

Working with Wider-Bandwidth Signals.

Not all satellite transmissions are going to be nice easy-to-mark CW signals. In most cases they will be modulated data packets, which could be many kHz wide (e.g. ~10 kHz wide for 9k6 FSK).

A few tips for working with these kinds of signals:

  • Try holding the mouse over the centre of the signal as accurately as you can, and then pressing 'w'. This does a wideband fit, which will work if the signal has a roughly gaussian spectral profile.
  • Sometimes adjusting the dynamic range ('v' and 'b') can bring out features in the signal which may make it easier to find the centre.
  • If the signal has a clearly defined sidebands (but no clear centre), you can mark out the sidebands and then use the -m parameter in rffit to apply a frequency offset in Hz when fitting.
  • Expect that the RMS fit errors to be higher than with a CW signal due to the marking error. You may need to use a higher rms limit.

Other useful Tips

Populating frequencies.txt from the SatNOGS DB

I have written a script which will dump the known satellite frequencies from the SatNOGS DB, and export them in a frequencies.txt comptible format. This script is available here:

To use it, you will need python, and the requests library. Under Debian/Ubuntu systems, you can get this by running:

$ sudo apt-get install python-requests

To download and use the script, run:

$ cd $ST_DATADIR/data
$ wget

To grab frequency data for the 2m and 70cm amateur radio bands, run:

$ python --fmin 144e6 --fmax 148e6 >> frequencies.txt
$ python --fmin 430e6 --fmax 440e6 >> frequencies.txt

Running a strf capture in parallel with a SatNOGS ground station

I've had a few situations where I wanted to have strf capturing doppler data in parallel with my main SatNOGS ground station. To do this, I wrote a python script which grabs the upcoming observations for my station and outputs a list of cronjob commands. The script is available here:

Run the script with: python <your_SatNOGS_station_id) e.g.:

$ python 16
# Obs ID: 1931414, NORAD Catalogue ID: 99831
13 02 28 03 * /home/pi/satobs/ 437000000 21m
# Obs ID: 1933499, NORAD Catalogue ID: 44329
25 01 28 03 * /home/pi/satobs/ 437000000 16m
# Obs ID: 1931273, NORAD Catalogue ID: 45258
06 18 27 03 * /home/pi/satobs/ 437000000 21m

Copy the lines into your users crontab and you should be good to go!

Copy link

zeke800 commented Aug 4, 2022

Thank you very much! This is very helpful :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment