fft – Windows, STFT, magnitude oh my

I’m trying to recover amplitude/magnitude from an audio stream. I’m using FFT to go from time domain to frequency.

If I feed in a signal of known amplitude, the results I get from either windowing or using scipy.signal.stft are lower than what is being fed in.

I wonder if this is inherent to using a window, or if I’m just missing something.

sr = 44100
t = np.arange(sr) / float(sr)
sig = np.sin(2 * np.pi * 200 * t) #amp = 1, frequency = 200hz

A = np.fft.rfft(sig[:2048])
A = np.abs(A * 2/2048.0)
np.max(A)
#0.8720133060255314

(zf, zt, B) = signal.stft(sig[:2048], fs=sr, nperseg=2048)
B = np.abs(B)
np.max(B)
#0.4738186881461125

What I’d really like is to be able to combine the windowed results in B to get something close to the amplitude of the data, but a linear scale average does not seem to help. I’m not sure if its inherent or if I’m missing a scaling factor.

I did notice if I window the rfft I get pretty close to the results of stft, e.g.

win = np.hanning(2048)
A = np.fft.rfft(sig[:2048] * win)
np.max(np.abs(A * 1/win.sum()))
#0.4738443584361969

If I use a frequency picked to be the centre of an FFT bin (150.73), np.max(A) ~= 1.0 and np.max(B) ~= 0.5.

scipy.signal.check_NOLA is True for my parameters, and I can recover the original signal from complex B with istft.

I would appreciate any advice or guidance, thanks.

Read more here: Source link