[Ground-station] channelized FM SDR

Phil Karn karn at ka9q.net
Sun Oct 25 17:02:25 PDT 2020


This may be of interest to those working on multi-channel voice
bandwidth satellite uplinks.

I've been working on my own multichannel SDR for some time. I've got it
demodulating all 216 FM channels in the TASMA 2m (soCal spectrum
coordinator) bandplan and multicasting the demodulated PCM and Opus
compressed audio on my home LAN.

The front end hardware is an Airspy R2 providing 20 Ms/s. The samples
are real, so it covers a 10 MHz bandwidth minus some for anti-alias
filtering. The R2 is connected to a Pi4 that multicasts the raw samples
on my home Ethernet at 250 Mb/s, where they're picked up by an 8-core
3.4 GHz i7 running Linux and the bulk of the SDR code.

I can plug the R2 directly into the i7 but I wanted to stress-test the
network and see what the Pi can do. Unless something major happens, I'll
see *no* sample drops between the Pi4 and the SDR program on the i7. I
tried connecting a second Airspy R2 on the same Pi4, but it only has a
single USB 2.0 bus and that was asking too much.

My SDR makes extensive use of the overlap-save method of fast
convolution for filtering. One of the really neat properties of
overlap-save is that you can have an arbitrary number of independent
filters all sharing a single forward FFT. The incoming sample stream is
converted to the frequency domain, and then each demodulator thread
picks just the frequency domain bins it wants. (The usable bin size is
controlled by the FFT block rate, which is currently 100 Hz.) The
forward FFT is shared by all demodulator threads. Each demodulator needs
its own inverse FFT to convert back to the time domain, but they run at
a much lower sample rate (48 kHz at present). The output sample rate is
controlled by the number of FFT bins chosen, so you can easily decimate
to any multiple of the block rate, i.e., any output sample rate that's a
multiple of 100 Hz.

The SDR is highly threaded so it takes good advantage of multi-core
CPUs. One thread runs the 400 k point forward FFT (10 ms block rate (100
frames/sec) with a 2:1 overlap for the fast convolutions. This takes
about 38% of one CPU core, shared by all demodulators.

Each channel demodulator runs in a separate thread and is completely
independent of the others. They downsample (to 48 kHz), apply the
desired filtering (currently 16 kHz, but easily changed) and demodulates
to baseband. I'm using the FM demodulator for 2m, but I also have a
'linear' demodulator for all the other modes (SSB, CW, IQ, envelope AM,
synchronous AM, etc). Fine tuning is done for RF frequencies not
multiples of 100 Hz, but that's more important for the linear modes than FM.

My FM demodulator has an experimental "threshold extension" scheme that
looks at the magnitude of each pre-demod sample and attenuates the
demodulator output when the magnitude is below some fraction of the
average amplitude. I haven't quantified it yet but it very audibly
attenuates the "popcorn" noise you get in a FM signal at threshold. My
squelch works from first principles: measure the mean and variance of
the signal amplitude, convert to SNR, and open the squelch if it's above
a threshold (currently 6 dB). It works so well I haven't felt the need
for a squelch knob.

While the NBFM demodulator needs the 48 kHz sample rate, I *could* use a
lower sample rate (e.g., 16 kHz or even 8 kHz) for the narrowband modes.
But I currently run the linear demodulator at 48 kHz since that's what
the Opus codec prefers, and it doesn't seem to cost much anyway. (The
compressed Opus bit rate only depends on the quality setting, not the
input sample rate).

Each FM demodulator thread uses about 0.7% - 1.0% of a CPU core, which
is too small to get an accurate reading. When demodulating 216 channels
everything uses about 133% CPU, i.e. 1.33 cores (of 8) on average. Opus
compression actually requires considerably more CPU horsepower than FM
demodulation, and I've discovered I need to thread it more. (Normal
activity on the 2m band isn't a problem; I discovered the Opus limit
only when I introduced a bug in my FM SNR routine that opened most of
the 216 squelches at once.)

I also have a 1200 bps AFSK AX.25 packet demodulator running on every
channel, reporting whatever it hears to the APRS network. This doesn't
take much CPU since it runs only when a squelch is open. The packet
demodulator is a separate Linux program, reading the demodulated PCM
audio from the SDR and multicasting its decoded frames back onto the
LAN, where they're picked up by yet another program that reports them to
the APRS network.

My thinking for some time is that a satellite transponder designed to
regenerate narrowband voice should have a multichannel receiver much
like mine feeding the received digital audio streams into a single
multiplexed downlink. In effect, I now have exactly this on my home
network. To listen, I fire up an audio monitor program on my laptop that
joins the IP multicast groups carrying the Opus-compressed audio and
each active 2m channel pops up on my local display. I can pan each
signal in the stereo image, adjust its gain, mute certain channels, etc.
Joining the multicast group is handled by the network subsystem
(including my smart Ethernet switch). The SDR itself just shovels out
the bits and it doesn't care or even know how many users are listening.

In a satellite, these multicast streams would come down multiplexed onto
a single high speed downlink like the DVB-S2 subsystem you're designing.
At the moment, my receiver only handles analog FM, compressing each
audio channel with Opus. But it provides the framework for narrowband
digital modes, or a hybrid analog/digital system. Each digital
demodulator can run as an independent Linux process, reading the
multicast output of a channel from my SDR, demodulating the signal and
multicasting its own bit stream back onto the network. I'm looking at
porting the MMDVM code to my system so it will work with multicast PCM
audio in and out.

In a satellite I envision a mixture of Opus-encoded analog FM streams
and demodulated digital uplink streams, with an eventual transition to
digital only.

Anyway, this is all a proof of concept I think you might find
interesting. The main programs are currently 'airspy', 'radio', 'opus',
'packet' and 'aprs'. Each runs as a Linux daemon, automatically started
at boot time. The 'radio' program reads a single configuration file
telling it the frequencies and modes on which to listen and where to
multicast the demodulated outputs (one IP multicast group can handle
multiple streams).

So this thing can operate totally turnkey with NO user interface except
for the config file. It just demodulates each stream and multicasts the
results for anybody on the LAN who wants to listen. I've been running an
earlier version as a turnkey APRS receive-only iGate for several years
on a Raspberry Pi 3 and an AMSAT UK Funcube Pro+ dongle (its 192 kHz
sample rate is easily handled by a Pi2 or 3).

There is an optional control/status interface to each demodulator that
uses my own UDP-based protocol for which I've written a control client.
You can enable/disable this on a per-demodulator basis in the config
file. I typically start the regular demodulators without a control
channel, then add one I can use to look around manually if I want.

I'm ready to put this code out for general play. It's still pretty rough
but I think it's a good proof of concept.

Phil







More information about the Ground-Station mailing list