Weather Satellite Images from Cork, Ireland

Receiver Control

[UPDATE 22 July 2018: The original WXToImg website described below seems to be permanently down. There is some discussion of site clones and file copies at https://www.rtl-sdr.com/new-alternative-wxtoimg-website-with-most-files/. The alternative links listed below are courtesy of the internet archival project.]

Receiver Control and Image Generation relies on a combination of Linux shell scripts and the WXToImg (alternative) (Professional Edition) signal to image decoder. By good fortune the Beta 2.11.2 (alternative) release includes a build for ARM architectures allowing it to run on the Raspberry Pi. While this build was found to be very slow on my original RPi 1 Model B, the performance on the RPi 3 Model B is very good.

Satellite Pass Scheduling

WXToImg provides support for automated satellite signal recording in addition to image decoding. By using the “wxctl” receiver type it is possible to call a script to start or stop an attached receiver. For the “wxctl” receiver type WXToImg attempts to call a script wxctl (note the deliberate omission of “.sh”) at the start and end of each satellite pass. At pass start the satellite name is argument 1, the frequency in MHz is argument 2, and the receiver port is argument 3 (e.g. equivalent to calling wxctl “NOAA 15” 137.62 0). At pass end the satellite name is an empty string and the frequency is 0.00 (e.g. equivalent to wxctl “” 0.00 0). It is worth noting that two additional scripts appear to be supported: wxpbegin and wxpend, however I did not explore their use and I believe them to be deprecated. On the RPi the wxctl receiver control script should be saved to /usr/local/bin/wxctl.

The listing below shows the wxctl script used to control the RTL-SDR receiver. The script only uses the satellite name and then passes hard-coded commands to a command pipe /tmp/record_noaa_cmd where they can be picked up by another program (further details below). Currently the script only supports the three active NOAA POES satellites. The command pipe isolates WXToImg from the receiver implementation and supports alternative system configurations and testing.


# Place receiver control commands in this fifo (command pipe)

# Log events

# Check to see if fifo exists
if [[ ! -p $fifo ]]; then
  echo "ERROR: Command fifo not found" >> $logfile
  exit 1

# Replace spaces with - in the satellite name to allow it to be passed
case "$1" in
'NOAA 15' )
  # Record from NOAA 15
  echo $(date -u +"%Y%^b%d-%H%M%S%Z")": Recording "$1" on "$2 >> $logfile
  echo "start NOAA-15 137.620M" > $fifo
'NOAA 18' )
  # Record from NOAA 18
  echo $(date -u +"%Y%^b%d-%H%M%S%Z")": Recording "$1" on "$2 >> $logfile
  echo "start NOAA-18 137.9125M" > $fifo
'NOAA 19' )
  # Record from NOAA 19
  echo $(date -u +"%Y%^b%d-%H%M%S%Z")": Recording "$1" on "$2 >> $logfile
  echo "start NOAA-19 137.100M" > $fifo
* )
  # Stop recording
  echo $(date -u +"%Y%^b%d-%H%M%S%Z")": Stopping" >> $logfile
  echo "stop" > $fifo

exit 0

While WXToImg provides support for recording the luminance modulated 2400 Hz subcarrier from an attached sound card, I was unable to get this working reliably using either Pulse or Alsa with the Loopback device on the RPi – Instead of a clean signal I observed significant discontinuities or loss of signal in the recorded data. Instead I settled on using the GUI version of WXToImg for scheduling only and instead call the command line version of WXToImg from a script to drive image generation from the WAV file saved by the SDR-based receiver demodulator.

WXToImg is therefore configured to simply schedule the recordings by using the following settings:

wxtoimg recording configuration

Additionally WXToImg is configured to “Record only”, “Automatically enter record mode”, and “Automatically update Keplers”, and all updating and processing during recording is disabled.

Control of the Software Defined Radio

In the current implementation the command pipe fifo referred to in wxctl is read by the receiver controller shell script record_noaa.sh. This script first creates the command pipe, an audio pipe, configures the audio subsystem, and then waits on the command pipe for commands issued by wxctl. It then starts the LuaRadio-based demodulator rtlsdr_noaa_apt.lua in response to start commands, stops the demodulator and generates imagery in response to stop commands, and supports a quit command to exit cleanly. Each part is discussed in turn below.

# See /usr/local/bin/wxctl for client

# Get absolute path to this script
BASE_PATH=$(realpath $(dirname $0))

# Path to bulk storage for recordings

# Expect commands through this fifo

# Audio will be published through this pipe at 11025 Hz S16LE

# Cleanup on exit
function on_exit {
  echo "Cleaning up..."
  pkill --signal SIGTERM luajit
  exec 3>&-				# Allow audio pipe to close
  rm -f $AUDIO_PIPE
  rm -f $CMD_FIFO

# Ensure clean up on signal

# Create new command fifo
rm -f $CMD_FIFO
mkfifo $CMD_FIFO

# Create new audio pipe 
mkfifo $AUDIO_PIPE

# Setup audio environment for sox
export AUDIODRIVER=alsa			# Use ALSA driver
export AUDIODEV=hw:Loopback,0,0	# Use ALSA loopback (output will be on hw:Loopback,0,1)

# Attach resampler and hold pipe open
cat $AUDIO_PIPE | play -q -V0 -t raw -e s -b 16 -L -c 1 -r 11025 - -V0 -c 1 &
exec 3>$AUDIO_PIPE		# Keep audio pipe open even if writer closes

# Initialise variables

# Main loop
echo "Waiting..."
while true; do
  if read line <$CMD_FIFO; then
    echo "`date -u +"%Y%^b%d-%H%M%S%Z"`: "$line

    # Look for start command to start recording (e.g. start NOAA-15 137.620M)
    if [[ "${params[0]}" == 'start' ]]; then
      if [ -z "$FILENAME" ]; then	# If a recording is in progress then ignore command
  	echo "================================================================================"
        FILENAME=${STORAGE_PATH}"audio/"$(date -u +"%Y%m%d%H%M%S")".wav"
        COMMENT=${SATELLITE}"_"$(date -u +"%Y%^b%d-%H%M%S%Z")
        luaradio rtlsdr_noaa_apt.lua $FREQUENCY $FILENAME &
        echo "WARNING: Ignoring start - recording already in progress..."  

    # Look for stop command to stop recording (e.g. stop)
    elif [[ "${params[0]}" == 'stop' ]]; then
      if [ -n "$FILENAME" ]; then	# Only process files once (can get multiple stops)
        pkill --signal SIGINT luajit
        ./process_recording.sh "$FILENAME" "$SATELLITE" &

    # Look for quit command (e.g. quit)
    elif [[ "${params[0]}" == 'quit' ]]; then

    # Invalid command
      echo "`date`: Invalid command: "$line


# Clean up before exiting


As described in The Receiver the system uses a USB memory stick to provide backup storage for the image archive, mounted at /media/pi/USB_DISK/. The CMD_FIFO is the command pipe between wxctl and record_noaa.sh. A second pipe AUDIO_PIPE is also created to carry audio samples in the format S16LE at 11025 S/s from the SDR-based demodulator to the Alsa device driver hosting the Loopback device. The output side of the Loopback device provides the audio input to WXToImg, however the resulting recording is later discarded and the audio file generated by the receiver software is used instead due to corruption of the WXToImg recording. The Alsa subsystem is also configured to apply a monitor to the Loopback device, allowing the audio stream to be copied to the RPi headphone audio output.

A cleanup function on_exit is registered to forcibly stop the receiver and close the pipes via trap, then the two pipes are opened using mkfifo.

The raw samples from the demodulator are converted into a valid audio stream by play (i.e. sox). Because the receiver attaches (opens) the write side of AUDIO_PIPE at the start of every pass and then detaches (closes) at the end of each pass it is necessary to use the exec 3>$AUDIO_PIPE to ensure that there is always one writer on the pipe and therefore sox never sees the pipe close and keeps the (possibly empty) audio stream alive.

Main Loop

Following initialisation the main loop waits forever for a command to be written to the CMD_FIFO. The command parser accepts start commands with the satellite name and frequency (e.g. start NOAA-15 137.620M), stop commands (e.g. stop), and quit commands (e.g. quit) which are issued by the wxctl script.

The start command reformats the current time into a UTC-based filename of the form YYYYMMDDHHMMSS expected by WXToImg to correctly indicate the recording start time. This is essential for accurately aligning the map overlay with the generated image and correctly identifying the satellite. It then spawns (i.e. asynchronously calls) luajit to start the rtlsdr_noaa_apt.lua script to demodulate the satellite signal on the specified frequency and record the modulated luminance subcarrier from the satellite pass. If a recording is in progress the command is ignored – this is identified by a non-empty FILENAME.

The stop command uses pkill to signal SIGINT to gracefully terminate luajit, and then spawns process_recording.sh to convert the WAV-format audio recording to an image in the background. Note that the RTL-SDR interface in luaradio uses SIGTERM to close the asynchronous data transfer handlers, therefore using SIGTERM to signal to luajit can result in untidy signal chain termination and data corruption – using SIGINT avoids this.

The quit command exits the main loop, subsequently calling on_exit to clean up.

Typical console output generated by this script is (lines 2-7):

2016NOV10-181357UTC: start NOAA-15 137.620M
Recording from 137.62 MHz to /media/pi/USB_DISK/audio/20161110181357.wav
Found Rafael Micro R820T tuner
Exact sample rate is: 1102500.002464 Hz
2016NOV10-182900UTC: stop
Processing recording: /media/pi/USB_DISK/audio/20161110181357.wav for NOAA 15
Recording start time: 10 Nov 2016 18:13:57 UTC
Generating map: /media/pi/USB_DISK/maps/20161110181357.map
Generating raw image: /media/pi/USB_DISK/raw/20161110181357.png
Satellite: NOAA
Status: signal processing............................
Generating HVCT image: /media/pi/USB_DISK/images/20161110181357_%s-%p-%E-%e-img.jpg
Generating projection: /media/pi/USB_DISK/composites/20161110181357_noaa-15-n-52-norm-img.jpg
2016NOV10-185402UTC: stop
2016NOV10-185509UTC: start NOAA-18 137.9125M

Generation of the image from the recorded modulated luminance subcarrier is described in Image Generation.

Leave a Reply

© 2020 wx

Theme by Anders Norén