Simultaneous Multi-Band WSPR Decoding with KiwiSDR and WsprDaemon

I've been interested in receiving Weak Signal Propagation Reporting (WSPR) signals recently, for two reasons. The first is that the picoballoons that we launch use WSPR for position information. Not only do I directly receive the picoballoons after we launch them, but I also use the WSPR network to check on their location around the world. I don't have a receiver in Europe, so I rely on other amateur radio operators to receive the balloon and post its location online, and I want to give back to the network.

The second reason is that I'm curious about how far I can receive signals with my somewhat compromised city antenna. While my fan/parallel dipole antenna will never perform as well as the huge antenna farms other amateurs operate, I can work on making my station a bit better by reducing local noise or improving my antenna. Incremental changes is what I'm going for.

Hardware Radio

Soon after we launched the first few picoballoons, I started receiving WSPR packets with my Kenwood TS-2000 using WSJT-X. This radio is a good basic all-mode HF radio, plus 2m and 70cm. After calibrating the TCXO, I set it to decode 20 meters WSPR.

Since 20 meters is a daytime band, during the daytime I would receive many WSPR transmissions from across North America. A typical 2-minute WSPR period would decode 3 to 10 signals, mostly from the North America, but sometimes from Japan and Australia when the band conditions were right.


However, using a ~$1,500 hardware radio for WSPR receiving seemed a bit wasteful. This radio can do so much more! The bandwidth of the WSPR band is only 200 Hz wide, well within the bandwidth of a computer soundcard. And while my hardware radio is decoding WSPR, I can't chase the latest SOTA station or Big DX.

As a first step towards using a software-defined radio (SDR), I tried my FunCube Dongle Pro+. Fundamentally just a downconverter connected to a USB sound card, the FunCube Pro+ Dongle has a bandwidth of 96 kHz and works on most frequencies from 150 kHz up to 2 GHz. It worked OK, although I think the TS-2000 worked a bit better. Recent versions of WSJT-X can directly control the FunCube Dongle frequency, so it was pretty painless to use.

Both the TS-2000 and the FunCube Dongle worked pretty well, but have the same major shortcoming: they can only receive one WSPR band at a time. I could have an RF splitter and multiple radios, but there must be a better solution to simultaneous multi-band WSPR decoding. A software-defined radio that received the entire HF band was what I needed.


After a lot of research, I selected the KiwiSDR for this project. This is a 0-30 MHz SDR board, with an SMA connector. It mounts onto the top of a BeagleBone processor board. The BeagleBone does all the "software" things for the SDR, and has a built-in web GUI based on OpenWebRX which can support up to four simultaneous web users streaming audio.


As you can see in the pic above, the regular kit comes with a plexiglas cover to keep the boards from shorting on things. A metal case is only another $20, but during the great Supply Chain Shortage of 2022 there were none available for less than $80.

The KiwiSDR also has a software-defined GPS receiver for frequency calibration, and uses a LTC2248 14-bit 65 MHz ADC, which is just fast enough to receive the 10 meter (30 MHz) amateur radio band. There is a lot more information about the overall design of the KiwiSDR in the design document (pdf).

Looking at the signals on the entire HF band here at my station in San Francisco, we can see that the AM broadcast bands around 1 MHz are very strong. This is not surprising, as the 50kW transmitters are only a few miles away.


In addition to the very strong AM broadcast stations, the medium-wave broadcast bands around 6 and 7 MHz are also relatively strong, as is WWV at 10 MHz. We don't see WWV at 15 MHz, indicating that when I took this screenshot in the evening Pacific time, the maximum useable frequency was somewhere between 10 and 15 MHz.

Another thing you can clearly see on the waterfall is a lot of noise! Unfortunately, I'm using a standard switching power supply for powering the KiwiSDR. This is not good, as the switching frequency is coupled through the power supply into the receiver, causing lots of spurs and noise. Here's a close up of the amateur radio 10 meter band (30 MHz), showing the switching frequency of around 60 kHz.

Switching power supply noise on the SDR

While the noise isn't as bad lower down in the HF bands, this is still a big problem. I also live in a city, so there is already a very high noise floor from all the neighbors TVs, computers, and other electronic devices. To try and cut down some of these noise issues, the next purchase is a linear power supply, aluminum case, and some ferrite cores.


Even though there is a WSPR decoder plugin for the KiwiSDR, the documentation and forums recommend using a different computer for WSPR decoding. This is because the single-core BeagleBoard computer is barely powerful enough to serve the waterfall and audio streams across a network, so it can't spare any horsepower for the complex forward error correction calculations required for WSPR decoding.

WsprDaemon, written by Rob Robinett AI6VN, is a shell script that connects to a KiwiSDR, saves an audio file, and sends that audio to WSJT-X for decoding. The interface between the KiwiSDR and WsprDaemon is just an audio stream of the WSPR bands of interest. This audio stream gets saved (in RAM) for 2 minutes, then the wsprd binary from WSJT-X decodes the audio file and outputs the decoded spots. The decoded spots then get uploaded to the wsprnet database, and also the wsprdaemon servers.

WsprDaemon was originally designed to run on a newer Raspberry Pi, and the latest version also works really well on a generic Ubuntu 20.04 installation. A comparison (pdf) between the internal KiwiSDR WSPR decoder and the external WsprDaemon decoder shows the external decoder is much better than the internal one.

There is no real GUI for WsprDaemon, so it's easiest to view your spots online at or wsprnet. WsprDaemon does measure and graph your local noise floor, and those graphs are served locally.

WsprDaemon Noise Graph

System Load

So how powerful a computer do you need to decode all WSPR signals on 7 or 8 bands? I have a collection of older Raspberry Pis at home (sadly I can't seem to get my hands on a new Pi 4), so I decided to run some tests. My test hardware consisted of a 2015 Raspberry Pi 2, a 2016 Pi 3, and my virtual machine guest with a 64-bit i3-5010U processor from 2015. (Ugh why are all my computers ~7 years old??)

The two Raspberry Pi computers were running 32-bit Debian 10 Buster Lite (no desktop GUI), which is the latest OS supported by WsprDaemon. The virtual machine was running 64-bit Ubuntu 20.04 Focal Server edition (no Desktop GUI) with 2 processor cores.

I let each of these computers decode 7 WSPR channels for a few days while making load measurements. Solar conditions were about the same during this test, and the number of decoded spots per 24-hour period was about the same. I mostly used htop for measuring computer load.

Hardware load for WsprDaemon

"Decode Load" is the 1-minute load when actively decoding WSPR packets (once every 2 minute period), and "15-min load" gives you an idea of the average load across multiple decode cycles. The "Max Decode time" column above is a bit subjective, as I just looked at how long the wsprd was running after the start of the decode cycle.

As you can see, the Pi 2 is barely powerful enough to run 7 bands. Decoding load is between 2.5 and 3.5 out of 4 cores, which is getting pretty close to the limit. It can take up to 1 minute (out of a 2 minute window) to decode all of the spots on a particular band; luckily there is 4 cores so 4 bands can be processed at a time. The bands that aren't open finish quickly, freeing up resources.

At no point did the Pi 2 spot decoding on a single band take longer than 110 seconds, which might cause problems if it's trying to decode the previous cycle and the current cycle at the same time.

The Pi 3 is a bit better, with the 15-minute load around 2.2 out of 4 cores. But my Intel NUC outperforms both Raspberry Pis, even though it has only 2 (virtual) cores.

In terms of network bandwidth between the KiwiSDR and the WsprDaemon computer, one audio channel sends about 215 kbit/sec or 27 kBytes/sec. For my setup, with 7 audio streams, this adds up to about 1.6 Mbits/second of bandwidth. Over the course of a day, this is around 16 GBytes of bandwidth, so you don't want to be sending this data across the actual internet.


After getting WsprDaemon all installed and working, I just let it run. Since it's using 7 of the 8 "receivers" on my KiwiSDR, I'm not making my receiver publicly available. Maybe I'll get a second KiwiSDR or change things in the future.

KF6ZEO Spots for 2022-03-17

The first thing I noticed was how many WSPR stations I was receiving. On a typical day, I would receive around 5,000 WSPR transmissions from across North America, and sometimes Japan and Australia. And this is in the middle of San Francisco, with lots of RFI, using a fan/parallel dipole antenna.

Weekly KF6ZEO Spots for March 13-19th

Looking at a week's worth of WSPR spots, I would typically receive over 2,000 spots per day on 20 meters. While this is about the same number of spots per day I was receiving with my TS-2000, I never realized how much WSPR activity was on the other bands. 1,000 spots per day on 40 meters, and 500 spots per day on 17 meters? Wow. Even 12 meters (that's an amateur band?) has several hundred spots received per day.

Hourly KF6ZEO Spot Count by Band

Diving deeper into one day of WSPR spot reception, you can clearly see when each band is open and closed. 40 meters is more of an evening and nighttime band, and I receive anywhere between 50 and 80 spots per hour when the sun is down. 20 meters is open during the daytime only, with counts dropping to zero between 10pm and 5am local Pacific time.

All in all, I'm pretty impressed at what I can receive with my station. While it's performance is nowhere near the big stations on the coast, such as KFS (pdf) and KPH (pdf), my station does receive around 5,000 WSPR spots per day.

I'll be adding a linear power supply and filters soon to try and bump up my place in the rankings.