Python Can';使用scipy.signal.welch无法找到正确的能量
对于给定的离散时间信号Python Can';使用scipy.signal.welch无法找到正确的能量,python,numpy,signal-processing,fft,discrete-mathematics,Python,Numpy,Signal Processing,Fft,Discrete Mathematics,对于给定的离散时间信号x(t),间隔dt(等于1/fs,fs为采样率),能量为: E[x(t)] = sum(abs(x)**2.0)/fs 然后我做一个x(t)的DFT: 再次计算能量: E[x_tf] = sum( abs( x_tf ) ** 2.0 ) * fs * 2 * np.pi / N (这里的系数fs*2*np.pi/N=脉动间隔dk,fftfreq的文档提供了关于频域间隔的更多细节),我具有相同的能量: E[x(t)] = E[x_tf] 但是。。。当我使用scipy.
x(t)
,间隔dt
(等于1/fs
,fs
为采样率),能量为:
E[x(t)] = sum(abs(x)**2.0)/fs
然后我做一个x(t)
的DFT:
再次计算能量:
E[x_tf] = sum( abs( x_tf ) ** 2.0 ) * fs * 2 * np.pi / N
(这里的系数fs*2*np.pi/N
=脉动间隔dk
,fftfreq
的文档提供了关于频域间隔的更多细节),我具有相同的能量:
E[x(t)] = E[x_tf]
但是。。。当我使用scipy.signal.welch
计算x(t)
的功率谱密度时,我找不到正确的能量scipy.signal.welch
返回频率f
和能量Pxx
(或每个频率的能量,取决于我们在scipy.signal.welch
的参数中输入的scaling
)
如何使用Pxx
找到与E[x(t)]
或E[x_tf]
相同的能量?我试图计算:
E_psd = sum(Pxx_den) / nperseg
其中,nperseg
是韦尔奇算法每段的长度,fs
和np.sqrt(2*np.pi)
等因子被抵消,并用nperseg
重新缩放E[x(t)],但没有任何成功(数量级小于E[x(t)]
)
我使用以下代码生成信号:
#Generate a test signal, a 2 Vrms sine wave at 1234 Hz, corrupted by 0.001 V**2/Hz of white noise sampled at 10 kHz.
fs = 10e3 #sampling rate, dt = 1/fs
N = 1e5
amp = 2*np.sqrt(2)
freq = 1234.0
noise_power = 0.001 * fs / 2
time = np.arange(N) / fs
x = amp*np.sin(2*np.pi*freq*time)
x += np.random.normal(scale=np.sqrt(noise_power), size=time.shape)
为了得到功率谱密度,我做了以下工作:
f, Pxx_den = signal.welch(x, fs )
解决这一明显差异的办法在于认真理解和应用
- 连续与离散傅里叶变换,以及
- 给定信号的能量、功率和功率谱密度
dt
等于相邻样本之间的时间间隔。回答您的问题的关键要求您认识到DTFT不等于相应的傅里叶变换!事实上,这两者是相互关联的
X{dt}(f)=(1/dt)*X(f)
此外,离散傅里叶变换(DFT)只是DTFT的离散样本。当然,DFT是Python在使用np.fft.fft(…)
时返回的。因此,计算出的DFT不等于傅里叶变换
功率谱密度
scipy.signal.welch(…,scaling='density',…)
返回离散信号x[n]的估计值。对PSD的全面讨论有点超出了本文的范围,但是对于简单的周期信号(例如在您的示例中),PSD S_{xx}(f)给出如下
S{xx}=|X(f)^2/T
式中,| X(f)|是信号的傅里叶变换,T是信号的总持续时间(时间)(如果你的信号X(T)是一个随机过程,我们必须对系统的许多实现进行集合平均…)。信号中的总功率只是系统频带上S_{xx}的积分。使用上面的代码,我们可以编写
import scipy.signal
# Estimate PSD `S_xx_welch` at discrete frequencies `f_welch`
f_welch, S_xx_welch = scipy.signal.welch(x, fs=fs)
# Integrate PSD over spectral bandwidth
# to obtain signal power `P_welch`
df_welch = f_welch[1] - f_welch[0]
P_welch = np.sum(S_xx_welch) * df_welch
要联系您的np.fft.fft(…)
计算(返回DFT),我们必须使用上一节中的信息,即
X[k]=X_{dt}(f_k)=(1/dt)*X(f_k)
因此,要从FFT计算中计算功率谱密度(或总功率),我们需要认识到
S{xx}=|X[k]^2*(dt^2)/T
p_welch
和p_fft
的值应该非常接近,并且接近信号中的预期功率,可以计算为
# Power in sinusoidal signal is simply squared RMS, and
# the RMS of a sinusoid is the amplitude divided by sqrt(2).
# Thus, the sinusoidal contribution to expected power is
P_exp = (amp / np.sqrt(2)) ** 2
# For white noise, as is considered in this example,
# the noise is simply the noise PSD (a constant)
# times the system bandwidth. This was already
# computed in the problem statement and is given
# as `noise_power`. Simply add to `P_exp` to get
# total expected signal power.
P_exp += noise_power
注意:p_welch
和p_fft
将不完全相等,甚至在数值精度范围内也可能不相等。这是由于功率谱密度估计存在随机误差。为了减少此类错误,Welch的方法将信号分成若干段(其大小由nperseg
关键字控制),计算每个段的PSD,并对PSD进行平均,以获得更好的信号PSD估计值(平均的段越多,产生的随机误差越小)。实际上,FFT方法相当于只对一个大段进行计算和平均。因此,我们期望P_-welch
和P_-fft
之间存在一些差异,但我们应该期望P_-welch
更准确
信号能量
正如你所说的,信号能量可以从帕塞瓦尔定理的离散版本中获得
# Energy obtained via "integrating" over time
E = np.sum(x ** 2)
# Energy obtained via "integrating" DFT components over frequency.
# The fact that `E` = `E_fft` is the statement of
# the discrete version of Parseval's theorem.
N = len(x)
E_fft = np.sum(np.abs(Xk) ** 2) / N
我们现在想了解上面通过scipy.signal.welch(…)
计算的sxx_welch
与信号中总能量E
的关系。从上面看,S_xx_fft=((np.abs(Xk)**dt)**2)/T
。重新排列这个表达式中的术语,我们可以看到np.abs(Xk)**2=(T/(dt**2))*S_xx_fft
。此外
从上面我们知道,np.sum(S_xx_fft)=p_fft/df_fft
,并且p_fft
和p_welch
近似相等。此外,P_-welch=np.sum(S_xx_-welch)/df_-welch
,因此我们得到
np.sum(S_xx_fft)=(df_welch/df_fft)*np.sum(S_xx_welch)
此外,S_xx_fft=((np.abs(Xk)**dt)**2)/T
。将sxx_fft
代入上述方程并重新排列项,我们得到
np.sum(np.abs(Xk)**2)=(T/(dt**2))*(df_-welch/df_-fft)*np.sum(S_-xx_-welch)
上述方程式中的左侧(LHS)现在看起来应该非常接近于计算出的fr信号中总能量的表达式
# Power in sinusoidal signal is simply squared RMS, and
# the RMS of a sinusoid is the amplitude divided by sqrt(2).
# Thus, the sinusoidal contribution to expected power is
P_exp = (amp / np.sqrt(2)) ** 2
# For white noise, as is considered in this example,
# the noise is simply the noise PSD (a constant)
# times the system bandwidth. This was already
# computed in the problem statement and is given
# as `noise_power`. Simply add to `P_exp` to get
# total expected signal power.
P_exp += noise_power
# Energy obtained via "integrating" over time
E = np.sum(x ** 2)
# Energy obtained via "integrating" DFT components over frequency.
# The fact that `E` = `E_fft` is the statement of
# the discrete version of Parseval's theorem.
N = len(x)
E_fft = np.sum(np.abs(Xk) ** 2) / N
# Signal energy from Welch's PSD
E_welch = (1. / dt) * (df_welch / df_fft) * np.sum(S_xx_welch)