Code Bits, Projects, & Tech Thoughts

WSPiR - A $50 Raspbery Pi Radio Beacon

WSPiR - A $50 Raspbery Pi Radio Beacon


Weak Signal Propagation (with Pi) Reporting - How a Raspberry Pi Zero can send digital messages across the world (or at least the continent) with with less power than a WiFi Router, for less than $50.


With the Low Pass Filter and a minimal laser-cut acrylic case, the Raspberry Pi WSPR Node is still smaller than (and as curiously strong as) a well-known tin of breath mints.


It's fair to say the first stage of this project was inspired by Jenny List's Australia Project. Her work, initially an entry for a Hackaday contest, was to use a Raspberry Pi Zero as a WSPR transmitter that could be heard in Australia. So, credit where credit is due – I would not have been able to complete this project without the knowledge base Jenny created.

"Australia is almost as far away as it is possible to go from the UK, hence the name: the Australia Project."

– J. List

I've spent a few years playing with Software Defined Radio, but I've never really done more than exploring and decoding, so I thought this project was a perfect candidate for a software engineer starting to learn about amateur radio. I also hoped this project would be an excellent testbed for radio experimentation, to build radio software skills

This brings up an important point about this project - to transmit on most radio services you need to be licensed with the FCC. WSPR is no exception, as all frequency bands that WSPSR uses are bands allocated for amateur radio use. To use WSPR you will need to be a licensed amateur radio operator.

Amateur Radio

This part of the project is completely dependent on your learning style and speed. Amateur radio has three license classes granted by the FCC: Technician, General, and Amateur Extra. Each upgrade in license class adds frequency and mode privileges. The American Radio Relay League (ARRL) has resources to learn how to get your license and to learn about each license class. This is where I started, to learn about the requirements. A quick google search lead me to Dan Romanchik's no nonsense study guides, which came highly recommended as effective study tools.

I knew that I wanted to use the 20m (or 14 MHz) band for my WSPR beacon, for a number of reasons. Essentially, the 20m band is nicely situated to maximize potential range during the day and night, and has the added benefit of a large network of reporting nodes. The 20m band, however, is not within the privileges of a Technician-class amateur radio operator. I therefore knew I'd need to pass at least the General-class license test.

bandplan The ARRL bandplan for the 20m band. Only (G)eneral, (A)dvanced, and (E)xtra classes have privileges.

So I downloaded Dan's No Nonsense, Technician Class License Study Guide and bought the General-class guide book. I spent about two weeks studying the guides, taking practice tests provided by the ARRL until I was consistently passing with 85% or higher, and found an arrl exam near me. The studying paid off, and a week after I passed the Technician and General exams, I was assigned a callsign by the FCC! Time to start broadcasting WSPR.

What's WSPR?

Weak Signal Propagation Reporting, or WSPR, is a type of digital encoding used by the amateur radio community to test low power propagation of radio signals. The protocol was initially created in 2008 by Joe Taylor, but since then several open-source WSPR software packages have been created. 1 The WSPRnet reporting site is a great place to begin exploring WSPR, and they recommend G4ILO's introduction article to begin learn the basics.

Essentially, WSPR specifies a digital encoding with an extremely slow baud, allowing decoding of signals almost imperceptible among background noise. This is a useful mechanism for testing the limits of propagation with low-power transmissions. As the Raspberry Pi does not have a power amplifier (or even an FM radio module) built in, we have a limited amount of power available. Nominally, we can create about a 10mW signal by modulating a GPIO pin.2 This should be sufficient power to transmit a WSPR signal, providing we can create a well-formatted FM output.

Conveniently, a software package called Wspprry Pi already exists for Raspberry Pi (1/ 2/ 3/ Zero) that allows transmission of WSPR packets. It does this by modulating GPIO4 (GPCLK0) to create an FM signal. This software package does most of the heavy listing for this project, allowing us to focus on hardware.

The Idea

The project will use three basic hardware components:

  • A Raspberry Pi Zero (And power, SD Card, Case, etc)
  • A low pass filter for the band we want to use
  • An antenna that is compact enough to install indoors

After installing the required software, plugging the LPF into the Pi, and attaching the antenna we should be ready to transmit!

Raspberry Pi Setup

I started by downloading an up-to-date copy of raspiban stretch with desktop, and following the Raspberry Pi Foundation's installation guide and SSH setup instructions. Then I followed the installation guide on the Wsprry Pi github. I made a short test transmission using Wsprry Pi's --test-tone flag, and verified using (via rtl-sdr) that the correct frequencies were being generated. Then, using a short breadboard lead I ran a brief transmit test on 2m (144 MHz) to test reception on my Baofeng handheld. Everything seemed to be working fine, but as expected the signal was noisy.

Pleasing the FCC with a LPF

Because the Pi's GPIO generates a square wave instead of a sine wave (and by the nature of RF generation) a raw transmission will also include harmonics that can seriously interfere with radio operations. I needed a low pass filter to reduce the harmonics below the FCC's for out of band emissions.

The LPF was very much a design based on Jenny List's work. It's a 7-Pole Chebyshev filter. I won't pretend to understand the physics behind filter design, instead I used the established 7-pole filter design, and a filter design tool to calculate the inductors and capacitors needed.

lpf_schema LPF schematic, a standard 7-pole design.

For a 20m Filter, the component list is as follows:

Part Value
C1,C4 430pF
C2,C3 620pF
C5 0.1uF
L1,L3 560nH
L2 680nH
ANT Edge-Launch SMA (F), 1.6mm
PI 2x5 Female 0.1" Header Socket

I made a quick PCB schematic and layout, and ordered the boards from OSH Park, a community PCB manufacturer. The boards took about two weeks for fabrication and delivery. Then an additional hour of time was spend soldering the headers, SMA edge-launch connectors, and surface mount capacitors and inductors.


Assembled LPF boards. The size is roughly 3x4cm.

Antenna Construction

Like the low pass filters, I leveraged tools to do the heavy calculation lifting. I had about 30 feet of two-strand speaker wire that I'd salvaged and wanted to reuse. I knew I wanted an antenna that could be installed along the top of my wall, so it would be as long as possible while still being out of the way. This gave me an overall length of about 12 feet (yuck, imperial). Since the non-driven element would be along the side wall at a 90 degree angle, I used calculations for a monopole 1/4-wavlength antenna. A quarter-wavelength antenna resonant at 14 MHz is a little over 17 feet, which is too long for this wall, so an loading coil must be added to "lengthen" the antenna's RF resonance.


Using a free dipole calculator to get antenna measurements.

Using an antenna calculator for loaded a antenna, I calculated a loading coil at 6" from the feedpoint would need to have an inductance of about 2.44 µH. Plugging the wire diameter into a coil inductance calculator, along with a diameter of a plastic tube I had on hand, I calculated the required number of turns to reach that inductance. I wrapped masking tape around the outside of the tube, sticky-side out, and wound on the required coils. Then, using a ziptie to hold both ends together, I glued the coil together with CA glue and let it dry overnight.

After pulling the tube out and removing the tape, the results look pretty clean, and the zip tie/glue mass at the top gives me more than enough confidence the coil will hold under tension.


The antenna feedpoint, loading coil (Right) and feedline balun.

I soldered an edge-launch SMA connector to a piece of perfboard and soldered on the speaker wire segments, taking care to connect the end with the loading coil to the center pole of the SMA connector. Then I secured the wires with zip ties and sealed them with a healthy glob of CA glue. When the glue had dried I marked the calculated length of each segment (treating it like a dipole), trimmed the ends long, and created mounting loops with the excess length.


I used nail-in electrical staples (like the kind used to secure electrical wiring to a home's framing) to create tiedowns near the feedpoint and ends of the antenna. Then I secured the antenna using zip ties. I looped 10 passes of the feedline around an FT114-43 ferrite toroid, and ran the other end to the LPF. Then I plugged the LPF into the Raspberry Pi, and powered it on.


The whole setup is minimally intrusive.

Start it up!

After logging in to the Pi, I started wspr using the command sudo wspr --repeat --offset --self-calibration CALLSIGN GRID 10 20m 0. 10 indicates the transmit power available, in this case about 10dbm, or 10 mW. 20m and 0 are the bands on which wspr will transmit, 0 to add time between transmissions on the 20m band. I waited to see that transmissions had successfully completed, then went to check the WSPRnet Map to see if there were any propagation reports.


Wsprry Pi command output, set to broadcast 10dbm (0.010 W) on the 20m (14MHz) band. Callsign and grid locator are blurred out.

And, success! After two or three transmissions I had a report from over 700 km away! I started screen session with screen -S WSPR, ran the wspr command above, and let it run. My plan was to leave the script for 24 hours and see what kind of reports I was getting. But after several hours I saw no more reports on WSPRnet, so I logged back into the Pi to investigate what was going on.

What I found seemed to be an issue with wspr crashing while waiting to transmit, as had been reported on the github. So I followed the recommended steps of adding consoleblank=0 to /boot/cmdline.txt and rebooted. But this seemed to have no effect on the crashes; wspr was still crashing every third or fourth transmission window. But this behaviour seemed to be reliable, and I did not see any crashes on the first transmission. So I wrote a quick script (below) to run wspr, configured to transmit once and wait once per loop.

# Run WSPR

while [ 1 -eq 1 ]; do  
    sudo wspr --terminate 2 --offset --self-calibration CALLSIGN GRID 10 20m 0

For convenience, I put the script in /usr/local/bin/wspr_beacon and added execute permissions with sudo chmod a+x /usr/local/bin/wspr_beacon. I wanted to run the script on boot, but again ran into issues with wspr crashing - but this time over and over inside the loop. For whatever reason, when manually executed the script behaves fine. So ultimately the beacon requires me to log in, create a screen session (to keep the script running once I log out), and launch the script. As I don't expect to be powering the Pi on and off with much frequency this is good enough.


Once I'd ironed out the execution issues, I let wspr run for about 24 hours, then checked the WSPRnet Map and WSPRnet Database for reports.


Propagation over a few hours, distance to the receiver's location is shown along the right. Over 2000 km of range!

Propagation Map

After about a day of transmitting I was getting reception reports from reports from across the US and even into Canada.

Success! A handful of propagation reports! Over a period of about 24 hours I had over 10 unique reports, and almost 100 reports total. Not bad for a transmitter with less than 10mW of power.

Cost Estimate

Since I acquired the hardware for this project over the course of several months, I don't have a perfect cost breakdown. Instead, here's an estimate of the project cost. Keep in mind, some of the items were ordered en masse due to order minimums or processing requirements. The LPF PCB's, for example, were ordered in a set of three, due to the way OSH Park handles their orders. I already had some of the parts as well, reducing the overall cost.

Item Cost
Raspberry Pi Zero W $5.00
Raspberry Pi Power Supply $10.99
16 GB SD Card $9.99
C4Labs Zebra Zero Case $5.99
Filter PCB, components, SMA Connector $8.78
25 ft 2-Strand Speaker Wire $1.99
Total $42.74

So the total project cost (from scratch) was about $45. That's about 33 miles (53 km) per USD of effectiveness.

Next Steps and Future Work

Next steps for the WSPR Beacon include:

  • Carefully matching the antenna's impedance by modifying or creating a new feedline balun
  • Tuning the antenna system exactly with an SWR meter to improve transfer of transmit power
  • Automatic report logging integration, via dashboard or light

This work serves as , hopefully, an introductory project into amateur radio systems. Future goals include a from-scratch High Altitude Balloon flight computer, and eventually a flight computer for balloon circumnavigation.

No writeups yet.



  2. 10mW Theoretical max output comes from the per-bus maximum current draw limited of the Raspberry Pi. 16 mA per pin is allowable on the 3.3V bus. From a derivation of Joule's First Law we get P = IV, which for us is P = 16mA * 3.3V = ~53 mW (not PEP). In practice, one pin could pull more current than this limit, possibly up to the 50 mA bus limit. However, internal resistance in the LPF and Raspberry Pi circuitry, and impedance mismatch between the LPF and load will act against this. When measured with an oscilloscope, the output of the LPF connected to a 50 ohm dummy load the RMS voltage of this system was about 720 mV. Therefore, Peak Envelope Power of the system can be calculated by PEP = (RMS voltage)^2 / R, for R=50 Ohms, which is PEP = (0.72^2) / 50 = ~10 mW.