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.
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);
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]
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With