I am using the Quadrature Demod module in GNU Radio to decode an FSK signal, but the signal is appearing quite noisy. It has two distinct peaks centered around the advertised frequency, but they are close together and only a little above the DC spike at the center.

In my first attempt, I set the baseband frequency of my HackRF SDR to the exact center frequency of transmission with a sample rate of $2\textrm{ MHz}$. I then applied a $30\textrm{ kHz}$ low-pass filter to the signal before doing the quadrature demod on the signal. What I got out was a near quiet signal during idle periods and something resembling digital data during the transmission, but a bit on the noisy side. It was easy to set a trigger and separate out individual packets, but hard to identify the bits. A screen shot of the start of a packet is here:

FSK Decode centered on signal

So I decided to try capturing offset from the center frequency by about $900\textrm{ kHz}$ and multiply the data by a corresponding complex signal to shift it back down to baseband. The signal now is well above the noise floor during transmission, however, my quadrature demod is capturing large amounts of noise during the idle periods. If I stop the capture at just the right moment, I can see what looks like a very clean data signal, but considerably weaker amplitude than the surrounding noise.

FSK captured at an offset

How do I get the best of both worlds so I can cleanly detect packets and decode the bits with GNU Radio?

My flow graph from the last test:

FSK Demod Flowgraph

  • $\begingroup$ Could you maybe add a picture of your flow graph, too? $\endgroup$ Jan 26, 2017 at 9:32
  • $\begingroup$ by the way, if you use the QT GUI sinks, you can use your middle mouse button to produce a menu which has a very comfortable "save figure" item, so you can store the plots :) $\endgroup$ Jan 26, 2017 at 9:33
  • $\begingroup$ @MarcusMüller OK, I've added a screenshot of my flowgraph. I'll take a look at QT for my next project and see how it compares. $\endgroup$
    – penguin359
    Jan 26, 2017 at 9:41
  • $\begingroup$ I'd heartily encourage you; GNU Radio is dropping the WX GUI sinks on the next branch of development (which is planned to become release 3.8). We simply have no-one to maintain the WX GUI sinks, and they are slower. $\endgroup$ Jan 26, 2017 at 9:43
  • $\begingroup$ Hm, so the difference between your hi and lo FSK frequencies is 1.8 MHz, or is it 0.9 MHz? $\endgroup$ Jan 26, 2017 at 9:45

1 Answer 1


That looks very nice:

good demod

I don't 100% agree with your phrasing on this one:

however, my quadrature demod is capturing large amounts of noise during the idle periods.

Well, the quadrature demod takes successive samples and gives you the phase advance between them. If you only capture silence, or more precisely, the noise between packets, the phase of each sample should (in theory, at least) be absolutely uniformly random – and hence, your phase increases, too, should be random. Remember: the amplitude of an FM-demodulated (analog or digital) signal is not proportional to the original signal's power at the receiver (that's the beauty of FM).

There's different ways to tackle this; a simple one is in the "Power Squelch" blocks in GNU Radio (which really do what their name suggests – make sure the signal is suppressed as long as its samples are below a certain |·|² threshold). You could add one before your quadrature demod.

Another method: The mean of your "demodulated noise" should be 0 – so if you low-pass filter your demodulated signal so that you can still make out the symbols, but the phase-noise induced "jumping" gets averaged to a 0, you could just have a decider afterwards that says "ok, this is a 1 or a -1 in a packet, or this is a 0 belonging to inter-packet time".


  • Instead of multiplying with a complex cosine, you can use the "Rotator" block; should be a bit faster (not that it matters at these rates at all).
  • Even more comfortably: You can simply replace your low-pass filter, multiplier and cosine by a single "Frequency Xlating FIR". Use the "Low Pass Filter Taps" block to calculate the taps for the filter you want, and use the id of that block in the xlating FIR's "taps" field.
  • As noted in the comments: I recommend new designs use Qt instead of WX GUI, because WX is no longer maintained and will go away in future releases (i.e. GNU Radio 3.8)
  • The hard part might be recovering the timing of the symbols – Look at the synchronizers GNU Radio offers. Classically, many designs used Müller&Muller, but to be honest, that is an algorithm designed for implementation in hardware, not software. It's a bit involved to parameterize that, the "PFB clock sync" should behave better (it does, in fact, work similarly to M&M, but is quite a bit more accurate in approximating the derivative of the signal)
  • A quadrature demod is not the only thing that can decode an FSK: try filters that select each FSK frequency, followed by a complex to mag square each, and a "max" block. If you're clever about designing your filters (ie. don't overspecify things), this is, on PC-style hardware, not necessarily harder on the CPU than the $\arctan$ that quadrature demod has to do.
  • $\begingroup$ Müller&Muller: any relation Marcus? :) $\endgroup$ Mar 27, 2017 at 23:22
  • $\begingroup$ Nope :) That would've been funny, though :) $\endgroup$ Mar 28, 2017 at 7:15
  • $\begingroup$ @MarcusMüller where can I find a reference for how to implement your final suggestion for selecting the FSK frequencies -> complex2mag -> max block? Sounds like an interesting way to demod binary FSK that I haven't seen yet. $\endgroup$
    – Yuval Adam
    Jan 15, 2018 at 9:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.