Thursday 28 March 2013

WSPR on a RaspberryPi

Building a reliable WSPR decoder on a headless Raspberry Pi (no GUI)

Version info
31/03/2013 - Fixed typo in configure statement --with-portaudio-lib-dir=/usr/lib/arm-linux-gnueabihf, changed from rrm-linux-gnueabihf to arm-linux-gnueabihf (thanks to JonOve LA3JJ for pointing this out)

7/4/2013 - Added frequency hopping howto, formatting cleaned up to improve readability

12/4/2013 - Added some additional info on hopping.ini

The Hardware

Raspberry Pi Model B (rev 2) with 512 MB of RAM

Disk media is an 8 GB SDHC card, I use class 10 cards for faster disk IO performance
RaspberryPi.jpg

Successfully tested USB sound cards -  Signalink USB & Terratec 5.1 USB



Aureon_51_USB_MK_II_trans


Download and install Raspbian Wheezy from http://www.raspberrypi.org/downloads


Once installed connect via ssh and perform the following changes with raspi-config


pi@raspberrypi ~ $ sudo raspi-config

Set the following parameters
  1. Change the default password from raspberrypi to something more secure
  2. Update raspi-config
  3. Expand the rootfs
  4. Set timezone
  5. Change GPU memory split to minimum value, 16 MB for GPU (we don't need a display) 
  6. Overclock to improve performance - **warning using over volt invalidates the Pi warranty** I'm happy to use Medium but modest may be a safer option for you (no over volt)







Update package lists first
sudo apt-get update

Download and install wspr dependencies

sudo apt-get install build-essential subversion python2.7-dev python-numpy python-imaging-tk python-pmw libportaudio2 portaudio19-dev libsamplerate0-dev gfortran cl-fftw3 python-dev hamlib-utils

Get the latest version of WSPR
svn co http://svn.berlios.de/svnroot/repos/wsjt/branches/wspr

Enter wspr directory

cd wspr

Configure source

./configure --with-portaudio-include-dir=/usr/include --with-portaudio-lib-dir=/usr/lib/arm-linux-gnueabihf

Edit the Makefile to enable hardfloat, this will improve decoding performance

pi@raspberrypi ~/wspr $ vi Makefile

Add the string -mfloat-abi=hard to the end of line 5 as shown below
FFLAGS = -g -O2 -fno-range-check -ffixed-line-length-none -Wall -Wno-character-truncation -Wno-conversion -Wtabs -fPIC -mfloat-abi=hard

And also to the end of line 9

CFLAGS = -Wall -O0 -g -Wall -O0 -g -mfloat-abi=hard

Make the build

sudo make

And Install

sudo make install 

As we will use the wspr_nogui.py program and not wspr.py copy the compiled w.so module from the WsprMod to the WsprModNoGui directory

pi@raspberrypi ~/wspr $ cp WsprMod/w.so WsprModNoGui/


Demote the on board Raspberry Pi sound card to the second device by adding/modifying the following parameters in /etc/modprobe.d/alsa-base.conf
pi@raspberrypi ~/wspr $ sudo vi /etc/modprobe.d/alsa-base.conf



#options snd-usb-audio index=-2
options snd_bcm2835 index=-2

Save the above file and reboot

sudo reboot

In order to improve USB stability add the following command to /boot/cmdline.txt, this limits the USB speed to 12Mbps (USB 1.1) - without this I have problems
dwc_otg.speed=1


Create a .libao file your home directory with the following lines
driver=alsa
dev=default

Reboot to activate changes
sudo reboot

Create a .asoundrc file (don't forget the leading dot) in your home directory (/home/pi/.asoundrc) and add the following lines

pcm.radio {
type hw
card 1
device 0
}
pcm_slave.radioslave {
pcm radio
rate 48000
}
pcm.radioconv {
type rate
slave radioslave
}

Create a wspr configuration file in the wspr directory (/home/pi/wspr/WSPR.INI in my case)

Add the following lines to the configuration file with vi, change MyCall and MyGrid to your callsign and location, the selected band in this example is 160 m (iband 2) - change this to your desired band


MyCall LX3KR
MyGrid JN39GT
CWID 0
dBm 37
PttPort None
CatPort None
AudioIn 2#radio
AudioOut 3#radioconv
BFOfreq 1500
PTTmode DTR
CATenable 0
Acal 0.0
Bcal 0.0
CalEnable 0
IQmode 0
IQrx 0
IQtx 0
FIQ 12000
Ntxdb 0
SerialRate 4800
DataBits 8
StopBits 2
Handshake None
Rig 214#####Kenwood#########TS-2000
Nsave 0
TRminutes 2
PctTx 0
DGain 5
Upload 1
Idle 0
Debug 0
MRUdir /home/pi/wspr
freq0_600 0.5024
freqtx_600 0.5039
freq0_160 1.8366
freqtx_160 1.8381
freq0_80 3.5926
freqtx_80 3.5941
freq0_60 5.2872
freqtx_60 5.2887
freq0_40 7.0386
freqtx_40 7.0401
freq0_30 10.1387
freqtx_30 10.1402
freq0_20 14.0956
freqtx_20 14.0971
freq0_17 18.1046
freqtx_17 18.1061
freq0_15 21.0946
freqtx_15 21.0961
freq0_12 24.9246
freqtx_12 24.9261
freq0_10 28.1246
freqtx_10 28.1261
freq0_6 50.293
freqtx_6 50.2945
freq0_4 70.0286
freqtx_4 70.0301
freq0_2 144.489
freqtx_2 144.4905
freq0_other 0.136
freqtx_other 0.1375
iband 2
StartIdle 0
NoBeep 0
Reject 0
RxApply 0



Each time wspr_nogui.py is run a file called audio_caps is created in the wspr directory, check that the audio device id's match the configuration file above


pi@raspberrypi ~/wspr $ more audio_caps
 0    2    2       0       0  USB Audio CODEC: USB Audio (hw:1,0)
 1   32   32       0       0  pulse
 2    2    2       0       0  radio
 3    2    2       0       0  radioconv


ID 2 (radio) is Audio in and ID 3 (radioconv) is audio out

If you choose to use the Terratec sound card you'll need to switch to line in mode and set the volume with the following commands (not necessary for the SignaLink USB)


/usr/bin/amixer -c 1 cset numid=13,iface=MIXER,name='Capture Source' 1
/usr/bin/amixer -c 1 cset numid=10,iface=MIXER,name='Line Capture Switch' 1
/usr/bin/amixer -c 1 set Line 45%


Now it's time to run wspr without a GUI (run from the wspr directory)

pi@raspberrypi ~/wspr $ python -O wspr_nogui.py



The RX noise will read -30 dB until the next 2 minute receive interval, the program output will be displayed on your ssh console, if you close the session the process will die


if you want to run in the background use the command below, with this method you can disconnect your ssh session and let the Pi operate in standalone mode (no keyboard, mouse or monitor needed)

pi@raspberrypi ~/wspr $ nohup python -O wspr_nogui.py 2>/dev/null 1>/dev/null &

Make sure your Raspberry Pi remains connected to a network for accurate time (NTP) and for spot uploads to wsprnet



Questions?

So where can I see my spots?
1) In the local text file /home/pi/wspr/ALL_WSPR.TXT
pi@raspberrypi ~/wspr $ more ALL_WSPR.TXT

2) http://www.wsprnet.org if you have a working Internet connection

How much CPU does the process use?
While receiving 2%, decoding about 98% and in transmit mode 6% 

What is the average time to decode at the end of each interval?

Between 15 and 35 seconds depending on the number of spots and band/noise conditions


Does the transmit function work? how do I enable it?
In the above example I've configured wspr to run in receive only mode with PctTx 0, to enable transmit for 20% of the time set PctTx 20 in WSPR.INI, PctTx 50 is 50% transmit

Does the Raspberry Pi provide enough current for the USB sound cards above? do I need a powered USB Hub?

For the cards in this howto I don't need a powered hub, the 100 mA provided by the Pi is adequate, for other cards/usb devices you may need a powered hub

How do I check/set the sound levels?

Run wspr_nogui from your console and wait for the start of the next receive interval

pi@raspberrypi ~/wspr $ python -O wspr_nogui.py

The RX level should be around 0 dB but +- 10 dB is still ok




With the Signalink USB sound can be adjusted with the TX/RX knobs, for other cards you will have to use alsamixer to adjust playback/capture levels 

pi@raspberrypi ~/wspr $ alsamixer (select F5 to show all inputs/outputs)







Frequency hopping configuration (optional)

So you want to frequency hop as well? no problem, you'll need a USB serial converter and a copy of the hamlib utilities.

This configuration has been tested without the need for an external USB powered hub, both the USB sound card and serial converter work fine together on the Raspberry USB ports.

So the first step is to install hamlib, the main site is here http://sourceforge.net/apps/mediawiki/hamlib/index.php?title=Main_Page

Download the latest tarball to your home dir
wget https://downloads.sourceforge.net/project/hamlib/hamlib/1.2.15.3/hamlib-1.2.15.3.tar.gz

Extract the contents
tar -zxvf hamlib-1.2.15.3.tar.gz

Enter hamlib directory
cd hamlib-1.2.15.3

Install dependencies
sudo apt-get install libltdl-dev

Run configure from hamlib dir
./configure

And make (can take some time - don't hog the cpu, make sure wspr is not running during compile)
make

And make install
sudo make install

OK all done, now connect the USB serial converter, it should show up as /dev/ttyUSB0.
The next step is to test CAT communication between your rig and Raspberry Pi with rigctld, for this test you need to know the baud rate, data and stop bits and rig id from hamlib.

You will find your rig id in the file:

pi@raspberrypi ~/wspr $ more /home/pi/wspr/hamlib_rig_numbers
 101  Yaesu                  FT-847                  0.5             Beta
 103  Yaesu                  FT-1000D                0.0.6           Alpha
 104  Yaesu                  MARK-V FT-1000MP        0.0.5           Alpha
 105  Yaesu                  FT-747GX                0.4.1           Beta
 106  Yaesu                  FT-757GX                0.4.1           Beta
 107  Yaesu                  FT-757GXII              0.4             Stable
 109  Yaesu                  FT-767GX                1.0             Stable
 110  Yaesu                  FT-736R                 0.3             Stable
 111  Yaesu                  FT-840                  0.1             Untested


To limit the search to Kenwood rigs only use grep

pi@raspberrypi ~/wspr $ more /home/pi/wspr/hamlib_rig_numbers | grep Kenwood
 201  Kenwood                TS-50S                  0.8             Untested
 202  Kenwood                TS-440                  0.8.0.6.1       Alpha
 203  Kenwood                TS-450S                 0.8.1           Beta
 204  Kenwood                TS-570D                 0.8.2           Stable
 205  Kenwood                TS-690S                 0.8.1           Beta
 206  Kenwood                TS-711                  0.8.0.6.1       Untested
 207  Kenwood                TS-790                  0.8.2           Alpha
 208  Kenwood                TS-811                  0.8.0.6.1       Untested
 209  Kenwood                TS-850                  0.8.1           Beta
 210  Kenwood                TS-870S                 0.8.0           Beta
 211  Kenwood                TS-940S                 0.8.0.6.1       Alpha
 213  Kenwood                TS-950SDX               0.8             Beta
 214  Kenwood                TS-2000                 0.8.4           Beta
 215  Kenwood                R-5000                  0.6.1           Alpha
 216  Kenwood                TS-570S                 0.8.1           Stable
 217  Kenwood                TH-D7A                  0.5             Alpha
 219  Kenwood                TH-F6A                  0.5             Beta
 220  Kenwood                TH-F7E                  0.5.1           Beta
 222  Kenwood                TS-930                  0.8             Untested
 223  Kenwood                TH-G71                  0.5             Beta
 224  Kenwood                TS-680S                 0.8.1           Beta
 225  Kenwood                TS-140S                 0.8.1           Beta
 226  Kenwood                TM-D700                 0.5             Beta
 227  Kenwood                TM-V7                   0.5             Beta
 228  Kenwood                TS-480                  0.8.5           Untested
 230  Kenwood                TRC-80                  0.8             Alpha
 231  Kenwood                TS-590S                 0.8.1           Beta
 233  Kenwood                TH-D72A                 0.5.1           Alpha
 234  Kenwood                TM-D710                 0.5             Untested




The test command for my Kenwood TS-480 is below:
rigctl -vvvvv -r /dev/ttyUSB0 -s 38400 -C stop_bits=1 -m 228

If it works you will get the following output

pi@raspberrypi ~/hamlib-1.2.15.3 $ rigctl -vvvvv -r /dev/ttyUSB0 -s 38400 -C stop_bits=1 -m 228
rigctl, Hamlib 1.2.15.1
Report bugs to <hamlib-developer@lists.sourceforge.net>

rig:rig_init called

rig: loading backend kenwood
initrigs2_kenwood called
rig_register (213)
rig_register (201)
rig_register (225)
rig_register (203)
rig_register (204)
rig_register (216)
rig_register (224)
rig_register (205)
rig_register (207)
rig_register (209)
rig_register (210)
rig_register (222)
rig_register (214)
rig_register (230)
rig_register (221)
rig_register (229)
rig_register (202)
rig_register (211)
rig_register (206)
rig_register (208)
rig_register (215)
rig_register (226)
rig_register (217)
rig_register (233)
rig_register (220)
rig_register (223)
rig_register (227)
rig_register (234)
rig_register (231)
rig_register (231)
rig_register (228)
rig_register (219)
rig_register (232)
kenwood_init called
kenwood_init: if_len = 38
rig_set_conf: stop_bits='1'
rig:rig_open called
kenwood_get_vfo_if called
kenwood_get_if called
kenwood_safe_transaction called
kenwood_transaction called
kenwood_transaction: cmdstr = IF
write_block(): TX 3 bytes
0000    49 46 3b                                            IF;
read_string(): RX 38 characters
0000    49 46 30 30 30 31 38 31 32 31 30 30 30 20 20 20     IF00018121000
0010    20 20 20 30 30 30 30 30 30 30 30 30 30 32 30 30        0000000000200
0020    30 30 30 38 30 3b                                   00080;
Opened rig model 228, 'TS-480'
Backend version: 0.8.5, Status: Untested

Rig command: f

kenwood_get_freq called
kenwood_safe_transaction called
kenwood_transaction called
kenwood_transaction: cmdstr = FA
write_block(): TX 3 bytes
0000    46 41 3b                                            FA;
read_string(): RX 14 characters
0000    46 41 30 30 30 31 38 31 32 31 30 30 30 3b           FA00018121000;
Frequency: 18121000

Rig command:



Great, let's configure WSPR to use CAT control, you'll need to set the following parameters in WSPR.INI (these parameters are specific to your rig)


CatPort /dev/ttyUSB0
CATenable 1
SerialRate 38400
DataBits 8
StopBits 1
Handshake Hardware
Rig 228#####Kenwood#########TS-480

And now have a look at hopping.ini in the wspr directory

pi@raspberrypi ~/wspr $ more hopping.ini
1 1
 600  0     0  0
 160  0     0  0
  80  0     0  0
  60  0     0  0
  40  1     0  0
  30  1     0  0
  20  1     0  0
  17  0     0  0
  15  0     0  0
  12  0     0  0
  10  0     0  0
   6  0     0  0
   4  0     0  0
   2  0     0  0
 Oth  0     0  0

On the first line you'll see two flags, the first flag is hopping enable 0=off 1=on, the second flag is standard or coordinated hopping 0=standard 1=coordinated

Check out K1JT's WSPR doc for more info (hopping function is described on page 11)

http://physics.princeton.edu/pulsar/K1JT/WSPR_3.0_User.pdf

The four columns have the following use:
1) Band id
2) Enable hopping for this band, 1=yes, 0=no
3) pctx
4) Tuneup on each band? - 1=yes, 0=no

Unfortunately frequency hopping will not work with wspr_nogui.py out of the box due to a small bug related to leftover code from the GUI, to fix this edit the following file with vi or nano
pi@raspberrypi ~/wspr $ nano WsprModNoGui/hopping.py


Add a hash in front of the globalupdate() line near the bottom of the file and save, this will stop the 'Error reading hopping.ini' message 
tuneupflag[r].set(int(s[r][13:16]))

                #globalupdate()
        except:
            print 'Error reading hopping.ini.'

All done, start wspr_nogui.py and after a couple of minutes your rig will start hopping in RX and TX if you choose, please let me know if I have missed anything.

73's LX3KR