What does nfft
parameter mean in this function? Please refer to this link for the documentation https://docs.scipy.org/doc/scipy-0.19.0/reference/generated/scipy.signal.spectrogram.html
1 Answers
scipy.signal.spectrogram
works by splitting the signal into (partially overlapping) segments of time, and then computing the power spectrum from the Fast Fourier Transform (FFT) of each segment. The length of these segments can be controlled using the nperseg
argument, which lets you adjust the trade-off between resolution in the frequency and time domains that arises due to the uncertainty principle. Making nperseg
larger gives you more resolution in the frequency domain at the cost of less resolution in the time domain.
In addition to varying the number of samples that go into each segment, it's also sometimes desirable to apply zero-padding to each segment before taking its FFT. This is what the nfft
argument is for:
nfft : int, optional
Length of the FFT used, if a zero padded FFT is desired. If None, the FFT length is nperseg. Defaults to None.
By default, nfft == nperseg
, meaning that no zero-padding will be used.
Why would you want to apply zero-padding?
- One reason is that this makes the FFT result longer, meaning that you end up with more frequency bins and a spectrogram that looks "smoother" over the frequency dimension. However, note that this doesn't actually give you any more resolution in the frequency domain - it's basically an efficient way of doing sinc interpolation on the FFT result (see here for a more detailed explanation).
- From a performance perspective it might make sense to pad the segments so that their length is a power of 2, since radix-2 FFTs can be significantly faster than more general methods.
-
Oh so you mean you only put value for nfft if you need zero padding? I actually thought that nperseg is the number of time localised points and nfft is the number of frequency used. Hmm Say you want to make number_of_time_localised_points = 3 and number_of_frequency_used = 56, how do you do it with this function. The time window is 500 samples and sampling frequency is 50 Hz (just to give you an example) – Chaine May 30 '17 at 20:57
-
So you mean nperseg is the only parameter used for adjusting both the temporal and frequency resolutions? (basically, given we dont have nfft) Does it have a formula so that we can get the exact values of number of time localised points and number of frequency considered? – Chaine May 30 '17 at 20:58
-
6The relationship between `nperseg` and the number of time bins (i.e. columns) in the output array also depends on the degree of overlap between the segments. By default, `noverlap = nperseg // 8`, so for an input of length `n` you will get `n // (nperseg - (nperseg // 8))` time bins. The number of frequency bins will be equal to the length of the real-valued DFT of each zero-padded segment (the same size as the result of `np.fft.rfft(zero_padded_segment)`), which is equal to `nfft // 2 + 1`. – ali_m May 30 '17 at 21:24
-
Thank you! Very helpful! I have another question. How do you control the range of frequencies and not just the number of frequency bins? – Chaine May 31 '17 at 21:22
-
2The range of frequencies in the FFT of the signal is always going to be bounded between zero and the [Nyquist frequency](https://en.wikipedia.org/wiki/Nyquist_frequency), which is equal to half your sample rate. If you want to increase the maximum frequency in the spectrogram then you need to increase your sample rate. If you're only interested in a band of frequencies then you can clip off the parts of the spectrogram you don't care about, but you can't compute it *only* for a given range of frequencies because FFTs calculate all of the frequency bins simultaneously. – ali_m May 31 '17 at 22:13
-
Wow awesome! May I know if you took your phD? :) – Chaine May 31 '17 at 22:15
-
Anyway I have another question before I mark your answer, I don't exactly get how the padding works. nfft says length of fft. So if it is greater than nperseg the fft is computed for each segment but is slightly bigger than nperseg in size? – Chaine May 31 '17 at 22:28
-
1Yes, if `nfft` is not `None` then it must be >= `nperseg`, and `nfft - nperseg` is the length of zero padding applied to each segment before taking the FFT. If you have follow-up questions then please post them separately - the comments here are getting a bit out of hand. – ali_m May 31 '17 at 22:34