# Running my code in a loop to make it more efficient

1 view (last 30 days)
Adil Saeed on 12 Jul 2022
Commented: Karim on 14 Jul 2022
x0 = 0;
y0 = 0;
Sr = [x0 y0]; %Source coordinates
SL = 220; %Source Level
a = 0.25; %Attenuation
IL = 180; %Impact Level
v = 2; %speed
t = 5; %seconds
s = v*t; %metres
n = 5;
I am modelling a flee response based on random initial 2D coordinated positions.
z = [randi([-10 10],1,n); randi([-10 10],1,n)]';
This produces a 5x2 matrix with x and y values being equal to shown below
x = z(:,1);
y = z(:,2);
I have calculated the distance between each coordinate in the matrix and the source at the origin to produce a 5x1 matrix.
d = sqrt((x-x0).^2+(y-y0).^2);
r = d;
From this a Transmission Loss (TL) can be calculated from the source to the position
TL = 20*log10(r) + a*r;
And the Recieive Level (RL) at this position can be calculated
RL = SL - TL;
This value of RL is compared to the Impact Level (IL) and if RL is higher than IL the model run agains.
To calculate the next position, assuming a flee response the gradient will remain the same along the line. This produces a 5x1 matrix
m = (y-y0)./(x-x0);
To calculate the new coordinates of the new position, a 5x2 matrix
z = [x,y] + diag(s./sqrt(1+m.^2))*[ones(size(x)),m];
Again where the x and y values
x = z(:,1);
y = z(:,2);
The new distance between the positions can be calculated using speed and time, therefore
r2 = r + s;
A side note; as he position changes, its the previous distance plus s (i.e. r3 = r2 + s, r4 = r3 +s)
Calculating TL at the new position
TL2 = 20*log10(r2) + a*r2;
Calculating RL at the new position
RL2 = SL - TL2;
Compare this RL to the IL.
The problem is, I can keep coding my model in this way and keep repeating however this is not very efficient and if conditions such as n, SL or IL change, this method will become very messy and i will not know how many times this loop needs to be run for.
Therfore i need a loop to run this code, until RL is lower than IL, but also be able to change n and caculate RL at each of these positions every 's' distance away. I would like RL to be stored to be used further along, and then also use the new position coordinates onto a plot, showcasing the flee response. I have included my current code below to show how i have done this.
x0 = 0;
y0 = 0;
Sr = [x0 y0]; %Source coordinates
SL = 220; %Source Level
a = 0.25; %Attenuation
IL = 180; %Impact Level
v = 2; %Speed
t = 5; %seconds
s = v*t; %metres
n = 5;
z1 = [randi([-10 10],1,n); randi([-10 10],1,n)]';
x1 = z1(1:n,1); %this shows the first 5 numbers in column 1
y1 = z1(1:n,2); %this shows the first 5 numbers in column 2
negative_values = x1<0;
x1(negative_values) = -1*x1(negative_values); %convert negative x values to positives
d = sqrt((x1-x0).^2+(y1-y0).^2); %Pythagoras Theorem for distance between the 2 (Source and Reciever) points
m = (y1-y0)./(x1-x0); %Gradient between the points
r1 = d;
TL1 = 20*log10(r1) + a*r1; %Transmission Loss
RL1 = SL - TL1; %Recieve Level
if RL1 < IL
disp('No Impact')
else
disp('Impact')
end
Impact
z2 = [x1,y1] + diag(s./sqrt(1+m.^2))*[ones(size(x1)),m]; %New coordinates for new positions 5s later at a speed of 1.5m/s
x2 = z2(1:n,1);
y2 = z2(1:n,2);
r2 = d + s; %distance from source to new receive position
TL2 = 20*log10(r2) + a*r2;
RL2 = SL - TL2;
if RL2 < IL
disp('No Impact')
else
disp('Impact')
end
Impact
z3 = [x2,y2] + diag(s./sqrt(1+m.^2))*[ones(size(x1)),m];
x3 = z3(1:n,1);
y3 = z3(1:n,2);
r3 = d + 2*s;
TL3 = 20*log10(r3) + a*r3;
RL3 = SL - TL3;
if RL3 < IL
disp('No Impact')
else
disp('Impact')
end
Impact
z4 = [x3,y3] + diag(s./sqrt(1+m.^2))*[ones(size(x1)),m];
x4 = z4(1:n,1);
y4 = z4(1:n,2);
r4 = d + 3*s;
TL4 = 20*log10(r4) + a*r4;
RL4 = SL - TL4;
if RL4 < IL
disp('No Impact')
else
disp('Impact')
end
Impact
z5 = [x4,y4] + diag(s./sqrt(1+m.^2))*[ones(size(x1)),m];
x5 = z5(1:n,1);
y5 = z5(1:n,2);
r5 = d + 4*s;
TL5 = 20*log10(r5) + a*r5;
RL5 = SL - TL5;
if RL5 < IL
disp('No Impact')
else
disp('Impact')
end
No Impact
X1 = [x1 x2 x3 x4 x5]';
Y1 = [y1 y2 y3 y4 y5]';
X1(:,negative_values) = -1*X1(:,negative_values);
figure
hold on;
plot(X1,Y1, '-*')
title('Flee Response')
xlabel('distance (m)')
ylabel('distance (m)')
ax = gca; %the change of the axes location to origin
ax.XAxisLocation = 'origin';
ax.YAxisLocation = 'origin'; Karim on 12 Jul 2022
Edited: Karim on 13 Jul 2022
You can create a for loop, and just save the variables directly into matrices, see below for an example with 10 iterations and 7 flees. I tried no to change the algorithm as you implemented it, however, the bit with the 'negative_values' is a bit weird at first glance.
x0 = 0;
y0 = 0;
Sr = [x0 y0]; %Source coordinates
SL = 220; %Source Level
a = 0.25; %Attenuation
IL = 180; %Impact Level
v = 2; %Speed
t = 5; %seconds
s = v*t; %metres
n = 7;
iter = 10;
X = zeros(iter,n);
Y = zeros(iter,n);
% currZ(:,1) --> this stores the x coordinates
% currZ(:,2) --> this stores the y coordinates
for i = 1:iter
if i == 1
% starting condition - random position start
currZ = [randi([-10 10],n,1) randi([-10 10],n,1)];
negative_values = currZ(:,1) < 0;
currZ(negative_values,1) = -1*currZ(negative_values,1); % convert negative x values to positives
d = sqrt((currZ(:,1)-x0).^2+(currZ(:,2)-y0).^2); % Pythagoras Theorem for distance between the 2 (Source and Reciever) points
m = (currZ(:,2)-y0)./(currZ(:,1)-x0); %Gradient between the points
else
% update with speed
currZ = currZ + diag(s./sqrt(1+m.^2))*[ones(n,1),m]; % New coordinates for new positions 5s later at a speed of 1.5m/s
end
r = d + (i-1)*s;
TL = 20*log10(r) + a*r; %Transmission Loss
RL = SL - TL; %Recieve Level
if RL < IL
disp('No Impact')
else
disp('Impact')
end
% save result
X(i,:) = currZ(:,1);
Y(i,:) = currZ(:,2);
end
Impact Impact Impact Impact
No Impact No Impact No Impact No Impact No Impact No Impact
X(:,negative_values) = -1*X(:,negative_values);
figure
plot(X,Y, '-*')
title('Flee Response')
xlabel('distance (m)')
ylabel('distance (m)')
ax = gca; %the change of the axes location to origin
ax.XAxisLocation = 'origin';
ax.YAxisLocation = 'origin'; Karim on 14 Jul 2022
Before the loop starts, place:
RL = zeros( n ,iter );
inside the loop change the RL lines into:
RL(:,i) = SL - TL; % Recieve Level
if RL(:,i) < IL
This way you create a matrix where each column stores the result of an iteration.