Generate a random point within a circle (uniformly)

前端 未结 21 2280
逝去的感伤
逝去的感伤 2020-11-22 15:45

I need to generate a uniformly random point within a circle of radius R.

I realize that by just picking a uniformly random angle in the interval [0 ... 2π),

相关标签:
21条回答
  • 2020-11-22 16:16

    Here is my Python code to generate num random points from a circle of radius rad:

    import matplotlib.pyplot as plt
    import numpy as np
    rad = 10
    num = 1000
    
    t = np.random.uniform(0.0, 2.0*np.pi, num)
    r = rad * np.sqrt(np.random.uniform(0.0, 1.0, num))
    x = r * np.cos(t)
    y = r * np.sin(t)
    
    plt.plot(x, y, "ro", ms=1)
    plt.axis([-15, 15, -15, 15])
    plt.show()
    
    0 讨论(0)
  • 2020-11-22 16:17

    The reason why the naive solution doesn't work is that it gives a higher probability density to the points closer to the circle center. In other words the circle that has radius r/2 has probability r/2 of getting a point selected in it, but it has area (number of points) pi*r^2/4.

    Therefore we want a radius probability density to have the following property:

    The probability of choosing a radius smaller or equal to a given r has to be proportional to the area of the circle with radius r. (because we want to have a uniform distribution on the points and larger areas mean more points)

    In other words we want the probability of choosing a radius between [0,r] to be equal to its share of the overall area of the circle. The total circle area is pi*R^2, and the area of the circle with radius r is pi*r^2. Thus we would like the probability of choosing a radius between [0,r] to be (pi*r^2)/(pi*R^2) = r^2/R^2.

    Now comes the math:

    The probability of choosing a radius between [0,r] is the integral of p(r) dr from 0 to r (that's just because we add all the probabilities of the smaller radii). Thus we want integral(p(r)dr) = r^2/R^2. We can clearly see that R^2 is a constant, so all we need to do is figure out which p(r), when integrated would give us something like r^2. The answer is clearly r * constant. integral(r * constant dr) = r^2/2 * constant. This has to be equal to r^2/R^2, therefore constant = 2/R^2. Thus you have the probability distribution p(r) = r * 2/R^2

    Note: Another more intuitive way to think about the problem is to imagine that you are trying to give each circle of radius r a probability density equal to the proportion of the number of points it has on its circumference. Thus a circle which has radius r will have 2 * pi * r "points" on its circumference. The total number of points is pi * R^2. Thus you should give the circle r a probability equal to (2 * pi * r) / (pi * R^2) = 2 * r/R^2. This is much easier to understand and more intuitive, but it's not quite as mathematically sound.

    0 讨论(0)
  • 2020-11-22 16:19

    Think about it this way. If you have a rectangle where one axis is radius and one is angle, and you take the points inside this rectangle that are near radius 0. These will all fall very close to the origin (that is close together on the circle.) However, the points near radius R, these will all fall near the edge of the circle (that is, far apart from each other.)

    This might give you some idea of why you are getting this behavior.

    The factor that's derived on that link tells you how much corresponding area in the rectangle needs to be adjusted to not depend on the radius once it's mapped to the circle.

    Edit: So what he writes in the link you share is, "That’s easy enough to do by calculating the inverse of the cumulative distribution, and we get for r:".

    The basic premise is here that you can create a variable with a desired distribution from a uniform by mapping the uniform by the inverse function of the cumulative distribution function of the desired probability density function. Why? Just take it for granted for now, but this is a fact.

    Here's my somehwat intuitive explanation of the math. The density function f(r) with respect to r has to be proportional to r itself. Understanding this fact is part of any basic calculus books. See sections on polar area elements. Some other posters have mentioned this.

    So we'll call it f(r) = C*r;

    This turns out to be most of the work. Now, since f(r) should be a probability density, you can easily see that by integrating f(r) over the interval (0,R) you get that C = 2/R^2 (this is an exercise for the reader.)

    Thus, f(r) = 2*r/R^2

    OK, so that's how you get the formula in the link.

    Then, the final part is going from the uniform random variable u in (0,1) you must map by the inverse function of the cumulative distribution function from this desired density f(r). To understand why this is the case you need to find an advanced probability text like Papoulis probably (or derive it yourself.)

    Integrating f(r) you get F(r) = r^2/R^2

    To find the inverse function of this you set u = r^2/R^2 and then solve for r, which gives you r = R * sqrt(u)

    This totally makes sense intuitively too, u = 0 should map to r = 0. Also, u = 1 shoudl map to r = R. Also, it goes by the square root function, which makes sense and matches the link.

    0 讨论(0)
  • 2020-11-22 16:19

    The area element in a circle is dA=rdr*dphi. That extra factor r destroyed your idea to randomly choose a r and phi. While phi is distributed flat, r is not, but flat in 1/r (i.e. you are more likely to hit the boundary than "the bull's eye").

    So to generate points evenly distributed over the circle pick phi from a flat distribution and r from a 1/r distribution.

    Alternatively use the Monte Carlo method proposed by Mehrdad.

    EDIT

    To pick a random r flat in 1/r you could pick a random x from the interval [1/R, infinity] and calculate r=1/x. r is then distributed flat in 1/r.

    To calculate a random phi pick a random x from the interval [0, 1] and calculate phi=2*pi*x.

    0 讨论(0)
  • 2020-11-22 16:22

    Let's approach this like Archimedes would have.

    How can we generate a point uniformly in a triangle ABC, where |AB|=|BC|? Let's make this easier by extending to a parallelogram ABCD. It's easy to generate points uniformly in ABCD. We uniformly pick a random point X on AB and Y on BC and choose Z such that XBYZ is a parallelogram. To get a uniformly chosen point in the original triangle we just fold any points that appear in ADC back down to ABC along AC.

    Now consider a circle. In the limit we can think of it as infinitely many isoceles triangles ABC with B at the origin and A and C on the circumference vanishingly close to each other. We can pick one of these triangles simply by picking an angle theta. So we now need to generate a distance from the center by picking a point in the sliver ABC. Again, extend to ABCD, where D is now twice the radius from the circle center.

    Picking a random point in ABCD is easy using the above method. Pick a random point on AB. Uniformly pick a random point on BC. Ie. pick a pair of random numbers x and y uniformly on [0,R] giving distances from the center. Our triangle is a thin sliver so AB and BC are essentially parallel. So the point Z is simply a distance x+y from the origin. If x+y>R we fold back down.

    Here's the complete algorithm for R=1. I hope you agree it's pretty simple. It uses trig, but you can give a guarantee on how long it'll take, and how many random() calls it needs, unlike rejection sampling.

    t = 2*pi*random()
    u = random()+random()
    r = if u>1 then 2-u else u
    [r*cos(t), r*sin(t)]
    

    Here it is in Mathematica.

    f[] := Block[{u, t, r},
      u = Random[] + Random[];
      t = Random[] 2 Pi;
      r = If[u > 1, 2 - u, u];
      {r Cos[t], r Sin[t]}
    ]
    
    ListPlot[Table[f[], {10000}], AspectRatio -> Automatic]
    

    enter image description here

    0 讨论(0)
  • 2020-11-22 16:22

    You can also use your intuition.

    The area of a circle is pi*r^2

    For r=1

    This give us an area of pi. Let us assume that we have some kind of function fthat would uniformly distrubute N=10 points inside a circle. The ratio here is 10 / pi

    Now we double the area and the number of points

    For r=2 and N=20

    This gives an area of 4pi and the ratio is now 20/4pi or 10/2pi. The ratio will get smaller and smaller the bigger the radius is, because its growth is quadratic and the N scales linearly.

    To fix this we can just say

    x = r^2
    sqrt(x) = r
    

    If you would generate a vector in polar coordinates like this

    length = random_0_1();
    angle = random_0_2pi();
    

    More points would land around the center.

    length = sqrt(random_0_1());
    angle = random_0_2pi();
    

    length is not uniformly distributed anymore, but the vector will now be uniformly distributed.

    0 讨论(0)
提交回复
热议问题