我在工作中又遇到了这个问题。似乎很多软件例程/书籍在FFT的规范化上有些松散。
我的最佳总结是:能量需要被保留——这就是Parseval定理。而且在Python编码时,你很容易失去一个元素而不知道它。请注意,numpy.arrays索引不包括最后一个元素。
a = [1,2,3,4,5,6]
a[1:-1] = [2,3,4,5]
a[-1] = 6
以下是我用于正确标准化FFT的代码:
import numpy as np
import matplotlib.pyplot as plt
import scipy.signal
sample_rate = 500.0e6
time_step = 1/sample_rate
carrier_freq = 100.0e6
num_samples = 2**18
t_stop = num_samples*time_step
t = np.arange(0, t_stop, time_step)
carrier_I = np.sin(2*np.pi*carrier_freq*t)
nfft = num_samples
f,Pxx_den = scipy.signal.welch(carrier_I, fs = 1/time_step,\
window = np.ones(nfft),\
nperseg = nfft,\
scaling='density')
integration_time = nfft*time_step
power_time_domain = sum((np.abs(carrier_I)**2)*time_step)/integration_time
print 'power time domain = %f' % power_time_domain
signal = carrier_I
xdft = scipy.fftpack.fft(signal, nfft)/nfft
power_freq_domain = sum(np.abs(xdft)**2)
print 'power frequency domain = %f' % power_freq_domain
plt.figure(0)
plt.subplot(2,1,1)
plt.plot(np.abs(xdft))
plt.title('magnitude')
plt.subplot(2,1,2)
plt.plot(np.angle(xdft))
plt.title('phase')
plt.show()
xdft_short = xdft[0:nfft/2+1]
Pxx = (np.abs(xdft_short))**2
Pxx_density = Pxx / (sample_rate/nfft)
Pxx_density[1:-1] = 2*Pxx_density[1:-1]
Pxx_density_dB = 10*np.log10(Pxx_density)
freq = np.linspace(0,sample_rate/2,nfft/2+1)
plt.figure(1)
plt.plot(freq,Pxx_density_dB,'^')
plt.figure(1)
plt.plot(f, 10.0*np.log10(Pxx_den))
plt.xlabel('Freq (Hz)'),plt.ylabel('dBm/Hz'),
plt.ylim([-200, 0])
plt.show()