繁体   English   中英

为什么 ifft2 不工作但 fft2 很好?

[英]Why ifft2 is not working but fft2 is fine?

我想使用 DFT 矩阵实现 ifft2。 以下代码适用于 fft2。

import numpy as np

def DFT_matrix(N):
    i, j = np.meshgrid(np.arange(N), np.arange(N))
    omega = np.exp( - 2 * np.pi * 1j / N )
    W = np.power( omega, i * j ) # Normalization by sqrt(N) Not included
    return W

sizeM=40
sizeN=20
np.random.seed(0)
rA=np.random.rand(sizeM,sizeN)

rAfft=np.fft.fft2(rA)


dftMtxM=DFT_matrix(sizeM)
dftMtxN=DFT_matrix(sizeN)

# Matrix multiply the 3 matrices together 
mA = dftMtxM @ rA @ dftMtxN


print(np.allclose(np.abs(mA), np.abs(rAfft)))
print(np.allclose(np.angle(mA), np.angle(rAfft)))

要到达 ifft2,我假设我只需要将 dft 矩阵更改为它的转置,所以期望以下工作,但我对最后两个打印错误有任何建议吗?

import numpy as np

def DFT_matrix(N):
    i, j = np.meshgrid(np.arange(N), np.arange(N))
    omega = np.exp( - 2 * np.pi * 1j / N )
    W = np.power( omega, i * j ) # Normalization by sqrt(N) Not included
    return W

sizeM=40
sizeN=20
np.random.seed(0)
rA=np.random.rand(sizeM,sizeN)

rAfft=np.fft.ifft2(rA)


dftMtxM=np.conj(DFT_matrix(sizeM))
dftMtxN=np.conj(DFT_matrix(sizeN))

# Matrix multiply the 3 matrices together 
mA = dftMtxM @ rA @ dftMtxN


print(np.allclose(np.abs(mA), np.abs(rAfft)))
print(np.allclose(np.angle(mA), np.angle(rAfft)))

我将根据我对您上一个问题的回答来构建一些东西。 请注意,我将尝试区分离散傅里叶变换( DFT )和快速傅里叶变换( FFT )这两个术语。 请记住, DFT是一种变换,而FFT只是一种执行它的有效算法。 包括我自己在内的人们通常将DFT称为FFT ,因为它实际上是用于计算DFT的唯一算法

这里的问题再次是数据的规范化。 有趣的是,这是任何DFT操作中如此基本且令人困惑的部分,但我在互联网上找不到很好的解释。 我将尝试在最后提供一个关于DFT规范化的总结,但我认为理解这一点的最好方法是自己研究一些例子。

为什么比较失败?

需要注意的是,尽管两个allclose测试看似都失败了,但它们实际上并不是比较两个复数 arrays 的好方法。

两个角度之间的差异

特别是,问题在于比较角度。 如果你只取-pipi边界上的两个近角的差,你可以得到一个大约2*pi的值。 allclose只取值之间的差异并检查它们是否低于某个阈值。 因此,在我们的案例中,它可以报告假阴性。

比较角度的更好方法是沿此 function 的路线:

def angle_difference(a, b):
    diff = a - b
    diff[diff < -np.pi] += 2*np.pi
    diff[diff > np.pi] -= 2*np.pi
    return diff

然后,您可以获取最大绝对值并检查它是否低于某个阈值:

np.max(np.abs(angle_difference(np.angle(mA), np.angle(rAfft)))) < threshold

在您的示例中,最大差异为3.072209153742733e-12

所以角度实际上是正确的!

幅度缩放

当我们查看矩阵iDFT和库iFFT之间的幅度比时,我们可以了解这个问题。

print(np.abs(mA)/np.abs(rAfft))

我们发现mA中的所有值都是800 ,这意味着我们的绝对值比库计算的值大800倍。 可疑的是, 800 = 40 * 20 ,我们数据的维度。 我想你可以看到我要去哪里。

令人困惑的DFT归一化

当我们查看取自Numpy FFT文档的FFT公式时,我们发现了一些迹象表明为什么会出现这种情况:

您会注意到,虽然前向变换没有通过任何方式进行归一化。 逆变换将 output 除以1/N 这些是 1D FFTs ,但同样适用于 2D 情况,逆变换将所有内容乘以1/(N*M)

所以在我们的例子中,如果我们更新这条线,我们将得到一致的幅度:

mA = dftMtxM @ rA/(sizeM * sizeN) @ dftMtxN

关于比较输出的旁注,比较复数的另一种方法是比较实部和虚部:

print(np.allclose(mA.real, rAfft.real))
print(np.allclose(mA.imag, rAfft.imag))

我们发现现在这两种方法确实是一致的。

为什么所有这些标准化混乱,我应该使用哪个?

DFT 变换必须满足的基本性质是iDFT(DFT(x)) = x 当您进行数学运算时,您会发现总和之前的两个系数的乘积必须是1/N

还有一个叫做Parseval 定理的东西。 简而言之,它指出信号中的能量只是时域和频域中的平方绝对值之和。 对于FFT ,这归结为这种关系:

这是用于计算信号能量的 function:

def energy(x):
    return np.sum(np.abs(x)**2)

您基本上面临关于1/N因子的选择:

  1. 您可以将1/N放在DFT sum 之前 这是有道理的,因为k=0 DC 分量将等于时域值的平均值。 但是,您必须将频域中的能量乘以N才能将其与时域频率匹配。

     N = len(x) X = np.fft.fft(x)/N # Compute the FFT scaled by `1/N` # Energy related by `N` np.allclose(energy(x), energy(X) * N) == True # Perform some processing... Y = X * H y = np.fft.ifft(Y*N) # Compute the iFFT, remember to cancel out the built in `1/N` of ifft
  2. 您将1/N放在iDFT之前 这是,有点违反直觉,大多数实现,包括 Numpy 所做的。 这背后的原因我无法找到明确的共识,但我认为这与实施效率有关。 (如果有人对此有更好的解释,请在评论中留下)如前面的等式所示,频域中的能量必须除以N以匹配时域能量。

     N = len(x) X = np.fft.fft(x) # Compute the FFT without scaling # Energy, related by 1/N np.allclose(energy(x), energy(X) / N) == True # Perform some processing... Y = X * H y = np.fft.ifft(Y) # Compute the iFFT with the build in `1/N`
  3. 您可以通过在每个变换之前放置1/sqrt(N)拆分1/N ,从而使它们完全对称。 Numpy中,您可以为fft函数提供参数norm="ortho" ,这将使它们使用1/sqrt(N)归一化: np.fft.fft(x, norm="ortho")这里的好属性是能量现在在两个域中匹配。

     X = np.fft.fft(x, norm='orth') # Compute the FFT scaled by `1/sqrt(N)` # Perform some processing... # Energy are equal: np.allclose(energy(x), energy(X)) == True Y = X * H y = np.fft.ifft(Y, norm='orth') # Compute the iFFT, with scaling by `1/sqrt(N)`

最后归结为你需要什么。 大多数时候,你的DFT的绝对大小实际上并不那么重要。 您最感兴趣的是各种分量的比率,或者您想在频域中执行一些操作,然后转换回时域,或者您对相位(角度)感兴趣。 在所有这些情况下,只要您保持一致,规范化并不会真正发挥重要作用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM