Projectile Motion using ode45 in Matlab - matlab

I'm trying to model projectile motion with drag in Matlab. Everything works perfectly....except I can't figure out how to get it to stop when the "bullet" hits the ground.
I initially tried an iteration loop, defining a data array, and emptying cells of that array for when the y value was negative....unfortunately the ode solver didn't like that too much.
Here is my code
function [ time , x_position , y_position ] = shell_flight_simulator(m,D,Ve,Cd,ElAng)
rho=1.2; % kg/m^3
g=9.84; % acceleration due to gravity
A = pi.*(D./2).^2; % m^2, shells cross-sectional area (area of circle)
function [lookfor,stop,direction] = linevent(t,y);
% stop projectile when it hits the ground
lookfor = y(1); %Sets this to 0
stop = 1; %Stop when event is located
direction = -1; %Specify downward direction
options = odeset('Events',#event_function); % allows me to stop integration at an event
function fvec = projectile_forces(x,y)
vx=y(2);
vy=y(4);
v=sqrt(vx^2+vy^2);
Fd=1/2 * rho * v^2 * Cd * A;
fvec(1) = y(2);
fvec(2) = -Fd*vx/v/m;
fvec(3) = y(4);
fvec(4) = -g -Fd*vy/v/m;
fvec=fvec.';
end
tspan=[0, 90]; % time interval of interest
y0(1)=0; % initial x position
y0(2)=Ve*cos(ElAng); % vx
y0(3)=0; % initial y position
y0(4)=Ve*sin(ElAng); % vy
% using matlab solver
[t,ysol] = ode45(#projectile_forces, tspan, y0);
end
end
x = ysol(:,1);
vx = ysol(:,2);
y = ysol(:,3);
vy = ysol(:,4);
plot(x,y, 'r-');
xlabel('X Position (m)');
ylabel('Y Position (m)');
title ('Position Over Time');
end
I thought this would define an event when y=0 and stop the projectile, but it doesn't do anything. What am I doing wrong?

When trying to find the time at which the solution to the ODE reaches a certain level you should use an
Events function - see the BALLODE demo for an example that stops the solution process when one of the components of the solution reaches 0.

Related

How to correctly use ode45 function in MATLAB for differential drive robot?

I am trying to determine the pose (x,y,theta) of a differential drive robot using ode45. The code I have below solves for the x position, but I am having an issue with the initial condition. I set it to 0 since at time 0 the robot is assumed to be at the origin, but I get an error. How do I set the initial condition for ode45 such that I get the expected output?
I tried to make the initial conditions vector of the same length as dxdt by setting initial conditions as a 41x1 zeros matrix, but I didn't understand the output and I don't believe I did it correctly.
% Given conditions for a differential drive robot:
B = 20; % (cm) distance along axle between centers of two wheels
r = 10; % (cm) diameter of both wheels
w_l = 5*sin(3*t); % (rad/s) angular rate of left wheel
w_r = 5*sin(3*t); % (rad/s) angular rate of right wheel
v_l = r*w_l; % (cm/s) velocity of left wheel
v_r = r*w_r; % (cm/s) velocity of right wheel
v = (v_r+v_l)/B; % (cm/s) velocity of robot
theta = 90; % constant orientation of robot since trajectory is straight
% Solve differential equation for x:
dxdt = v*cos(theta); % diff equaition for x
tspan = [0 20]; % time period to integrate over
x0 = 0; % initial condition since robot begins at origin
[t,x] = ode45(#(t,y) dxdt, tspan, x0);
I want to solve the differential equation dxdt for 0 to 20 seconds with an initial condition of 0. I expect the output to give me a vector of time from 0 to 20 and an array of for x. The problem I believe lies with the initial condition. MATLAB gives me an error in the live editor telling me, " #(t,y)dxdt returns a vector of length 69, but the length of initial conditions vector is 1. The vector returned by #(t,y)dxdt and the initial conditions vector must have the same number of elements."
The issue is not the initial condition. You need to define dxdt as a function i.e.
% Define differential equation
function derivative = dxdt(t,y)
% Given conditions for a differential drive robot:
B = 20; % (cm) distance along axle between centers of two wheels
r = 10; % (cm) diameter of both wheels
w_l = 5*sin(3*t); % (rad/s) angular rate of left wheel
w_r = 5*sin(3*t); % (rad/s) angular rate of right wheel
v_l = r*w_l; % (cm/s) velocity of left wheel
v_r = r*w_r; % (cm/s) velocity of right wheel
v = (v_r+v_l)/B; % (cm/s) velocity of robot
theta = 90; % constant orientation of robot since trajectory is straight
derivative = v*cos(theta); % diff equation for x
end
Then when you use ode45 you should tell it to pass the t and y variables as arguments to dxdt like
[t,x] = ode45(#(t,y) dxdt(t,y), tspan, x0);
This should then work. In this case, as dxdt only takes the default arguments, you could also write
[t,x] = ode45(#dxdt, tspan, x0);
The error you got indicates that at some point you made dxdt into a vector of length 69, whilst MATLAB was expecting to get back 1 value for dxdt when it passed one t and one y to your dxdt 'function'. Whenever you get errors like this, I'd recommend putting
clear all
`clearvars` % better than clear all - see am304's comment below
at the top of your script to avoid polluting your workspace with previously defined variables.

How to make animation of aircraft trajectory during flight in Matlab 2015b?

I have a flying aircraft in Matlab.
I want to make animation of its trajectory during flight like it is leaving trace behind.
I tried to use animatedline function if Matlab, but I'm just stuck here. My function just displays only сoordinate axes and nothing more.
Coordinates of aircraft are entering during flight from Simulink model.
Please, help me!
function trajectory(uu)
pn = uu(1); % inertial North position
pe = uu(2); % inertial East position
pd = uu(3); % inertial Down position
t = uu(4); % time
if t==0,
figure(10), clf
S = 1500;
view(0,90)
axis([-S,S,-S,S,-.1, S]);
grid on
drawnow
else
h = animatedline;
x=pe, y=pn; z=-pd;
addpoints (h, x, y, z);
drawnow
end
You are trying to plot using the handle h, but it gets destroyed at the end of the function call. I propose the following solution,
% Function
function trajectory(uu, hLine)
pn = uu(1); % inertial North position
pe = uu(2); % inertial East position
pd = uu(3); % inertial Down position
x = pe; y = pn; z = -pd;
addpoints (hLine, x, y, z);
drawnow
end
% script
figure(10);
S = 1500;
view(0,90)
axis([-S, S, -S, S, -.1, S]);
grid on
lineHandle = animatedline('Color','r','LineWidth',3);
for i = 1:nPoints
% replace this with your value
currentValue = 1000*rand(1, 4);
trajectory(currentValue, lineHandle);
end

if statement in MATLAB for plotting the height of a ball

I am using MATLAB to calculate the height of a ball in case of projectile motion. Here is my code :
v = 10;
teta = 20; % angle of the projectile motion
vx = v*cos(teta); % velocity in x axis
vy = v*sin(teta); % velocity in y axis
x = 0:10;
y = zeros(length(x),1);
for xx=1:length(x)
% here I calculate the height of the ball in y axis
y(xx,:) = vy*(xx/vx)-(0.5*9.81*(xx./vx)^2);
% here I want to break the system when the height of the ball is
% zero (on the ground surface)
if y(xx,:) == 0
break
end
end
plot(x,y, '*')
The problem that when I plot the motion it does not stop when the height is zero
but it continues for negative values of y axis ..
What is the wrong in my if-statement?
You should never compare a float or double number to an integer. When you say if y(xx,:)== 0 you are breaking the loop only when the height is exactly zero, and that will never happen (just see the values stored in y).
If you want to keep your data from been negative, you should try if y(xx,:) < 0. Keep in mind that if you use this approach, you should always delete the last value added to y, because when that statement breaks you loop, you've already stored the first negative value. So, just add y(xx)= 0; before the break line.
<teacher_mode>
What I would do is use constant time increments rather than using constant x increments. This is not only more intuitive, but also provides a much better building block for if you'd want to level up in the future. This approach makes it easier to include additional effects (like airdrag, 3D, bounces, ...) and is a stepping stone towards more advanced methods to do these computations (numerical integration of the vector-valued equations of motion; see ode45 in MATLAB for some examples).
Here is an example of a "bouncy" ball:
v = 100; % initial speed
theta = 20; % initial angle (°) with X-axis
vx = v * cosd(theta); % initial velocity in x axis
vy = v * sind(theta); % initial velocity in y axis
T = 0 : 0.01 : 50; % times to sample
x = zeros(length(T),1);
y = zeros(length(T),1);
ay = -9.80665; % gravity
ax = 0; % ...wind perhaps
ex = 0.9; % elasticity in X-direction
ey = 0.5; % elasticity in Y-direction
for ii = 2:numel(T)
% Update time step
dt = T(ii) -T(ii-1);
% Update speed
vx = vx + ax*dt;
vy = vy + ay*dt;
% Update position
x(ii) = x(ii-1) + [vx ax/2] * dt.^(1:2)';
y(ii) = y(ii-1) + [vy ay/2] * dt.^(1:2)';
% Bounce the ball!
if y(ii) <= 0
y(ii) = 0;
vx = ex* vx;
vy = abs( ey*vy );
end
end
clf, hold on
plot(x,y)
</teacher_mode>
You can avoid for loop at all:
v=10;
theta=20; % angle of the projectile motion
vx=v*cos(theta); % velocity in x axis
vy=v*sin(theta); % velocity in y axis
x=0:0.1:10;
y=zeros(size(x));
y=vy.*(x./vx)-(0.5*9.81*(x./vx).^2); %% Calculate values for all x
x=x(y>=0); %% keep the x values where y>=0
y=y(y>=0); %% keep the y valuse where y>=0
plot(x,y,'*')

Find maxima on a surf plot using Particle Swarm Optimization

I'm new to Particle swarm optimization.
I have a surf plot of a 2D image as shown below:
And is it possible to fire up the particles randomly and make them find the maxima (global)?
If yes, Can anyone please provide an algorithm or a sample code.
Thank you.
EDIT:
Did some coding and got the answer, for a small number of iterations like 10-15 the particles swarm at the maxima but if the iterations are made more than 15 like 50 etc, the particles move away from the maxima.
Can someone give a solution for it, I've included the matlab code and a sample image:
img = imread('gray_scale_img.jpg');
%img is grayscale
a=10; b=0.2; %a is convergence and b is convergence rate
% range=[xmin xmax ymin ymax zmin zmax];
range=[0 440 0 228 0 255]; %<<<---size of the image
Num_iterations = 15;%<<<----problem exists if more iterations
n = 30; % number of particles
best=zeros(Num_iterations,3);
% ----- Start Particle Swarm Optimization -----------
% generating the initial locations of n particles
xrange=range(2)-range(1);
yrange=range(4)-range(3);
zrange=range(6)-range(5);
xn=(rand(1,n)*xrange+range(1));
yn=(rand(1,n)*yrange+range(3));
% Start iterations
for k=1:Num_iterations,
% Show the contour of the function
surfc(double(img)); hold on;
% Find the current best location (xo,yo)
for d = 1:n
xn = ceil(xn);
yn = ceil(yn);
zn(d)=img(yn(d),xn(d));
end
zn_min=max(max(zn));
xo=max(max(xn(zn==zn_min)));
yo=max(max(yn(zn==zn_min)));
zo=max(max(zn(zn==zn_min)));
% Trace the paths of all roaming particles
% Display these roaming particles
plot3(xn,yn,zn,'.',xo,yo,zo,'rp'); axis(range);
% Move all the particles to new locations
nn=size(yn,2); %a=alpha, b=beta
xn=xn.*(1-b)+xo.*b+a.*(rand(1,nn)-0.5);
yn=yn.*(1-b)+yo.*b+a.*(rand(1,nn)-0.5);
%zn=zn.*(1-b)+zo.*b+a.*(rand(1,nn)-0.5);
%To make sure the particles are well within the range
nn=length(yn);
for l=1:nn,
if xn(l)<=range(1), xn(l)=range(1); end
if xn(l)>=range(2), xn(l)=range(2); end
if yn(l)<=range(3), yn(l)=range(3); end
if yn(l)>=range(4), yn(l)=range(4); end
%if zn(l)<=range(5), yn(l)=range(5); end
%if zn(l)>=range(6), yn(l)=range(6); end
end
drawnow;
hold off;
best(k,1)=xo; best(k,2)=yo; best(k,3)=zo;pause(0.2);
end %%%%% end of iterations
x_best = best(k,1);
y_best = best(k,2);
z_best = best(k,3);
global_maxima_coordinate =[x_best,y_best]
figure(3);
imshow(A,[]);
hold on
plot(x_best, y_best, 'bx')
% Draw circle of required radius around the global maxima
theta = 0:pi/50:2*pi;
radius_1 = 15;
xunit_circle_1 = radius_1 * cos(theta) + x_best;
yunit_circle_1 = radius_1 * sin(theta) + y_best;
h_1 = plot(xunit_circle_1, yunit_circle_1,'r');
hold off
title('Global maxima');
Did some coding and got the answer, for a small number of iterations like 10-15 the particles swarm at the maxima but if the iterations are made more than 15 like 50 etc, the particles move away from the maxima.
Can someone give a solution for it, I've included the matlab code and a sample image:
img = imread('gray_scale_img.jpg');
%img is grayscale
a=10; b=0.2; %a is convergence and b is convergence rate
% range=[xmin xmax ymin ymax zmin zmax];
range=[0 440 0 228 0 255]; %<<<---size of the image
Num_iterations = 15;%<<<----problem exists if more iterations
n = 30; % number of particles
best=zeros(Num_iterations,3);
% ----- Start Particle Swarm Optimization -----------
% generating the initial locations of n particles
xrange=range(2)-range(1);
yrange=range(4)-range(3);
zrange=range(6)-range(5);
xn=(rand(1,n)*xrange+range(1));
yn=(rand(1,n)*yrange+range(3));
% Start iterations
for k=1:Num_iterations,
% Show the contour of the function
surfc(double(img)); hold on;
% Find the current best location (xo,yo)
for d = 1:n
xn = ceil(xn);
yn = ceil(yn);
zn(d)=img(yn(d),xn(d));
end
zn_min=max(max(zn));
xo=max(max(xn(zn==zn_min)));
yo=max(max(yn(zn==zn_min)));
zo=max(max(zn(zn==zn_min)));
% Trace the paths of all roaming particles
% Display these roaming particles
plot3(xn,yn,zn,'.',xo,yo,zo,'rp'); axis(range);
% Move all the particles to new locations
nn=size(yn,2); %a=alpha, b=beta
xn=xn.*(1-b)+xo.*b+a.*(rand(1,nn)-0.5);
yn=yn.*(1-b)+yo.*b+a.*(rand(1,nn)-0.5);
%zn=zn.*(1-b)+zo.*b+a.*(rand(1,nn)-0.5);
%To make sure the particles are well within the range
nn=length(yn);
for l=1:nn,
if xn(l)<=range(1), xn(l)=range(1); end
if xn(l)>=range(2), xn(l)=range(2); end
if yn(l)<=range(3), yn(l)=range(3); end
if yn(l)>=range(4), yn(l)=range(4); end
%if zn(l)<=range(5), yn(l)=range(5); end
%if zn(l)>=range(6), yn(l)=range(6); end
end
drawnow;
hold off;
best(k,1)=xo; best(k,2)=yo; best(k,3)=zo;pause(0.2);
end %%%%% end of iterations
x_best = best(k,1);
y_best = best(k,2);
z_best = best(k,3);
global_maxima_coordinate =[x_best,y_best]
figure(3);
imshow(A,[]);
hold on
plot(x_best, y_best, 'bx')
% Draw circle of required radius around the global maxima
theta = 0:pi/50:2*pi;
radius_1 = 15;
xunit_circle_1 = radius_1 * cos(theta) + x_best;
yunit_circle_1 = radius_1 * sin(theta) + y_best;
h_1 = plot(xunit_circle_1, yunit_circle_1,'r');
hold off
title('Global maxima');
And here is a sample image:

Matlab Animation

I'm currently trying to animate a particle in 2D obeying a system of ODEs. I currently have the code below, based on examples online, but I really don't know how to proceed.
If anyone could offer assistance, I'd be most appreciative.
function Animation()
% Solving the systemP1 using ode45
sol=ode45(#systemP1,[0,0.0001],[10e-7,-1,10e-7,-1]);
t = linspace(0,0.0001)
p = deval(sol,t);
% Xposition
x = p(1,:)';
xdot = p(2,:)' ;
% Yposition
y = p(3,:)';
ydot = p(4,:)' ;
position = [x, y];
% Trajectory of the particle
path = plot(position(1,1), position(1,2),'k');
end
You almost have it correct. What you can do is put the plot in a for loop and plot each point individually. That way, you can see how the point moves in a more "real-time" sense. Make sure that at end of the for loop, add drawnow at the end of the iteration. It forces MATLAB to empty the graphic event queue. I also add pause at the end as well just in case the drawing goes too fast.
Make sure you have a hold on statement at the beginning before the for loop. I would also recommend freezing the axis to prevent auto scaling the axis when a new point is being the added. As such, your code would be modified to be:
function Animation()
% Solving the systemP1 using ode45
sol=ode45(#systemP1,[0,0.0001],[10e-7,-1,10e-7,-1]);
t = linspace(0,0.0001)
p = deval(sol,t);
% Xposition
x = p(1,:)';
xdot = p(2,:)' ;
% Yposition
y = p(3,:)';
ydot = p(4,:)' ;
position = [x, y];
%// Modifications start here
figure(1);
hold on;
%// Find limits of x and y axes
minX = min(x);
maxX = max(x);
minY = min(y);
maxY = max(y);
%// Prevent axis from auto-scaling
axis([minX maxX minY maxY]);
axis manual;
%//Plot each position vector over time
for idx = 1 : size(position,1)
%//Trajectory of the particle
plot(position(idx,1), position(idx,2),'k.', 'MarkerSize', 18);
pause(0.1); %// Pause 0.1 seconds to slow things down. Remove if necessary
drawnow;
end
end
The MarkerSize parameter changes the size of each point. I set it to 18 as it looks large enough on my machine. Make this larger or smaller according to your preference. I don't see why xdot and ydot are defined, so I left it out of the code. However, if you want to use these, basically replicate the same code I have above but for xdot and ydot. If you'd like me to do this for you, let me know in a comment and I'll modify my post.
Note
This post was inspired by Luis Mendo's post on plotting objects as animation. That post can be found here: Octave plot points as animation