我有兴趣用Python计算3D空间中粒子系统(~100,000)的功率谱。到目前为止我发现的是Numpy(fft
,fftn
,..)中的一组函数,它们计算离散傅里叶变换,其中绝对值的平方是功率谱。我的问题是我的数据如何被表示 - 并且如实回答可能相当简单。
我所拥有的数据结构是一个数组,其形状为( 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。代码的输出给了我类似的东西:
正如你所看到的,我认为这给了我三个1D功率谱(我的数据每列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
为您完成所有肮脏的工作。