Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate a uniformly random point within an annulus (ring) [duplicate]

Possible Duplicate:
Create random number within an annulus

I would like to obtain a uniformly obtained random point within an annulus, that is, the area that lies inside a circle of radius R1, but outside a circle of radius R2, where R1 > R2 and both circles are centered at the same point. I would like to avoid using rejection sampling.

If possible, I would like the solution to be similar to this one —used for calculating random points within a circle— which I find it extremely elegant and intuitive. That is, I would also like to avoid using the square root.

like image 961
Ricardo Sanchez-Saez Avatar asked Oct 25 '12 08:10

Ricardo Sanchez-Saez


3 Answers

Its very easy. Use polar coordinates, i.e. you generate one random value for the angular value theta, and one for the distance from the origin. As your circles are both at the same origin this gets very easy.

BUT ATTENTION: you can generate the theta value by a uniform random function, that is fine, but for the distance you cant do that, as then the points will cluster around the origin. You have to take into consideration that the perimeter of a circle grows in ^2 (you have to use the inverse which is the square root).

Using a uniform distributed random function rnd (0..1) it would be like this:

theta = 360 * rnd();
dist = sqrt(rnd()*(R1^2-R2^2)+R2^2);

EDIT: For conversion into cartesion coordinates, you just compute:

x =  dist * cos(theta);
y =  dist * sin(theta);
like image 157
flolo Avatar answered Nov 18 '22 00:11

flolo


EDIT: Please note that this solution might not be uniform. See comments by Mark Dickinson below.

Ok, I think I figured it out. Note that this solution is heavily inspired in this answer, and that r1 = R1/R1 and r2 = R2/R1.

Pseudo-code:

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

Here it is in Mathematica.

f[] := Block[{u, t, r}, u = Random[] + Random[];
r1 = 1; r2 = 0.3;
t = Random[] 2 Pi;
r = If[u > 1, 2 - u, u];
r = If[r < r2, r2 + r*((R1 - R2)/R2), r];
{r Cos[t], r Sin[t]}]

ListPlot[Table[f[], {10000}], AspectRatio -> Automatic]

Distribution of the simple algorithm

What it does is to remap all the numbers falling inside the inner circle into the annulus, spreading them evenly. If somebody finds a problem regarding the uniformity of this solution please comment.

Compare with this other solution found here:

Distribution of the sqrt algorithm

like image 26
Ricardo Sanchez-Saez Avatar answered Nov 17 '22 22:11

Ricardo Sanchez-Saez


The easiest way to do this is to use rejection sampling. Generate a large number of points uniformly in a square of side length 2*R2, then filter those samples to those inside the outer circle and not in the inner circle.

Not pretty or efficient, but in most cases, sufficient.

like image 1
Andrew Walker Avatar answered Nov 18 '22 00:11

Andrew Walker