显然rfft2函数只是计算输入矩阵的离散fft。但是,如何解释给定的输出索引?给定输出的指数,我看哪个傅立叶系数?
我对输出的大小感到特别困惑。对于n×n矩阵,输出似乎是n乘(n / 2)+1矩阵(对于偶数n)。为什么方阵最终会得到非方形傅里叶变换?
答案 0 :(得分:4)
numpy.fft.rfft2
的输出只是标准二维FFT的左半部分(加一列),由numpy.fft.fft2
计算得出。 rfft2
不需要提供正确的一半结果,因为实数组的FFT具有natural and simple symmetry,因此完整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
):
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]])
请注意,此处存在对称性:对于i
和j
0 <= i < 6
和0 <= j < 6
的{{1}},fft2_result[i, j]
是{@ 1}}的复杂共轭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)
这意味着我们不需要来包含输出的右半部分,因为它可以从左半部分派生。我们可以通过仅计算完整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]])
请注意rfft2_result
匹配fft2_result[:, :4]
,至少是数字错误:
In [12]: np.allclose(rfft2_result, fft2_result[:, :4])
Out[12]: True
我们还可以选择保留输出的上半部分而不是左半部分,方法是使用axes
的{{1}}参数:
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]])
的{{3}}所述,NumPy在指定的最后一个轴上执行实数FFT,而在其他轴上执行复数FFT。
当然,np.fft.rfftn
中还有一些冗余:我们可以丢弃第一列的下半部分和最后一列的下半部分,并且仍然可以使用与以前相同的对称性。位置rfft2_result
,[0, 0]
,[0, 3]
和[3, 0]
的条目都是真实的,因此我们可以放弃它们的虚部。但这会让我们的阵列表示不太方便。
答案 1 :(得分:2)
来自docs:
https://docs.scipy.org/doc/numpy/reference/generated/numpy.fft.rfft2.html
这实际上只是具有不同默认行为的rfftn。更多 详情见rfftn。
numpy.fft.rfft2(a, s=None, axes=(-2, -1), norm=None)[source]
VS
numpy.fft.rfftn(a, s=None, axes=None, norm=None)[source]
https://docs.scipy.org/doc/numpy/reference/generated/numpy.fft.rfftn.html#numpy.fft.rfftn
注释
实际输入的变换是在最后一次变换中执行的 轴,如通过rfft,然后对其余轴的变换是 由fftn执行。输出的顺序与rfft的顺序相同 最终转换轴,以及剩余的fftn 转换轴。
有关详细信息,使用的定义和惯例,请参阅fft。
https://docs.scipy.org/doc/numpy/reference/generated/numpy.fft.fft.html#numpy.fft.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)
答案 2 :(得分:1)
还要注意fft
输出中系数的排序:
根据文档:默认情况下,第一个元素是0频率分量的系数(实际上是数组的和或平均值),从第2个开始,我们有正序频率的系数按递增顺序,并从n / 2 + 1它们按降序排列为负频率。要查看长度为10的数组的频率:
np.fft.fftfreq(10)
输出是:
array([ 0. , 0.1, 0.2, 0.3, 0.4, -0.5, -0.4, -0.3, -0.2, -0.1])
使用np.fft.fftshift(cf)
,其中cf=np.fft.fft(array)
,输出被移位,以便它对应于此频率排序:
array([-0.5, -0.4, -0.3, -0.2, -0.1, 0. , 0.1, 0.2, 0.3, 0.4])
这对绘图很有意义。
在2D情况下,它是相同的。而fft2
和rfft2
的差异正如其他人所解释的那样。