Parseval 定理 - 平均功率

信息处理 功率谱密度
2022-02-11 06:46:56

我想通过其频谱计算时域信号的平均功率。我猜 Parseval 是正确的工具。

所以我在一秒钟内采样了一个 100 Hz 10000x 的正弦波。

不幸的是,平方样本的总和不是 FFT 幅度的总和(由 FFT 箱的数量加权)。错误在哪里?

# Some python code

import numpy
import matplotlib.pyplot as plt

# Create Time Domain Signal for 1 sec
fs = n = 10000    # Samplingfrequency
ti = numpy.linspace(0,1,num=fs)
sx = 1*numpy.sin(2*numpy.pi*100*ti)    

# Calculate spectrum via FFT and account for scaling n/2
# taking the real fft (rfft) only the positive frequencies are calculated
fx = numpy.fft.rfft(sx)/(n/2)
no_of_points = fx.shape[0]

# Calculate RMS for time domains signal + spectrum
parseval_sx = numpy.sum(sx**2)
parseval_fx = numpy.sum(numpy.abs(fx)**2)/no_of_points

print parseval_sx, " equals not ", parseval_fx

输出:

4999.5  equals not  0.000199940012002
2个回答

可以用 计算平均功率(与 RMS 幅度成正比) ,但它更复杂,因为 DC 和 Nyquist bin 在完整 fft 中没有加倍(如果n是奇数rfft,则 Nyquist bin 不存在)。

NumPyrfft优于 SciPy,因为它输出与 N 维数组兼容的复数,而不是 SciPy 的“打包”格式。

def rms_rfft(spectrum, n=None):
    """
    Use Parseval's theorem to find the RMS value of an even-length signal
    from its rfft, without wasting time doing an inverse real FFT.

    spectrum is produced as spectrum = numpy.fft.rfft(signal)

    For a signal x with an even number of samples, these should produce the
    same result, to within numerical accuracy:

    rms_flat(x) ~= rms_rfft(rfft(x))

    If len(x) is odd, n must be included, or the result will only be
    approximate, due to the ambiguity of rfft for odd lengths.
    """
    if n is None:
        n = (len(spectrum) - 1) * 2
    sq = real(spectrum * conj(spectrum))
    if n % 2:  # odd
        mean = (sq[0] + 2*sum(sq[1:])           )/n
    else:
        mean = (sq[0] + 2*sum(sq[1:-1]) + sq[-1])/n
    root = sqrt(mean)
    return root/sqrt(n)

更多细节在这里:https ://gist.github.com/endolith/1257010

有几件事正在发生。首先,真正的FFTrfft函数改用reginal fft

其次,我不知道你从哪里得到你在这两行上缩放结果的数字:

fx = numpy.fft.rfft(sx)/(n/2)
parseval_fx = numpy.sum(numpy.abs(fx)**2)/no_of_points

这些对我来说都没有意义。所以让我们解决这个问题。

为了进行正交FFT 变换(不缩放分量),我们需要按点数的平方根进行缩放。所以这就是我的建议:

# Some python code

import numpy
import math

# Create Time Domain Signal for 1 sec
fs = n = 10000    # Samplingfrequency
ti = numpy.linspace(0,1,num=fs)
sx = 1*numpy.sin(2*numpy.pi*100*ti)    

# Calculate spectrum via FFT and account for scaling 1/sqrt(N)
# taking the real fft (rfft) only the positive frequencies are calculated
fx = numpy.fft.fft(sx)/(math.sqrt(len(sx)))

# Calculate RMS for time domains signal + spectrum
parseval_sx = numpy.sum(sx**2)
parseval_fx = numpy.sum(numpy.abs(fx)**2)

print parseval_sx, " equals ", parseval_fx