|
|
Log in / Subscribe / Register

Listening to the radio with Rust

By Daroc Alden
September 24, 2026

RustConf

Many of the transmissions sent over the radio spectrum can be decoded with a relatively cheap hardware dongle. Thomas Eckert presented at RustConf 2026 in Montreal about his hobby: decoding radio transmissions with Rust. In his presentation, he covered all of the math necessary to get started with software-defined radio, and gave demonstrations of listening to AM and FM radio, as well as decoding transmissions from aircraft transponders. His slides and example code are available on GitHub.

Eckert said that all of his demos relied on the same fundamental pipeline. He then ran a program that started picking up a FM radio station from Montreal's Mt. Royal. That signal starts as a current being applied to the transmitting antenna, pushing the electrons in the metal back and forth. A changing electric field means a changing magnetic field and vice versa; the changing field propagates out through the air until it reaches his antenna. For the FM and AM radio demos, that antenna was clipped to the side of the podium; for the aircraft demo, which uses a different wavelength, the antenna in question was located up on the roof, with the data relayed by a Raspberry Pi that the conference organizers had allowed him to place up there.

Antennas receive the entire radio spectrum at once, Eckert explained, but different antennas are more sensitive to different parts of the spectrum. Generally, for simple linear antennas, the ideal length is one quarter of the wavelength of the radio signal. The FM radio station that he had briefly tuned into was broadcasting with a wavelength of about three meters, so the ideal antenna was 77 centimeters long — exactly the length to which he had extended the silvery collapsible antenna at the podium. For aircraft transponders, the ideal length drops to about five centimeters.

[Thomas Eckert]

No matter the length, the electrons in the receiving antenna oscillate in time with the incoming radio wave, producing a current. The software-defined radio dongle that Eckert was using — the RTL-SDR Blog V3, a small $30 device with a USB cord on one side and a coaxial antenna cable on the other — samples that current to turn the analog wave into digital data. It also has a tuning circuit that focuses on one relatively narrow slice of the radio spectrum at a time. The data that comes out of the dongle is a stream of pairs of numbers. These numbers represent two separate components of the radio wave at right angles to each other: a cosine wave (also called the "in-phase component") and a sine wave (called the "quadrature"). The dongle provides these as a continuous stream of unsigned bytes. The code centers and scales them to produce floats between -1 and +1. Combining these as a complex number gives an "I/Q" signal. The distance of an I/Q sample from the origin is the amplitude, and the speed at which successive samples rotate about the origin is the frequency.

The hardware in the dongle uses chips originally designed for television receivers, Eckert said. It only digitizes the signal as it exists; it has no circuitry for detecting amplitude modulation (AM) or frequency modulation (FM) signals. All of the decoding of the signal happens in code.

Exactly what that decoding looks like depends on the kind of signal being interpreted. The dongle produces millions of samples per second, covering a 960-kilohertz slice of the radio spectrum. That is enough bandwidth to fit five FM channels next to each other, for example. To focus on just one station, the code needs to separate out one particular frequency component to analyze. Practically, that means using a low-pass filter to attenuate out the uninteresting signals. For AM radio, which is the simplest, the audio is then encoded into changes in the amplitude of the signal. Each sample is converted into a distance from the origin, and then the whole signal is shifted and rescaled to fit into the range of signals that sound cards expect. Then the data can be put into a ring buffer for the sound card and played directly.

FM radio is slightly more complicated: the data comes from changes in the frequency. Therefore, the decoding implementation has to look at the difference in phase (angle) between the previous sample and the current sample. That data can be rescaled and played directly, but it will sound harsh and thin. That's because FM is more sensitive to small changes in the signal, which tends to introduce more noise, especially in high-frequency sounds. Therefore, FM radio stations boost the treble component of their signals to drown out the noise, and the radio receiver has to undo the transformation to get the original sound back. The boost is "75 µs" in North America and "50 µs" in Europe. That measurement doesn't actually represent a time shift; it's a short-hand convention for how to tune a resistor-capacitor circuit to shape the signal. Once the boost has been corrected for, however, the output can again be used directly as audio samples.

Eckert then went on to explain that he chose Rust because the dongle provides more than one million samples per second, so he has one microsecond per sample to do any necessary analysis. And the audio card is going to keep playing samples from its ring buffer whether or not new values have been provided — this is a real-time task that demands a language with good, predictable performance. Even a pause of a few milliseconds would cause an audible gap in the output. Working with a simple decoding pipeline like this in Rust has been pleasant, he said.

The last demonstration that he wanted to share was looking at a digital signal, rather than an analog one. Every plane with an automatic dependent surveillance-broadcast transponder, which is most of them, broadcasts telemetry information twice a second. That data is sent at a frequency of 1090 MHz, which requires a small antenna with a good view of the sky. The signal is amplitude-modulated, just like AM radio, but rather than conveying sound, the magnitude is a pattern of digital pulses. Each message starts with a recognizable eight-microsecond preamble, and lasts for a total of 120 µs, encoding 112 bits. Each bit lasts for one microsecond, and is split into two parts, called half-slots. A high-to-low transition is a one, and low-to-high transition is a zero. That way a constant signal, high or low, is not interpreted as actual data.

At the maximum frequency that Eckert's dongle samples, 2.4MHz, each half-slot is 1.2 samples wide, which puts it right on the boundary of signals that he can correctly decode. His code scans over the signal in search of something that matches the preamble, and then samples the two halves of each bit and subtracts them, to eliminate any constant bias in the signal. Then, the resulting bits are parsed into a Rust structure that encapsulates different possible messages. The code sends that structured data to a small web application that plots the received information on a map, showing each aircraft's identity, position, and velocity.

His first implementation of the decoding logic did not work well; it only found about a sixth of the information that is present in the signal, Eckert said. It took a good deal of thought to produce an implementation that was robust to interference and sampling errors. That's one thing that makes this a good hobby, he explained: there are so many things that use the radio spectrum, which means there is always something new to look at. Basic decoding of analog signals is simple enough to get working without much effort, but it's always possible to go more in-depth on better decoding methods, or to look at new types of signals.

So far, Eckert has experimented with receiving AM and FM radio, timing-synchronization signals, and aircraft transponders, but there is much more than that out there. There are weather reports, complete with weather maps, polarization-modulated digital signals, HAM radio, and many more. All one needs to start are a relatively cheap hardware dongle, a working knowledge of complex numbers, and a programming language — Rust in his case.

[ Thanks to the Linux Foundation, LWN's travel sponsor, for assistance with traveling to RustConf. ]


Index entries for this article
ConferenceRustConf/2026


to post comments

So, a subset of GNU Radio in Rust?

Posted Sep 24, 2026 17:02 UTC (Thu) by JoeBuck (subscriber, #2330) [Link] (6 responses)

I would have expected to see at least some mention of GNU Radio, which has been around a long time.

So, a subset of GNU Radio in Rust?

Posted Sep 24, 2026 17:11 UTC (Thu) by NYKevin (subscriber, #129325) [Link] (3 responses)

This is clearly a hobby project. I wish we could be more supportive of people doing hobby work, instead of comparing it against the state of the art. I imagine he wrote it in Rust because he wanted to write it in Rust, and I see nothing wrong with that.

So, a subset of GNU Radio in Rust?

Posted Sep 24, 2026 17:35 UTC (Thu) by ballombe (subscriber, #9523) [Link] (2 responses)

The issue is as always that LWN cover very few projects.

So, a subset of GNU Radio in Rust?

Posted Sep 24, 2026 19:22 UTC (Thu) by ejr (subscriber, #51652) [Link]

I'm sure they'd be interested in article contributions of sufficient quality.

So, a subset of GNU Radio in Rust?

Posted Sep 25, 2026 4:12 UTC (Fri) by interalia (subscriber, #26615) [Link]

I'd say this article was more covering the talk and the hobby detail, rather than the project.

So, a subset of GNU Radio in Rust?

Posted Sep 25, 2026 7:33 UTC (Fri) by taladar (subscriber, #68407) [Link]

Being around for a really long time sounds like a really good reason not to want to work on its codebase if it is like most projects that have been around for a while.

So, a subset of GNU Radio in Rust?

Posted Sep 25, 2026 8:46 UTC (Fri) by egb (subscriber, #163244) [Link]

I think the operative term here is "in Rust;" since this is an article about a talk given at RustConf, I think it's sensible to omit mentioning something related only by domain.

superhet build / analog is fun too on Linux

Posted Sep 26, 2026 14:47 UTC (Sat) by RazeLighter777 (subscriber, #130021) [Link]

I've been building a much less high tech 40M radio reciever (analog superheterodyne, not an SDR) and controlling it with linux via an si5351 over I2C for my BFO and VFO).

I'd be interested in doing an SDR build and messing with Linux's ax.25 support, once I understand fundementals. I've built one crystal, one regenerative reciever, (I failed my direct conversion reciever attempt), now I'm doing superhet with better soldering skills and more careful planning. I'm planning on taking the technician and general ham exams on Oct 12th, so I can start doing transmitter stuff.

One super cool thing Linux can do is the usbtmc driver, which let's me see my oscilliscope in /dev/usbtmc0 and configure it with scripts. I can ask AI agents to run the si5351 and measure the clock and run various diagnostics, very fun. (I see why Linus likes doing analog circuits too with his guitar pedal projects, they feel much more alive and less deterministic than the software world and it's a nice break. Wonder if he's messed with oscilliscopes)

As for doing and SDR in Rust, it sounds cool for it's safety when doing digital signal processing, but I'm starting old-school and doing most of things analog for now. Since SDR feels a bit "cheaty" for me, and building analog recievers is good practice for the exam and soldering, winding toroids, etc is quite relaxing...


Copyright © 2026, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds