Попытка генерировать случайные координаты X, Y внутри кольца в Python

Я пытаюсь сгенерировать случайные координаты x и y внутри кольца, которое имеет внешний радиус 3,5 и внутренний радиус 2. Поэтому для x и y должно быть верно следующее:

x**2 + y**2 < 12.25 and x**2 + y**2 > 4

Я написал следующую функцию:

def meteorites():
    circle = False
    while circle == False:        
        r = np.array([uniform(-6., 6.), uniform(-6., 6.)])
        # we will regenerate random numbers untill the coordinates
        # are within the ring x^2+y^2 < 3,5^2 and x^2+y^2 > 2^2
        if (r[0]**2+r[1]**2 < 12.25) and (r[0]**2+r[1]**2 > 4.):
            circle = True

       else :
            circle = False

    return r[0], r[1]

x = np.zeros(1000)
y = np.zeros(1000)
for i in range(1000):
    x[i] = meteorites()[0]
    y[i] = meteorites()[1]
plt.scatter(x,y)
plt.show()  

Когда я строю полученные координаты, я получаю квадрат от -3,5 до 3,5. Я не могу найти проблему. Я также не уверен, является ли это ошибкой кодирования, или некоторой математической проблемой. Так как вы, ребята, обычно хорошо умеете и то и другое, вы понимаете, что я здесь делаю неправильно?

7 ответов

Решение

Чтобы получить равномерное распределение случайной точки в кольце, необходимо учитывать относительные площади тонких круговых областей. Как это работает для круга

Для вашего случая сгенерируйте равномерное распределение SquaredR в диапазоне квадратов внутреннего и внешнего радиусов. псевдокод:

 Fi  = RandomUniform(0, 2 * Pi)
 SquaredR  = RandomUniform(inner*inner, outer*outer)
 R = Sqrt(SquaredR)
 x,y = R * Cos(Fi), R * Sin(Fi)

Возьмите случайный угол и случайное расстояние между двумя ограничениями; вам нужно создать равномерное распределение по кругу:

from math import sin, cos, radians, pi, sqrt

def meteorites():
    angle = uniform(0, 2 * pi)  # in radians
    distance = sqrt(uniform(4, 12.25))
    return distance * cos(angle), distance * sin(angle)

Вы получаете случайные очки, которые не попадают на ваше кольцо, потому что эти две линии не делают то, что вы хотите:

x[i] = meteorites()[0]
y[i] = meteorites()[1]

Они назначают x значение от одной точки на кольце до x[i]и y значение из другой точки на кольце y[i], Вы получаете координаты из разных точек, потому что вы звоните meteorites() дважды.

Вместо этого вы, вероятно, захотите вызвать функцию один раз, а затем присвоить каждой координате или выполнить присваивание с повторяемой распаковкой, где обе цели находятся слева от знака равенства:

x[i], y[i] = meteorites()

Ваша реализация также будет работать, если вы исправите одну строку: вместо вызова meteorites() дважды, позвоните только один раз.

x = np.zeros(1000)
y = np.zeros(1000)
for i in range(1000):
    x[i], y[i] = meteorites()
plt.scatter(x,y)
plt.show()  

Я также предпочел бы пройти через цикл, который выбирает случайный угол и случайное расстояние в пределах вашего диапазона колец. Затем рассчитайте координаты из этого.

Но в вашем коде первая проблема заключается в том, что следует написать:

x[i],y[i] = meteorites()

вместо

x[i] = meteorites()[0] 
y[i] = meteorites()[1]

В вашем примере вас дважды называют meteorites(), в результате x и y образуют два разных метеорита.

Как предложил @Martijn Pieters, просто нарисуйте полярные координаты равномерно в требуемом диапазоне.

theta = uniform(0,2*np.pi)
r = uniform(2.,3.5)
x = r*np.cos(theta)
y = r*np.sin(theta)

РЕДАКТИРОВАТЬ: чисто математически Там будет равной вероятностью для каждой точки в кольце.

Но практически будет меньше пикселей для данного theta ближе r находится на нижнем пределе. Так что "метеориты" с меньшими r будет происходить с большей вероятностью.

Я считаю, что этот эффект незначителен.

Вы можете попробовать следующее, чтобы сгенерировать 1000 образцов, используя numpy:

import numpy 
n = 1000
phi = numpy.random.uniform(0, 2*numpy.pi, n)
r = numpy.random.uniform(2, 3.5, n)

Тогда координаты x, y можно построить следующим образом, используя преобразование из радиальных в декартовы координаты:

x = r * numpy.cos(phi)
y = r * numpy.sin(phi)

Это показывает силу numpy, поскольку x и y теперь являются массивами без необходимости итерации по n.

Другие вопросы по тегам