I have found this equation in a paper which represents a helix-shaped movement of an object:
When I plotted the S vector in Matlab I got a different result, not helix shape.
Where is the problem, is it in the equation or in the code?
l is a random number in [-1,1]
r is a random vector in [0,1]
b is a constant for defining the shape of the logarithmic spiral.
Matlab code:
dim =3;
Max_iter =10;
X_star=zeros(1,dim);
ub = 100;
lb = -100;
X=rand(1,dim).*(ub-lb)+lb;
S = [];
t=0;
while t<Max_iter
a=-1+t*((-1)/Max_iter);
r=rand();
b=1;
l=(a-1)*rand + 1;
for j=1:size(X,2)
D= abs(X_star(j) - X(1,j));
X(1,j)= D * exp(b.*l).* cos(l.*2*pi) + X_star(j);
end
X_star=X(1,:);
S = [S X];
plot(S);
t = t+1;
end
that equations does not look like helix at all. Lets do this for 3D. First some definitions:
p0,p1 - centers of start and end of the helix 3D points
r - scalar radius of the helix
m - scalar number of screws (if not integer than the screws will not start and end at the same angular position)
We first need TBN vectors:
n = p1-p0
t = (1,0,0)
if (|dot(n/|n|,t)|>0.9) t = (0,1,0)
b = cross(n,t)
b = r*b / |b|
t = cross(b,n)
t = r*t / |t|
And now we can do the helix using TBN as basis vectors:
// x' y' z'
p(a) = p0 + t*cos(2*Pi*m*a) + b*sin(2*Pi*m*a) + n*a
Where a = <0.0,1.0> is the parameter which point on helix you want. If you move out of this interval you will extrapolate the helix before p0 and after p1. You can consider a is the time...
As you can see the equation is just 2D parametric circle (x',y') + linear movement (z') and transformed by basis vectors to p0,p1 direction and position.
If you need equations/code for the dot,cross and abs value of 3D vectors see:
Understanding 4x4 homogenous transform matrices
They are at the bottom of that answer of mine.
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 have a set of N points in k dimensions as a matrix of size N X k.
How can I find the best fitting line through these points? The line will be a plane (hyerpplane) in k dimensions. It will have k coefficients and one bias term.
Existing functions like fit seem to be usable only for points in 2 or 3 dimension.
You can fit a hyperplane (or any lower dimensional affine space) to a set of D dimensional data using Principal Component Analysis. Here's an example of fitting a plane to a set of 3D data. This is explained in more detail in the MATLAB documentation but I tried to construct the simplest example I could.
% generate some random correlated data
D = 3;
mu = zeros(1,D);
sqrt_sig = randn(D);
sigma = sqrt_sig'*sqrt_sig;
% generate 50 points in a D x 50 matrix
X = mvnrnd(mu, sigma, 50)';
% perform PCA
coeff = pca(X');
% The last principal component is normal to the best fit plane and plane goes through mean of X
a = coeff(:,D);
b = -mean(X,2)'*a;
% plane defined by a'*x + b = 0
dist = abs(a'*X+b) / norm(a);
mse = mean(dist.^2)
Edit: Added example plot of results for D = 3. I take advantage of the orthogonality of the other principal components here. Ignore the code if you want it's just to demonstrate that the plane does in fact fit the data pretty well.
% plot in 3D
X0 = bsxfun(#minus,X,mean(X,2));
b1 = coeff(:,1); b2 = coeff(:,2);
y1 = b1'*X0; y2 = b2'*X0;
y1_min = min(y1); y1_max = max(y1);
y1_span = y1_max - y1_min;
y2_min = min(y2); y2_max = max(y2);
y2_span = y2_max - y2_min;
pad = 0.2;
y1_min = y1_min - pad*y1_span;
y1_max = y1_max + pad*y1_span;
y2_min = y2_min - pad*y2_span;
y2_max = y2_max + pad*y2_span;
[y1_m,y2_m] = meshgrid(linspace(y1_min,y1_max,5), linspace(y2_min,y2_max,5));
grid = bsxfun(#plus, bsxfun(#times,y1_m(:)',b1) + bsxfun(#times,y2_m(:)',b2), mean(X,2));
x = reshape(grid(1,:),size(y1_m));
y = reshape(grid(2,:),size(y1_m));
z = reshape(grid(3,:),size(y1_m));
figure(1); clf(1);
surf(x,y,z,'FaceColor','black','FaceAlpha',0.3,'EdgeAlpha',0.6);
hold on;
plot3(X(1,:),X(2,:),X(3,:),' .');
axis equal;
axis vis3d;
Edit2: When I say "principal component" I'm being a bit sloppy (or just plain wrong) with the wording. I'm actually referring to the orthogonal basis vectors that the principal components are expressed in.
Here's a simpler solution, that just uses MATLAB's \ operator. We start with defining a plane in k dimensions:
% 0 = a + x(1) * b(1) + x(2) * b(2) + ... + x(k) * 1
k = 8;
a = randn(1);
b = randn(k-1,1);
(note that we assume b(k)=1, you can always multiply the plane parameters by any value without changing the plane).
Next we generate N random points within this plane:
N = 1000;
x = rand(N,k-1);
x(:,k) = -(a + x * b);
...sorry, it's not the best way to generate random points on the plane, but it's good enough for the demonstration here. Add noise to the points:
x = x + 0.05*randn(size(x));
To find the parameters of the plane, we solve the system of equations
% a + x(1:k-1) * b == -x(k)
in the least-squares sense. a and b are the unknowns there. We can rewrite the left-hand side as [1,x(1:k-1)] * [a;b]. If we have a matrix equation M*p=v we can solve for p by writing p=M\v:
p = [ones(N,1),x(:,1:k-1)]\(-x(:,k));
disp(['ground truth: [a,b,1] = ',mat2str([a,b',1],3)]);
disp(['estimated : [a,b,1] = ',mat2str([p',1],3)]);
This gives as output:
ground truth: [a,b,1] = [-1.35 -1.44 -1.48 1.17 0.226 -0.214 0.234 -1.59 1]
estimated : [a,b,1] = [-1.41 -1.38 -1.43 1.14 0.219 -0.195 0.221 -1.54 1]
The less noise or the more points in the dataset, the smaller the error will be of course!
I have a piecewise function, where domain changes for each case. The function is as follows:
For
(x,y)greater than Divider v= f(x,y) (A1)
(x,y)less than Divider v = g(x,y) (A2)
The location of the divider changes with tilt angle of the rectangle given in figures 1 and 2.Figure 1 & 2 The divider will always be a bisector of the rectangle. For example, the divider makes an angle (alpha + 90) with the horizontal.
If the rectangle makes an angle 0, it's easy to implement above functions as I can create meshgrid from
x =B to C & y = A to D for A1
x =A to B & y = A to D for A2
However, when the angles for the rectangle are different, I can't figure out how to create the mesh to calculate the function v using the algorithm A1 and A2 above.
I was thinking of using some inequality and using the equation of the line (as I have the co-ordinates for the center of the rectangle and the angle of tilt). But, I can't seem to think of a way to do it for all angles (for example , slope of pi/2 as in the first figure, yields infinity). Even if I do create some kind of inequality, I can't create a mesh.
1Please help me with this problem. I have wasted a lot of time on this. It seems to be out of my reach
%% Constants
Angle1=0;
Angle1=Angle1.*pi./180;
rect_center=0; % in m
rect_length=5; % in m
rect_width=1; % in m
rect_strength=1.8401e-06;
Angle2=0;
Angle2 =Angle2.*pi./180;
%% This code calculates the outer coordinates of the rectangle by using the central point
% the following code calculates the vertices
vertexA=rect_center+(-rect_width./2.*exp(1i.*1.5708)-rect_length./2).*exp(1i.*Angle2);
vertexA=[vertexA,vertexA+2.*(rect_width./2.*exp(1i.*1.5708)).*exp(1i.*Angle2)];
vertexB=rect_center+(-rect_width./2.*exp(1i.*1.5708)+rect_length./2).*exp(1i.*Angle2);
vertexB=[vertexB,vertexB+2.*(rect_width./2.*exp(1i.*1.5708)).*exp(1i.*Angle2)];
za1=vertexA(1:numel(vertexA)/2);
za2=vertexA(1+numel(vertexA)/2:numel(vertexA));
zb1=vertexB(1:numel(vertexB)/2);
zb2=vertexB(1+numel(vertexB)/2:numel(vertexB));
arg1=exp(-1i.*Angle2);
%% This Section makes the two equations necessary for making the graphs
syms var_z
% Equation 1
Eqn1(var_z)=1.5844e-07.*exp(-1i.*Angle1).*var_z./9.8692e-13;
% subparts of the Equation 2
A = 1.0133e+12.*(-1i.*rect_strength.*exp(-1i*Angle2)./(2*pi.*rect_length.*rect_width*0.2));
ZA1 = var_z+za1-2*rect_center;
ZA2 = var_z+za2-2*rect_center;
ZB1 = var_z+zb1-2*rect_center;
ZB2 = var_z+zb2-2*rect_center;
ZAA2 = log(abs(ZA2)) + 1i*mod(angle(ZA2),2*pi);
ZAA1 = log(abs(ZA1)) + 1i*mod(angle(ZA1),2*pi);
ZBB1 = log(abs(ZB1)) + 1i*mod(angle(ZB1),2*pi);
ZBB2 = log(abs(ZB2)) + 1i*mod(angle(ZB2),2*pi);
%Equation 2 ; this is used for the left side of the center
Eqn2= A*(ZA2*(log(ZA2)-1)-(ZA1*(log(ZA1)-1))+(ZB1*(log(ZB1)-1))-(ZB2*(log(ZB2)-1)));
%Equation 3 ; this is used for the right side of the center
Eqn3 = A.*(ZA2*(ZAA2-1)-(ZA1*(ZAA1-1))+(ZB1*(ZBB1-1))-(ZB2*(ZBB2-1)));
%Equation 4 :Add Equation 2 and Equation 1; this is used for the left side of the center
Eqn4 = matlabFunction(Eqn1+Eqn2,'vars',var_z);
%Equation 5: Add Equation 3 and Equation 1; this is used for the right side of the center
Eqn5 = matlabFunction(Eqn1+Eqn3,'vars',var_z);
%% Prepare for making the plots
minx=-10; %min x coordinate
maxx=10; %max x coordinate
nr_x=1000; %nr x points
miny=-10; %min y coordinate
maxy=10; %max y coordinate
nr_y=1000; %nr y points
%This vector starts from left corner (minx) to the middle of the plot surface,
%The middle of the plot surface lies at the center of the rectange
%created earlier
xvec1=minx:(rect_center-minx)/(0.5*nr_x-1):rect_center;
%This vector starts from middle to the right corner (maxx) of the plot surface,
%The middle of the plot surface lies at the center of the rectange
%created earlier
xvec2=rect_center:(maxx-rect_center)/(0.5*nr_x-1):maxx;
%the y vectors start from miny to maxy
yvec1=miny:(maxy-miny)/(nr_y-1):maxy;
yvec2=miny:(maxy-miny)/(nr_y-1):maxy;
% create mesh from above vectors
[x1,y1]=meshgrid(xvec1,yvec1);
[x2,y2]=meshgrid(xvec2,yvec2);
z1=x1+1i*y1;
z2=x2+1i*y2;
% Calculate the above function using equation 4 and equation 5 using the mesh created above
r1 = -real(Eqn5(z1));
r2 = -real(Eqn4(z2));
%Combine the calculated functions
Result = [r1 r2];
%Combine the grids
x = [x1 x2];
y = [y1 y2];
% plot contours
[c,h]=contourf(x,y,Result(:,:,1),50,'LineWidth',1);
% plot the outerboundary of the rectangle
line_x=real([vertexA;vertexB]);
line_y=imag([vertexA;vertexB]);
line(line_x,line_y,'color','r','linestyle',':','linewidth',5)
The final Figure is supposed to look like this.Final Expected Figure.
I'm not sure which angle defines the dividing line so I assume it's Angle1. It looks like logical indexing is the way to go here. Instead of creating two separate mesh grids we simply create the entire mesh grid then partition it into two sets and operate on each independently.
%% Prepare for making the plots
minx=-10; %min x coordinate
maxx=10; %max x coordinate
nr_x=1000; %nr x points
miny=-10; %min y coordinate
maxy=10; %max y coordinate
nr_y=1000; %nr y points
% create full mesh grid
xvec=linspace(minx,maxx,nr_x);
yvec=linspace(miny,maxy,nr_y);
[x,y]=meshgrid(xvec,yvec);
% Partition mesh based on divider line
% Assumes the line passes through (ox,oy) with normal vector defined by Angle1
ox = rect_center;
oy = rect_center;
a = cos(Angle1);
b = sin(Angle1);
c = -(a*ox + b*oy);
% use logical indexing to opperate on the appropriate parts of the mesh
idx1 = a*x + b*y + c < 0;
idx2 = ~idx1;
z = zeros(size(x));
z(idx1) = x(idx1) + 1i*y(idx1);
z(idx2) = x(idx2) + 1i*y(idx2);
% Calculate the above function using equation 4 and equation 5
% using the mesh created above
Result = zeros(size(z));
Result(idx1) = -real(Eqn5(z(idx1)));
Result(idx2) = -real(Eqn4(z(idx2)));
For example with Angle1 = 45 and Angle2 = 45 we get the following indexing
>> contourf(x,y,idx1);
>> line(line_x,line_y,'color','r','linestyle',':','linewidth',5);
where the yellow region uses Eqn5 and the blue region uses Eqn4. This agrees with the example you posted but I don't know what the resulting contour map for other cases is supposed to look like.
Hope this helps.
I am trying to create N random pairs of points (N = 50) of a given distances, inside a 500 meters hexagon. The distance D created by using (dmax - dmin).*rand(N,1) + dmin, with dmin = 10 and dmax = 100 in Matlab. I understant that the first I have to generate a set of points ([x1 y1]) that have at least distance D from the main hexagon border, then generate the second set of points ([x2 y2]) that have exact distance D from the first set. But sometime I got the problem with the second point outside of hexagon, because if the first position on the hexagol border and plus Ddisance, then the second position is outside of hexagon (I mean that I want to generate random pair position inside of hexagol). Could anybody help me in generating this kind of scenario and fix the problem? Thanks.
For example as
R = 500; % hexagol radius
N = 50; % number pair positions
d_min = 10; % minimum distance
d_max = 100; % maximum distance
D = (d_max - d_min).*rand(N,1) + d_min; % randomly distance
X = [0,0]; % hexagol center
j=0;
while j < N
j=j+1;
theta(j)=2*pi*rand(1,1);
u= rand()+ rand();
if u < 1
r(j) = R * u;
else
r(j) = R * (2 - u);
end
% to create the first position
x1(j)=r(j)*cos(theta(j)) + X(1,1); % first x positions
y1(j)=r(j)*sin(theta(j)) + X(1,2); % first y positions
end
% to create the second position
x2(j) = x1(j) + D(j); % second x positions
y2(j) = y1(j) + D(j); % second y positions
This is quite like your other question and its solution is almost the same, but it needs a little more math. Let’s focus on one pair of points. There still are two steps:
Step 1: Find a random point that is inside the hexagon, and has distance d from its border.
Step 2: Find another point that has distance d from first point.
Main problem is step 1. We can say that a points that has distance d form a hexagon with radius r, is actually inside a hexagon with radius r-d. Then we just need to find a random point that lays on a hexagon!
Polar Formula of Hexagons:
I want to solve this problem in polar space, so I have to formulate hexagons in this space. Remember circle formula in polar space:
The formula of a hexagon in polar space is pretty much like its circumscribe circle, except that the radius of the hexagon differs at every t (angle). Let’s call this changing radius r2. So, if we find the function R2 that returns r2 for all ts then we can write polar formula for hexagon:
This image demonstrates parameters of the problem:
The key parameter here is α. Now we need a function Alpha that returns α for all ts:
Now we have all points on border of the hexagon in polar space:
r = 500;
T = linspace(0, 2*pi, 181);
Alpha = #(t) pi/2-abs(rem(t, pi/3)-(pi/6));
R2 = #(t) r*cos(pi/6)./sin(Alpha(t));
X = R2(T).*cos(T);
Y = R2(T).*sin(T);
hold on
plot(X, Y, '.b');
plot((r).*cos(T), (r).*sin(T), '.r')
Polar Formula of a Regular Polygon:
Before I go on I’d like to generalize Alpha and R2 functions to cover all regular polygons:
Alpha = #(t) pi/2-abs(rem(t, 2*pi/(n))-(pi/(n)));
R2 = #(t) r*cos(pi/n)./sin(Alpha(t));
Where n is the number of edges of the polygon.
Answer:
Now we can generate pairs of points just like what we did for the circle problem:
r = 500; n = 6;
a = 10; b = 50;
N = 100;
D = (b - a).*rand(N,1) + a;
Alpha = #(t) pi/2-abs(rem(t, 2*pi/(n))-(pi/(n)));
R2 = #(t) r*cos(pi/n)./sin(Alpha(t));
T1 = rand(N, 1) * 2 * pi;
RT1 = rand(N, 1) .* (R2(T1)-D);
X1 = RT1.*cos(T1);
Y1 = RT1.*sin(T1);
T2 = rand(N, 1) * 2 * pi;
X2 = X1+D.*cos(T2);
Y2 = Y1+D.*sin(T2);
Rotating the polygon:
For rotating the polygon we just need to update the Alpha function:
t0 = pi/8;
Alpha = #(t) pi/2-abs(rem(t+t0, 2*pi/(n))-(pi/(n)));
This is a test for n=7, N=50000 and t0=pi/10:
The following diagram is a schematic of a lake, and the equation illustrates how to calculate the effective heat flux of a lake.
where S is a vector of surface fluxes, q is short wave radiation, h is depth of the mixed layer, and z is the depth of the lake. For example:
q0 = 400+(1-400).*rand(100,1); % This is the short wave radiation
kd = 0.8; % extinction coefficient
h = 10; % depth of the surface mixed layer
for i = 1:length(q0); % loop for calculating short wave radiation at depth h
qh(i) = q0(i).*exp(-kd*h); % here, qh is calculated according to the Lambert Beer law
end
given
dz = 0.5
and z varies from 0 (surface) to depth h in increments of dz i.e.
z = 0:dz:h
how would I calculate the last portion of this equation in matlab i.e. how to calculate q at depth z between the surface and h? which is expressed here as an integral?
Apologies if this should be on another one of the stack overflow forums but it seems more related to programming than pure physics or maths questions.
To integrate this correctly, you will need compute all values of q(z) in the range [0, h]. If q0 and qh are N-by-1 column vectors, this means that q should be an N-by-M matrix, where M is the number of sample points in the range [0, h].
First, lets define z properly:
z = linspace(0, h, 200); %// M=200, but it's an arbitrary number to your choosing
The computation of q can be reduced to:
q = q0 * exp(-kd * z);
and qh actually equals to the final column of q, i.e q(:, end).
The integral itself can be approximated to a sum and computed using sum:
dz = z(2) - z(1);
I = sum(q, 2) * dz;
P.S.
Since q(z) = e(-kd ·z), it's simple enough for you to compute the integral analytically:
I = q0 * (1 - exp(-kd * h)) / kd;