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,'*')
Related
I have to plot the speed vector of an object orbiting around a central body. This is a Keplerian context. The trajectory of object is deduced from the classical formula ( r = p/(1+e*cos(theta)) with e=eccentricity.
I manage into plotting the elliptical orbit but now, I would like to plot for each point of this orbit the velocity speed of object.
To compute the velocity vector, I start from classical formulas (into polar coordinates), below the 2 components :
v_r = dr/dt and v_theta = r d(theta)/dt
To take a time step dt, I extract the mean anomaly which is proportional to time.
And Finally, I compute the normalization of this speed vector.
clear % clear variables
e = 0.8; % eccentricity
a = 5; % semi-major axis
b = a*sqrt(1-e^2); % semi-minor axis
P = 10 % Orbital period
N = 200; % number of points defining orbit
nTerms = 10; % number of terms to keep in infinite series defining
% eccentric anomaly
M = linspace(0,2*pi,N); % mean anomaly parameterizes time
% M varies from 0 to 2*pi over one orbit
alpha = zeros(1,N); % preallocate space for eccentric anomaly array
%%%%%%%%%%
%%%%%%%%%% Calculations & Plotting
%%%%%%%%%%
% Calculate eccentric anomaly at each point in orbit
for j = 1:N
% initialize eccentric anomaly to mean anomaly
alpha(j) = M(j);
% include first nTerms in infinite series
for n = 1:nTerms
alpha(j) = alpha(j) + 2 / n * besselj(n,n*e) .* sin(n*M(j));
end
end
% calcualte polar coordiantes (theta, r) from eccentric anomaly
theta = 2 * atan(sqrt((1+e)/(1-e)) * tan(alpha/2));
r = a * (1-e^2) ./ (1 + e*cos(theta));
% Compute cartesian coordinates with x shifted since focus
x = a*e + r.*cos(theta);
y = r.*sin(theta);
figure(1);
plot(x,y,'b-','LineWidth',2)
xlim([-1.2*a,1.2*a]);
ylim([-1.2*a,1.2*a]);
hold on;
% Plot 2 focus = foci
plot(a*e,0,'ro','MarkerSize',10,'MarkerFaceColor','r');
hold on;
plot(-a*e,0,'ro','MarkerSize',10,'MarkerFaceColor','r');
% compute velocity vectors
for i = 1:N-1
vr(i) = (r(i+1)-r(i))/(P*(M(i+1)-M(i))/(2*pi));
vtheta(i) = r(i)*(theta(i+1)-theta(i))/(P*(M(i+1)-M(i))/(2*pi));
vrNorm(i) = vr(i)/norm([vr(i),vtheta(i)],1);
vthetaNorm(i) = vtheta(i)/norm([vr(i),vtheta(i)],1);
end
% Plot velocity vector
quiver(x(30),y(30),vrNorm(30),vthetaNorm(30),'LineWidth',2,'MaxHeadSize',1);
% Label plot with eccentricity
title(['Elliptical Orbit with e = ' sprintf('%.2f',e)]);
Unfortunately, once plot performed, it seems that I get a bad vector for speed. Here for example the 30th element of vrNorm and vthetaNorm arrays :
As you can see, the vector has the wrong direction (If I assume to take 0 for theta from the right axis and positive variation like into trigonometrics).
If someone could see where is my error, this would nice.
UPDATE 1: Has this vector representing the speed on elliptical orbit to be tangent permanently to the elliptical curve ?
I would like to represent it by taking the right focus as origin.
UPDATE 2:
With the solution of #MadPhysicist, I have modified :
% compute velocity vectors
vr(1:N-1) = (2*pi).*diff(r)./(P.*diff(M));
vtheta(1:N-1) = (2*pi).*r(1:N-1).*diff(theta)./(P.*diff(M));
% Plot velocity vector
for l = 1:9 quiver(x(20*l),y(20*l),vr(20*l)*cos(vtheta(20*l)),vr(20*l)*sin(vtheta(20*l)),'LineWidth',2,'MaxHeadSize',1);
end
% Label plot with eccentricity
title(['Elliptical Orbit with e = ' sprintf('%.2f',e)]);
I get the following result :
On some parts of the orbit, I get wrong directions and I don't understand why ...
There are two issues with your code:
The normalization is done incorrectly. norm computes the generalized p-norm for a vector, which defaults to the Euclidean norm. It expects Cartesian inputs. Setting p to 1 means that it will just return the largest element of your vector. In your case, the normalization is meaningless. Just set vrNorm as
vrNorm = vr ./ max(vr)
It appears that you are passing in the polar coordinates vrNorm and vthetaNorm to quiver, which expects Cartesian coordinates. It's easy to make the conversion in a vectorized manner:
vxNorm = vrNorm * cos(vtheta);
vyNorm = vrNorm * sin(vtheta);
This assumes that I understand where your angle is coming from correctly and that vtheta is in radians.
Note
The entire loop
for i = 1:N-1
vr(i) = (r(i+1)-r(i))/(P*(M(i+1)-M(i))/(2*pi));
vtheta(i) = r(i)*(theta(i+1)-theta(i))/(P*(M(i+1)-M(i))/(2*pi));
vrNorm(i) = vr(i)/norm([vr(i),vtheta(i)],1);
vthetaNorm(i) = vtheta(i)/norm([vr(i),vtheta(i)],1);
end
can be rewritten in a fully vectorized manner:
vr = (2 * pi) .* diff(r) ./ (P .* diff(M))
vtheta = (2 * pi) .* r .* diff(theta) ./ (P .* diff(M))
vrNorm = vr ./ max(vr)
vxNorm = vrNorm * cos(vtheta);
vyNorm = vrNorm * sin(vtheta);
Note 2
You can call quiver in a vectorized manner, on the entire dataset, or on a subset:
quiver(x(20:199:20), y(20:199:20), vxNorm(20:199:20), vyNorm(20:199:20), ...)
I'm trying to plot the following equation (let's call it "Equation 1"):
This is the code I'm testing:
clear all;
xl=0; xr=1; % x domain [xl,xr]
J = 10; % J: number of division for x
dx = (xr-xl) / J; % dx: mesh size
tf = 0.1; % final simulation time
Nt = 60; % Nt: number of time steps
dt = tf/Nt/4;
x = xl : dx : xr; % generate the grid point
u_ex = zeros(J+1,Nt);
for n = 1:Nt
t = n*dt; % current time
for j=1:J+1
xj = xl + (j-1)*dx;
suma = zeros(100 , 1);
for k= 1:100
suma(k) = 4/(((2*k-1)^2) *pi*pi);
suma(k) = suma(k) * exp(-((2*k-1)^2) *pi*pi*t) * cos(2*k-1)*pi*xj;
end
m = sum(suma);
u_ex(j, n)= 0.5 - m;
end
end
tt = dt : dt : Nt*dt;
figure(1)
surf(x,tt, u_ex'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
The problem is that all I get is a flat surface:
Equation 1 is suppossed to be the solution of the following parabolic partial differential equation with boundary values:
And after getting the numerical solution, it should look like this:
This plot gets the right values at the boundaries x = 0 and x = 1. The plot of Equation 1 doesn't have those values at the boundaries.
My complete .m code (that plots both the numerical solution and Equation 1) is:
clear all; % clear all variables in memory
xl=0; xr=1; % x domain [xl,xr]
J = 10; % J: number of division for x
dx = (xr-xl) / J; % dx: mesh size
tf = 0.1; % final simulation time
Nt = 60; % Nt: number of time steps
dt = tf/Nt/4;
mu = dt/(dx)^2;
if mu > 0.5 % make sure dt satisy stability condition
error('mu should < 0.5!')
end
% Evaluate the initial conditions
x = xl : dx : xr; % generate the grid point
% store the solution at all grid points for all time steps
u = zeros(J+1,Nt);
u_ex = zeros(J+1,Nt);
% Find the approximate solution at each time step
for n = 1:Nt
t = n*dt; % current time
% boundary condition at left side
gl = 0;
% boundary condition at right side
gr = 0;
for j=2:J
if n==1 % first time step
u(j,n) = j;
else % interior nodes
u(j,n)=u(j,n-1) + mu*(u(j+1,n-1) - 2*u(j,n-1) + u(j-1,n-1));
end
end
u(1,n) = gl; % the left-end point
u(J+1,n) = gr; % the right-end point
% calculate the analytic solution
for j=1:J+1
xj = xl + (j-1)*dx;
suma = zeros(100 , 1);
for k= 1:100
suma(k) = 4/(((2*k-1)^2) *pi*pi);
suma(k) = suma(k) * exp(-((2*k-1)^2) *pi*pi*t) * cos(2*k-1)*pi*xj;
end
m = sum(suma);
u_ex(j, n)= 0.5 - m;
end
end
% Plot the results
tt = dt : dt : Nt*dt;
figure(1)
colormap(gray); % draw gray figure
surf(x,tt, u'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
title('Numerical solution of 1-D parabolic equation')
figure(2)
surf(x,tt, u_ex'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
title('Analytic solution of 1-D parabolic equation')
maxerr=max(max(abs(u-u_ex))),
The code is taken from the book "Computational Partial Differential Equations Using MATLAB" by Yi-Tung Chen, Jichun Li, chapter 2, exercise 3.
In short: I'm not asking about the differential equation or the boundary problem, I want to know is: Why am I getting a flat surface when plotting Equation 1? Am I missing a parenthesis?
I do not want to use the symsum function because it never stop the script execution and I want to learn how to plot Equation 1 with no using symsum.
I've tested this code with Matlab R2008b and Octave 4.2.1. I got the same results (even with sums of 1000, 10000 and 50000 terms in the for loop with the k variable).
Edit!
Thanks, Steve!
I was missing a couple of parenthesis near the cosine, the right code is:
clear all; % clear all variables in memory
xl=0; xr=1; % x domain [xl,xr]
J = 10; % J: number of division for x
dx = (xr-xl) / J; % dx: mesh size
tf = 0.1; % final simulation time
Nt = 60; % Nt: number of time steps
dt = tf/Nt/4;
mu = dt/(dx)^2;
if mu > 0.5 % make sure dt satisy stability condition
error('mu should < 0.5!')
end
% Evaluate the initial conditions
x = xl : dx : xr; % generate the grid point
% store the solution at all grid points for all time steps
u = zeros(J+1,Nt);
u_ex = zeros(J+1,Nt);
% Find the approximate solution at each time step
for n = 1:Nt
t = n*dt; % current time
% boundary condition at left side
gl = 0;
% boundary condition at right side
gr = 0;
for j=2:J
if n==1 % first time step
u(j,n) = j;
else % interior nodes
u(j,n)=u(j,n-1) + mu*(u(j+1,n-1) - 2*u(j,n-1) + u(j-1,n-1));
end
end
u(1,n) = gl; % the left-end point
u(J+1,n) = gr; % the right-end point
% calculate the analytic solution
for j=1:J+1
xj = xl + (j-1)*dx;
suma = zeros(1000 , 1);
for k= 1:1000
suma(k) = 4/(((2*k-1)^2) *pi*pi);
suma(k) *= exp(-((2*k-1)^2) *pi*pi*t) * cos((2*k-1)*pi*xj);
end
m = sum(suma);
u_ex(j, n)= 0.5 - m;
end
end
% Plot the results
tt = dt : dt : Nt*dt;
figure(1)
colormap(gray); % draw gray figure
surf(x,tt, u'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
title('Numerical solution of 1-D parabolic equation')
figure(2)
surf(x,tt, u_ex'); % 3-D surface plot
xlabel('x')
ylabel('t')
zlabel('u')
title('Analytic solution of 1-D parabolic equation')
Now my Equation 1 looks much better:
Also Steve was right when pointing out that my numerical solution may be wrong. I didn't notice that the boundary values are for the derivatives of my function, not the actual values of the function. I'll ask my teacher about this.
Edit2!
Ok, I got it. To calculate the derivatives at the boundaries you have to use hint 2.21 in the same book:
% hint 2.21 given by the book
% it is better to calculate the boundary values after calculating the inner points inside the for j = 1:m loop because you will need them:
u(1, n) = u(2, n) - dx * gl; % the left-end point
u(J+1,n) = u(J, n) + dx * gr; % the right-end point
Now my numerical solution looks like my analytic solution :D
Matlab R2008b can't recognize the *= operator that Octave does. I'm not tested this operator in other versions of Matlab because I'm too poor.
Yvon: I think the analytical solution formula comes from the real part of a Fourier expansion, but authors don't tell how they got it.
I am trying to produce this graph using Matlab. The built-in ellipsoid function is confusing. For this problem I have two variables ( width and length ) and a constant height.
to make it very simple I want to show that the width is changing while we approach the tip but height is constant. w,x,h are the variables shown in the graph.
I would really appreciate it if someone can help.
The following code gets you a long way, I think. See example output:
I added enought comments that you should be able to take it from here...
% plot ellipsoid in 3D
% height and width of ellipsoid:
e_h = 10;
e_w = 3;
% position where the "quivers" (arrows) go:
q_offset = 2; % distance from axis
q_scale = 0.5; % multiplier to give parabola some size
q_spacing = 0.5; % distance between arrows
q_height = 2.5; % height above XY plane where arrows are drawn
N = 1000; % number of points for drawing
theta = linspace(0, 2*pi, N); % parameter to help drawing ellipse
zerov = zeros(1, N); % array of zeros that I will need
% coordinates of main ellipse:
x = e_w * sin(theta);
y = zeros(size(x));
z = e_h * cos(theta);
% plot main ellipse:
figure;
plot3(x, y, z)
% secondary plot
y2 = q_scale*(e_w.^2 - x.^2) + 2; % offset parabola - what your plot looked like...
hold on
plot3(x, y2, zerov+q_height); % plotting the parabola in the XY plane at height
axis equal % make the plot dimensions isotropic
% add quivers
q_base = -e_w:q_spacing:e_w; % x coordinate; y and z are fixed
q_length = (e_w.^2 - q_base.^2)*q_scale; % length of quiver - just an equation I chose
q0 = zeros(size(q_base)); % another vector I will need multiple times
q1 = ones(size(q_base)); % ditto
% plot the arrows: the "-1" argument means "don't scale"
quiver3(q_base, q0+q_offset, q_height*q1, q0, q_length, q0, -1)
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.
I'm trying to model projectile motion with air resistance.
This is my code:
function [ time , x , y ] = shellflightsimulator(m,D,Ve,Cd,ElAng)
% input parameters are:
% m mass of shell, kg
% D caliber (diameter)
% Ve escape velocity (initial velocity of trajectory)
% Cd drag coefficient
% ElAng angle in RADIANS
A = pi.*(D./2).^2; % m^2, shells cross-sectional area (area of circle)
rho = 1.2 ; % kg/m^3, density of air at ground level
h0 = 6800; % meters, height at which density drops by factor of 2
g = 9.8; % m/s^2, gravity
dt = .1; % time step
% define initial conditions
x0 = 0; % m
y0 = 0; % m
vx0 = Ve.*cos(ElAng); % m/s
vy0 = Ve.*sin(ElAng); % m/s
N = 100; % iterations
% define data array
x = zeros(1,N + 1); % x-position,
x(1) = x0;
y = zeros(1,N + 1); % y-position,
y(1) = y0;
vx = zeros(1,N + 1); % x-velocity,
vx(1) = vx0;
vy = zeros(1,N + 1); % y-velocity,
vy(1) = vy0;
i = 1;
j = 1;
while i < N
ax = -Cd*.5*rho*A*(vx(i)^2 + vy(i)^2)/m*cos(ElAng); % acceleration in x
vx(i+1) = vx(i) + ax*dt; % Find new x velocity
x(i+1) = x(i) + vx(i)*dt + .5*ax*dt^2; % Find new x position
ay = -g - Cd*.5*rho*A*(vx(i)^2 + vy(i)^2)/m*sin(ElAng); % acceleration in y
vy(i+1) = vy(i) + ay*dt; % Find new y velocity
y(i+1) = y(i) + vy(i)*dt + .5*ay*dt^2; % Find new y position
if y(i+1) < 0 % stops when projectile reaches the ground
i = N;
j = j+1;
else
i = i+1;
j = j+1;
end
end
plot(x,y,'r-')
end
This is what I am putting into Matlab:
shellflightsimulator(94,.238,1600,.8,10*pi/180)
This yields a strange plot, rather than a parabola. Also it appears the positions are negative values. NOTE: ElAng is in radians!
What am I doing wrong? Thanks!
You have your vx and vy incorrect... vx= ve*sin(angle in radians) and opposite for vy. U also u do not need a dot in between ur initial velocity and the *... That is only used for element by element multiplication and initial velocity is a constant variable. However the dot multiplier will not change the answer, it just isn't necessary..