Removing that Center Frequency DC Spike in Gnuradio the Easy Way

Recently reader ghostop14 wrote in to us and wanted to share his GNU Radio block and tutorial that shows how to get rid of the DC spike in GNU Radio. The DC spike is the annoying spike in the middle of the spectrum that appears no matter where you tune and shows up with almost all SDRs, such as the HackRF used by ghostop14. Software programs like SDRsharp and HDSDR have algorithms in place to filter and remove the DC spike, but until now there was no block that existed for GNU Radio.

If you’re looking for the quick solution, the CorrectIQ GNU Radio block by ghostop14 is available at But if you want an interesting read on how ghostop14 figured out how to create the block, then he’s done a nice writeup which is available here (pdf). Some excerpts:

It’s your first time with gnuradio and you love your hackrf. You’ve played with receiver software like SDRSharp and audio piping to decode your favorite signal of choice, and now you’re ready to dig deeper and learn more about SDR. Everyone’s talked about gnuradio, so you install it and fire up your first flowgraph. You drop in an osmocom source block and set the device to hackrf, set your sample rate, frequency, and gain then connect it to a frequency sink and hit the button to generate your flowgraph. The ease with which you just built a receiver and the excitement about the possibilities is overwhelming… you can’t wait to hit play.

Then it happens. Right in the middle of your first flowgraph is this huge signal spike that you know is not the signal you want to receive, and as you change the frequency it follows you. What?!? So your first thought is you did something wrong. After all you’re new to gnuradio and you’re sure you’re making a newbie mistake. First you make sure there really isn’t a signal there. You go back to SDRSharp and there’s no spike. Then you swap out your hackrf for your airspy and rtl-sdr dongle, feed that into gnuradio, and there’s still no spike. What’s going on? Why is my favorite SDR that I want to use doing this? What you’ve stumbled on is an artifact of the way SDR radios do IQ sampling. Your first attempts at searching on the problem reveal that it’s called a DC spike and it’s going to appear in the raw IQ data and there’s nothing you can do to stop it. So you go back to your favorite search engine because you can’t be the first person to want to get rid of it and you find that folks say that you have 3 options: 1.) ignore it (yeah not happening. It’s huge and right in the middle of my spectrum!) 2.) Offset tune away from it on your center frequency (which means every flowgraph I make or download I’m going to have to custom change to actually get a clean center frequency signal to make them work. There has to be a better way!), or 3.) filter it out.


I finally had a few hours to look into the problem further and spent the time to search and understand what was happening, and the math behind fixing it. Then researched how others were doing the same thing in their code. Turns out the solution is simple. Since the data represents an alternating RF signal, over time the signal average in a clean signal should be zero (I know I’m oversimplifying it). When there’s the IQ DC spike, that average isn’t zero. So the solution is to calculate a weighted average over ongoing samples and simply subtract it from each future sample. It doesn’t affect the overall quality of the filtered signal, but as long as the spike is on the center frequency, this approach very efficiently gets rid of it. And that was what I was hoping to accomplish.

The CorrectIQ block which gets rid of the DC spike in GNU Radio.
The CorrectIQ block which gets rid of the DC spike in GNU Radio.


  1. Moh Nezami

    The continuous subtraction of the mean of I and Q will remove the DSP accumulated DC offset, but in most cases the real DC problem is the one present at the ADC input which reduces the dynamic range of the ADC and will fool the AGC to lower the front gain. For this reason, the Lime 6x chip had an additional DAC that is fed to the I and Q channel in the baseband section.

    What I did is use the histogram of the I and Q to estimate the real DC static offset present at the ADC input and steer that with a feedback loop to cancel it using those two DACs.

    I have some write ups on that if someone is interested.

    Moh Nezami

  2. hennichodernich

    a) Subtracting the moving average is equivalent to FIR filtering with coefficients 1, -1/N, -1/N, -1/N, …, -1/N where N is the filter order. So writing a dedicated block was not necessary.
    b) This filter obviously has a frequency response which will distort your signal. You need to consider this, in particular for signal components around DC.
    That’s the reason why most practical systems don’t downconvert to 0, but to a small “digital IF”, i.e., tune to a small offset frequency.

Post a comment

You may use the following HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.