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

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:

Related

How do I find exact rest points?

I have a displacement and a time data of a movement of an object.
The object oscillates around zero. That is, first - it gets set into motion by a small amount of force, then it comes to rest. again, a little force is applied and object gets set into motion.
I have found out the velocity and acceleration using
V= [0 ; diff(disp) ./ diff(times)];
A= [0; diff(V) ./ diff(times)];
I was thinking of finding points where velocity is zero. But i guess there are more than required such instances. Find the graph below:
velocity plot
I am interested in only circles time values. Is there a way to get these?
I observe a pattern
velocity increases then decreases by almost same amount.
Then due to friction, it crosses zero by a smaller amount and again becomes negative
finally comes to rest, but a very little velocity is still present.
It is this touch point to zero that I want. Then again force is applied and the same cycle repeats.
Pl note that I do not have a time of when force is applied. Otherwise there was nothing to be done.
Also, I did plot the acceleration. But is seems so useless..
I am using matlab.
Here's one way to find approximate zeros in gridded data:
% some dummy synthetic data
x = linspace(0, 10, 1e3);
y = exp(-0.3*x) .* sin(x) .* cos(pi*x);
% its derivative (presumably your "acceleration")
yp = diff(y) ./ diff(x);
% Plot data to get an overview
plot(x,y), hold on
% Find zero crossings (product of two consecutive data points is negative)
zero_x = y(1:end-1) .* y(2:end) < 0;
% Use derivative for linear interpolation between those points
x_cross = x(zero_x) + y(zero_x)./yp(zero_x);
% Plot those zeros
plot(x_cross, zeros(size(x_cross)), 'ro')
Result:
It is then up to you to select which zeros you need, because I could not understand from the question what made those points in the circles so special...
The resting points you asked have the following property:
dx / dt = v = 0
d^2 x / dt^2 = a = 0 # at the instance that the object becomes v = 0, there is no force on it.
So you may want to check also the second formula to filter the resting points.

Integrating Velocity Over a Complex 2-D Surface

I'm using matlab to calculate the the average velocity in the cross section of a pipe by integrating discrete velocity points over a surface. The points are scattered in a random pattern that form a circle (almost).
I used scatteredinterpolant to create a function relating x and y to v (velocity) in order to create a grid of interpolated values.
F = scatteredInterpolant(x, y, v,'linear');
vq = F(xq,yq); % where xq and yq are a set of query points
The problem I am now having is trying to calculate the the surface area of this function, but only in this circular portion that contains all the scatter points.
The first way I went about this was using the quad2d function.
int = quad2d(#(x,y) F(x,y), min(x), max(x), min(y), max(y), 'MaxFunEvals', 100000);
However this gives is incorrect as it takes the area over a rectangle and a circle.
Now I can probably define the surface area with a circle but in the future I will have to work with more complex shapes so I want to use points that define the boundary of the scatter points.
I'm doing this through triangulation, using the following command.
DT = delaunayTriangulation(x,y);
However I have no idea how I can incorporate these points into a quad2d function. I was hoping someone might have a suggestion or possibly another method I could use in calculating the area over these complex surfaces.
Thanks!
You could assume your function to be piecewise linear on your integration area and then integrate it using a midpoint quadrature rule:
For every triangle you compute the midpoint value as the mean of the nodal values and multiply by the triangle's area. You sum it all up to get your integral.
function int = integrate(T, values)
meanOnTriangle = mean(values(T.ConnectivityList),2);
int = sum(getElementAreas(T).*meanOnTriangle);
end
function areas = getElementAreas(T)
X = #(d) T.Points(T.ConnectivityList(:,d),:);
d21 = X(2)-X(1);
d31 = X(3)-X(1);
areas = abs(1/2*(d21(:,1).*d31(:,2)-d21(:,2).*d31(:,1)));
end
As your goal is the average velocity, you want to compute the following quantity:
averageVelocity = integrate(DT,v)/sum(getElementAreas(DT));

Plotting a closed interal function MATLAB

I need a help. I have to generate a curve using MATLAB. The plot is defined by the formula (an analytic expression) :-
where, the meaning of the variables are as follows: R is the distributed resistive function, S is the distributive conductive function, k is the sheet resistance and r(x,y) is the distance between *
(x,y)*, and the perimeter dl with the integration made around all the perimeter of the chip.
A squared foil as shown in the figure with sides (a) 10 arbitrary units long and an unitary unit sheet resistance (k=1 ohm) is used for our consideration. The plot of the function R(x,y) is supposed to come out like this...
I literally have no clue how to plot this function. I could not even get the idea how to define the distance function r(x,y) with respect to dl. On top of that it is complicated further by the closed integral. Please help me. Any help in even simplifying the expression is also welcome. Is there any possible closed form expression for such a square structure ?
Thanks in advance. The link to the paper is here. paper here
Reconstructing the math
The definition of the function R is not particularly clear, but I guess what they mean is:
With dOmega being the boundary of the foil and p a point p = [px,py] on the foil.
Imagine that for a point p on the sheet you are computing R(p) by going around the boundary of the foil (what they call the perimeter), your position being q, and integrating one divided by the distance from you (q) to the point p multiplied by k.
I guess you could analytically compute the integral for this rectangular sheet, but if you just want to plot the function, you could simply approximate the integral by defining a finite number of points on the boundary, evaluating the integrand in those points, then taking the mean and multiplying by the perimeter. [The same way you could approximate integral(f(x), x=0...pi) by pi*(f(0)+f(pi/2)+f(pi))/3]
Alternative representation using coordinates:
If you are only familiar with integrals along the real line in coordinate representation you could write this in the following way, which is frankly quite UGGGLY:
Plotting an approximation
%% Config:
xlen = 10;
ylen = 10;
k = 1;
%% Setting up points on the boundary of the square
x = linspace(0,xlen,50);
y = linspace(0,ylen,50);
perimeter = 2*(xlen+ylen);
boundary = [x(1)*ones(length(y),1), y'
x', y(1)*ones(length(x),1); ...
x(end)*ones(length(y),1), y'; ...
x', y(end)*ones(length(x),1)];
%% Function definition
norm2 = #(X) sqrt(sum(X.^2,2));
R = #(p) 1/(perimeter*mean(1./(k*norm2(bsxfun(#minus,boundary,p)))));
%% Plotting
[X_grid,Y_grid] = ndgrid(x,y);
R_grid = zeros(size(X_grid));
for ii = 1:length(x)
for jj = 1:length(y)
R_grid(ii,jj) = R([x(ii),y(jj)]);
end
end
surf(X_grid, Y_grid, R_grid);
axis vis3d;
This will give you the following plot:

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 get normal vector from position vector function in 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));