Friday, August 05, 2016

WSPR decoding on a headless Raspberry Pi

At last Sunday's ARNSW Home Brew group meeting, Peter, VK2EMU handed me a Raspberry Pi a USB audio dongle and my mission instructions... to set up the Pi to decode and report WSPR spots in a headless configuration.

In the end I've built on the excellent work by DJ0ABR.

I had trouble recording the 118 seconds of audio at a sample rate of 12000 samples per second as it produced buffer overruns. Instead I've used the rec command from sox to record at the native sample rate of the USB audio dongle and then convert the file using sox.

I've pretty much used the code and scripts as supplied, with some modest improvements here and there.

Source code for the decoder is from here. This is a fork of the original code which has gone and been integrated into wsjt-x. I have forked it here and added my versions of the record and decode script and the simpler crontab. I've fixed a few things and pushed those changes to my fork of the code so I'd recommend that as a starting point.

Here's some spots on reported from the raspberry pi:

Install a library you'll need, and sox which I use for recording:

sudo apt-get install libfftw3-dev sox

In the directory with the Makefile, type "make" to build the software. Also do mkdir wav.

The USB audio dongle is a low cost one called "3D Sound". I found that it picked up lots of hum until a junkbox audio transformer was wired in line.

Find the USB audio card with:
   cat /proc/asound/cards
and then create /etc/asound.conf with following:
   defaults.pcm.card 1
   defaults.ctl.card 1

# set audio levels
alsamixer # graphical in terminal

To allow the pi user access to the audio devices:

sudo nano /etc/group

and add the sound group to the pi user. You'll need to log out and back in for this to take effect.

To test the recording you can record while showing a level meter like this:

arecord -vv -fdat test.wav

Press Control-C to end the recording.

There are two scripts: record and decode. record is called from a cron job every two minutes to record 118 seconds of audio, convert it and kick off decode.

I installed in /home/pi/wsprcan

Here's my version of record:

# WSPR Audio Recorder Script by DJ0ABR
# record WSPR signal at every even minute
# called by cronjob
# number of files in wav folder
cd ${BASEDIR}/wav
file_num=$(ls -1 --file-type | grep -v '/$' | wc -l)
cd ..
if [ "$file_num" -le "1" ] ; then
        DT=$(date -u +"%y%m%d_%H%M")
        echo recording to ${RECFILE}
        #arecord -d 114 -f S16_LE -r 12000 -t wav ${RECFILE}
rec -V1 -c 1 -t wav ${RECFILE} trim 0 118 &>/dev/null
echo "converting sample rate..."
sox ${RECFILE} -r 12000 /tmp/out.wav
echo removing ${RECFILE}
echo moving /tmp/out.wav to ${RECFILE}
mv /tmp/out.wav ${RECFILE}
        echo "running decode on ${RECFILE}..."
        ./decode ${DT} &

Here's my version of decode:

# Script for the K9AN WSPR decoder, by DJ0ABR
# ===========================================
# use the k9an decoder to get the spots out of the wav sound file
# the file 'spots' is used for storing all the spots and debug information
# the file wsprd.out contains the current spots in the format for
# wsprdsum.out is used as a temporary storage if the upload fails


echo decoding >> spots
echo "decoding: /home/pi/wsprcan/wav/wspr_${1}.wav"
./k9an-wsprd -f 14.0956 /home/pi/wsprcan/wav/wspr_${1}.wav >>spots

# the wav file is processed, delete it (it should be in a ram disk folder if an SD card is used !)
rm ${BASEDIR}/wav/wspr_${1}.wav

# check if spots are available
FILESIZE=$(stat -c%s "${BASEDIR}/wspr_spots.txt")
echo data size= $FILESIZE >> spots
if [ $FILESIZE -ne 0 ] ; then

        # add the spots to a temporary file used for uploading to
        echo add to wsprdsum.out >> spots
        cat ${BASEDIR}/wspr_spots.txt >> ${BASEDIR}/wsprdsum.out

        # upload the spots
        echo upload by curl >> spots
        # ping helps curl to contact the DNS server under various conditions, i.e. if the internet connection was lost
        ping -W 2 -c 1 #> /dev/null;
        curl -m 8 -F allmept=@${BASEDIR}/wsprdsum.out -F call=${MYCALL} -F grid=${MYGRID} > /dev/null;

        # check if curl uploaded the data successfully
        # delete only if uploaded
        if [ $RESULT -eq 0 ] ; then
                # data uploaded, delete them
                echo Upload OK, deleting >> spots
                rm wsprdsum.out
        echo curl result: $RESULT , done. >> spots

Please replace VK2TPM with your call and grid square.
The crontab file:

# Start WSPR Recording at every even minute 
*/2 * * * * /home/pi/wsprcan/record

To see what's going on you need local email. I installed postfix and mutt for this. There's a log file called spots that shows what's going on and any decodes:

0648 -15 -2.5  14.097089 -2  K6PZB CM88 37 
0648 -20 -2.9  14.097099 -2  VK8ZI PH57 23 
0648 -24 -2.7  14.097116 -2  KD6RF EM22 37 

data size= 222
add to wsprdsum.out
upload by curl
Upload OK, deleting
curl result: 0 , done.
0650 -23 -2.6  14.097048 -2  K5XL EM12 33 
0650 -20 -2.1  14.097072 -2  AL7Q BP40 37 
0650 -19 -2.7  14.097158 -2  JA5NVN PM74 33 

data size= 222
add to wsprdsum.out
upload by curl
Upload OK, deleting
curl result: 0 , done.

So far I haven't used the ram disk but that's probably a good idea in the long term.

I also tried VisualWSPR which looks hopeful but crashed on startup for me. 

No comments: