有没有办法从np.fft2中选择x / y输出轴范围? 我有一段代码计算光圈的衍射图案。光圈定义为2k x 2k像素阵列。衍射图案基本上是孔径的2D FT的内部部分。 np.fft2给出了一个与输入大小相同的输出数组,但是有一些预设的x / y轴范围。当然我可以使用图像查看器放大,但我已经丢失了细节。解决方案是什么?
谢谢, 格特
import numpy as np
import matplotlib.pyplot as plt
r= 500
s= 1000
y,x = np.ogrid[-s:s+1, -s:s+1]
mask = x*x + y*y <= r*r
aperture = np.ones((2*s+1, 2*s+1))
aperture[mask] = 0
plt.imshow(aperture)
plt.show()
ffta= np.fft.fft2(aperture)
plt.imshow(np.log(np.abs(np.fft.fftshift(ffta))**2))
plt.show()
答案 0 :(得分:0)
不幸的是,FFT的大部分速度和精度来自输出与输入相同的大小。
增加输出傅立叶域中视在分辨率的传统方法是对输入进行零填充:np.fft.fft2(aperture, [4 * (2*s+1), 4 * (2*s+1)])
告诉FFT将输入填充为4 * (2*s+1)
像素高和宽,即使输入变大四倍(像素数的十六倍)。
从一开始我说“明显”的分辨率,因为你的实际数据量没有增加,但傅里叶变换看起来会更平滑,因为输入域中的零填充会导致傅里叶变换插值输出。在上面的示例中,使用一个像素可以看到的任何功能都将显示为四个像素。为了使这一点完全具体,这个例子表明,零填充FFT的每四个像素在数字上与原始无填充FFT的每个像素相同:
# Generate your `ffta` as above, then
N = 2 * s + 1
Up = 4
fftup = np.fft.fft2(aperture, [Up * N, Up * N])
relerr = lambda dirt, gold: np.abs((dirt - gold) / gold)
print(np.max(relerr(fftup[::Up, ::Up] , ffta))) # ~6e-12.
(relerr
只是一个简单的相对误差,你想要接近机器精度,大约2e-16
。零填充FFT的每第4个样本与未填充的FFT之间的最大误差FFT为6e-12
,非常接近机器精度,这意味着这两个数组在数值上几乎相同。)结束
零填充是解决问题最直接的方法。但它确实花了你很多很多的内存。这令人沮丧,因为你可能只关心变换的一小部分。有一种称为啁啾z变换的算法(CZT,或俗称“缩放FFT”)可以做到这一点。如果您的输入为N
(对于您2*s+1
)并且您希望在任何地方评估FFT输出的M
个样本,则会计算三个大小为N + M - 1
的傅立叶变换以获取输出的所需M
个样本。这也可以解决您的问题,因为您可以在感兴趣的区域中请求M
个样本,并且它不需要过多的内存,尽管它需要至少3倍的CPU时间。缺点是CZT的可靠实现尚未在Numpy / Scipy中:请参阅scipy issue及其引用的code。 Matlab's CZT似乎可靠,如果这是一个选择; Octave-forge也有一个,Octave人通常会努力匹配/超过Matlab。
但是如果你有内存,那么输入就是零填充。