[Ground-station] Operation PFB

Phil Karn karn at ka9q.net
Tue Jan 15 04:31:37 EST 2019

On 11/20/18 08:56, Michelle Thompson via Ground-Station wrote:

> This filter bank is in the payload. We call it a channelizer. The
> receive bandwidth is organized into channels by this filter bank. >From
> there, the communications are multiplexed into the time division
> downlink DVB frames. 

I am very actively working on this, and of course my code will be open
source. It's a module in my SDR package.

I use fast convolution throughout my package for filtering and
correlation. The channelizer I'm working on extends this mechanism.

There are two main forms of fast convolution; I use the technique called
"overlap and scrap". If the data blocksize is 'L' and the length of your
filter impulse response is 'M' samples, then you use a FFT length N = L
+ M - 1. Each FFT operates on L new I/Q samples and M-1 I/Q samples from
the previous block. Then you multiply the transform by the transform of
your desired filter's impulse response, perform the inverse FFT, and
take only the last L samples from the output. Overlapping and scrapping
is necessary because the FFT performs circular convolution and we want
linear convolution when doing filtering. This method keeps the tail of
the convolved result from "wrapping around" and messing up the start of
the block.

I also decimate with this method. To downsample from 192 kHz to 48 kHz,
I simply use an IFFT of length N/4 that uses only the first N/4
frequency bins from the forward FFT. I still have to multiply by the
filter response in the frequency domain, and I have ensure that the
impulse response spectrum is essentially zero through all the high
frequency bins I'm ignoring or I will get unwanted aliasing. I use a
Kaiser window with a fairly large beta factor to give low sidelobes at
the expense of a wide main lobe. But since I'm only using a fraction of
the 48 kHz bandwidth for communications-quality audio, this is not a

Now here's the really fun part. Not only will the shorter IFFT execute
faster than the bigger forward FFT, BUT MANY INVERSE FFTs CAN SHARE ONE
FORWARD FFT. This is key to making an efficient channelizer.

With the right values of L and M, you can turn this into a versatile
channelizer by simply selecting different frequency bins from the
forward transform for each inverse transform. Each bin will be
Input_Samprate/N Hz wide, but your frequency shift must also be an
integral number of cycles within L samples (as well as N). So by making
L = M, you can shift by any even number of bins.

I typically make L = M = 20 milliseconds at whatever sample rate I'm
using (usually some multiple of 48 kHz). At 12.288 MHz, that's a forward
FFT of N=491,520 samples. 20 milliseconds is 50 Hz, so I can shift by
any multiple of 2*50 = 100 Hz. Each channel can be independently
centered on any multiple of 100 Hz with an arbitrary bandwidth in
increments of 100 Hz (with allowance for broadening from windowing.)

I can certainly switch to a smaller FFT with a correspondingly higher
channel roster, but this FFT is fast enough on my CPU so I haven't tried
that yet.

This ability to place channels on fractions of their bandwidths will
come in handy when I channelize the entire 2m band and demodulate every
FM signal at the same time. 2m has a convoluted band plan with 20 kHz
channels below 146 MHz, 15 kHz above, and many oddball local variations.

I don't know if a conventional polyphase filter bank can handle an
irregular bandplan, but I know I can.

My HackRF is now sampling at 12.288 MHz (256x 48 kHz) and generating a
200 Mb/s I/Q multicast stream on my home network. Amazingly, with a
little tuning my switches and hosts handle this sustained data rate
without loss.

The program that handles the HackRF USB stream and generates the
multicast RTP stream performs analog AGC, DC removal and I/Q gain and
phase balance. It's running on an old 4-core 1.66 GHz Atom CPU, with two
main threads consuming 63% and 23% of a core.

I'm processing this stream on a 4-core (8 with hyperthreading) 2.4 GHz
Xeon that's probably 10 years old now. The thread that processes the I/Q
multicast stream and does the forward FFT uses 68% of one CPU and 27% of
another. (I'm using FFTW3 with two threads, and I've run fftwf-wisdom on
my transform sizes. 491,520 has no factors greater than 5, so it's
fast.) The rest of the receiver runs at 48 kHz, so naturally those
threads take up much less CPU (2-3% to demodulate FM by brute force with
arctangent, plus a squelch driven by a SNR estimator, and other overhead

My goal in all this is to build a proof of concept for how I think a
modern digital amateur radio satellite should work. It should have a
single high speed downlink (for which DVB-S2 with LDPC is ideal)
relaying a multiplexed stream of uplink digital voice and data from a
bank of analog FM and low speed digital receivers. Each analog FM
channel is demodulated and encoded with Opus, which sounds pretty good
on voice at its lowest rate of 6 kb/s. Digital uplinks would be simply
turned around and retransmitted as-is; presumably these would also be
Opus-compressed digital voice but they could also be non-voice data streams.

73, Phil

More information about the Ground-Station mailing list