我希望能够生成一个随机均匀的粒子位置样本,该样本落在球形体积内。
下面的图片(由http://nojhan.free.fr/metah/提供)显示了我正在寻找的内容。这是穿过球体的切片,显示了点的均匀分布:
这就是我目前所得到的:
由于球面和笛卡尔坐标之间的转换,您可以看到中心有一组点。
我使用的代码是:
def new_positions_spherical_coordinates(self):
radius = numpy.random.uniform(0.0,1.0, (self.number_of_particles,1))
theta = numpy.random.uniform(0.,1.,(self.number_of_particles,1))*pi
phi = numpy.arccos(1-2*numpy.random.uniform(0.0,1.,(self.number_of_particles,1)))
x = radius * numpy.sin( theta ) * numpy.cos( phi )
y = radius * numpy.sin( theta ) * numpy.sin( phi )
z = radius * numpy.cos( theta )
return (x,y,z)
下面是一些MATLAB代码,据说可以创建一个统一的球形样本,类似于http://nojhan.free.fr/metah给出的等式。我似乎无法破译它或理解他们做了什么。
function X = randsphere(m,n,r)
% This function returns an m by n array, X, in which
% each of the m rows has the n Cartesian coordinates
% of a random point uniformly-distributed over the
% interior of an n-dimensional hypersphere with
% radius r and center at the origin. The function
% 'randn' is initially used to generate m sets of n
% random variables with independent multivariate
% normal distribution, with mean 0 and variance 1.
% Then the incomplete gamma function, 'gammainc',
% is used to map these points radially to fit in the
% hypersphere of finite radius r with a uniform % spatial distribution.
% Roger Stafford - 12/23/05
X = randn(m,n);
s2 = sum(X.^2,2);
X = X.*repmat(r*(gammainc(s2/2,n/2).^(1/n))./sqrt(s2),1,n);
我非常感谢有关在Python中从球形体积生成真正统一样本的任何建议。
似乎有很多例子展示了如何从均匀的球壳采样,但这似乎更容易一个问题。这个问题与缩放有关 - 半径为0.1的粒子应该比半径为1.0的粒子少,以便从球体的体积中生成均匀的样本。
编辑: 修正并删除了我正常要求的事实,我的意思是制服。
答案 0 :(得分:36)
虽然我更喜欢球体的丢弃方法,但为了完整性I offer the exact solution。
在球坐标系中,利用sampling rule:
phi = random(0,2pi)
costheta = random(-1,1)
u = random(0,1)
theta = arccos( costheta )
r = R * cuberoot( u )
现在您有一个(r, theta, phi)
组,可以通常的方式转换为(x, y, z)
x = r * sin( theta) * cos( phi )
y = r * sin( theta) * sin( phi )
z = r * cos( theta )
答案 1 :(得分:14)
生成一组均匀分布在立方体内的点,然后丢弃距离中心的距离超过所需球体半径的点。
答案 2 :(得分:13)
在n维空间中有一种很好的方法可以在球体上生成均匀的点,你已经在你的问题中指出了这一点(我的意思是MATLAB代码)。
为什么会这样?答案是:让我们看一下n维正态分布的概率密度。它是相等的(达到常数)
exp(-x_1 * x_1 / 2)* exp(-x_2 * x_2 / 2)... = exp(-r * r / 2), 所以它不依赖于方向,只取决于距离!这意味着,在对矢量进行标准化后,得到的分布密度将在整个球体上保持不变。
这种方法应该是绝对优选的,因为它简单,通用和高效(和美观)。 代码,在三维中生成 on 球体上的1000个事件:
size = 1000
n = 3 # or any positive integer
x = numpy.random.normal(size=(size, n))
x /= numpy.linalg.norm(x, axis=1)[:, numpy.newaxis]
顺便说一句,看看的好链接:http://www-alg.ist.hokudai.ac.jp/~jan/randsphere.pdf
至于在球体内具有均匀分布,而不是对矢量进行归一化,你应该将vercor乘以一些f(r):f(r)* r的分布密度与r ^成比例n在[0,1]上,这是在您发布的代码中完成的
答案 3 :(得分:2)
这是否足够统一以达到您的目的?
In []: p= 2* rand(3, 1e4)- 1
In []: p= p[:, sum(p* p, 0)** .5<= 1]
In []: p.shape
Out[]: (3, 5216)
它的一部分
In []: plot(p[0], p[2], '.')
看起来像:
答案 4 :(得分:2)
Normed高斯3d矢量均匀分布在球体上,参见http://mathworld.wolfram.com/SpherePointPicking.html
例如:
N = 1000
v = numpy.random.uniform(size=(3,N))
vn = v / numpy.sqrt(numpy.sum(v**2, 0))
答案 5 :(得分:2)
我同意Alleo。我将您的Matlab代码翻译成Python,它可以非常快地生成数千个点(在我的计算机中用于2D和3D的几分之一)。我甚至为高达5D的超球体运行它。 我发现您的代码非常有用,我将其应用于研究中。 Tim McJilton,我应该添加谁作为参考?
import numpy as np
from scipy.special import gammainc
from matplotlib import pyplot as plt
def sample(center,radius,n_per_sphere):
r = radius
ndim = center.size
x = np.random.normal(size=(n_per_sphere, ndim))
ssq = np.sum(x**2,axis=1)
fr = r*gammainc(ndim/2,ssq/2)**(1/ndim)/np.sqrt(ssq)
frtiled = np.tile(fr.reshape(n_per_sphere,1),(1,ndim))
p = center + np.multiply(x,frtiled)
return p
fig1 = plt.figure(1)
ax1 = fig1.gca()
center = np.array([0,0])
radius = 1
p = sample(center,radius,10000)
ax1.scatter(p[:,0],p[:,1],s=0.5)
ax1.add_artist(plt.Circle(center,radius,fill=False,color='0.5'))
ax1.set_xlim(-1.5,1.5)
ax1.set_ylim(-1.5,1.5)
ax1.set_aspect('equal')
答案 6 :(得分:0)
import numpy as np
import matplotlib.pyplot as plt
r= 30.*np.sqrt(np.random.rand(1000))
#r= 30.*np.random.rand(1000)
phi = 2. * np.pi * np.random.rand(1000)
x = r * np.cos(phi)
y = r * np.sin(phi)
plt.figure()
plt.plot(x,y,'.')
plt.show()
&#13;
这就是你想要的
答案 7 :(得分:0)
import random
R = 2
def sample_circle(center):
a = random.random() * 2 * np.pi
r = R * np.sqrt(random.random())
x = center[0]+ (r * np.cos(a))
y = center[1] + (r * np.sin(a))
return x,y
ps = np.array([sample_circle((0,0)) for i in range(100)])
plt.plot(ps[:,0],ps[:,1],'.')
plt.xlim(-3,3)
plt.ylim(-3,3)
plt.show()
答案 8 :(得分:-1)
您可以在spherical coordinates中生成随机点(假设您正在使用3D):S(r,θ,φ),其中r∈[0,R),θ∈[0,π] ,φ∈[0,2π),其中R是球体的半径。这也可以让你直接控制生成的点数(即你不需要丢弃任何点)。
为了补偿半径密度的损失,您将根据幂律分布生成径向坐标(有关如何执行此操作的说明,请参阅 dmckee的答案)。
如果您的代码需要(x,y,z)(即笛卡尔坐标)坐标,那么您只需将随机生成的点球形转换为笛卡尔坐标,如here所述。