How to get normal vector from position vector function in MATLAB - matlab

I have this equation:
f(t) = <x(t),y(t)>
What I would first like to do is figure out the normal vector at some point, t1. How do I do this in MATLAB?
I would then like to figure out the angle between the normal vector and the x-axis in MATLAB. If I can bypass finding the normal vector and just figure out the angle straight from f(t), that might be better.
it would be nice if there were some vector manipulation functions or something that I could use instead of manually taking the derivative of x(t) and y(t) and then finding the magnitude and all that stuff. Any help would be great!

With dx being the time derivative of x, i.e. (x(t+1)-x(t-1))/(2dt) (you can also use forward differentiation instead of central differences, of course), and dy the corresponding time derivative of y, you can find the angle between the normal and the x-axis easily from the vector [dx,dy], since its normal is just [-dy,dx].
Assuming n-by-1 arrays x and y with the coordinates, you do this as follows:
%# take the time derivative
dx = (x(3:end)-x(1:end-2))/2;
dy = (y(3:end)-y(1:end-2))/2;
%# create the normal vector
nvec = [-dy,dx];
%# normalize the normal vector
nvecN = bsxfun(#rdivide,nvec,sqrt(sum(nvec.^2,2)));
%# take the arc-cosine to get the angle in degrees (acos for radian)
%# of the projection of the normal vector onto the x-axis
angle = acosd(nvecN(:,1));

Related

How to calculate the point-by-point radius of curvature of a trajectory that is not a proper function

with Matlab i'm trying to calculate the "radius of curvature" signal of a trajectory obtained using GPS data projected to the local cartesian plane.
The value of the signal onthe n-th point is the one of the osculating circle tangent to the trajectory on that point.
By convention the signal amplitude has to be negative when related to a left turn and viceversa.
With trajectories having a proper function as graph i'm building the "sign" signal evaluating the numeric difference between the y coordinate of the center of the osculating circle:
for i=1:length(yCenter) -1
aux=Y_m(closestIndex_head:closestIndex_tail );
if yCenter(i) - aux(i) > 0
sign(i)=-1;
else
sign(i)=+1;
end
end
yCenter contains x-coordinates of all osculating circles related to each point of the trajectory;
Y_m contain the y-coordinates of every point in trajectory.
The above simple method works as long as the trajectory's graph is a proper function (for every x there is only one y).
The trajectory i'm working on is like that:
and the sign signal got some anomalies:
The sign seems to change within a turn.
I've tried to correct the sign using the sin of the angle between the tangent vector and the trajectory, the sign of the tangent of the angle and other similar stuff, but still i'm looking at some anomalies:
I'm pretty sure that those anomalies came from the fact that the graph is not a proper function and that the solution lies on the angle of the tangent vector, but still something is missing.
Any advice will be really appreciated,
thank you.
Alessandro
To track a 2D curve, you should be using an expression for the curvature that is appropriate for general parametrized 2D functions.
While implementing the equation from Wikipedia, you can use discrete differences to approximate the derivatives. Given the x and y coordinates, this could be implemented as follows:
% approximate 1st derivatives of x & y with discrete differences
dx = 0.5*(x(3:end)-x(1:end-2))
dy = 0.5*(y(3:end)-y(1:end-2))
dl = sqrt(dx.^2 + dy.^2)
xp = dx./dl
yp = dy./dl
% approximate 2nd derivatives of x & y with discrete differences
xpp = (x(3:end)-2*x(2:end-1)+x(1:end-2))./(dl.^2)
ypp = (y(3:end)-2*y(2:end-1)+y(1:end-2))./(dl.^2)
% Compute the curvature
curvature = (xp.*ypp - yp.*xpp) ./ ((xp.^2 + yp.^2).^(1.5))
For demonstration purposes I've also constructed a synthetic test signal (which can be used to recreate the same conditions), but you can obviously use your own data instead:
z1 = linspace(2,1,N).*exp(1i*linspace(0.75*pi,-0.25*pi,N))
z2 = 2*exp(-1i*0.25*pi) + linspace(1,2,N)*exp(1i*linspace(0.75*pi,2.25*pi,N))
z = cat(1,z1,z2)
x = real(z)
y = imag(z)
With the corresponding curvature results:

How to plot a sinus uniformly in MATLAB?

If I plot sinus like this
x=0:0.05:2*pi;
y=sin(x);
plot(x,y,'.-')
I'm getting obviously non-uniformly density of points.Please see attachment.sin
What I want is, that points should be at the equivalent distance each other. So, I need to define x array somehow.. or is there is another way?
The point density is uniform in x. If you want the points to be uniform in y, you could use:
y=-1:.05:1;
plot(asin(y),y,'o')
But then the points aren't uniform in x.
EDIT: Just for fun or for any future readers, to get points uniform in overall distance, the distance between points is d=sqrt(h^2+(f(x+h)-f(x))^2) which is approximately d=h*sqrt(1+f'(x)^2), i.e. h=d/sqrt(1+cos(x)^2) in this case. The curve length is the integral of sqrt(1+f'(x)^2) which in this case is 4*sqrt(2)*ellipticE(1/2) = 7.6404:
N = 100;
d = 7.6404/N;
x = zeros(1,N);
for n = 2:N
x(n) = x(n-1) + d/sqrt(1+cos(x(n-1))^2);
end
y = sin(x);
plot(x,y,'x')
You can check that the distance between points is approximately constant by looking at sqrt(diff(y).^2+diff(x).^2). It's only approximate because of the use of the derivative (at the left endpoint of the interval at that) for the distance, but this gets better as N increases. To get the distance exact, we'd need to numerically solve a trig equation for each point. The curve length is also affected by the approximation and tends to miss the last point.

Limit cycle in Matlab for 2nd order autonomous system

I wish to create a limit cycle in Matlab. A limit cycle looks something like this:
I have no idea how to do it though, I've never done anything like this in Matlab.
The equations to describe the limit cycle are the following:
x_1d=x_2
x_2d=-x_1+x_2-2*(x_1+2*x_2)x_2^2
It is to be centered around the equilibrium which is (0,0)
Can any of you help me?
If you use the partial derivatives of your function to make a vector field, you can then use streamlines to visualize the cycle that you are describing.
For example, the function f = x^2+y^2
Gives me partial derivatives dx = 2x, dy=2y For the visualization, I sample from the partial derivatives over a grid.
[x,y] = meshgrid(0:0.1:1,0:0.1:1);
dx = 2*x;
dy = 2*y;
To visualize the vector field, I use quiver;
figure;
quiver(x, y, dx, dy);
Using streamline, I can visualize the path a particle injected into the vector field would take. In my example, I inject the particle at (0.1, 0.1)
streamline(x,y, dx, dy, 0.1, 0.1);
This produces the following visualization
In your case, you can omit the quiver step to remove the hedgehog arrows at every grid point.
Here's another example that shows the particle converging to an orbit.
Edit: Your function specifically.
So as knedlsepp points out, the function you are interested in is a bit ambiguously stated. In Matlab, * represents the matrix product while .* represents the element-wise multiplication between matrices. Similarly, '^2' represents MM for a matrix M, while .^2 represents taking the element-wise power.
So,
[x_1,x_2] = meshgrid(-4:0.1:4,-4:0.1:4);
dx_1 = x_2;
dx_2 = -x_1+x_2-2*(x_1+2*x_2)*(x_2)^2;
figure; streamline(x_1,x_2, dx_1, dx_2, 0:0.1:4, 0:0.1:4);
Looks like
This function will not show convergence because it doesn't converge.
knedlsepp suggests that the function you are actually interested in is
dx_1 = -1 * x_2;
dx_2 = -1 * -x_1+x_2-2*(x_1+2*x_2).*(x_2).^2;
His post has a nice description of the rest.
This post shows the code to produce the integral lines of your vector field defined by:
dx/dt = y
dy/dt = -x+y-2*(x+2*y)*y^2.
It is important to properly vectorize this function. (i.e. Introducing dots at all the important places)
dxdt = #(x,y) y;
dydt = #(x,y) -x+y-2*(x+2*y).*y.^2;
[X,Y] = meshgrid(linspace(-4,4,100));
[sx,sy] = meshgrid(linspace(-3,3,20));
streamline(stream2(X, Y, ... % Points
dxdt(X,Y), dydt(X,Y),... % Derivatives
sx, sy)); % Starting points
axis equal tight
To get a picture more similar to yours, change the grid size and starting points:
[X,Y] = meshgrid(linspace(-1,1,100));
[sx,sy] = meshgrid(linspace(0,0.75,20),0.2);

Rotating Axes Around Line of Fit MATLAB

I'm currently frustrated by the following problem:
I've got trajectory data (i.e.: Longitude and Latitude data) which I interpolate to find a linear fitting (using polyfit and polyval in matlab).
What I'd like to do is to rotate the axes in a way that the x-axis (the Longitude one) ends up lying on the best-fit line, and therefore my data should now lie on this (rotated) axis.
What I've tried is to evaluate the rotation matrix from the slope of the line-of-fit (m in the formula for a first grade polynomial y=mx+q) as
[cos(m) -sin(m);sin(m) cos(m)]
and then multiply my original data by this matrix...to no avail!
I keep obtaining a plot where my data lay in the middle and not on the x-axis where I expect them to be.
What am I missing?
Thank you for any help!
Best Regards,
Wintermute
A couple of things:
If you have a linear function y=mx+b, the angle of that line is atan(m), not m. These are approximately the same for small m', but very different for largem`.
The linear component of a 2+ order polyfit is different than the linear component of a 1st order polyfit. You'll need to fit the data twice, once at your working level, and once with a first order fit.
Given a slope m, there are better ways of computing the rotation matrix than using trig functions (e.g. cos(atan(m))). I always try to avoid trig functions when performing geometry and replace them with linear algebra operations. This is usually faster, and leads to fewer problems with singularities. See code below.
This method is going to lead to problems for some trajectories. For example, consider a north/south trajectory. But that is a longer discussion.
Using the method described, plus the notes above, here is some sample code which implements this:
%Setup some sample data
long = linspace(1.12020, 1.2023, 1000);
lat = sin ( (long-min(long)) / (max(long)-min(long))*2*pi )*0.0001 + linspace(.2, .31, 1000);
%Perform polynomial fit
p = polyfit(long, lat, 4);
%Perform linear fit to identify rotation
pLinear = polyfit(long, lat, 1);
m = pLinear(1); %Assign a common variable for slope
angle = atan(m);
%Setup and apply rotation
% Compute rotation metrix using trig functions
rotationMatrix = [cos(angle) sin(angle); -sin(angle) cos(angle)];
% Compute same rotation metrix without trig
a = sqrt(m^2/(1+m^2)); %a, b are the solution to the system:
b = sqrt(1/(1+m^2)); % {a^2+b^2 = 1}, {m=a/b}
% %That is, the point (b,a) is on the unit
% circle, on a line with slope m
rotationMatrix = [b a; -a b]; %This matrix rotates the point (b,a) to (1,0)
% Generally you rotate data after removing the mean value
longLatRotated = rotationMatrix * [long(:)-mean(long) lat(:)-mean(lat)]';
%Plot to confirm
figure(2937623)
clf
subplot(211)
hold on
plot(long, lat, '.')
plot(long, polyval(p, long), 'k-')
axis tight
title('Initial data')
xlabel('Longitude')
ylabel('Latitude')
subplot(212)
hold on;
plot(longLatRotated(1,:), longLatRotated(2,:),'.b-');
axis tight
title('Rotated data')
xlabel('Rotated x axis')
ylabel('Rotated y axis')
The angle you are looking for in the rotation matrix is the angle of the line makes to the horizontal. This can be found as the arc-tangent of the slope since:
tan(\theta) = Opposite/Adjacent = Rise/Run = slope
so t = atan(m) and noting that you want to rotate the line back to horizontal, define the rotation matrix as:
R = [cos(-t) sin(-t)
sin(-t) cos(-t)]
Now you can rotate your points with R

How to plot a second graph instead of color coding in matlab

i just started with my master thesis and i already am in trouble with my capability/understanding of matlab.
The thing is, i have a trajectory on a surface of a planet/moon whatever (a .mat with the time, and the coordinates. Then i have some .mat with time and the measurement at that time.
I am able to plot this as a color coded trajectory (using the measurement and the coordinates) in scatter(). This works awesomely nice.
However my problem is that i need something more sophisticated.
I now need to take the trajectory and instead of color-coding it, i am supposed to add the graph (value) of the measurement (which is given for each point) to the trajectory (which is not always a straight line). I will added a little sketch to explain what i want. The red arrow shows what i want to add to my plot and the green shows what i have.
You can always transform your data yourself: (using the same notation as #Shai)
x = 0:0.1:10;
y = x;
m = 10*sin(x);
So what you need is the vector normal to the curve at each datapoint:
dx = diff(x); % backward finite differences for 2:end points
dx = [dx(1) dx]; % forward finite difference for 1th point
dy = diff(y);
dy = [dy(1) dy];
curve_tang = [dx ; dy];
% rotate tangential vectors 90° counterclockwise
curve_norm = [-dy; dx];
% normalize the vectors:
nrm_cn = sqrt(sum(abs(curve_norm).^2,1));
curve_norm = curve_norm ./ repmat(sqrt(sum(abs(curve_norm).^2,1)),2,1);
Multiply that vector with the measurement (m), offset it with the datapoint coordinates and you're done:
mx = x + curve_norm(1,:).*m;
my = y + curve_norm(2,:).*m;
plot it with:
figure; hold on
axis equal;
scatter(x,y,[],m);
plot(mx,my)
which is imo exactly what you want. This example has just a straight line as coordinates, but this code can handle any curve just fine:
x=0:0.1:10;y=x.^2;m=sin(x);
t=0:pi/50:2*pi;x=5*cos(t);y=5*sin(t);m=sin(5*t);
If I understand your question correctly, what you need is to rotate your actual data around an origin point at a certain angle. This is pretty simple, as you only need to multiply the coordinates by a rotation matrix. You can then use hold on and plot to overlay your plot with the rotated points, as suggested in the comments.
Example
First, let's generate some data that resembles yours and create a scatter plot:
% # Generate some data
t = -20:0.1:20;
idx = (t ~= 0);
y = ones(size(t));
y(idx) = abs(sin(t(idx)) ./ t(idx)) .^ 0.25;
% # Create a scatter plot
x = 1:numel(y);
figure
scatter(x, x, 10, y, 'filled')
Now let's rotate the points (specified by the values of x and y) around (0, 0) at a 45° angle:
P = [x(:) * sqrt(2), y(:) * 100] * [1, 1; -1, 1] / sqrt(2);
and then plot them on top of the scatter plot:
hold on
axis square
plot(P(:, 1), P(:, 2))
Note the additional things have been done here for visualization purposes:
The final x-coordinates have been stretched (by sqrt(2)) to the appropriate length.
The final y-coordinates have been magnified (by 100) so that the rotated plot stands out.
The axes have been squared to avoid distortion.
This is what you should get:
It seems like you are interested in 3D plotting.
If I understand your question correctly, you have a 2D curve represented as [x(t), y(t)].
Additionally, you have some value m(t) for each point.
Thus we are looking at the plot of a 3D curve [x(t) y(t) m(t)].
you can easily achieve this using
plot3( x, y, m ); % assuming x,y, and m are sorted w.r.t t
alternatively, you can use the 3D version of scatter
scatter3( x, y, m );
pick your choice.
Nice plot BTW.
Good luck with your thesis.