# Q：在MATLAB随机方向

I am programming in matlab. A point moves using random direction into a circle. When the point reaches the limit of the area, the point must change its angle between 0-180. I can find when the point reaches the limit. But I do not know how to change the angle and continue to the process because when I change angles the point appears at another coordinate (x, y) -- I do not want that. When the point reaches the limit at position (x, y), I want to change the angle and have the point continue from that (x, y).

Here's what I have so far:

``````function [ X ] = random_direction( )
bs = rsmak('circle',500,[0 0]);
fnplt(bs,'b'), axis square;
hold on
magnitud=0;
x=0;
y=0;

base_station(1:10)=struct('id',0,'position_x',0, 'position_y',0);
dis=rand()*500;
angulo=2*pi*rand();
base_station(1).position_x =dis*cos(angulo);
base_station(1).position_y =dis*sin(angulo);
bandera=0;

for i=1:100

magnitud = sqrt(base_station(1).position_x^2+base_station(1).position_y^2);
angulo=atan(base_station(1).position_y/base_station(1).position_x);

if magnitud >= 500
if bandera==0
angulo=2*pi*rand();
end
x=10 * cos(angulo);
y=10 * sin(angulo);

base_station(1).position_x= base_station(1).position_x+x;
base_station(1).position_y=base_station(1).position_y+y;
bandera=1;
end

if magnitud <500 && bandera==0
base_station(1).position_x= base_station(1).position_x+10;
base_station(1).position_y=base_station(1).position_y+10;
end

bs = rsmak('circle',10,[base_station(1).position_x base_station(1).position_y ]);
fnplt(bs,'g'), axis square;
end
end
``````

``````function [ X ] = random_direction( )
bs = rsmak('circle',500,[0 0]);
fnplt(bs,'b'), axis square;
hold on
magnitud=0;
x=0;
y=0;

base_station(1:10)=struct('id',0,'position_x',0, 'position_y',0);
dis=rand()*500;
angulo=2*pi*rand();
base_station(1).position_x =dis*cos(angulo);
base_station(1).position_y =dis*sin(angulo);
bandera=0;

for i=1:100

magnitud = sqrt(base_station(1).position_x^2+base_station(1).position_y^2);
angulo=atan(base_station(1).position_y/base_station(1).position_x);

if magnitud >= 500
if bandera==0
angulo=2*pi*rand();
end
x=10 * cos(angulo);
y=10 * sin(angulo);

base_station(1).position_x= base_station(1).position_x+x;
base_station(1).position_y=base_station(1).position_y+y;
bandera=1;
end

if magnitud <500 && bandera==0
base_station(1).position_x= base_station(1).position_x+10;
base_station(1).position_y=base_station(1).position_y+10;
end

bs = rsmak('circle',10,[base_station(1).position_x base_station(1).position_y ]);
fnplt(bs,'g'), axis square;
end
end
``````

As pointed in some of the comments that have been provided, the two main problems are:

the way the new angle is computed

a bug in the "if" block "if magnitud <500 && bandera==0" in which "x" and "y" are not multiplied by, respectively cos(angulo) and sin(angulo)

A possible solution for the computation of the new angle is adding to "angulo":

pi (180°) just to reverse the trajectory

an random angle offset to differentiate the new trajectory from the previous one to avoid going up and down along the same line)

the angle offset is defined as the product of a fixed angle and a random number between "-0.5 and 0.5".

When the new angle is computed, a validity check is made in order to verify if the new trajectory will "exit" the circle. If so, the sign of the offset angle in changed.

The proposed solution has been implemented in the code that follows.

In the code, the original lines of code modified have been "commented" with "%%%"(three %).

Also, some redundant / uncecessary lines of code have been commented too.

Some features have been also added:

the trajectory markers can be either be plot "interactively" (at each iteratiion") or all together at the end of the functions.

Plotting the trajectory at the end of the script makes the script faster (of course), 30000 iterations are computed in about 1.5 seconds

the trajectoty points are stored in the "X" output varaible

the number of iteration is defined by a parameter

the comments in the script should clarify the modifications.

The script has been tested up to 30000 iterations.

``````function [ X ] = random_direction( )
% updated plot of the circle
%%%bs = rsmak('circle',500,[0 0]);
%%%fnplt(bs,'b'), axis square;
plot([cos([0:.01:2*pi])*500],[sin([0:.01:2*pi])*500],'b')
hold on
daspect([1 1 1])
set(gca,'xlim',[-600 600],'ylim',[-600 600])
grid on

magnitud=0;
x=0;
y=0;

% added interactive plot mode flag:
% interactive=1 plots a mark at each iteraton
% interactive=0 plots the whole trajectory at the end of the run
%               trajectory points are also stored in the X output
%               variable
interactive=0;
% added setting of the number of iterations
n_iterations=30000;
X=zeros(n_iterations,2);

% location from 2 to 10 are not used
base_station(1:10)=struct('id',0,'position_x',0, 'position_y',0);
dis=rand()*500;
angulo=2*pi*rand();
base_station(1).position_x =dis*cos(angulo);
base_station(1).position_y =dis*sin(angulo);
bandera=0;
% off_angle is used when the point has to invert its direction. its
% value is multiplied by (rand_numb -0.5). The desired effect is to
% avoid the point just comes back in the opposite direction
off_angle=120*pi/180;

for i=1:n_iterations

magnitud = sqrt(base_station(1).position_x^2+base_station(1).position_y^2);
% added reset of bandera if magnitud < 500
if(magnitud < 500)
bandera=0;
end
% angulo changes only when magnitud is >= 500, so it does not need
% to be calculated at each iteration
%%%angulo=atan(base_station(1).position_y/base_station(1).position_x);

if magnitud >= 500
if bandera==0
% updated computation of the new angulo
%%%angulo=2*pi*rand();
n_rand=rand();
rand_off_angle=off_angle*(n_rand - 0.5);
% added check for new angle validity
tmp_x=base_station(1).position_x + 10*3 * cos(angulo + pi + rand_off_angle);
tmp_y=base_station(1).position_y + 10*3 * sin(angulo + pi + rand_off_angle);
tmp_d=sqrt(tmp_x^2+tmp_y^2);
if(tmp_d > 500)
rand_off_angle= - rand_off_angle;
end
angulo=angulo + pi + rand_off_angle;
% added check for new angle > 360°
if(angulo > 2*pi)
angulo=angulo-2*pi;
end
end
x=10 * cos(angulo);
y=10 * sin(angulo);

base_station(1).position_x= base_station(1).position_x+x;
base_station(1).position_y=base_station(1).position_y+y;
bandera=1;
end

if magnitud <500 && bandera==0
% positions are respectively multiplied by cos(angulo) and
% sin(angulo)
%%%base_station(1).position_x= base_station(1).position_x+10;
%%%base_station(1).position_y=base_station(1).position_y+10;
base_station(1).position_x= base_station(1).position_x + 10 * cos(angulo);
base_station(1).position_y=base_station(1).position_y + 10  * sin(angulo);
end

% not neede to re-plot the circle at each iteration
%%%bs = rsmak('circle',10,[base_station(1).position_x base_station(1).position_y ]);
%%%fnplt(bs,'g'), axis square;
% check for interactive plot
if(interactive)
plot(base_station(1).position_x , base_station(1).position_y,'xr')
pause(0.001);
end
% added storing of trajectory points
X(i,1)=base_station(1).position_x;
X(i,2)=base_station(1).position_y;
% added "pause" command just to slow down the plot
end
% added plot of trajectory if not interactive has not been selected
if(~interactive)
plot(X(:,1),X(:,2),'r')
end
end
``````

The following images show the results for: 300, 3000, 10000 and 30000 iterations.

Hope this helps.

an random angle offset to differentiate the new trajectory from the previous one to avoid going up and down along the same line)

the trajectory markers can be either be plot "interactively" (at each iteratiion") or all together at the end of the functions.

``````function [ X ] = random_direction( )
% updated plot of the circle
%%%bs = rsmak('circle',500,[0 0]);
%%%fnplt(bs,'b'), axis square;
plot([cos([0:.01:2*pi])*500],[sin([0:.01:2*pi])*500],'b')
hold on
daspect([1 1 1])
set(gca,'xlim',[-600 600],'ylim',[-600 600])
grid on

magnitud=0;
x=0;
y=0;

% added interactive plot mode flag:
% interactive=1 plots a mark at each iteraton
% interactive=0 plots the whole trajectory at the end of the run
%               trajectory points are also stored in the X output
%               variable
interactive=0;
% added setting of the number of iterations
n_iterations=30000;
X=zeros(n_iterations,2);

% location from 2 to 10 are not used
base_station(1:10)=struct('id',0,'position_x',0, 'position_y',0);
dis=rand()*500;
angulo=2*pi*rand();
base_station(1).position_x =dis*cos(angulo);
base_station(1).position_y =dis*sin(angulo);
bandera=0;
% off_angle is used when the point has to invert its direction. its
% value is multiplied by (rand_numb -0.5). The desired effect is to
% avoid the point just comes back in the opposite direction
off_angle=120*pi/180;

for i=1:n_iterations

magnitud = sqrt(base_station(1).position_x^2+base_station(1).position_y^2);
% added reset of bandera if magnitud < 500
if(magnitud < 500)
bandera=0;
end
% angulo changes only when magnitud is >= 500, so it does not need
% to be calculated at each iteration
%%%angulo=atan(base_station(1).position_y/base_station(1).position_x);

if magnitud >= 500
if bandera==0
% updated computation of the new angulo
%%%angulo=2*pi*rand();
n_rand=rand();
rand_off_angle=off_angle*(n_rand - 0.5);
% added check for new angle validity
tmp_x=base_station(1).position_x + 10*3 * cos(angulo + pi + rand_off_angle);
tmp_y=base_station(1).position_y + 10*3 * sin(angulo + pi + rand_off_angle);
tmp_d=sqrt(tmp_x^2+tmp_y^2);
if(tmp_d > 500)
rand_off_angle= - rand_off_angle;
end
angulo=angulo + pi + rand_off_angle;
% added check for new angle > 360°
if(angulo > 2*pi)
angulo=angulo-2*pi;
end
end
x=10 * cos(angulo);
y=10 * sin(angulo);

base_station(1).position_x= base_station(1).position_x+x;
base_station(1).position_y=base_station(1).position_y+y;
bandera=1;
end

if magnitud <500 && bandera==0
% positions are respectively multiplied by cos(angulo) and
% sin(angulo)
%%%base_station(1).position_x= base_station(1).position_x+10;
%%%base_station(1).position_y=base_station(1).position_y+10;
base_station(1).position_x= base_station(1).position_x + 10 * cos(angulo);
base_station(1).position_y=base_station(1).position_y + 10  * sin(angulo);
end

% not neede to re-plot the circle at each iteration
%%%bs = rsmak('circle',10,[base_station(1).position_x base_station(1).position_y ]);
%%%fnplt(bs,'g'), axis square;
% check for interactive plot
if(interactive)
plot(base_station(1).position_x , base_station(1).position_y,'xr')
pause(0.001);
end
% added storing of trajectory points
X(i,1)=base_station(1).position_x;
X(i,2)=base_station(1).position_y;
% added "pause" command just to slow down the plot
end
% added plot of trajectory if not interactive has not been selected
if(~interactive)
plot(X(:,1),X(:,2),'r')
end
end
``````

matlab