After experimenting with converting radio signals to audio frequencies I thought it would be interesting to receive some actual real-world radio signals using this method.
Picking a challenge
To frame the experiments I decided to try and create a general coverage communication receiver capable of receiving radio communications from stuff like radio amateur, aircraft and broadcast.
The construction of these receivers has typically been very complicated with lots of specialized circuitry, expensive filters and high end analog circuitry.
Traditional communication receiver:

I thought it would be interesting to see how much of this could be replicated in the digital domain with minimal hardware. The hardware I build, inspired by the NanoVNA device, is capable of converting a small portion (15kHz) any (‘ish) frequency between DC and about 200MHz to Audio frequencies. This (converted) baseband signal can then in turn be processed by a DSP into useful information like speech or data.
Picking up weak signals
Originally I only considered this frequency converter as a sub-system that had to be supplied with a highly filtered and amplified signal from an antenna. I imagined that some sort of high gain amplifier would be needed to bring the radio frequency signals up to a level that in turn could be processed by the converter. In a conventional radio receiver a device called a LNA (Low Noise Amplifier) brings the signal level from the antenna up to a level that can be further processed. Often the LNA also have the job of adjusting the signal levels depending on the signal received and filtering away unwanted signals.
I spend some time building various LNA’s since I thought these would be the key to building a good receiver.

The amplifiers would have a filter part that restricted their operations to some part of the radio spectrum and a variable gain part that could be controlled with a control voltage. I also experimented with controlling the filter part electrically to cover larger parts of the radio band.
I was able to get pretty good performance out of these LNA’s but they all possessed a high degree of compromise between amplification, noise and bandwidth.
How much signal is actually needed?
I then turned my attention to the converter/DSP part. I decided to use a ESP32 Microcontroller as the DSP since I had previously made some DSP stuff for this controller. I used a PCM1808 A/D converter and a PCM5102 D/A converter.
The A/D-D/A converters are capable of sample rates up to 96KSPS with a resolution of 24bit. When evaluating the performance of the A/D converter it dawned on me that these things have a dynamic range of around 144dB . 144dB is an insane amount of range. If you consider that in terms of amplification it would be 16777216 times! Say the full voltage swing of the A/D input is 5V then the signal that result in the smallest digital change would be:
5V/16777216 = 0.298 Microvolt!
In practice you would need say 6 bits of resolution to make up a usable signal. The remaining 18 bits- or around 54 dB of resolution, would be free to regulate the sensitivity of the digital system. It turns out that this is comparable to the range of a decent communication receiver, for the digital part alone!
Even though that lands the sensitivity around 10microVolt for a 6bit output signal the electronics of the frequency converter part also imparts some analog amplification landing the sensitivity well below 0.1 microvolt.
Doing more with less
In essence: it turns out that a LNA is not needed after all. The antenna can essentially be connected directly to the input of the frequency converter. In practice a simple low pass filter is needed after the antenna to remove mirror sensitivity and other spurious signals.
I ended up with this system:
I now had a system that would receive weak signals from an antenna, convert them into a complex (quadrature) analog signal that was digitized by an A/D converter to be processed by a DSP and eventually sent to speakers via. a D/A converter. The challenge now lay in the DSP software.
Software
The software essentially receives buffers of I/Q data (right and left channel) from the A/D converter. These buffers are run through various algorithms sample by sample depending on the demodulation mode selected. The transmitted sound information is extracted and placed into other buffers that are in turn send to the D/A converter via. an adjustable biquad audio filter. This filter can be used for noise reduction and signal emphasis. The content of the received buffers are also passed to a FFT algorithm for display purposes.
Most communication receivers are capable of receiving the following modulation types:
Each of these comes with their own challenges to decode digitally. I decided to implement them all.
I started with FM. In FM demodulation you are only interested in the frequency of the signal but for the simplest decoding algorithm to work the received signal had to have a constant amplitude. In a real world the amplitude of radio signals constantly changes so I needed to implement automatic gain control- AGC. As mentioned earlier this could be achieved in software by simply detecting the amplitude of the signal and multiplying with an appropriate factor. Since the input is represented as a quadrature signal the amplitude can easily be found.
SSB decoding is more mathematically involved since it requires a special filter (Hilbert transformer) that will phase shift all signals by 90 degrees or in reality two filters each phase shifting 45 degrees in opposite directions. There are a lot of math heavy descriptions out there but I learned about practical Hilbert transform in this article.
AM decoding in simple. It is basically the first part of the FM decoding where the amplitude is found but in stead of using this to change the signal level this amplitude _is_ the information.
For decoding CW signals I am basically abusing the SSB decoder and tuning the radio 800Hz beside the signal. The adjustable output filter is configured as a bandpass filter to enhance the generated tones.
For AM,SSB and CW. the signal gain needed to be controlled manually which required some sort of user interaction. Unlike the traditional receivers with lots of buttons and dials I wanted to keep the hardware as minimalistic as possible so I decided to take advantage of the fact that the ESP32 comes with WiFi. I made this user interface in JavaScript that connects via. websocket to a small server on the ESP32 and runs in a browser:
The user interface provides a simple interaction with the receiver. Two dials on the physical receiver allows for real time tuning of the frequency and audio filter cutoff frequency.
In conclusion
All things being equal I am really impressed over the performance I have managed to get out of this simple circuit. It has shown that it is possible to make a highly customable very wideband and surprisingly sensitive communication receiver out of a few cheap bits from eBay.
I was really surprised that the receiver could be implemented without a LNA. I had expected to spend a significant amount of effort designing high gain LNAs and dealing with external analog control circuitry. This kind of receiver may eventually benefit from some kind of pre-amplifier but this would be able to have discrete amplification levels rather than a continuously variable gain. I have gained a new respect for the sensitivity and resolution of inexpensive contemporary audio electronics.
All software for the receiver is written in Arduino uses straight c/c++ . It uses float point math and no effort has been made to optimize or use fixed point math. As a matter of fact it turns out that on the ESP32 float point math is actually faster since the ESP has a built in float point co-processor.
No external libraries has been used and everything including the Javascript app has been written from the bottom up.
I may polish and release some of it in conjunction with some future post here on the blog where I will go into some more details about the construction of this receiver.
I also ran into a lot of other challenges that I have not covered in this post. With this level of sensitivity power supply noise and crosstalk between components is a real nightmare:

I eventually figured out the critical points that needed extra attention.
Testing DSP algorithms is also a challenge. I used MAX/MSP for rapid prototyping where I was able to implement and test all the algorithms in real time.
All in all a really comprehensive learning exercise that I will share more of in the future.
Examples
Receiving the infamous UVB-76 “The Buzzer”:
Receiving amateur SSB transmission:
Receiving APRS (Packet radio):
Receiving DCF-77 Time signal:
Using the controls:
Algorithms
These are the (simplified) algorithms I use to decode the IQ signals: