Matlab line fitting: Singular value decomposition (SVD) - matlab

I tried to fit a line using 2D points. By using the SVD, I've successfully fit lines. However, in the one case, I failed to fit lines. Please, give me some advise and let me know the reasons.
% Data
X = [487,520.40,553.81,587.22,620.63,654.04,500,533.01,566.02,599.03,642,674.61,707.22,517,552.35,587.71,647,682.35,717.71,522,555.97,589.94,623.91,657.88];
Y = [521,558.20,595.40,632.60,669.80,707.00,533,570.55,608.10,645.66,695,732.90,770.80,564,599.35,634.71,694,729.35,764.71,562,598.68,635.37,672.06,708.75];
% b1*x + b2*y +b3 = 0
M = [X', Y', ones(size(X'))];
[~, ~, V] = svd(M);
B = V(:, 3);
b1 = B(1);
b2 = B(2);
b3 = B(3);
% Draw points
figure(111)
hold on;
plot(X, Y, 'ro');
% Draw line
minX = min(X);
maxX = max(X);
valY_minX = -(b3 + b1*minX) / b2;
valY_maxX = -(b3 + b1*maxX) / b2;
Pt1 = [minX; valY_minX];
Pt2 = [maxX; valY_maxX];
plot([Pt1(1), Pt2(1)], [Pt1(2), Pt2(2)]);
I've got succeed fit the line when I changed to 'V(:, 2)'. Why the second largest eigen value brings the best solution??

Related

I can not figure out why my for loop is not being taken in MATLAB

In MATLAB, I am trying to write a program that will take 3 coordinates on a graph, (x,y), use those values to solve a system of equations that will find the coefficients of a polynomial equation, y = ax^2 + bx + c, which I can then use to plot a parabola.
To test my code, I figured I could start with a polynomial, graph it, find the minimum location of the parabola, use its immediate neighbors for my other 2 locations, then run those 3 locations through my code which should spit out the coefficients of my original polynomial. But for some reason, my resulting parabola is right shifted and my values for b and c are incorrect.
Does anyone see where my issue is? I am out of ideas
clear all; close all;
x = -10:10;
%Original Polynomial
y = 6.*x.^2 + 11.*x -35;
% Find 3 Locations
[max_n, max_i] = min(y)
max_il = max_i - 1 % left neighbor of max_ni
max_nl = y(max_il) % value at max_il
max_ir = max_i + 1 % left neighbor of max_ni
max_nr = y(max_ir) % value at max_ir
% Solve for coefficients
syms a b c
equ = (a)*(max_i)^2 + (b)*(max_i) + (c) == (max_n);
equ_l = (a)*(max_il)^2 + (b)*(max_il) + (c) == (max_nl);
equ_r = (a)*(max_ir)^2 + (b)*(max_ir) + (c) == (max_nr);
sol = solve([equ, equ_l, equ_r],[a, b, c]);
Sola = sol.a
Solb = sol.b
Solc = sol.c
% New Polynomial
p = (sol.a).*(x).^2 + (sol.b).*(x) +(sol.c);
%Plot
plot(x,y); grid on; hold on;
plot(x, p);
axis([-10 10 -41 40])
[max_np, max_ip] = min(p)
legend('OG', 'New')
You are confusing the index into your array y, and the corresponding x coordinate.
x = -10:10;
y = 6.*x.^2 + 11.*x -35;
[max_n, max_i] = min(y)
Here. max_i is the index into the y array, the corresponding x coordinate would be x(max_i).
I suggest you find three data points to fit your curve to as follows:
[~, max_i] = min(y);
pts_x = x(max_i + (-1:1));
pts_y = y(max_i + (-1:1));
then use pts_x(i) and pts_y(i) as your x and y values:
syms a b c
equ = a * pts_x.^2 + b * pts_x + c == pts_y;
sol = solve(equ, [a, b, c]);

How to plot 4 separate lines to form a square in MATLAB?

I am plotting 4 random separate lines in a plot, and I want them to be connected to form a square. This is what I've got so far, any pointers would be really helpful. Also, this is my first time using MATLAB so please don't come for me.
N = 1;
L = 0.2;
x = L +rand(1,N)*(1-2*L);
y = L +rand(1,N)*(1-2*L);
angs = rand(1,N)*360;
xe = x - L*cosd(angs);
ye = y + L*sind(angs);
xb = -x - L*cosd(angs);
yb = y + L*sind(angs);
ax = axes;
plot(ax,[x;xe],[y;ye],[x;xb],[y;yb])
axis square
I need them to be 4 lines of the same length that join to make a square. The above code gives me 2 connecting lines but I really don't know where to go from there.
My attempt of the above code:
The plot function simply plots the x- and y- coordinates that you give it. Giving it the correct coordinates to plot is your job. So how would you figure out the coordinates of a square, given a starting point and the length and direction of one of the sides?
Suppose we have
p0 = rand(1, 2); % p0(1) => x; p0(2) => y
L = 10;
d0 = rand(1, 2); % The direction vector.
First, let's convert the direction into a unit vector.
u_vec = d0 ./ norm(d0);
Next, let's rotate this vector by 90 degrees to get the unit vector for the perpendicular side
u_perp = ([0, -1; 1 0] * u_vec')';
Using vector addition, we know that the second point is p1 = p0 + L * u_vec. The third point is p2 = p1 + L * u_perp, and the final point is p3 = p_0 + L * u_perp. We can stack these vectors just to make it easier to type out the plotting code:
l1 = [p0; p1];
l2 = [p1; p2];
l3 = [p2; p3];
l4 = [p3; p0];
And finally plot them:
figure();
hold on;
plot(l1(:, 1), l1(:, 2));
plot(l2(:, 1), l2(:, 2));
plot(l3(:, 1), l3(:, 2));
plot(l4(:, 1), l4(:, 2));
axis square;
Or, you could stack everything into one array and plot using a single line:
sq = [p0; p1; p2; p3; p0];
figure();
plot(sq(:, 1), sq(:, 2));
axis square;

MATLAB plotting trajectory

I would like to plot the angular velocity of point B by using MATLAB. However, there is some mistake in my code for angular velocity that I couldn't fix.
The length of the input link OA of the mechanism is r = 50 mm, length of AB is l = 150 mm. Fixed coordinates of point C are xC = d = 80 mm and yC = 0 mm.
Angular velocity of OA is ω = 15 rad/s.
%Full trajectory of B
%Linkage dimensions
clear
r = 50;
l = 150;
xC = 80;
yC = 0;
n = 361; % Number of position calculations
fii = linspace(0,2*pi,n);
omega = 15;
[xA,yA] = pol2cart(fii,r);
d = xA + xC;
alpha = atan(yA./(xC-xA));
lx = l*cos(alpha);
ly = l*sin(alpha);
xB = xA + lx;
yB = yA + ly;
plot(xB,yB) %Plots the trajectory
title('Full trajectory of AB')
% Angular velocity of AB
for ind = 1:n
omegaAB(ind) = (-(r^2-d*r*cos(fii))/(r^2 + d^2 - 2*d*r*cos(fii)))*omega;
end
figure(2)
plot(fii,omegaAB, 'linewidth', 2, 'color', 'red')
title('Angular velocity of AB')
ylabel('\omega_{AB} [1/s]')
xlabel('\phi [rad]')
I think there is just one mistake in your code when you compute alpha:
alpha = atan(yA./(xC-xA));
This gives the following trajectory:
Your code is partially vectorized but you're still looping over ind which is why you are getting matrix dimensions errors. You can either remove the loop and make it completely vectorized or you can make sure that all of your vectors with length n are indexed properly:
for ind = 1:n
omegaAB(ind) = (-(r^2-d*r*cos(fii(ind)))/(r^2 + d(ind)^2 - 2*d*r*cos(fii(ind))))*omega;
end

Unexpected result when calculating mean curvature in MatLab

I am running simulations of a protein/membrane system, and want to quantify the degree of membrane deformation. I have averaged the membrane surface on a grid during the simulation, which results in a text file with three columns, containing the x, y, and z points of the membrane. I then convert this information to a mesh surface in matlab, which I then use to calculate the gaussian and/or mean curvature. The problem is, I'm getting similar values at the very beginning of the simulation, when the surface (membrane) is very flat, and at the end, when it is completely deformed. Unless I'm misunderstanding what curvature is, this is not correct and I believe I am doing something wrong in the matlab portion of this process. Here's the script where I loop over many frames (each of which is a different file containing x,y,z coordinates of the averaged membrane) and convert it to a mesh:
https://pastebin.com/reqWAz01
for i = 0:37
file = strcat('cg-topmem_pos-', num2str(i), '.out');
A = load(file);
x = A(:,1);
y = A(:,2);
z = A(:,3);
xv = linspace(min(x), max(x), 20);
yv = linspace(min(y), max(y), 20);
[X,Y] = meshgrid(xv, yv);
Z = griddata(x,y,z,X,Y);
[K,H,Pmax,Pmin] = surfature(X,Y,Z);
M = max(max(H))
if i == 0
fileID = fopen('Average2-NoTMHS-5nmns.txt', 'a');
fprintf(fileID, '%f %f\n',M);
fclose(fileID);
else
fileID = fopen('Average2-NoTMHS-5nmns.txt', 'a');
fprintf(fileID, '\n%f %f\n',M);
fclose(fileID);
end
end
Then using the following calculates curvature:
https://pastebin.com/5D21PdBQ
function [K,H,Pmax,Pmin] = surfature(X,Y,Z),
% SURFATURE - COMPUTE GAUSSIAN AND MEAN CURVATURES OF A SURFACE
% [K,H] = SURFATURE(X,Y,Z), WHERE X,Y,Z ARE 2D ARRAYS OF POINTS ON THE
% SURFACE. K AND H ARE THE GAUSSIAN AND MEAN CURVATURES, RESPECTIVELY.
% SURFATURE RETURNS 2 ADDITIONAL ARGUMENTS,
% [K,H,Pmax,Pmin] = SURFATURE(...), WHERE Pmax AND Pmin ARE THE MINIMUM
% AND MAXIMUM CURVATURES AT EACH POINT, RESPECTIVELY.
% First Derivatives
[Xu,Xv] = gradient(X);
[Yu,Yv] = gradient(Y);
[Zu,Zv] = gradient(Z);
% Second Derivatives
[Xuu,Xuv] = gradient(Xu);
[Yuu,Yuv] = gradient(Yu);
[Zuu,Zuv] = gradient(Zu);
[Xuv,Xvv] = gradient(Xv);
[Yuv,Yvv] = gradient(Yv);
[Zuv,Zvv] = gradient(Zv);
% Reshape 2D Arrays into Vectors
Xu = Xu(:); Yu = Yu(:); Zu = Zu(:);
Xv = Xv(:); Yv = Yv(:); Zv = Zv(:);
Xuu = Xuu(:); Yuu = Yuu(:); Zuu = Zuu(:);
Xuv = Xuv(:); Yuv = Yuv(:); Zuv = Zuv(:);
Xvv = Xvv(:); Yvv = Yvv(:); Zvv = Zvv(:);
Xu = [Xu Yu Zu];
Xv = [Xv Yv Zv];
Xuu = [Xuu Yuu Zuu];
Xuv = [Xuv Yuv Zuv];
Xvv = [Xvv Yvv Zvv];
% First fundamental Coeffecients of the surface (E,F,G)
E = dot(Xu,Xu,2);
F = dot(Xu,Xv,2);
G = dot(Xv,Xv,2);
m = cross(Xu,Xv,2);
p = sqrt(dot(m,m,2));
n = m./[p p p];
% Second fundamental Coeffecients of the surface (L,M,N)
L = dot(Xuu,n,2);
M = dot(Xuv,n,2);
N = dot(Xvv,n,2);
[s,t] = size(Z);
% Gaussian Curvature
K = (L.*N - M.^2)./(E.*G - F.^2);
K = reshape(K,s,t);
% Mean Curvature
H = (E.*N + G.*L - 2.*F.*M)./(2*(E.*G - F.^2));
H = reshape(H,s,t);
% Principal Curvatures
Pmax = H + sqrt(H.^2 - K);
Pmin = H - sqrt(H.^2 - K);
Any help would be greatly appreciated. I'm afraid that there is some issue between how the mesh is created and how curvature is calculated, but I am not matlab literate and could use some help. Thanks very much.

Plotting a Parametric Spline Curve Using a Periodic Spline

I want to plot a curve like this using a periodic spline:
I have the following values:
And so, I have created the following matlab code to plot this function:
%initializing values
t = [1,2,3,4,5,6,7,8,9,10,11,12,13];
tplot = [1:0.1:13];
x = [2.5,1.3,-0.25,0.0,0.25,-1.3,-2.5,-1.3,0.25,0.0,-0.25,1.3,2.5];
y = [0.0,-0.25,1.3,2.5,1.3,-0.25,0.0,0.25,-1.3,-2.5,-1.3,0.25,0.0];
[a1, b1, c1, d1] = perspline2(t,x);
[a2, b2, c2, d2] = perspline2(t,y);
for i = 1:12
xx = linspace(x(i), x(i+1), 100);
xxx = a1(i) + b1(i)*(xx-x(i)) + c1(i)*(xx-x(i)).^2 ...
+ d1(i)*(xx-x(i)).^3;
yyy = a2(i) + b2(i)*(xx-x(i)) + c2(i)*(xx-x(i)).^2 ...
+ d2(i)*(xx-x(i)).^3;
h3=plot(xxx, yyy, 'r-');
hold on
end
plot(x,y,'k.', 'MarkerSize', 30)
hold off
With perspline2() looking like this:
function [a1,b1,c1,d1] = perspline2(xnot,ynot)
x = xnot';
y = ynot';
n = length(x) - 1;
h = diff(x);
diag0 = [1; 2*(h(1:end-1)+h(2:end)); 2*h(end)];
A = spdiags([[h;0], diag0, [0;h]], [-1, 0, 1], n+1, n+1);
% Do a little surgery on the matrix:
A(1,2) = 0;
A(1,end) = -1;
A(end,1) = 2*h(1);
A(end,2) = h(1);
dy = diff(y);
rhs = 6*[0; diff(dy./h); dy(1)/h(1)-dy(end)/h(end)];
m = A \ rhs; % Solve for the slopes, S''(x_i)
% Compute the coefficients of the cubics.
a1 = y;
b1 = dy./h - h.*m(1:end-1)/2 - h.*diff(m)/6;
c1 = m/2;
d1 = diff(m)./h/6;
So basically, I know that I must use a parametric spline in order to find the correct points to plot.
I use t = [1,2,3,4,5,6,7,8,9,10,11,12,13]; as my indexes. So, I find the coefficients for the cubic spline polynomial of t vs. x and then find the coefficients for t vs. y, and then I attempt to plot them against each other using values from t in order to plot the parametric curve. However, I keep getting this curve:
I am really not sure why this is occurring.
P.S I know I can use the matlab spline function but when I do, it results in the right cusp being a bit bigger than the other cusps. I want all cusps to be equal in size and the assignment says that we must use a cubic spline.
Any help is greatly appreciated.