Change the grid points of parametric splines in Matlab - matlab

My Code right now
% Create some example points x and y
t = pi*[0:.05:1,1.1,1.2:.02:2]; a = 3/2*sqrt(2);
for i=1:size(t,2)
x(i) = a*sqrt(2)*cos(t(i))/(sin(t(i)).^2+1);
y(i) = a*sqrt(2)*cos(t(i))*sin(t(i))/(sin(t(i))^2+1);
end
Please note: The points (x_i|y_i) are not necessarily equidistant, that's why t is created like this. Also t should not be used in further code as for my real problems it is not known, I just get a bunch of x, y and z values in the end. For this example I reduced it to 2D.
Now I'm creating ParametricSplines for the x and y values
% Spline
n=100; [x_t, y_t, tt] = ParametricSpline(x, y, n);
xref = ppval(x_t, tt); yref = ppval(y_t, tt);
with the function
function [ x_t, y_t, t_t ] = ParametricSpline(x,y,n)
m = length(x);
t = zeros(m, 1);
for i=2:m
arc_length = sqrt((x(i)-x(i-1))^2 + (y(i)-y(i-1))^2);
t(i) = t(i-1) + arc_length;
end
t=t./t(length(t));
x_t = spline(t, x);
y_t = spline(t, y);
t_t = linspace(0,1,n);
end
The plot generated by
plot(x,y,'ob',...
xref,yref,'xk',...
xref,yref,'-r'),...
axis equal;
looks like the follows: Plot Spline
The Question:
How do I change the code so I always have one of the resulting points (xref_i|yref_i) (shown as Black X in the plot) directly on the originally given points (x_j|y_j) (shown as Blue O) with additionally n points between (x_j|y_j) and (x_j+1|y_j+1)?
E.g. with n=2 I would like to get the following:
(xref_1|yref_1) = (x_1|y_1)
(xref_2|yref_2)
(xref_3|yref_3)
(xref_4|yref_4) = (x_2|y_2)
(xref_5|yref_5)
[...]
I guess the only thing I need is to change the definition of tt but I just can't figure out how... Thanks for your help!

Use this as your function:
function [ x_t, y_t, tt ] = ParametricSpline(x,y,nt)
arc_length = 0;
n = length(x);
t = zeros(n, 1);
mul_p = linspace(0,1,nt+2)';
mul_p = mul_p(2:end);
tt = t(1);
for i=2:n
arc_length = sqrt((x(i)-x(i-1))^2 + (y(i)-y(i-1))^2);
t(i) = t(i-1) + arc_length;
add_points = mul_p * arc_length + t(i-1);
tt = [tt ; add_points];
end
t=t./t(end);
tt = tt./tt(end);
x_t = spline(t, x);
y_t = spline(t, y);
end
The essence:
You have to construct tt in the same way as your distance vector t plus add additional nt points in between.

Related

Using the Runge-Kutta integration method in a system

h=0.005;
x = 0:h:40;
y = zeros(1,length(x));
y(1) = 0;
F_xy = ;
for i=1:(length(x)-1)
k_1 = F_xy(x(i),y(i));
k_2 = F_xy(x(i)+0.5*h,y(i)+0.5*h*k_1);
k_3 = F_xy((x(i)+0.5*h),(y(i)+0.5*h*k_2));
k_4 = F_xy((x(i)+h),(y(i)+k_3*h));
y(i+1) = y(i) + (1/6)*(k_1+2*k_2+2*k_3+k_4)*h;
end
I have the following code, I think it's right. I know there's parts missing on the F_xy because this is my follow up question.
I have dx/dt = = −x(2 − y) with t_0 = 0, x(t_0) = 1
and dy/dt = y(1 − 2x) with t_0 = 0, y(t_0) = 2.
My question is that I don't know how to get these equations in to the code. All help appreciated
You are using both t and x as independent variable in an inconsistent manner. Going from the actual differential equations, the independent variable is t, while the dependent variables of the 2-dimensional system are x and y. They can be combined into a state vector u=[x,y] Then one way to encode the system close to what you wrote is
h=0.005;
t = 0:h:40;
u0 = [1, 2]
u = [ u0 ]
function udot = F(t,u)
x = u(1); y = u(2);
udot = [ -x*(2 - y), y*(1 - 2*x) ]
end
for i=1:(length(t)-1)
k_1 = F(t(i) , u(i,:) );
k_2 = F(t(i)+0.5*h, u(i,:)+0.5*h*k_1);
k_3 = F(t(i)+0.5*h, u(i,:)+0.5*h*k_2);
k_4 = F(t(i)+ h, u(i,:)+ h*k_3);
u(i+1,:) = u(i,:) + (h/6)*(k_1+2*k_2+2*k_3+k_4);
end
with a solution output
Is F_xy your derivative function?
If so, simply write it as a helper function or function handle. For example,
F_xy=#(x,y)[-x*(2-y);y*(1-2*x)];
Also note that your k_1, k_2, k_3, k_4, y(i) are all two-dimensional. You need to re-size your y and rewrite the indices in your iterating steps accordingly.

Plotting a 2d vector on 3d axes in matlab

I have three vectors x,y,t. For each combination x,y,t there is a (u,v) value associated with it. How to plot this in matlab? Actually I'm trying to plot the solution of 2d hyperbolic equation
vt = A1vx + A2vy where A1 and A2 are 2*2 matrices and v is a 2*1 vector. I was trying scatter3 and quiver3 but being new to matlab I'm not able to represent the solution correctly.
In the below code I have plot at only a particular time-level. How to show the complete solution in just one plot? Any help?
A1 = [5/3 2/3; 1/3 4/3];
A2 = [-1 -2; -1 0];
M = 10;
N = 40;
delta_x = 1/M;
delta_y = delta_x;
delta_t = 1/N;
x_points = 0:delta_x:1;
y_points = 0:delta_y:1;
t_points = 0:delta_t:1;
u = zeros(M+1,M+1,N+1,2);
for i=1:M+1,
for j=1:M+1,
u(i,j,1,1) = (sin(pi*x_points(i)))*sin(2*pi*y_points(j)) ;
u(i,j,1,2) = cos(2*pi*x_points(i));
end
end
for j=1:M+1,
for t=1:N+1,
u(M+1,j,t,1) = sin(2*t);
u(M+1,j,t,2) = cos(2*t);
end
end
for i=1:M+1
for t=1:N+1
u(i,1,t,1) = sin(2*t);
u(i,M+1,t,2) = sin(5*t) ;
end
end
Rx = delta_t/delta_x;
Ry = delta_t/delta_y;
for t=2:N+1
v = zeros(M+1,M+1,2);
for i=2:M,
for j=2:M,
A = [(u(i+1,j,t-1,1) - u(i-1,j,t-1,1)) ; (u(i+1,j,t-1,2) - u(i-1,j,t-1,2))];
B = [(u(i+1,j,t-1,1) -2*u(i,j,t-1,1) +u(i-1,j,t-1,1)) ; (u(i+1,j,t-1,2) -2*u(i,j,t-1,2) +u(i-1,j,t-1,2))];
C = [u(i,j,t-1,1) ; u(i,j,t-1,2)];
v(i,j,:) = C + Rx*A1*A/2 + Rx*Rx*A1*A1*B/2;
end
end
for i=2:M,
for j=2:M,
A = [(v(i,j+1,1) - v(i,j-1,1)) ; (v(i,j+1,2) - v(i,j-1,2)) ];
B = [(v(i,j+1,1) - 2*v(i,j,1) +v(i,j-1,1)) ; (v(i,j+1,2) - 2*v(i,j,2) +v(i,j-1,2))];
C = [v(i,j,1) ; v(i,j,2)];
u(i,j,t,:) = C + Ry*A2*A/2 + Ry*Ry*A2*A2*B/2;
end
end
if j==2
u(i,1,t,2) = u(i,2,t,2);
end
if j==M
u(i,M+1,t,1) = u(i,M,t,1);
end
if i==2
u(1,j,t,:) = u(2,j,t,:) ;
end
end
time_level = 2;
quiver(x_points, y_points, u(:,:,time_level,1), u(:,:,time_level,2))
You can plot it in 3D, but personally I think it would be hard to make sense of.
There's a quiver3 equivalent for your plotting function. z-axis in this case would be time (say, equally spaced), and z components of the vectors would be zero. Unlike 2D version of this function, it does not support passing in coordinate vectors, so you need to create the grid explicitly using meshgrid:
sz = size(u);
[X, Y, Z] = meshgrid(x_points, y_points, 1:sz(3));
quiver3(X, Y, Z, u(:,:,:,1), u(:,:,:,2), zeros(sz(1:3)));
You may also color each timescale differently by plotting them one at a time, but it's still hard to make sense of the results:
figure(); hold('all');
for z = 1:sz(3)
[X, Y, Z] = meshgrid(x_points, y_points, z);
quiver3(X, Y, Z, u(:,:,z,1), u(:,:,z,2), zeros([sz(1:2),1]));
end

Matlab: Editing the lhsnorm() function for Latin Hypercube

I am attempting to edit the lhsnorm function so that I can obtain Latin Hypercube sample from a Normally distributed set of data.
The lhsnorm function is as follows:
function [X,z] = lhsnorm(mu,sigma,n,dosmooth)
%LHSNORM Generate a latin hypercube sample with a normal distribution
z1 = mvnrnd(mu,sigma,numel(z));
%%%%%%%%Is it possible for me to change this to a univariate distribution
% without affecting the rest of the code ?????
% Find the ranks of each column
p = length(mu);
x = zeros(size(z),class(z));
for i=1:p
x(:,i) = rank(z(:,i));
end
% Get gridded or smoothed-out values on the unit interval
if (nargin<4) || isequal(dosmooth,'on')
x = x - rand(size(x));
else
x = x - 0.5;
end
x = x / n;
% Transform each column back to the desired marginal distribution,
% maintaining the ranks (and therefore rank correlations)
for i=1:p
x(:,i) = norminv(x(:,i),mu(i), sqrt(sigma(i,i)));
end
X = x;
function r=rank(x)
% Similar to tiedrank, but no adjustment for ties here
[sx, rowidx] = sort(x);
r(rowidx) = 1:length(x);
r = r(:);
I am editing the code as is shown below:
function [X] = lhsnorm_sid(z,dosmooth)
[muhat,sigmahat] = normfit(z);
z = z';
% Find the ranks of each column
p = length(muhat);
x = zeros(size(z),class(z));
s = size(z);
n = s(1,1);
for i=1:p
x(:,i) = rank(z(:,i));
end
if (nargin<4) || isequal(dosmooth,'on')
x = x - rand(size(x));
else
x = x - 0.5;
end
x = x / n;
for i=1:p
x(:,i) = norminv(x(:,i),muhat(i), sqrt(sigmahat(i,i)));
end
X = x;
function r=rank(x)
[sx, rowidx] = sort(x);
r(rowidx) = 1:length(x);
r = r(:);
However, I end up with Latin Hypercube values which are way off what is expected. I also tried directly substituting z with d(1,:) which contains a Normally distributed set of data, however the Latin Hypercube I obtained did not contain any of the values in d(1,:).
Thanks

Debugging construction of splines between a variable amount of points

Given an amount of points in x and y I want to create splines that intersect all points and that have the same slopes in intersections.
My approach has been to establish a set of equations for intersection of points as well as dictating equal slopes at intersections and then use fsolve() to determine coefficients.
However, when plotting the found splines they do not have the same slopes at intersecting points though they do intersect the correct points given in x and y.
I have been trying to debug this script for most of two days now without any luck. Can someone point out why my splines are not getting the correct slopes? Or can it be that fsolve() quits before a satisfactory solution has been found?
Main file:
result = fsolve(#(K) eqns(x,y,K) , ones(1,(size(x,1)-1)*3) ); %Calls eqns() in eqns.m
A = result(1 : size(x,1)-1 );
B = result(size(x,1) : 2*size(x,1)-2 );
C = result(2*size(x,1)-1 : 3*size(x,1)-3 );
%Plot splines
splinePts = size(A,2)*100;
x_spline = [0 : x(end)/splinePts : x(end)];
fx = ones(splinePts,1);
for i = 1:size(A,2)
for j = 1:100
k = i*100-100 + j;
fx(k) = A(i) * x_spline(k)^2 + B(i) * x_spline(k) + C(i);
end
end
plot(fx);
eqns.m
function fcns=eqns(x,y,K)
A = K(1 : size(x,1)-1 ); %Coefficients for X^2
B = K(size(x,1) : 2*size(x,1)-2); %Coefficients for X
C = K(2*size(x,1)-1 : 3*size(x,1)-3); %Constants
%Equations for hitting all points
syms H;
temp = H; %Initiate variable for containing equations.
for i = 1:size(B,2)
temp(end+1) = eqn(x(i),y(i),A,B,C,i); %Calls eqn() in eqn.
temp(end+1) = eqn(x(i+1),y(i+1),A,B,C,i);
end
%Equations for slopes at spline intersections
syms X;
temp(end+1) = subs( diff(eqn(X,0,A,B,C,1),X) - 0 , 'X' , x(1) );
for i = 1:size(A,2)-1
temp(end+1) = subs( diff(eqn(X,1,A,B,C,i),X) - diff(eqn(X,1,A,B,C,i+1),X) , 'X' , x(i)+1 );
end
fcns = double( temp(2:end) );
end
eqn.m
function fcn=eqn(X,Y,A,B,C,i)
fcn = A(i)*X^2 + B(i)*X + C(i) - Y;
end

Least squares circle fitting using MATLAB Optimization Toolbox

I am trying to implement least squares circle fitting following this paper (sorry I can't publish it). The paper states, that we could fit a circle, by calculating the geometric error as the euclidean distance (Xi'') between a specific point (Xi) and the corresponding point on the circle (Xi'). We have three parametres: Xc (a vector of coordinates the center of circle), and R (radius).
I came up with the following MATLAB code (note that I am trying to fit circles, not spheres as it is indicated on the images):
function [ circle ] = fit_circle( X )
% Kör paraméterstruktúra inicializálása
% R - kör sugara
% Xc - kör középpontja
circle.R = NaN;
circle.Xc = [ NaN; NaN ];
% Kezdeti illesztés
% A köz középpontja legyen a súlypont
% A sugara legyen az átlagos négyzetes távolság a középponttól
circle.Xc = mean( X );
d = bsxfun(#minus, X, circle.Xc);
circle.R = mean(bsxfun(#hypot, d(:,1), d(:,2)));
circle.Xc = circle.Xc(1:2)+random('norm', 0, 1, size(circle.Xc));
% Optimalizáció
options = optimset('Jacobian', 'on');
out = lsqnonlin(#ort_error, [circle.Xc(1), circle.Xc(2), circle.R], [], [], options, X);
end
%% Cost function
function [ error, J ] = ort_error( P, X )
%% Calculate error
R = P(3);
a = P(1);
b = P(2);
d = bsxfun(#minus, X, P(1:2)); % X - Xc
n = bsxfun(#hypot, d(:,1), d(:,2)); % || X - Xc ||
res = d - R * bsxfun(#times,d,1./n);
error = zeros(2*size(X,1), 1);
error(1:2:2*size(X,1)) = res(:,1);
error(2:2:2*size(X,1)) = res(:,2);
%% Jacobian
xdR = d(:,1)./n;
ydR = d(:,2)./n;
xdx = bsxfun(#plus,-R./n+(d(:,1).^2*R)./n.^3,1);
ydy = bsxfun(#plus,-R./n+(d(:,2).^2*R)./n.^3,1);
xdy = (d(:,1).*d(:,2)*R)./n.^3;
ydx = xdy;
J = zeros(2*size(X,1), 3);
J(1:2:2*size(X,1),:) = [ xdR, xdx, xdy ];
J(2:2:2*size(X,1),:) = [ ydR, ydx, ydy ];
end
The fitting however is not too good: if I start with the good parameter vector the algorithm terminates at the first step (so there is a local minima where it should be), but if I perturb the starting point (with a noiseless circle) the fitting stops with very large errors. I am sure that I've overlooked something in my implementation.
For what it's worth, I implemented these methods in MATLAB a while ago. However, I did it apparently before I knew about lsqnonlin etc, as it uses a hand-implemented regression. This is probably slow, but may help to compare with your code.
function [x, y, r, sq_error] = circFit ( P )
%# CIRCFIT fits a circle to a set of points using least sqaures
%# P is a 2 x n matrix of points to be fitted
per_error = 0.1/100; % i.e. 0.1%
%# initial estimates
X = mean(P, 2)';
r = sqrt(mean(sum((repmat(X', [1, length(P)]) - P).^2)));
v_cen2points = zeros(size(P));
niter = 0;
%# looping until convergence
while niter < 1 || per_diff > per_error
%# vector from centre to each point
v_cen2points(1, :) = P(1, :) - X(1);
v_cen2points(2, :) = P(2, :) - X(2);
%# distacnes from centre to each point
centre2points = sqrt(sum(v_cen2points.^2));
%# distances from edge of circle to each point
d = centre2points - r;
%# computing 3x3 jacobean matrix J, and solvign matrix eqn.
R = (v_cen2points ./ [centre2points; centre2points])';
J = [ -ones(length(R), 1), -R ];
D_rXY = -J\d';
%# updating centre and radius
r_old = r; X_old = X;
r = r + D_rXY(1);
X = X + D_rXY(2:3)';
%# calculating maximum percentage change in values
per_diff = max(abs( [(r_old - r) / r, (X_old - X) ./ X ])) * 100;
%# prevent endless looping
niter = niter + 1;
if niter > 1000
error('Convergence not met in 1000 iterations!')
end
end
x = X(1);
y = X(2);
sq_error = sum(d.^2);
This is then run with:
X = [1 2 5 7 9 3];
Y = [7 6 8 7 5 7];
[x_centre, y_centre, r] = circFit( [X; Y] )
And plotted with:
[X, Y] = cylinder(r, 100);
scatter(X, Y, 60, '+r'); axis equal
hold on
plot(X(1, :) + x_centre, Y(1, :) + y_centre, '-b', 'LineWidth', 1);
Giving: