It seems quite common to use np.diff() for removing DC components of signals when plotting spectrograms.

I noticed some unexpected behaviour during analyis which indicated that a numeric derivative may amplify higher frequencies and I've been trying to check myself since.

So, I decided to treat the derivative as an FIR filter where b = [1, -1] and plot the frequency response to confirm my suspicions. Please excuse the plot, it's a work in progress.

This post seems to express the same problem, though OP is hardly surprised.

If some journeymen may weigh-in here and confirm/disprove my assumption. I would use a notch filter centered at DC as an alternative, but any advice is welcome.

enter image description here

  • $\begingroup$ Actually that doesn't seem common to me at all. np.diff() is commonly used to approximate a first order differentiator. The DC blocking is simply a side effect (the derivative of a DC signal is indeed zero). However DC blocking is normally done with real high pass filters that has a cutoff frequency below the frequency range of interest or simply by subtracting out the mean. $\endgroup$
    – Hilmar
    Aug 24, 2023 at 8:15
  • $\begingroup$ @Hilmar Thank you, I think this is a subtle error that has become commonplace. $\endgroup$ Aug 29, 2023 at 9:44

1 Answer 1


You're correct, the first order difference in the time domain (np.diff) is equivalent to a first order high-pass filter with coefficients $h[0] = 1, h[1] = -1$ in the frequency domain. This filter then effectively removes the DC component, which is the component with frequency 0, i.e the signal's average value.

However, as you have rightly showed in your plot of the magnitude response, this filter isn't particularly satisfactory if one is interested in removing the DC component only: it attains unity gain only at about 1/3rd of Nyquist, and amplifies everything above that.

Common, better ways to remove DC before spectral analysis include:

  • Removing the mean: x = x - mean(x)
  • Use detrending functions: x = detrend(x)
  • Use DC blocking filters

More detail

To see why the first order difference is indeed a high-pass filter , consider the time-domain equation: $$y[n] = x[n] - x[n-1]$$ In the frequency domain, the transfer function is: $$H(z) = 1-z^{-1}$$ and the frequency response at $z = e^{j\omega}$: $$H(\omega) = 1-e^{-j\omega}$$ From this, the magnitude response: $$|H(\omega)| = |1-e^{-j\omega}| = |1-\cos(\omega) + j\sin(\omega)| = \sqrt{(1-\cos(\omega))^2 +\sin^2(\omega)} = \sqrt{2 - 2\cos(\omega)}$$

This is a high-pass filter:

  • At $\omega = 0$, $|H(\omega)| = 0$
  • At $\omega = \pi$, $|H(\omega)| = \sqrt{2}$
  • Unity gain is achieved at $\sqrt{2 - 2\cos(\omega)} = 1 \leftrightarrow \omega = \pi/3$
  • $\begingroup$ Another way to write this $H(\omega) = -j\cdot \sin(\omega)\cdot e^{-j\omega/2}$, which shows that for low frequency this behaves like an analog differentiator ($-j\omega$) cascaded with a half sample delay. $\endgroup$
    – Hilmar
    Aug 24, 2023 at 8:11
  • $\begingroup$ @Jdip Thanks so much for your input. That puts my self-doubt at ease. $\endgroup$ Aug 29, 2023 at 9:43

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.