简体   繁体   English

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

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

I want to implement ifft2 using DFT matrix.我想使用 DFT 矩阵实现 ifft2。 The following code works for fft2.以下代码适用于 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)))

To get to ifft2 I assumd I need to change only the dft matrix to it's transpose, so expected the following to work, but I got false for the last two print any suggesetion please?要到达 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)))

I am going to be building on some things from my answer to your previous question .我将根据我对您上一个问题的回答来构建一些东西。 Please note that I will try to distinguish between the terms Discrete Fourier Transform ( DFT ) and Fast Fourier Transform ( FFT ).请注意,我将尝试区分离散傅里叶变换( DFT )和快速傅里叶变换( FFT )这两个术语。 Remember that DFT is the transform while FFT is only an efficient algorithm for performing it.请记住, DFT是一种变换,而FFT只是一种执行它的有效算法。 People, including myself, however very commonly refer to the DFT as FFT since it is practically the only algorithm used for computing the DFT包括我自己在内的人们通常将DFT称为FFT ,因为它实际上是用于计算DFT的唯一算法

The problem here is again the normalization of the data.这里的问题再次是数据的规范化。 It's interesting that this is such a fundamental and confusing part of any DFT operations yet I couldn't find a good explanation on the internet.有趣的是,这是任何DFT操作中如此基本且令人困惑的部分,但我在互联网上找不到很好的解释。 I will try to provide a summary at the end about DFT normalization however I think the best way to understand this is by working through some examples yourself.我将尝试在最后提供一个关于DFT规范化的总结,但我认为理解这一点的最好方法是自己研究一些例子。

Why the comparisons fail?为什么比较失败?

It's important to note, that even though both of the allclose tests seemingly fail, they are actually not a very good method of comparing two complex number arrays.需要注意的是,尽管两个allclose测试看似都失败了,但它们实际上并不是比较两个复数 arrays 的好方法。

Difference between two angles两个角度之间的差异

In particular, the problem is when it comes to comparing angles.特别是,问题在于比较角度。 If you just take the difference of two close angles that are on the border between -pi and pi , you can get a value that is around 2*pi .如果你只取-pipi边界上的两个近角的差,你可以得到一个大约2*pi的值。 The allclose just takes differences between values and checks that they are bellow some threshold. allclose只取值之间的差异并检查它们是否低于某个阈值。 Thus in our cases, it can report a false negative.因此,在我们的案例中,它可以报告假阴性。

A better way to compare angles is something along the lines of this function:比较角度的更好方法是沿此 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

You can then take the maximum absolute value and check that it's bellow some threshold:然后,您可以获取最大绝对值并检查它是否低于某个阈值:

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

In the case of your example, the maximum difference was 3.072209153742733e-12 .在您的示例中,最大差异为3.072209153742733e-12

So the angles are actually correct!所以角度实际上是正确的!

Magnitude scaling幅度缩放

We can get an idea of the issue is when we look at the magnitude ratio between the matrix iDFT and the library iFFT .当我们查看矩阵iDFT和库iFFT之间的幅度比时,我们可以了解这个问题。

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

We find that all the values in mA are 800 , which means that our absolute values are 800 times larger than those computed by the library.我们发现mA中的所有值都是800 ,这意味着我们的绝对值比库计算的值大800倍。 Suspiciously, 800 = 40 * 20 , the dimensions of our data.可疑的是, 800 = 40 * 20 ,我们数据的维度。 I think you can see where I am going with this.我想你可以看到我要去哪里。

Confusing DFT normalization令人困惑的DFT归一化

We spot some indications why this is the case when we have a look at the FFT formulas as taken from the Numpy FFT documentation:当我们查看取自Numpy FFT文档的FFT公式时,我们发现了一些迹象表明为什么会出现这种情况:

You will notice that while the forward transform doesn't normalize by anything.您会注意到,虽然前向变换没有通过任何方式进行归一化。 The reverse transform divides the output by 1/N .逆变换将 output 除以1/N These are the 1D FFTs but the exact same thing applies in the 2D case, the inverse transform multiplies everything by 1/(N*M)这些是 1D FFTs ,但同样适用于 2D 情况,逆变换将所有内容乘以1/(N*M)

So in our example, if we update this line, we will get the magnitudes to agree:所以在我们的例子中,如果我们更新这条线,我们将得到一致的幅度:

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

A side note on comparing the outputs, an alternative way to compare complex numbers is to compare the real and imaginary components:关于比较输出的旁注,比较复数的另一种方法是比较实部和虚部:

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

And we find that now indeed both methods agree.我们发现现在这两种方法确实是一致的。

Why all this normalization mess and which should I use?为什么所有这些标准化混乱,我应该使用哪个?

The fundamental property of the DFT transform must satisfy is that iDFT(DFT(x)) = x . DFT 变换必须满足的基本性质是iDFT(DFT(x)) = x When you work through the math, you find that the product of the two coefficients before the sum has to be 1/N .当您进行数学运算时,您会发现总和之前的两个系数的乘积必须是1/N

There is also something called the Parseval's theorem .还有一个叫做Parseval 定理的东西。 In simple terms, it states that the energy in the signals is just the sum of square absolutes in both the time domain and frequency domain.简而言之,它指出信号中的能量只是时域和频域中的平方绝对值之和。 For the FFT this boils down to this relationship:对于FFT ,这归结为这种关系:

Here is the function for computing the energy of a signal:这是用于计算信号能量的 function:

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

You are basically faced with a choice about the 1/N factor:您基本上面临关于1/N因子的选择:

  1. You can put the 1/N before the DFT sum .您可以将1/N放在DFT sum 之前 This makes senses as then the k=0 DC component will be equal to the average of the time domain values.这是有道理的,因为k=0 DC 分量将等于时域值的平均值。 However you will have to multiply the energy in frequency domain by N in order to match it with time domain frequency.但是,您必须将频域中的能量乘以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. You put the 1/N before the iDFT .您将1/N放在iDFT之前 This is, slightly counterintuitively, what most implementations, including Numpy do.这是,有点违反直觉,大多数实现,包括 Numpy 所做的。 I could not find a definitive consensus on the reasoning behind this, but I think it has something to do with the implementation efficiency.这背后的原因我无法找到明确的共识,但我认为这与实施效率有关。 (If anyone has a better explanation for this, please leave it in the comments) As shown in the equations earlier, the energy in the frequency domain has to be divided by N to match the time domain energy. (如果有人对此有更好的解释,请在评论中留下)如前面的等式所示,频域中的能量必须除以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. You can split the 1/N by placing 1/sqrt(N) before each of the transforms making them perfectly symmetric.您可以通过在每个变换之前放置1/sqrt(N)拆分1/N ,从而使它们完全对称。 In Numpy , you can provide the parameter norm="ortho" to the fft functions which will make them use the 1/sqrt(N) normalization instead: np.fft.fft(x, norm="ortho") The nice property here is that the energy now matches in both domains.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)`

In the end it boils down to what you need.最后归结为你需要什么。 Most of the time the absolute magnitude of your DFT is actually not that important.大多数时候,你的DFT的绝对大小实际上并不那么重要。 You are mostly interested in the ratio of various components or you want to perform some operation in the frequency domain but then transform back to the time domain or you are interested in the phase (angles).您最感兴趣的是各种分量的比率,或者您想在频域中执行一些操作,然后转换回时域,或者您对相位(角度)感兴趣。 In all of these case, the normalization does not really play an important role, as long as you stay consistent.在所有这些情况下,只要您保持一致,规范化并不会真正发挥重要作用。

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

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