我该如何解释numpy.fft.rfft2的输出?

dim*_*pol 8 python numpy fft

显然,rfft2函数只是计算输入矩阵的离散fft.但是,如何解释给定的输出索引?给定一个输出指数,我看哪个傅立叶系数?
我对输出的大小感到特别困惑.对于n×n矩阵,输出似乎是n乘(n/2)+1矩阵(对于偶数n).为什么方阵最终会得到非方形傅立叶变换?

Mar*_*son 6

的输出numpy.fft.rfft2只是标准二维FFT的左半部分(加一列),由计算numpy.fft.fft2。不需要rfft2提供结果的右半部分,因为实际数组的FFT具有自然且简单的对称性,因此可以使用该对称性从左半部分得出完整FFT的右半部分。

这是一个示例,以进行说明。首先,为了易于复制和查看,我将设置NumPy的随机状态和打印选项:

In [1]: import numpy as np

In [2]: np.set_printoptions(precision=3, suppress=True, linewidth=128)

In [3]: random = np.random.RandomState(seed=15206)
Run Code Online (Sandbox Code Playgroud)

让我们创建一个包含6行6列的实际输入数组:

In [4]: x = random.randn(6, 6)

In [5]: x
Out[5]: 
array([[ 1.577,  0.426,  0.322, -0.891, -0.793,  0.017],
       [ 0.238,  0.603, -0.094, -0.087, -0.936, -1.139],
       [-0.583,  0.394,  0.323, -1.384,  1.255,  0.457],
       [-0.186,  0.687, -0.815, -0.54 ,  0.762, -0.674],
       [-1.604, -0.557,  1.933, -1.122, -0.516, -1.51 ],
       [-1.683, -0.006, -1.648, -0.016,  1.145,  0.809]])
Run Code Online (Sandbox Code Playgroud)

现在看一下完整的FFT(使用fft2,而不是rfft2):

In [6]: fft2_result = np.fft.fft2(x)

In [7]: fft2_result
Out[7]: 
array([[ -5.834+0.j   ,   1.084-2.33j ,  -6.504-3.884j,   3.228-0.j   ,  -6.504+3.884j,   1.084+2.33j ],
       [  1.475-3.311j,   1.865-3.699j,   2.777-0.095j,  -2.570-1.152j,   4.705-3.373j,   4.555-3.657j],
       [  2.758+3.339j,  -3.512+0.398j,   5.824-4.045j,   1.149-3.705j,   0.661-2.127j,  12.368+1.464j],
       [  1.326-0.j   ,   1.191-4.479j,  -3.263+6.19j ,   8.939-0.j   ,  -3.263-6.19j ,   1.191+4.479j],
       [  2.758-3.339j,  12.368-1.464j,   0.661+2.127j,   1.149+3.705j,   5.824+4.045j,  -3.512-0.398j],
       [  1.475+3.311j,   4.555+3.657j,   4.705+3.373j,  -2.570+1.152j,   2.777+0.095j,   1.865+3.699j]])
Run Code Online (Sandbox Code Playgroud)

请注意,这里有一个对称性:对于任何索引,i并且j0 <= i < 60 <= j < 6fft2_result[i, j]都是的复共轭fft_result[-i, -j]。例如:

In [8]: fft2_result[2, 4]
Out[8]: (0.66075993512998199-2.127249005984857j)

In [9]: fft2_result[-2, -4].conj()
Out[9]: (0.66075993512998199-2.127249005984857j)
Run Code Online (Sandbox Code Playgroud)

这意味着我们不需要包括输出的右半部分,因为它可以从左半部分派生。仅计算完整FFT的左半部分,就可以节省内存,甚至可以节省一点时间。这就是它的rfft2作用:

In [10]: rfft2_result = np.fft.rfft2(x)

In [11]: rfft2_result
Out[11]: 
array([[ -5.834+0.j   ,   1.084-2.33j ,  -6.504-3.884j,   3.228+0.j   ],
       [  1.475-3.311j,   1.865-3.699j,   2.777-0.095j,  -2.570-1.152j],
       [  2.758+3.339j,  -3.512+0.398j,   5.824-4.045j,   1.149-3.705j],
       [  1.326-0.j   ,   1.191-4.479j,  -3.263+6.19j ,   8.939-0.j   ],
       [  2.758-3.339j,  12.368-1.464j,   0.661+2.127j,   1.149+3.705j],
       [  1.475+3.311j,   4.555+3.657j,   4.705+3.373j,  -2.570+1.152j]])
Run Code Online (Sandbox Code Playgroud)

请注意,至少可rfft2_result匹配fft2_result[:, :4],但不会出现数值错误:

In [12]: np.allclose(rfft2_result, fft2_result[:, :4])
Out[12]: True
Run Code Online (Sandbox Code Playgroud)

通过使用以下axes参数,我们还可以选择保留输出的上半部分而不是左半部分np.fft.rfft2

In [13]: np.fft.rfft2(x, axes=[1, 0])
Out[13]: 
array([[ -5.834+0.j   ,   1.084-2.33j ,  -6.504-3.884j,   3.228-0.j   ,  -6.504+3.884j,   1.084+2.33j ],
       [  1.475-3.311j,   1.865-3.699j,   2.777-0.095j,  -2.570-1.152j,   4.705-3.373j,   4.555-3.657j],
       [  2.758+3.339j,  -3.512+0.398j,   5.824-4.045j,   1.149-3.705j,   0.661-2.127j,  12.368+1.464j],
       [  1.326+0.j   ,   1.191-4.479j,  -3.263+6.19j ,   8.939-0.j   ,  -3.263-6.19j ,   1.191+4.479j]])
Run Code Online (Sandbox Code Playgroud)

作为文档np.fft.rfftn说,NumPy的执行过去轴所指定的真实FFT,和复杂的FFT超过其它轴。

当然,仍然存在一些冗余rfft2_result:我们可以丢弃第一列的下半部分和最后一列的下半部分,并且仍然能够使用与以前相同的对称性来重构它们。而在位置上的条目[0, 0][0, 3][3, 0]并且[3, 3]都将是真实的,所以我们可以抛弃虚部。但这将给我们带来不太方便的数组表示形式。