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$
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$