Problem to converting km to geographical coordinates - matlab

I have some questions about converting kilometers to geographical coordinates.
As you can see figure attached, the left one is trajectory interms of kilometers. I entered geographical coordinates and calculate trajectory as kilometers. For my calculations I need to convert degrees to kilometers. I used this code:
LAT=[41.030503; 41.048334; 41.071551 ]*pi/180;
LON=[28.999000; 29.037494; 29.052138 ]*pi/180;
for i=1:length(LAT)-1
psi_coordinate(i,1) = atan2( sin (LON(i+1)-LON(i)) * cos (LAT(i+1)) , cos (LAT(i)) *sin (LAT(i+1)) - sin (LAT(i)) * cos (LAT(i+1)) * cos (LON(i+1)-LON(i)) );
a=(sin((LAT(i+1)-LAT(i))/2))^2+cos(LAT(i))*cos(LAT(i+1))*(sin((LON(i+1)-LON(i))/2))^2;
c=2*atan2(sqrt(a),sqrt(1-a));
d(i,1)=R*c;
pos_x(i+1,1)=pos_x(i,1)+d(i,1)*cos(psi_coordinate(i,1)); %convert to kilometer
pos_y(i+1,1)=pos_y(i,1)+d(i,1)*sin(psi_coordinate(i,1)); %convert to kilometer
distance_h(i,1)=sqrt(((LAT(i+1)-LAT(i))^2)+((LON(i+1)-LON(i))^2))*1000 ; %kilometer
end
distance=sum(d);
pos_x=pos_x*1000; %convert to meter
pos_y=pos_y*1000; %convert to meter
pos_x and pos_y are ploted as circle at the figure (left).
After I calculate ship trajectory, I need to convert them degrees again.
If I use "km2deg" command I obtained my coordinates as given figure (right) and the code that I used is:
ydeg=LON(1)*180/pi+km2deg(y/1000);
xdeg=LAT(1)*180/pi+km2deg(x/1000);
But as you can see the blue line (ship trajectory) is not close to the desired path as figure given left. Normally it should be the same trend for these two plot. Because all I do is here is just converting the units. I guess I have some troubles to used "km2deg" command.
Do you have any suggestions to convert my points correctly from km to deg?

Related

deg2km command does not calculate distance between two points in matlab

I am trying to calculate distance between two geographical coordinates and I want to convert geographical coordinates to the km. Therefore I used deg2km function. However, I realise that it is not convert points properly.
For instance, I used these two points.
p_x=[5; 10]; %degree
p_y=[8; 16]; %degree
pos_y=deg2km(p_y,6378);
pos_x=deg2km(p_x,6378);
It returns as:
pos_x= [556.58549846099 1113.17099692198]
pos_y= [890.536797537587 1781.07359507517]
When I calculate distance ( sqrt((556.5-1113.2)^2+(890.5368-1781.1)^2) ) between these points I obtained distance as : 1050.2464
However I checked it google map and also other websites it should be 1042 km.
Do you have any suggestion to calculate distance and also points as kilometers properly?
Thanks in advance!
edited as :
I've points(deg)and I need to convert them km and calculate distance between points.
LAT=[41.000173;41.010134]*pi/180;
LON=[28.995882;28.995584]*pi/180;
I used this code to calculate distance. It calculates properly.
But I can not convert my points to kilometers.
LAT=[41.000173;41.010134]*pi/180;
LON=[28.995882;28.995584]*pi/180;
R=6378; %km
for i=1:length(LAT)-1
psi(i,1) = atan2( sin (LON(i+1)-LON(i)) * cos (LAT(i+1)) , cos (LAT(i)) *sin (LAT(i+1)) - sin (LAT(i)) * cos (LAT(i+1)) * cos (LON(i+1)-LON(i)) );
a=(sin((LAT(i+1)-LAT(i))/2))^2+cos(LAT(i))*cos(LAT(i+1))*(sin((LON(i+1)-LON(i))/2))^2;
c=2*atan2(sqrt(a),sqrt(1-a));
d(i,1)=R*c;
end

Incorrect angle detected between two planes

I want to calculate the angle between 2 planes, Reference plane and Plane1. When I feed the X,Y,Z co-ordinates of pointCloud to the function plane_fit.m (by Kevin Mattheus Moerman), I get the coefficients:
reference_plane_coeff: [-0.13766204 -0.070385590 130.69409]
Plane1_coeff: [0.0044337390 -0.0013548643 95.890228]
Next, I find the intersection of both planes, separately on the XZ plane and get a line equation; ref_line_XZ and plane1_line_XZ respectively. For this, I make the second coefficient 0. (Is this right?)
Aref = reference_plane_coeff(1);
Cref = reference_plane_coeff(3);
ref_line_XZ = [Aref Cref];
Arun = Plane1_coeff(1);
Crun = Plane1_coeff(3);
plane1_line_XZ = [Arun Crun];
angle_XZ = acos( dot(ref_line_XZ,plane1_line_XZ ) / (norm(ref_line_XZ) * norm(plane1_line_XZ )) )
I get the angle_XZ value as 0.0012 rad. i.e. 0.0685 degrees
When I plot these planes on a graph and view it, the angle seems to be much more than 0.0012 degrees. I'm talking about the angle made by the two lines after intersection of both planes with the XZ plane.
What am I doing wrong?
Also, when I tried to find angle between its normals, using:
angle_beta_deg = acosd( dot(reference_plane_coeff,Plane1_coeff) / (norm(reference_plane_coeff) * norm(Plane1_coeff)) )
I got the angle as 0.0713.
On visual inspection of both planes' plots and manually calculating from the plot, angle_XZ should be around 9 degrees.
plane_fit.m (by Kevin Mattheus Moerman)

Calculate heading angle from x and y information

I have data that records the x and y positions of an animal in a 2D assay over time stored in a matlab matrix. I can plot these co-ordinates over time, and extract the velocity information and plot this using cline.
The problem I am having at the moment is calculating the heading angle. It should be a trivial trigonometry question, but I am drawing a blank on the best way to start.
The data is stored in a matrix xy representing x and y co-ordinates:
796.995391705069 151.755760368664
794.490825688073 150.036697247706
788.098591549296 145.854460093897
786.617021276596 144.327659574468
781.125000000000 140.093750000000
779.297872340426 138.072340425532
775.294642857143 133.879464285714
What I would like to be able to do is know the angle of the line drawn from (796.995, 151.755) to (794.490, 150.036), and so on. My research suggests atan2 will be the appropriate function, but I am unsure how to call it correctly to give useful information.
difx = xy(1,1) - xy(2,1);
dify = xy(1,2) - xy(2,2);
angle = atan2(dify,difx);
angle = angle*180/pi % convert to degrees
The result is 34.4646. Is this correct?
If it is correct, how do I get the value to be in the range 0-360?
You can use the diff function to get all the differences at once:
dxy = diff(xy); % will contain [xy(2,1)-xy(1,1) xy(2,2)-xy(1,2); ...
Then you compute the angle using the atan2 function:
a = atan2(dxy(:,2), dxy(:,1));
You convert to degrees with
aDeg = 180 * a / pi;
And finally take the angle modulo 360 to get it between 0 and 360:
aDeg = mod(aDeg, 360);
So - you pretty much got it right, yes. Except that you have calculated the heading from point 2 to point 1, and I suspect you want to start at 1 and move towards 2. That would give you a negative number - or modulo 360, an angle of about 325 degrees.
Also, using the diff function gets you the entire array of headings all at once which is a slight improvement over your code.
[rc mi]=
EDIT the problem of "phase wrapping" - when the heading goes from 359 to 0 - is quite a common problem. If you are interested in knowing when a large change happens, you can try the following trick (using aDeg from above - angle in degrees).
dDeg1 = diff(aDeg); % the change in angle
dDeg2 = diff(mod(aDeg + 90, 360)); % we moved the phase wrap point by 180 degrees
dDeg12 = [dDeg1(:) dDeg2(:)]';
[rc mi]= min(abs(dDeg12));
indx = sub2ind(size(dDeg12), mi, 1:size(dDeg12, 2));
result = dDeg12(ii);
What I did there: one of the variables (dDeg or dDeg2) does not see the phase wrap, and the min function finds out which one (it will have a smaller absolute difference). The sub2ind looks up that number (it is either positive or negative - but it's the smaller one of the two), and that is the value that ends up in result.
You can verify the angle by plotting a little line that starts at the first point and end in the direction of the heading. If the angle is correct, it will point in the direction of the next point in xy. Everything depends on where yo define 0 degrees at (straight up, say) from and whether positive degrees is rotation counterclockwise (I do) or clockwise. In MATLAB you can get the numbers between 0 and 360 but using modulo---or you can just add 180 to your results but this will change the definition of where the 0 degree mark is.
I made the following script that is a bit complex but shows how to calculate the heading/angle for all points in vector format and then displays them.
xy =[ 796.995391705069 151.755760368664
794.490825688073 150.036697247706
788.098591549296 145.854460093897
786.617021276596 144.327659574468
781.125000000000 140.093750000000
779.297872340426 138.072340425532
775.294642857143 133.879464285714];
% t = linspace(0,3/2*pi, 14)';
% xy = [sin(t), cos(t)];
% calculate the angle:
myDiff = diff(xy);
myAngle = mod(atan2(myDiff(:,1), myDiff(:,2))*180/pi, 360);
% Plot the original Data:
figure(1);
clf;
subplot(1,3,1);
plot(xy(:,1), xy(:,2), '-bx', 'markersize', 12);
hold all
axis equal;grid on;
title('Original Data');
% Plot the calculated angle:
subplot(1,3,2);
plot(myAngle);
axis tight; grid on;
title('Heading');
% Now plot the result with little lines pointing int he heading:
subplot(1,3,3);
plot(xy(:,1), xy(:,2), '-bx', 'markersize', 12);
hold all
% Just for visualization:
vectorLength = max(.8, norm(xy(1,:)- xy(2,:)));
for ind = 1:length(xy)-1
startPoint = xy(ind,:)';
endPoint = startPoint + vectorLength*[sind(myAngle(ind)); cosd(myAngle(ind))];
myLine = [startPoint, endPoint];
plot(myLine(1,:), myLine(2, :), ':r ', 'linewidth', 2)
end
axis equal;grid on;
title('Original Data with Heading Drawn On');
For example, if you use my test data
t = linspace(0,3/2*pi, 14)';
xy = [sin(t), cos(t)];
You get the following:
and if you do yours you get
Note how the little red line starts at the original data point and moves in the direction of the next point---just like the original blue line connecting the points.
Also note that the use of diff in the code to difference all the points properly at once. This is faster and avoids any problems with the direction--looks like in your case it's swapped.

Draw circle using latitude and longitude

I want to plot a latitude and longitude using matlab. Using that latitude and longitude as center of the circle, I want to plot a circle of radius 5 Nm.
r = 5/60;
nseg = 100;
x = 25.01;
y = 55.01;
theta = 0 : (2 * pi / nseg) : (2 * pi);
pline_x = r * cos(theta) + x;
pline_y = r * sin(theta) + y;
hold all
geoshow(pline_x, pline_y)
geoshow(x, y)
The circle does not look of what I expected.
Drawing a circle on earth is more complex that it looks like.
Drawing a line or a poly line is simple, because the vertices are defined.
Not so on circle.
a circle is defined by all points having the same distance from center (in meters! not in degrees!!!)
Unfortuantley lat and lon coordinates have not the same scale.
(The distance between two degrees of latidtude is always approx. 111.3 km, while for longitude this is only true at the equator. At the poles the distance between two longitudes approach zero. In Europe the factor is about 0.6. (cos(48deg))
There are two solution, the first is more universal, usefull for nearly all problems.
convert spherical coordinate (of circle center) to cartesian plane with unit = 1m, using a transformation (e.g equidistant transformation, also called equirectangular transf., this transformation works with the cos(centerLat) compensation factor)
calculate points (e.g circle points) in x,y plane using school mathematics.
transform all (x,y) points back to spherical (lat, lon) coordinates, using the inverse transformation of point 1.
Other solution
1. write a function which draws an ellipse in defined rectangle (all cartesian x,y)
2. define bounding of the circle to draw:
2a: calculate north-south diameter of circle/ in degrees: this a bit tricky: the distance is define in meters, you need a transformation to get the latitudeSpan: one degrees of lat is approx 111.3 km (eart circumence / 360.0): With this meters_per_degree value calc the N-S disatcne in degrees.
2b: calculate E-W span in degrees: now more tricky: calculate like 2a, but now divide by cos(centerLatitude) to compensate that E-W distances need more degrees when moving north to have the same meters.
Now draw ellipseInRectangle using N-S and E_W span for heigh and width.
But a circle on a sphere looks on the projected monitor display (or paper) only like a circle in the center of the projection. This shows:
Tissot's Error Ellipse

Converting 3D point clouds to range image

I have many 3D point clouds gathered by velodyne sensor. eg(x, y, z) in meter.
I'd like to convert 3D point clouds to range image.
Firstly, I've got transformtation from Catesian to spherical coordinate.
r = sqrt(x*x + y*y + z*z)
azimuth angle = atan2(x, z)
elevation angle = asin(y/r)
Now. How can I convert 3D point to Range image using these transformation in matlab?
Whole points are about 180,000 and I want 870*64 range image.
azimuth angle range(-180 ~ 180), elevation angle range(-15 ~ 15)
Divide up your azimuth and elevation into M and N ranges respectively. Now you have M*N "bins" (M = 870, N = 64).
Then (per bin) accumulate a histogram of points that project into that bin.
Finally, pick a representative value from each bin for the final range image. You could pick the average value (noisy, fast) or fit some distribution and then use that to pick the value (more precise, slow).
The pointcloud2image code available from Matlab File Exchange can help you to directly convert point cloud (in x,y,z format) to 2D raster image.