Debugging construction of splines between a variable amount of points - matlab

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

Related

Change the grid points of parametric splines in 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.

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

Can't recover the parameters of a model using ode45

I am trying to simulate the rotation dynamics of a system. I am testing my code to verify that it's working using simulation, but I never recovered the parameters I pass to the model. In other words, I can't re-estimate the parameters I chose for the model.
I am using MATLAB for that and specifically ode45. Here is my code:
% Load the input-output data
[torque outputs] = DataLogs2();
u = torque;
% using the simulation data
Ixx = 1.00;
Iyy = 2.00;
Izz = 3.00;
x0 = [0; 0; 0];
Ts = .02;
t = 0:Ts:Ts * ( length(u) - 1 );
[ T, x ] = ode45( #(t,x) rotationDyn( t, x, u(1+floor(t/Ts),:), Ixx, Iyy, Izz), t, x0 );
w = x';
N = length(w);
q = 1; % a counter for the A and B matrices
% The Algorithm
for k=1:1:N
w_telda = [ 0 -w(3, k) w(2,k); ...
w(3,k) 0 -w(1,k); ...
-w(2,k) w(1,k) 0 ];
if k == N % to handle the problem of the last iteration
w_dash(:,k) = (-w(:,k))/Ts;
else
w_dash(:,k) = (w(:,k+1)-w(:,k))/Ts;
end
a = kron( w_dash(:,k)', eye(3) ) + kron( w(:,k)', w_telda );
A(q:q+2,:) = a; % a 3N*9 matrix
B(q:q+2,:) = u(k,:)'; % a 3N*1 matrix % u(:,k)
q = q + 3;
end
% Forcing J to be diagonal. This is the case when we consider our quadcopter as two thin uniform
% rods crossed at the origin with a point mass (motor) at the end of each.
A_new = [A(:, 1) A(:, 5) A(:, 9)];
vec_J_diag = A_new\B;
J_diag = diag([vec_J_diag(1), vec_J_diag(2), vec_J_diag(3)])
eigenvalues_J_diag = eig(J_diag)
error = norm(A_new*vec_J_diag - B)
where my dynamic model is defined as:
function [dw, y] = rotationDyn(t, w, tau, Ixx, Iyy, Izz, varargin)
% The output equation
y = [w(1); w(2); w(3)];
% State equation
% dw = (I^-1)*( tau - cross(w, I*w) );
dw = [Ixx^-1 * tau(1) - ((Izz-Iyy)/Ixx)*w(2)*w(3);
Iyy^-1 * tau(2) - ((Ixx-Izz)/Iyy)*w(1)*w(3);
Izz^-1 * tau(3) - ((Iyy-Ixx)/Izz)*w(1)*w(2)];
end
Practically, what this code should do, is to calculate the eigenvalues of the inertia matrix, J, i.e. to recover Ixx, Iyy, and Izz that I passed to the model at the very begining (1, 2 and 3), but all what I get is wrong results.
Is the problem with using ode45?
Well the problem wasn't in the ode45 instruction, the problem is that in system identification one can create an n-1 samples-signal from an n samples-signal, thus the loop has to end at N-1 in the above code.

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:

Cubic Spline Program

I'm trying to write a cubic spline interpolation program. I have written the program but, the graph is not coming out correctly. The spline uses natural boundary conditions(second dervative at start/end node are 0). The code is in Matlab and is shown below,
clear all
%Function to Interpolate
k = 10; %Number of Support Nodes-1
xs(1) = -1;
for j = 1:k
xs(j+1) = -1 +2*j/k; %Support Nodes(Equidistant)
end;
fs = 1./(25.*xs.^2+1); %Support Ordinates
x = [-0.99:2/(2*k):0.99]; %Places to Evaluate Function
fx = 1./(25.*x.^2+1); %Function Evaluated at x
%Cubic Spline Code(Coefficients to Calculate 2nd Derivatives)
f(1) = 2*(xs(3)-xs(1));
g(1) = xs(3)-xs(2);
r(1) = (6/(xs(3)-xs(2)))*(fs(3)-fs(2)) + (6/(xs(2)-xs(1)))*(fs(1)-fs(2));
e(1) = 0;
for i = 2:k-2
e(i) = xs(i+1)-xs(i);
f(i) = 2*(xs(i+2)-xs(i));
g(i) = xs(i+2)-xs(i+1);
r(i) = (6/(xs(i+2)-xs(i+1)))*(fs(i+2)-fs(i+1)) + ...
(6/(xs(i+1)-xs(i)))*(fs(i)-fs(i+1));
end
e(k-1) = xs(k)-xs(k-1);
f(k-1) = 2*(xs(k+1)-xs(k-1));
r(k-1) = (6/(xs(k+1)-xs(k)))*(fs(k+1)-fs(k)) + ...
(6/(xs(k)-xs(k-1)))*(fs(k-1)-fs(k));
%Tridiagonal System
i = 1;
A = zeros(k-1,k-1);
while i < size(A)+1;
A(i,i) = f(i);
if i < size(A);
A(i,i+1) = g(i);
A(i+1,i) = e(i);
end
i = i+1;
end
for i = 2:k-1 %Decomposition
e(i) = e(i)/f(i-1);
f(i) = f(i)-e(i)*g(i-1);
end
for i = 2:k-1 %Forward Substitution
r(i) = r(i)-e(i)*r(i-1);
end
xn(k-1)= r(k-1)/f(k-1);
for i = k-2:-1:1 %Back Substitution
xn(i) = (r(i)-g(i)*xn(i+1))/f(i);
end
%Interpolation
if (max(xs) <= max(x))
error('Outside Range');
end
if (min(xs) >= min(x))
error('Outside Range');
end
P = zeros(size(length(x),length(x)));
i = 1;
for Counter = 1:length(x)
for j = 1:k-1
a(j) = x(Counter)- xs(j);
end
i = find(a == min(a(a>=0)));
if i == 1
c1 = 0;
c2 = xn(1)/6/(xs(2)-xs(1));
c3 = fs(1)/(xs(2)-xs(1));
c4 = fs(2)/(xs(2)-xs(1))-xn(1)*(xs(2)-xs(1))/6;
t1 = c1*(xs(2)-x(Counter))^3;
t2 = c2*(x(Counter)-xs(1))^3;
t3 = c3*(xs(2)-x(Counter));
t4 = c4*(x(Counter)-xs(1));
P(Counter) = t1 +t2 +t3 +t4;
else
if i < k-1
c1 = xn(i-1+1)/6/(xs(i+1)-xs(i-1+1));
c2 = xn(i+1)/6/(xs(i+1)-xs(i-1+1));
c3 = fs(i-1+1)/(xs(i+1)-xs(i-1+1))-xn(i-1+1)*(xs(i+1)-xs(i-1+1))/6;
c4 = fs(i+1)/(xs(i+1)-xs(i-1+1))-xn(i+1)*(xs(i+1)-xs(i-1+1))/6;
t1 = c1*(xs(i+1)-x(Counter))^3;
t2 = c2*(x(Counter)-xs(i-1+1))^3;
t3 = c3*(xs(i+1)-x(Counter));
t4 = c4*(x(Counter)-xs(i-1+1));
P(Counter) = t1 +t2 +t3 +t4;
else
c1 = xn(i-1+1)/6/(xs(i+1)-xs(i-1+1));
c2 = 0;
c3 = fs(i-1+1)/(xs(i+1)-xs(i-1+1))-xn(i-1+1)*(xs(i+1)-xs(i-1+1))/6;
c4 = fs(i+1)/(xs(i+1)-xs(i-1+1));
t1 = c1*(xs(i+1)-x(Counter))^3;
t2 = c2*(x(Counter)-xs(i-1+1))^3;
t3 = c3*(xs(i+1)-x(Counter));
t4 = c4*(x(Counter)-xs(i-1+1));
P(Counter) = t1 +t2 +t3 +t4;
end
end
end
P = P';
P(length(x)) = NaN;
plot(x,P,x,fx)
When I run the code, the interpolation function is not symmetric and, it doesn't converge correctly. Can anyone offer any suggestions about problems in my code? Thanks.
I wrote a cubic spline package in Mathematica a long time ago. Here is my translation of that package into Matlab. Note I haven't looked at cubic splines in about 7 years, so I'm basing this off my own documentation. You should check everything I say.
The basic problem is we are given n data points (x(1), y(1)) , ... , (x(n), y(n)) and we wish to calculate a piecewise cubic interpolant. The interpolant is defined as
S(x) = { Sk(x) when x(k) <= x <= x(k+1)
{ 0 otherwise
Here Sk(x) is a cubic polynomial of the form
Sk(x) = sk0 + sk1*(x-x(k)) + sk2*(x-x(k))^2 + sk3*(x-x(k))^3
The properties of the spline are:
The spline pass through the data point Sk(x(k)) = y(k)
The spline is continuous at the end-points and thus continuous everywhere in the interpolation interval Sk(x(k+1)) = Sk+1(x(k+1))
The spline has continuous first derivative Sk'(x(k+1)) = Sk+1'(x(k+1))
The spline has continuous second derivative Sk''(x(k+1)) = Sk+1''(x(k+1))
To construct a cubic spline from a set of data point we need to solve for the coefficients
sk0, sk1, sk2 and sk3 for each of the n-1 cubic polynomials. That is a total of 4*(n-1) = 4*n - 4 unknowns. Property 1 supplies n constraints, and properties 2,3,4 each supply an additional n-2 constraints. Thus we have n + 3*(n-2) = 4*n - 6 constraints and 4*n - 4 unknowns. This leaves two degrees of freedom. We fix these degrees of freedom by setting the second derivative equal to zero at the start and end nodes.
Let m(k) = Sk''(x(k)) , h(k) = x(k+1) - x(k) and d(k) = (y(k+1) - y(k))/h(k). The following
three-term recurrence relation holds
h(k-1)*m(k-1) + 2*(h(k-1) + h(k))*m(k) + h(k)*m(k+1) = 6*(d(k) - d(k-1))
The m(k) are unknowns we wish to solve for. The h(k) and d(k) are defined by the input data.
This three-term recurrence relation defines a tridiagonal linear system. Once the m(k) are determined the coefficients for Sk are given by
sk0 = y(k)
sk1 = d(k) - h(k)*(2*m(k) + m(k-1))/6
sk2 = m(k)/2
sk3 = m(k+1) - m(k)/(6*h(k))
Okay that is all the math you need to know to completely define the algorithm to compute a cubic spline. Here it is in Matlab:
function [s0,s1,s2,s3]=cubic_spline(x,y)
if any(size(x) ~= size(y)) || size(x,2) ~= 1
error('inputs x and y must be column vectors of equal length');
end
n = length(x)
h = x(2:n) - x(1:n-1);
d = (y(2:n) - y(1:n-1))./h;
lower = h(1:end-1);
main = 2*(h(1:end-1) + h(2:end));
upper = h(2:end);
T = spdiags([lower main upper], [-1 0 1], n-2, n-2);
rhs = 6*(d(2:end)-d(1:end-1));
m = T\rhs;
% Use natural boundary conditions where second derivative
% is zero at the endpoints
m = [ 0; m; 0];
s0 = y;
s1 = d - h.*(2*m(1:end-1) + m(2:end))/6;
s2 = m/2;
s3 =(m(2:end)-m(1:end-1))./(6*h);
Here is some code to plot a cubic spline:
function plot_cubic_spline(x,s0,s1,s2,s3)
n = length(x);
inner_points = 20;
for i=1:n-1
xx = linspace(x(i),x(i+1),inner_points);
xi = repmat(x(i),1,inner_points);
yy = s0(i) + s1(i)*(xx-xi) + ...
s2(i)*(xx-xi).^2 + s3(i)*(xx - xi).^3;
plot(xx,yy,'b')
plot(x(i),0,'r');
end
Here is a function that constructs a cubic spline and plots in on the famous Runge function:
function cubic_driver(num_points)
runge = #(x) 1./(1+ 25*x.^2);
x = linspace(-1,1,num_points);
y = runge(x);
[s0,s1,s2,s3] = cubic_spline(x',y');
plot_points = 1000;
xx = linspace(-1,1,plot_points);
yy = runge(xx);
plot(xx,yy,'g');
hold on;
plot_cubic_spline(x,s0,s1,s2,s3);
You can see it in action by running the following at the Matlab prompt
>> cubic_driver(5)
>> clf
>> cubic_driver(10)
>> clf
>> cubic_driver(20)
By the time you have twenty nodes your interpolant is visually indistinguishable from the Runge function.
Some comments on the Matlab code: I don't use any for or while loops. I am able to vectorize all operations. I quickly form the sparse tridiagonal matrix with spdiags. I solve it using the backslash operator. I counting on Tim Davis's UMFPACK to handle the decomposition and forward and backward solves.
Hope that helps. The code is available as a gist on github https://gist.github.com/1269709
There was a bug in spline function, generated (n-2) by (n-2) should be symmetric:
lower = h(2:end);
main = 2*(h(1:end-1) + h(2:end));
upper = h(1:end-1);
http://www.mpi-hd.mpg.de/astrophysik/HEA/internal/Numerical_Recipes/f3-3.pdf