Open
Description
Bug summary
If my understanding is correct:
NFFT
ofmlab._spectral_helper
corresponds tonperseg
of spectral funtions ofscipy.signal
.
It's the actual length of signal (segment) for DFT.pad_to
ofmlab._spectral_helper
corresponds tonfft
of spectral funtions ofscipy.signal
.
It's the length of DFT, i.e. parametern
offft
funtion.
matplotlib/lib/matplotlib/mlab.py
Line 385 in 3418bad
But the implementation of Matplotlib is really confusion:
-
If length of signal is less than NFFT, signal will pad to length of NFFT.
matplotlib/lib/matplotlib/mlab.py
Lines 342 to 351 in 3418bad
And the window is determined by NFFT instead of actual length of signal. This would cause wrong window correction.
matplotlib/lib/matplotlib/mlab.py
Lines 376 to 380 in 3418bad
-
The Nyquist frequency is
NFFT/2
instead ofpad_to/2
.
matplotlib/lib/matplotlib/mlab.py
Lines 411 to 416 in 3418bad
Code for reproduction
import numpy as np
from matplotlib import mlab
fs = 1000
t = np.arange(0, 1, 1/fs)
rng = np.random.default_rng(42)
s = np.sin(2 * np.pi * 100 * t) + 0.5 * rng.normal(size=t.shape)
nfft = 2048
nsignal = len(s) #1000
psd, freqs = mlab.psd(s, NFFT=nfft, Fs=fs, window=mlab.window_none)
mag = np.abs(np.fft.rfft(s, n=nfft))
psd1 = (mag)**2/nsignal/fs
if not nfft % 2:
psd1[1:-1] *= 2
else:
psd1[1:] *= 2
relative_error = np.abs( 2 * (psd-psd1)/(psd + psd1) )
print(relative_error.max())
Actual outcome
0.6876640419947717
Expected outcome
0