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

Python 我应该如何解释numpy.fft.rfft2的输出?,python,numpy,fft,Python,Numpy,Fft,显然,rfft2函数只计算输入矩阵的离散fft。但是,如何解释给定的输出索引?给定一个输出索引,我在看哪个傅里叶系数? 我对输出的大小尤其感到困惑。对于n×n矩阵,输出似乎是n×n(n/2)+1矩阵(对于偶数n)。为什么平方矩阵最终会得到非平方傅里叶变换?来自文档: 这实际上只是具有不同默认行为的rfftn。更多 详情见rfftn vs 注释 实际输入的转换在最后一次转换中执行 轴,如rfft所示,则剩余轴上的变换为 由fftn执行。输出的顺序与 最终转换轴,对于剩余的fftn 变换轴 有关

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

来自文档:

这实际上只是具有不同默认行为的rfftn。更多 详情见rfftn

vs

注释

实际输入的转换在最后一次转换中执行 轴,如rfft所示,则剩余轴上的变换为 由fftn执行。输出的顺序与 最终转换轴,对于剩余的fftn 变换轴

有关详细信息、定义和使用的约定,请参见fft

我没有使用过2d fftn,但我创建了这个用于解释1d fft的工具,这可能会让您对2d输出的解释有一些了解:

import math
import numpy as np

PERIOD          = 30
SIFT            = 2 # integer from 1 to PERIOD/2

def fourier_series(array, period, sift):

    # Create an array of length data period; then reverse its order
    signal          = (array[-period:])[::-1]  

    # Extract amplitude and phase in (a + bi) complex form
    complex_fft     = np.fft.fft(signal)

    ''' Calculate amplitude, phase, frequency, and velocity '''
    # Define empty lists for later use
    amplitude       = []
    phase           = []
    frequency       = []
    velocity        = []

    # Extract real and imaginary coefficients from complex scipy output
    for n in range(period, 0, -1):   
        amplitude.append(complex_fft.real[-n])
        phase.append(complex_fft.imag[-n])

    # The final equation will need to be divided by period
    # I do it here so that it is calculated once saving cycles     
    amplitude = [(x/period) for x in amplitude]    

    # Extract the carrier
    carrier = max(amplitude)

    # The frequency is a helper function of fft 
    # It only has access to the length of the data set
    frequency.append(np.fft.fftfreq(signal.size, 1))

    # Convert frequency array to list
    frequency       = frequency[-1]

    # Velocity is 2*pi*frequency; I do this here once to save cpu time    
    velocity        = [x*2*math.pi for x in frequency]

    ''' Calculate the Full Spectrum Sinusoid '''
    # Recombine ALL elements in the form An*sin(2*pi(Fn) + Pn) for full spectrum
    full_spectrum   = 0
    for m in range(1, period+1):
        full_spectrum += amplitude[-m]*(1+math.sin(velocity[-m] + phase[-m]))

    ''' Calculate the Filtered Sinusoid '''
    # Normalize user sift input as an integer
    sift = int(sift)

    # If sift is more than half of the period, return full spectrum
    if sift >= period/2:
        filtered_transform = full_spectrum

    # If sift is 0 or 1, return the carrier    
    else:
        filtered_transform = carrier

        # For every whole number of sift over 1, but less than 0.5*period: 
        # Add an 2 elements to the sinusoid respective of 
        # a negative and positive frequency pair
        if sift > 1:
            for m in range(1, sift): 
                p = period - m
                filtered_transform += amplitude[-m]*(1+math.sin(velocity[-m] + phase[-m]))
                filtered_transform += amplitude[-p]*(1+math.sin(velocity[-p] + phase[-p]))

    ''' Print Elements and Return FFT'''
    if 1:
        print('**********************************')
        print('Carrier: %.3f' % amplitude[-period])
        print(['%.2f' % x for x in amplitude])    
        print(['%.2f' % x for x in velocity]) 
        print(['%.2f' % x for x in phase])

    return filtered_transform, carrier, full_spectrum

stochastic = # Your 1d input array
y, y_carrier, y_full = fourier_series(stochastic, PERIOD, SIFT)
的输出只是标准二维FFT的左半部分(加上一列),由计算得出。不需要
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)
让我们创建一个真正的输入数组,包含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]])
现在看看完整的FFT(使用
fft2
,而不是
rfft2
):


注意,这里有一个对称性:对于具有
0的任何索引
i
j
,还要注意
fft
输出中系数的顺序:

根据文档:默认情况下,第一个元素是0频率分量的系数(实际上是数组的总和或平均值),从第二个元素开始,我们以递增的顺序计算正频率的系数,从n/2+1开始,它们以递减的顺序计算负频率的系数。要查看长度为10的阵列的频率,请执行以下操作:


np.fft.fftfreq(10)
输出为:

数组([0,0.1,0.2,0.3,0.4,-0.5,-0.4,-0.3,-0.2,-0.1])

使用
np.fft.fft移位(cf)
,其中
cf=np.fft.fft(数组)
,输出移位,使其对应于此频率顺序:

数组([-0.5,-0.4,-0.3,-0.2,-0.1,0,0.1,0.2,0.3,0.4])
这对于绘图是有意义的


在2D情况下,它是相同的。而
fft2
rfft2
的区别正如其他人所解释的那样。

我不确定你的问题是关于
rfft2
(与
fft2
相反),还是NumPy的2d FFT。您对通常的complex
numpy.fft.fft2
函数的行为满意吗?Mark,从上面的讨论来看,我似乎可以通过以特定方式复制rfft2的输出来创建fft2数组,但我似乎无法使其工作。对于大型阵列,通过使用rfft2获得的速度提升是巨大的,因此我正在尝试创建一个包装器来处理我的软件的实际输入。@Will.Evo当然可以从rfft2输出重建fft2输出。这可能值得一个单独的问题。(我也可能会抽出时间来扩展这个答案,在某个时候包括这些细节,但请不要为此屏住呼吸)。我问了这个问题,找到了解决方案,并回答了我自己的问题。很不错的!谢谢你的链接。@MarkDickinson谢谢你的回答。在你的最后一段中,你说他们可以从两列中去掉一半;为什么这不是默认行为?他们为什么只丢弃最后一列的一半?
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)
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]])
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]])
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)
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]])
In [12]: np.allclose(rfft2_result, fft2_result[:, :4])
Out[12]: True
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]])