3

在 python 中进行 2D FFT 时,我有一个关于规范化的简单问题。我的理解是,可以通过使数组充满一个来确定归一化因子。

例如,在 1d 中,[1,1,1,1] 的 FFT 会给我 [4+0j,0+0j,0+0j,0+0j] 所以归一化因子应该是 1/N=1/4。

在 2D 中,[[1,1],[1,1]] 的 FFT 会给我 [[4+0j,0+0j],[0+0j,0+0j]] 所以归一化应该是 1/MN =1/(2*2)=1/4。

现在假设我们有一个 3000 x 3000 矩阵,每个元素都有一个均值为 0 的高斯分布值。当我们对其进行 FFT 并对其进行归一化(归一化因子 = 1/(3000*3000))时,我们得到 10 阶的平均幂^- 7.

现在我们使用 1000 x 1000 元素的子区域重复此操作(归一化因子 = 1/(1000*1000))。我们从中得到的平均功率是 10^-6 阶。我想知道为什么会有~10的差异。平均功率不应该相同吗?我错过了一个额外的归一化因子吗?

如果我们说因子差异实际上是 9,那么我可以猜测这来自元素的数量(3000 x 3000 的元素是 1000 x 1000 的 9 倍),但是这个额外因子的直观原因是什么?此外,我们如何确定绝对归一化因子以获得“真实”的潜在平均功率?

任何见解将不胜感激。提前致谢!

示例代码:

import numpy as np
a   = np.random.randn(3000,3000)
af  = np.fft.fft2(a)/3000.0/3000.0
aP  = np.mean(np.abs(af)**2)

b   = a[1000:2000,1000:2000]
bf  = np.fft.fft2(b)/1000.0/1000.0
bP  = np.mean(np.abs(bf)**2)

print aP,bP

>1.11094908545e-07 1.00226264535e-06
4

1 回答 1

3

首先,需要注意的是,这个问题与 1D 和 2D FFT 之间的差异无关,而是与总功率和平均功率如何随阵列中的元素数量缩放有关。

当您说 9 的因数来自比 中多 9 倍的元素时,您是完全正确ab。可能令人困惑的是,您注意到您已经通过除以np.fft.fft2(a)/3000./3000.np.fft.fft2(b)/1000./1000.归一化实际上,这些归一化对于使空间域和频域中的总(而不是平均)功率相等是必要的。要获得平均值,您必须再次除以数组大小。

您的问题实际上是关于 Parseval 定理,该定理指出两个域(空间/时间和频率)的总功率相等。它的声明,对于 DFT 是这样的。请注意,尽管右侧有 1/N,但这不是平均功率,而是功率。1/N 的原因是 DFT 的归一化约定。

放在 Python 中,这意味着对于时间/空间信号sig,Parseval 等价性可以表述为:

np.sum(np.abs(sig)**2) == np.sum(np.abs(np.fft.fft(sig))**2)/sig.size

下面是一个完整的示例,从一些玩具案例(一维和二维数组填充一个 1)开始,到您自己的案例结束。请注意,我使用了.sizenumpy.ndarray 的属性,它返回数组中元素的总数。它相当于你的/1000./1000.等。希望这会有所帮助!

import numpy as np

print 'simple examples:'

# 1-d, 4 elements:
ones_1d = np.array([1.,1.,1.,1.])
ones_1d_f = np.fft.fft(ones_1d)

# compute total power in space and frequency domains:
space_power_1d = np.sum(np.abs(ones_1d)**2)
freq_power_1d = np.sum(np.abs(ones_1d_f)**2)/ones_1d.size
print 'space_power_1d = %f'%space_power_1d
print 'freq_power_1d = %f'%freq_power_1d

# 2-d, 4 elements:
ones_2d = np.array([[1.,1.],[1.,1.]])
ones_2d_f = np.fft.fft2(ones_2d)

# compute and print total power in space and frequency domains:
space_power_2d = np.sum(np.abs(ones_2d)**2)
freq_power_2d = np.sum(np.abs(ones_2d_f)**2)/ones_2d.size
print 'space_power_2d = %f'%space_power_2d
print 'freq_power_2d = %f'%freq_power_2d

# 2-d, 9 elements:
ones_2d_big = np.array([[1.,1.,1.],[1.,1.,1.],[1.,1.,1.]])
ones_2d_big_f = np.fft.fft2(ones_2d_big)

# compute and print total power in space and frequency domains:
space_power_2d_big = np.sum(np.abs(ones_2d_big)**2)
freq_power_2d_big = np.sum(np.abs(ones_2d_big_f)**2)/ones_2d_big.size
print 'space_power_2d_big = %f'%space_power_2d_big
print 'freq_power_2d_big = %f'%freq_power_2d_big
print


# asker's example array a and fft af:
print 'askers examples:'
a = np.random.randn(3000,3000)
af = np.fft.fft2(a)

# compute the space and frequency total powers:
space_power_a = np.sum(np.abs(a)**2)
freq_power_a = np.sum(np.abs(af)**2)/af.size

# mean power is the total power divided by the array size:
freq_power_a_mean = freq_power_a/af.size

print 'space_power_a = %f'%space_power_a
print 'freq_power_a = %f'%freq_power_a
print 'freq_power_a_mean = %f'%freq_power_a_mean
print
# the central 1000x1000 section of the 3000x3000 original array:
b = a[1000:2000,1000:2000]
bf = np.fft.fft2(b)

# we expect the total power in the space and frequency domains 
# to be about 1/9 of the total power in the space frequency domains 
# for matrix a:
space_power_b = np.sum(np.abs(b)**2)
freq_power_b = np.sum(np.abs(bf)**2)/bf.size
# we expect the mean power to be the same as the mean power from
# matrix a:
freq_power_b_mean = freq_power_b/bf.size

print 'space_power_b = %f'%space_power_b
print 'freq_power_b = %f'%freq_power_b
print 'freq_power_b_mean = %f'%freq_power_b_mean
于 2014-09-08T18:49:21.930 回答