Matlab - plot speed vector of a satellite in Keplerian orbit - matlab

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), ...)

Related

Graphing electric potential of a ring of charge using MATLAB

My code is not plotting the correct contour plot for a plane perpendicular to a ring of charge running through its center properly. My problem is that the contour plot is not filling 2D space.
I've made two versions of code, one uses a for loop to calculate a
Riemann sum and the other simply uses the sum command. Both rely on the
'subs' command for substituting values from a meshgrid into my expression for V (electric potential).
Version 1 (using for loop):
%% Computing a symbolic expression for V for anywhere in space
syms x y z % phiprime is angle that an elemental dq of the circular
charge is located at, x,y and z are arbitrary points in space outside the
charge distribution
N = 200; % number of increments to sum
R = 2; % radius of circle is 2 meters
dphi = 2*pi/N; % discretizing the circular line of charge which spans 2pi
integrand = 0;
for phiprime = 0:dphi:2*pi
% phiprime ranges from 0 to 2pi in increments of dphi
integrand = integrand + dphi./(sqrt(((x - R.*cos(phiprime) )).^2 + ((y -
R.*sin(phiprime) ).^2) + z.^2));
end
intgrl = sum(integrand);
% uncessary but harmless step that I leave to show that I am using the
sum of the above expression for each dphi
eps0 = 8.854e-12;
kC = 1/(4*pi*eps0);
rhol = 1*10^-9; % linear charge density
Vtot = kC*rhol*R.*intgrl; % symbolic expression for Vtot
%% Graphing V & E in plane perpedicular to ring & passing through center
[Y1, Z1] = meshgrid(-4:.5:4, -4:.5:4);
Vcont1 = subs(Vtot, [x,y,z], {0,Y1,Z1}); % Vcont1 stands for V contour; 1
is because I do the plane of the ring next
contour(Y1,Z1,Vcont1)
xlabel('y - axis [m]')
ylabel('z - axis [m]')
title('V in a plane perpendicular to a ring of charge (N = 200)')
str = {'Red line is side view', 'of ring of charge'};
text(-1,2,str)
hold on
% visually displaying line of charge on plot
circle = rectangle('Position',[-2 0 4 .1],'Curvature',[1,1]);
set(circle,'FaceColor',[1, 0, 0],'EdgeColor',[1, 0, 0]);
% taking negative gradient of V and finding symbolic equations for Ex, Ey
and Ez
g = gradient(-1.*(kC*rhol*R.*intgrl),[x,y,z]);
%% now substituting all the values of the 2D coordinate system for the
symbolic x and y variables to get numeric values for Ex and Ey
Ey1 = subs(g(2), [x y z], {0,Y1,Z1});
Ez1 = subs(g(3), [x y z], {0,Y1,Z1});
E1 = sqrt(Ey1.^2 + Ez1.^2); % full numeric magnitude of E in y-z plane
Eynorm1 = Ey1./E1; % This normalizes the electric field lines
Eznorm1 = Ez1./E1;
quiver(Y1,Z1,Eynorm1,Eznorm1);
hold off
Version 2 (using sum command):
syms x y z
R = 2; % radius of circle is 2 meters
N=100;
dphi = 2*pi/N; % discretizing the circular line of charge which spans 2pi
phiprime = 0:dphi:2*pi; %phiprime ranges from 0 to 2pi in increments of
dphi
integrand = dphi./(sqrt(((x - R.*cos(phiprime) )).^2 + ((y -
R.*sin(phiprime) ).^2) + z.^2));
phiprime = 0:dphi:2*pi;
intgrl = sum(integrand); % Reimann sum performed here
eps0 = 8.854e-12;
kC = 1/(4*pi*eps0);
rhol = 1*10^-9; % linear charge density
Vtot = kC*rhol*R.*intgrl; % symbolic expression for Vtot
Everything else after that point for version 2 is the same as version 1 (substituting for the symbols x,y,z etc)
I would post images of what the code produces but apparently you need 10 reputation for that. Thanks stackoverflow. This will be much more confusing to understand without the images.
The vector field produced by my code is correct while the contour plot seems to use only a few points around the ends of the ring and connect them with straight lines in a strange diamond shape. I can't get it to fill space.
I receive no error messages. The contour lines accumulate around the ends of the ring (where the potential would approach infinity) in a strange diamond shape but aren't graphed anywhere else. I need the contour plot to fill the 2D grid
I received a solution to this question from MATLAB's community and posted about it here:
https://scicomp.stackexchange.com/questions/32834/graphing-electric-potential-of-a-ring-of-charge-using-matlab-help/32842#32842
I would post here but this "you can't post images because you don't have enough reputation" thing would make my explanation too abstract and difficult to understand so go take a look if you are having MATLAB contour plot issues and want to see my problem and solution

Plot quiver polar coordinates

I want to plot the field distribution inside a circular structure with radius a.
What I expect to see are circular arrows that from the centre 0 go toward a in the radial direction like this
but I'm obtaining something far from this result. I wrote this
x_np = besselzero(n, p, 1); %toolbox from mathworks.com for the roots
R = 0.1:1:a; PHI = 0:pi/180:2*pi;
for r = 1:size(R,2)
for phi = 1:size(PHI,2)
u_R(r,phi) = -1/2*((besselj(n-1,x_np*R(1,r)/a)-besselj(n+1,x_np*R(1,r)/a))/a)*cos(n*PHI(1,phi));
u_PHI(r,phi) = n*(besselj(n,x_np*R(1,r)/a)/(x_np*R(1,r)))*sin(PHI(1,phi));
end
end
[X,Y] = meshgrid(R);
quiver(X,Y,u_R,u_PHI)
where u_R is supposed to be the radial component and u_PHI the angular component. Supposing the formulas that I'm writing are correct, do you think there is a problem with for cycles? Plus, since R and PHI are not with the same dimension (in this case R is 1x20 and PHI 1X361) I also get the error
The size of X must match the size of U or the number of columns of U.
that I hope to solve it if I figure out which is the problem with the cycles.
This is the plot that I get
The problem has to do with a difference in co-ordinate systems.
quiver expects inputs in a Cartesian co-ordinate system.
The rest of your code seems to be expressed in a polar co-ordinate system.
Here's a snippet that should do what you want. The initial parameters section is filled in with random values because I don't have besselzero or the other details of your problem.
% Define initial parameters
x_np = 3;
a = 1;
n = 1;
% Set up domain (Cartesian)
x = -a:0.1:a;
y = -a:0.1:a;
[X, Y] = meshgrid(x, y);
% Allocate output
U = zeros(size(X));
V = zeros(size(X));
% Loop over each point in domain
for ii = 1:length(x)
for jj = 1:length(y)
% Compute polar representation
r = norm([X(ii,jj), Y(ii,jj)]);
phi = atan2(Y(ii,jj), X(ii,jj));
% Compute polar unit vectors
rhat = [cos(phi); sin(phi)];
phihat = [-sin(phi); cos(phi)];
% Compute output (in polar co-ordinates)
u_R = -1/2*((besselj(n-1, x_np*r/a)-besselj(n+1, x_np*r/a))/a)*cos(n*phi);
u_PHI = n*(besselj(n, x_np*r/a)/(x_np*r))*sin(phi);
% Transform output to Cartesian co-ordinates
U(ii,jj) = u_R*rhat(1) + u_PHI*phihat(1);
V(ii,jj) = u_R*rhat(2) + u_PHI*phihat(2);
end
end
% Generate quiver plot
quiver(X, Y, U, V);

Plotting cantilever and beam plots using Matlab

Problem
I have to plot a beam/cantilever using Matlab. Where my inputs are:
Length of the beam
Position of the loads (input is a vector)
Forces of the load (input is a vector)
Whether is it a cantilever or not. Because I have different equations for calculating the displacement.
My Solution
I have come to an idea on how I can actually plot the cantilever, but I can not formulate it into a code in MATLAB. I have spent hours trying to write something on Matlab but I have gotten nowhere. (I am a novice to Matlab)
My solution is as follow: I have the formula for the displacement from starting position.
I can define a vector using loop for x coordinates until the given beam length. Hence,
x=[0 ... L]
Then I want to define another vector where the difference is calculated (this is where I can't figure out Matlab)
y = [h, h - y(x1), h - y(x2), .... h - y(L)]
where h is the starting height, which I have thought to be defined as (y(x1) - y(L)) + 1, so that the graph then doesn't go into the negative axes. y(x) is the function which will calculate the displacement or fall of the beam.
Once that is done, then I can simply plot(x,y) and that would give me a graph of a shape of deflected beam for the given range from 0 to beam length. I have tested my theory on excel and it works as per the graph is concerned but I can not figure out implementation on Matlab.
My incomplete code
%Firstly we need the inputs
%Length of the beam
l = str2double(input('Insert the length of your beam: ', 's'));
%Now we need a vector for the positions of the load
a = [];
while 1
a(end+1) = input('Input the coordinate for the position of your load: ');
if length(a)>1; break; end
end
%Now we need a vector for the forces of the load
W = [];
while 1
W(end+1) = input('Input the forces of your load: ');
if length(W)>1; break; end
end
%
%
%
%Define the formula
y = ((W * (l - a) * x)/(6*E*I*l)) * (l^2 - x^2 - (l - a)^2);
%Where
E = 200*10^9;
I = 0.001;
%
%
%
%Now we try to plot
%Define a vector with the x values
vectx = [];
for i = 1:l
vectx = [vectx i];
end
%Now I want to calculate displacement for each x value from vectx
vecty = [];
for i=1:l
vecty=[10 - y(x(i)) i];
end
%Now I can plot all the information
plot(vectx, vecty)
hold on
%Now I plot the coordinate of the positions of the load
plot(load)
end
Really need some help/guidance. Would be truly grateful if someone can help me out or give me a hint :)
I have edited the question with further details
There are several things that do not work in your example.
For instance, parameters should be defined BEFORE you use them, so E and I should be defined before the deflection equation. And you should define x.
I do not understand why you put your inputs whithin a while loop, if you stop it at length(a)>1;. You can remove the loop.
You do not need a loop to calculate displacements, you can just use a substraction between vectors, like displacement = 10 - y. However, I do not understand what is H in your example; since your beam is initially at position 0, your displacement is just -y.
Finally, your equation to calculate the deformed shape is wrong; it only accounts for the first part of the beam.
Here, try if this code works:
%Length of the beam
l = input('Insert the length of your beam: ');
%Now we need a vector for the positions of the load
a = input('Input the coordinate for the position of your load: ');
%Now we need a vector for the forces of the load
W = input('Input the forces of your load: ');
%Define the formula
E = 200*10^9;
I = 0.001;
% x Position along the beam
x = linspace(0,l,100);
b = l - a;
% Deflection before the load position
pos = x <= a;
y(pos) = ((W * b .* x(pos))/(6*E*I*l)) .* (l^2 - x(pos).^2 - b^2);
% Cantilever option
% y(pos) = W*x(pos).^2/(6*E*I).*(3*a-x(pos));
% Deflection after the load position
pos = x > a;
y(pos) = ((W * b )/(6*E*I*l)) .* (l/b*(x(pos)-a).^3 + (l^2 - b^2)*x(pos) - x(pos).^3);
% Cantilever option
% y(pos) = W*a^2/(6*E*I).*(3*x(pos)-a);
displacement = 10 - y; % ???
% Plot beam
figure
plot(x , x .* 0 , 'k-')
hold on;
% Plot deflection
plot(x , y , '--')
% Plot load position
% Normalize arrow size as 1/10 of the beam length
quiver(a , 0 , 0 , sign(W) .* max(abs(y))/2)

Oblique to rectangular coordinate basis transformation of a matrix

I have my 2D-data stored in a [K,K] matrix. The indices represent coordinates (q_1, q_2) in the oblique coordinate system defined by its strain -0.5<gamma<0.5. The goal is to transform the data to a rectangular coordinate system, which is given by the coordinates:
q_x = q_1
q_y = q_2 - gamma*q_1
The result is illustrated in this picture:
The code below achieves this transformation on a pixel-by-pixel basis. Would anyone happen to know a more elegant and vectorized approach obtain the same result?
% Oblique-to-rectangular coordinate transformation
K = 10; % number of pixels
gamma = 0.37; % some arbitrary strain position range (-0.5; 0.5)
Koffset = (1-(-1).^(K-1))/4; % =0.5 when K is even, =0.0 when K is odd
% Mock data
S0 = rand(K,K); % data collected in the oblique coordinate system
qindex = -ceil((K-1)/2) : floor((K-1)/2); % all the possible q-values, with the zero'th element in the middle. Must be in this order to comply with FFT's convention
S = zeros(K,K); % data to be transformed to the rectangular coordinate system
% let indices (i,j) run through all the positions of the oblique matrix
for i=1:K
for j=1:K
% obtain the q-values corresponding to the current matrix position (i,j)
q1 = qindex(i);
q2 = qindex(j);
% apply the coordinate transformation to get the q-values in the rectangular system
qx = round(q1);
qy = round(q2-gamma*q1);
% apply periodic boundary condition
qy = qy - K*round((qy+Koffset)/K); % should be a unique value in the range of qindex
% find out the indices in the rectangular system
ii = i;
jj = find(qindex == qy);
% add the element
S(ii,jj) = S(ii,jj) + S0(i,j);
end
end
The best way to do this is to create a grid of points using meshgrid, deform the grid using your transformations, and then use interp2 to sample the original image at these locations.
% Desired output range
[xx,yy] = meshgrid(-3:0.01:3, -3:0.01:3);
% Transform these X and Y coordinates to q1 and q2 coordinates
q1 = xx;
q2 = yy + gamma*q1;
% Sample the original image using these coordinates where q1range and q2
% range and the q1 and q2 values corresponding to each element in the image qdata
output = interp2(q1range, q2range, qdata, q1, q2);

Ideas for reducing the complexity of a 3D density function for generating a ternary surface plot in Matlab

I have a 3D density function q(x,y,z) that I am trying to plot in Matlab 8.3.0.532 (R2014a).
The domain of my function starts at a and ends at b, with uniform spacing ds. I want to plot the density on a ternary surface plot, where each dimension in the plot represents the proportion of x,y,z at a given point. For example, if I have a unit of density on the domain at q(1,1,1) and another unit of density on the domain at q(17,17,17), in both cases there is equal proportions of x,y,z and I will therefore have two units of density on my ternary surface plot at coordinates (1/3,1/3,1/3). I have code that works using ternsurf. The problem is that the number of proportion points grows exponentially fast with the size of the domain. At the moment I can only plot a domain of size 10 (in each dimension) with unit spacing (ds = 1). However, I need a much larger domain than this (size 100 in each dimension) and much smaller than unit spacing (ideally as small as 0.1) - this would lead to 100^3 * (1/0.1)^3 points on the grid, which Matlab just cannot handle. Does anyone have any ideas about how to somehow bin the density function by the 3D proportions to reduce the number of points?
My working code with example:
a = 0; % start of domain
b = 10; % end of domain
ds = 1; % spacing
[x, y, z] = ndgrid((a:ds:b)); % generate 3D independent variables
n = size(x);
q = zeros(n); % generate 3D dependent variable with some norm distributed density
for i = 1:n(1)
for j = 1:n(2)
for k = 1:n(2)
q(i,j,k) = exp(-(((x(i,j,k) - 10)^2 + (y(i,j,k) - 10)^2 + (z(i,j,k) - 10)^2) / 20));
end
end
end
Total = x + y + z; % calculate the total of x,y,z at every point in the domain
x = x ./ Total; % find the proportion of x at every point in the domain
y = y ./ Total; % find the proportion of y at every point in the domain
z = z ./ Total; % find the proportion of z at every point in the domain
x(isnan(x)) = 0; % set coordinate (0,0,0) to 0
y(isnan(y)) = 0; % set coordinate (0,0,0) to 0
z(isnan(z)) = 0; % set coordinate (0,0,0) to 0
xP = reshape(x,[1, numel(x)]); % create a vector of the proportions of x
yP = reshape(y,[1, numel(y)]); % create a vector of the proportions of y
zP = reshape(z,[1, numel(z)]); % create a vector of the proportions of z
q = reshape(q,[1, numel(q)]); % create a vector of the dependent variable q
ternsurf(xP, yP, q); % plot the ternary surface of q against proportions
shading(gca, 'interp');
colorbar
view(2)
I believe you meant n(3) in your innermost loop. Here are a few tips:
1) Loose the loops:
q = exp(- ((x - 10).^2 + (y - 10).^2 + (z - 10).^2) / 20);
2) Loose the reshapes:
xP = x(:); yP = y(:); zP = z(:);
3) Check Total once, instead of doing three checks on x,y,z:
Total = x + y + z; % calculate the total of x,y,z at every point in the domain
Total( abs(Total) < eps ) = 1;
x = x ./ Total; % find the proportion of x at every point in the domain
y = y ./ Total; % find the proportion of y at every point in the domain
z = z ./ Total; % find the proportion of z at every point in the domain
PS: I just recognized your name.. it's Jonathan ;)
Discretization method probably depends on use of your plot, maybe it make sense to clarify your question from this point of view.
Overall, you probably struggling with an "Out of memory" error, a couple of relevant tricks are described here http://www.mathworks.nl/help/matlab/matlab_prog/resolving-out-of-memory-errors.html?s_tid=doc_12b?refresh=true#brh72ex-52 . Of course, they work only up to certain size of arrays.
A more generic solution is too save parts of arrays on hard drive, it makes processing slower but it'll work. E.g., you can define several q functions with the scale-specific ngrids (e.g. ngridOrder0=[0:10:100], ngridOrder10=[1:1:9], ngridOrder11=[11:1:19], etc... ), and write an accessor function which will load/save the relevant grid and q function depending on the part of the plot you're looking.