Software Defined Radio for Global Online Listening
Disclosure: Skywavelinux.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program such that this site earns advertising fees by linking to Amazon.com. If you make a qualifying purchase after clicking a link on this website, the associate affiliated with this site may earn a comission at no cost to you.

#Advert: Supercharge your computing with a new ASUS motherboard.


Main Menu --- Click to Unfold --- HOME
Skywave Linux 11/2020 Update
i3 Key Bindings
Neovim Key Bindings
Tmux Key Bindings
Bash Aliases
Downloads
Source Code
Skywave Linux Hard Drive Installation
Skywave Linux USB Installation
WebSDRs in 2019
Programmatic RTL-SDR Calibration
Fixing Audio: Dell, HP, Compaq
Skywave Linux Tumblr Page
Gqrx Spyserver Linux Client
Best Internet SDR Servers
Quick Tune HFGCS List
Quick Tune VOLMET List
New Features: Quick Tune Global Internet SDR List Quick Tune HFCGS List Quick Tune VOLMET List

Programmatic RTL-SDR Calibration

RTL-SDRs are great devices. They are known for being small, inexpensive, light in power demand, operable from low frequencies through L band, and workable with numerous signal processing packages. They are NOT known for having precise and stable clock oscillators. Frequency errors of 30 to 50 parts per million are common. For users tuning VHF narrowband voice or digital modes, such an error is enough to cause signals to fall on the edge of the receiver passband. In some cases, signals may fall out of a narrow passband and be completely missed.

One solution is to only use RTL-SDRs sold with upgraded clock oscillators, such as the NESDR SMArt or RTL-SDR.com V3. Another way to put the RTL-SDR on frequency is to check it against a known signal and manually program the offset into applications controlling the dongle. That is often accurate enough, but still a broad approximation. A better solution, also applicable to upgraded devices, is to automate the process of checking against known signals and get a more precise measurement based on a time series of phase measurements. For that, there is a nifty application named Kalibrate-RTL.

Kalibrate-RTL uses mobile telephone calibration signals, which are derived from GNSS signals as a precise frequency and time reference. Also, it eliminates human factors in measuring offsets. In fact it takes multiple readings and averages them to work out a mean offset. That is good enough (quite good enough) for most users. For critical applications needing top notch, minimal drift, precision tuning, an SDR better than RTL dongles should be considered...

#Advert: Supercharge your computing on systems and parts from Eluktronics

Given below is a bash script for running Kalibrate-RTL. It was developed on a modest Ubuntu Linux system, and tested on run of the mill RTL-SDR hardware. It can get the PPM offset, then save it along with a gain setting and SoapySDR device string for other applications to use. For example, OpenWebRX or Dump1090 can configured with the help of a short bit of code to read the offset and gain settings before bringing up the SDR for signal collection.

#!/bin/bash

# Copyright (c) 2019 by Philip Collier, radio AB9IL 
# This script is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version. There is NO warranty; not even for
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

# Measure and save rtl-sdr calibration information using GSM base stations.
# Edit the file referenced for gain setting by certain applications.
# Save SoapySDR device string and key for other uses.

Encoding=UTF-8
savedir="/usr/local/etc"

get_offset(){
echo "Measuring ppm offset on channel "$best_channel
offset=($(kal -c $best_channel 2>&1 | grep "absolute error" | grep -Po "\d*\." | awk '{printf "%.0f", $0}'))

if [[ -z "$offset" ]]; then
		notifyerror
fi

echo $offset > $savedir/sdr_offset  # save offset for general usage
sed -i "s/corr_freq=.*/corr_freq=${offset}000000/g" ~/.config/gqrx/default.conf # save offset for gqrx

	WINDOW=$(zenity --info --height 100 --width 350 \
	--title="Calibration and Gain" \
	--text="An offset of $offset ppm has been written to file $savedir/sdr_offset.");
}

notifyerror(){
	WINDOW=$(zenity --info --height 100 --width 350 \
	--title="Calibration and Gain" \
	--text="Something went wrong.");
	exit
}

scan_band(){
echo "Please stand by.  Scanning for $band stations..."
mapfile -t arr < <(kal -v -s $band -g 40 2>&1 | grep 'chan:' | awk '{printf $2" "$7"\n"}' | sort -nrk2)
echo "Chan Strength"
printf '%s\n' "${arr[@]}"
set -- ${arr[0]}
best_channel=$1
get_offset
}

set_device(){
OUTPUT=$(zenity --forms --title="SoapySDR Device Type" --width 400 --height 100 \
--text="Enter the SDR start-up parameters
reported by \"SoapySDRUtil --find\"." \
--separator="," \
--add-entry="SoapySDR Device Driver (e.g. rtlsdr):" \
--add-entry="SoapySDR Device Key (e.g. rtl=0):" \
);

if [[ "$?" -ne "0" ]]; then
	notifyerror
fi

driver=$(awk -F, '{print $1}' <<<$OUTPUT)
devkey=$(awk -F, '{print $2}' <<<$OUTPUT)

# write device driver data to the reference file
echo $driver > $savedir/sdr_driver

# write device key to the reference file
echo $devkey > $savedir/sdr_key

	WINDOW=$(zenity --info --height 100 --width 350 \
	--title="SoapySDR Device Type" \
	--text="Device driver $driver has been written to file $savedir/sdr_driver.
Device key $devkey has been written to file $savedir/sdr_key.");
}

set_gain(){
OUTPUT=$(zenity --forms --title="Calibration and Gain" --width 400 --height 100 \
--text="Enter the desired SDR gain." \
--add-entry="Gain:");

if [[ "$?" -ne "0" || -z "$?" ]]; then
    exit
fi

gain=$(awk -F, '{print $1}' <<<$OUTPUT)

# write gain setting to the reference file
echo $gain > $savedir/sdr_gain

	WINDOW=$(zenity --info --height 100 --width 350 \
	--title="Calibration and Gain" \
	--text="A gain of $gain has been written to file $savedir/sdr_gain.");
}

set_offset(){
OUTPUT=$(zenity --forms --title="Calibration and Gain" --width 400 --height 100 \
--text="Enter the desired SDR offset (ppm)." \
--add-entry="Offset:");

if [[ "$?" -ne "0" || -z "$?" ]]; then
    exit
fi

offset=$(awk -F, '{print $1}' <<<$OUTPUT)

echo $offset > $savedir/sdr_offset  # save offset for general usage
sed -i "s/corr_freq=.*/corr_freq=${offset}000000/g" ~/.config/gqrx/default.conf # save offset for gqrx

	WINDOW=$(zenity --info --height 100 --width 350 \
	--title="Calibration and Gain" \
	--text="An offset of $offset ppm has been written to file $savedir/sdr_offset.");
}

gui(){
ans=$(zenity  --list  --title "SDR Operating Parameters" --width=500 --height=290 \
--text "Manage RTL-SDR frequency calibration and gain.
1) Calibration uses measurements of GSM base stations.
2) Device gain is saved for reference by other applications." \
--radiolist  --column "Pick" --column "Action" \
TRUE "Scan for GSM 850 MHz base stations." \
FALSE "Scan for GSM 900 MHz base stations." \
FALSE "Scan for E-GSM base stations." \
FALSE "Manually program the SDR offset." \
FALSE "Manually program the SDR gain." \
FALSE "Manually program the SoapySDR device data.");

	if [  "$ans" = "Scan for GSM 850 MHz base stations." ]; then
		band='GSM850'
		scan_band

	elif [  "$ans" = "Scan for GSM 900 MHz base stations." ]; then
		band='GSM900'
		scan_band

	elif [  "$ans" = "Scan for E-GSM base stations." ]; then
		band='EGSM'
		scan_band

	elif [  "$ans" = "Manually program the SDR offset." ]; then
		set_offset

	elif [  "$ans" = "Manually program the SDR gain." ]; then
		set_gain

	elif [  "$ans" = "Manually program the SoapySDR device data." ]; then
		set_device

	fi
}

case "$1" in
	gui)
		gui
	;;
	gsm850)
		band='GSM850'
		scan_band
	;;
	gsm900)
		band='GSM900'
		scan_band
	;;
	egsm)
		band='EGSM'
		scan_band
	;;
	offset)
		if [[ "$2" -ne "0" || -z "$2" ]]; then
    		exit
		fi
		echo "$2" > $savedir/sdr_offset
	;;
	gain)
		if [[ "$2" -ne "0" || -z "$2" ]]; then
    		exit
		fi
		echo "$2" > $savedir/sdr_gain
	;;
	device)
		if [[ "$2" -ne "0" || -z "$2" ]]; then
    		exit
		fi
		echo "$2" > $savedir/sdr_driver
		if [[ "$3" -ne "0" || -z "$3" ]]; then
    		exit
		fi
		echo "$3" > $savedir/sdr_key
	;;
	*)
	echo "Usage: kal.sh  

			gui			Use the graphical interface to select a function.
			gsm850		Scan for GSM 850 MHz base stations.
			gsm900		Scan for GSM 900 MHz base stations.
			egsm		Scan for E-GSM base stations.
			offset		Manually program the SDR offset .
			gain		Manually program the SDR gain .
			device		Manually program the SoapySDR device data  .

" >&2
	exit 3
	;;
esac

It is a simple matter to calibrate a dedicated receiver at boot time, as the script can be executed from a system init script. Here is a snippet of code which would run from a launcher in /etc/xdg/autostart/ or the script /etc/init.d/rc.local:

# calibrate the rtl-sdr
sh -c "kal.sh gsm850" &

The above example could also be run regularly as a cron job, but be aware that some scripting would be necessary to stop anther process which may be using the device, then start it up again after the calibration finishes. Calibration of SDR devices with very large offsets may fail, as the cell tower signals may fall outside of the receiver passband. In that case, use your favorite SDR application to manually find the strongest GSM signals, then invoke kal manually to tune one of them.

kal -v -f  -g 

For more scrpts and snippets useful for SDR operating, see the Skywave Linux Github repository.


Tags:Manual or automatic frequency calibration for RTL-SDR devices.
©2015-2020 Skywavelinux.com, All Rights Reserved.
Contact Us, Privacy Policy and Affiliate Disclosure, XML Sitemap.