FCL, a fast spectrum channelizer

FCL splits wideband spectrum from your SDR into narrowband channels. This is useful for networks that have lots of transmitters side-by-side, like for example FM broadcast, TETRA, Tetrapol and GSM.

It supports everything you would expect from a decent channelizer:

  • Channelization 8-)
  • Oversampling and overlapping channels.
  • On-the-fly frequency correction and signal power detection.
  • Multiple input formats (float, unsigned and signed integer).
  • Multithreading.

We use a straightforward implementation that is cache- and vector-friendly and we have a sane pthreads scheduler. At least on our computers, FCL is 2 to 5 times faster than the GnuRadio implementation. Hence fcl stands for Fastest Channelizer in Litoměřice.

You can find description of the mathematical principles of the channelizer in Chapter 2 of my thesis.

The following chart compares FCL with GnuRadio 3.7.10. FCL was tuned using the hints below on this page, GnuRadio was profiled using volk_profile. Frequency correction in FCL was disabled.

Practical results: Raspberry Pi 3 + rtl-sdr is able to receive 13 Tetra or Tetrapol channels in real time. As it maxes the usage of CPU and memory, proper cooling is necessary!




On Raspberry Pi, adding “-march=native -mthumb-interwork -mfloat-abi=hard -mfpu=neon -mtune=native” to CFLAGS makes things even faster. Make sure you have correct GCC and core libraries!
It builds .so modules for FIR of lengths 8-24 (where compiler can unroll loops) and one generic. These are loaded dynamically runtime.


mkfifo /tmp/myout.ch

rtl_sdr -f 90e6 -s 2e6 -g 49 -p 44 - | ./fcl -n 20 -s 13 -f "./fir.py 2e6 55e3 11e3" -c 3,8 -i U8 -o /tmp/myout.ch

i.e. read data as uint8_t, channelize to 20 channels with 20/13 oversample, select channels 3 and 8 (they are interleaved in the output stream, use the GnuRadio Deinterleave block to get them), output to /tmp/myout.ch

The tool listens on localhost:3333 (can be changed with -b and -p) and supports these commands:

  • setrot - set frequency correction in milliradians per sample
  • getrot - print current frequency correction
  • setchannels - set channels you want to output, format same as with -c option, e.g. “1,8,17”
  • getpwr - print relative power of your channels. You can use this to e.g. detect BTSs
    • getpwn N - increase number of FFT bins N-times (i.e. get much more detailed view of the spectrum); 1 ⇐ N ⇐ 32
  • gethisto - print histogram (evenly spaced at [0, 1] absolute values of input floats) of samples

There is a convenient wrapper around gnuradio firdes called fir.py.

usage: ./fir.py samplerate passband transition [rcos]
passband/samplerate ... how much of spectrum to pass
transition          ... either transition width in Hz (for non-rcos filter), lower value means higher signal quality and higher computational complexity, or filter length in taps for rcos filter
rcos                ... use root raised cosine filter instead of Hamming window.

There is and example of how to use FCL to receive TETRA in examples/tetra.py. Other examples may follow as we port other brmlab tools to FCL.

Performance hints

  • The most expensive part is evaluating FIR filters. Computational demands scale almost linearly with filter length. So try to design your filters as short as possible.
  • On fast computers with many cores, you can try increasing BUFSIZE and RETURNWORK in finetune.h. You can gain ~10 %.


  • write unit tests
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Noncommercial-Share Alike 4.0 International
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki