Numpy中数据的功率谱和自相关

时间:2013-05-29 17:02:07

标签: python numpy fft correlation

我有兴趣用Python计算3D空间中粒子系统(~100,000)的功率谱。到目前为止我发现的是Numpy(fftfftn,..)中的一组函数,它们计算离散傅里叶变换,其中绝对值的平方是功率谱。我的问题是我的数据如何被表示 - 并且如实回答可能相当简单。

我所拥有的数据结构是一个数组,其形状为( n ,2), n 是我拥有的粒子数,每列代表 n 粒子的x,y和z坐标。函数我认为我应该使用fftn()函数,该函数采用 n - 维数组的离散傅里叶变换 - 但它没有说明格式。如何将数据表示为要输入fftn的数据结构?

以下是我迄今为止尝试过的功能:

import numpy as np
import random
import matplotlib.pyplot as plt

DATA = np.zeros((100,3))

for i in range(len(DATA)):
    DATA[i,0] = random.uniform(-1,1)
    DATA[i,1] = random.uniform(-1,1)
    DATA[i,2] = random.uniform(-1,1)

FFT = np.fft.fftn(DATA)
PS = abs(FFT)**2

plt.plot(PS)
plt.show()

名为DATA的数组是一个模拟数组,最终形状为100,000×3。代码的输出给了我类似的东西: enter image description here

正如你所看到的,我认为这给了我三个1D功率谱(我的数据每列1个),但实际上我想要一个功率谱作为半径的函数。

是否有人有任何建议或他们知道的替代方法/包计算功率谱(我甚至满足于两点自相关函数)。

1 个答案:

答案 0 :(得分:4)

它的设置方式并不完全......

你需要一个函数,我们称之为f(x, y, z),它描述了空间中的质量密度。在您的情况下,您可以将星系视为点质量,因此您将具有以每个星系的位置为中心的delta函数。您可以通过此功能计算三维自相关,从中可以计算出功率谱。

如果你想使用numpy为你做这件事,你首先必须离散你的功能。一个可能的模拟示例是:

import numpy as np
import matplotlib.pyplot as plt

space = np.zeros((100, 100, 100), dtype=np.uint8)

x, y, z = np.random.randint(100, size=(3, 1000))
space[x, y, z] += 1

space_ps = np.abs(np.fft.fftn(space))
space_ps *= space_ps

space_ac = np.fft.ifftn(space_ps).real.round()
space_ac /= space_ac[0, 0, 0]

现在space_ac保存数据集的三维自相关函数。这不是你想要的,为了得到一维相关函数,你必须平均原点周围的球壳上的值:

dist = np.minimum(np.arange(100), np.arange(100, 0, -1))
dist *= dist
dist_3d = np.sqrt(dist[:, None, None] + dist[:, None] + dist)
distances, _ = np.unique(dist_3d, return_inverse=True)
values = np.bincount(_, weights=space_ac.ravel()) / np.bincount(_)

plt.plot(distances[1:], values[1:])

另外一个问题就是你自己这样做:当你如上所述计算功率谱时,数学上好像你的三维数组缠绕在边界上,即点[999, y, z]是{{1}的邻居}}。所以你的自相关可以显示两个非常遥远的星系作为近邻。解决这个问题最简单的方法是在每个维度上使你的数组​​大两倍,用额外的零填充,然后丢弃额外的数据。

或者,您可以[0, y, z]使用scipy.ndimage.filters.correlate为您完成所有肮脏的工作。