Solving Coupled partial differential equations of stiff nature using MATLAB - matlab

I want to solve coupled partial differential equations of first order, which are of stiff nature. I have coded in MATLAB to solve this pde's, I have used Method of line to convert PDE into ODE, and i have used beam and warmings(second order upwind) method to discritize the spatial derivative. The discretization method is total variation diminishing(TVD) to eliminate the oscillation. But rather using TVD and ode15s solver to integrate resultant stiff ode's the resultant plot is oscillatory(not smooth). What should i do to eliminate this oscillation and get correct results.
I have attached my MATLAB code.. please see it and suggest some improvement.
∂y(1)/∂t=-0.1 ∂y(1)/∂x + (0.5*e^(15*(y(2)⁄(1+y(2))))*(1- y(1))
∂y(2)/∂t=-0.1 ∂y(2)/∂x - (0.4*e^(15*(y(2)⁄(1+y(2))))*(1- y(1))-0.4
Initial condition: at t = 0 y(1)= y(2)=0
Boundary condition: y(1)= y(2) = 0 at x=0
I have attached my MATLAB code.. please see it and suggest some improvement.
function brussode(N)
if nargin<1
N = 149;
end
tspan = [0 10];
m = 0.00035
t = (1:N)/(N+1)*m;
y0 = [repmat(0,1,N); repmat(0,1,N)];
p = 0.5
q = 0.4
options = odeset('Vectorized','on','JPattern',jpattern(N));
[t,y] = ode15s(#f,tspan,y0,options);
a = size(y,2)
u = y(:,1:2:end);
x = (1:N)/(N+1);
figure;
%surf(x,t(end,:),u);
plot(x,u(end,:))
xlabel('space');
ylabel('solution');
zlabel('solution u');
%--------------------------------------------------------------
%Nested function -- N is provided by the outer function.
%
function dydt = f(t,y)
%Derivative function
dydt = zeros(2*N,size(y,2)); %preallocate dy/dt
x = (1:N)/(N+1);
% Evaluate the 2 components of the function at one edge of the grid
% (with edge conditions).
i = 1;
%y(1,:) = 0;
%y(2,:) = 0;
dydt(i,:) = -0.1*(N+1)*(y(i+2,:)-0)+ (0.01/2)*m*((N+1).^3)*(y(i+2,:)-0) + p*exp(15*(0/(1+0)))*(1-0);
dydt(i+1,:) = -0.1*(N+1)*(y(i+3,:)-0)+ (0.01/2)*m*((N+1).^3)*(y(i+3,:)-0) - q*exp(15*(0/(1+0)))*(1-0)+0.25;
i = 3;
%y(1,:) = 0;
%y(2,:) = 0;
dydt(i,:) = -0.1*(N+1)*(y(i+2,:)-y(i,:)) + (0.01/2)*m*((N+1).^3)*(y(i+3,:)-y(i,:)) + p*exp(15*(y(i+1,:)/(1+y(i+1,:))))*(1-y(i,:));
dydt(i+1,:) = -0.1*(N+1)*(y(i+3,:)-y(i+1,:)) + (0.01/2)*m*((N+1).^3)*(y(i+3,:)-y(i,:)) - q*exp(15*(y(i+1,:)/(1+y(i+1,:))))*(1-y(i,:))+0.25;
%Evaluate the 2 components of the function at all interior grid
%points.
i = 5:2:2*N;
%y(1,:) = 0;
% y(2,:) = 0;
dydt(i,:) = (-0.1/2)*(N+1)*(3*y(i,:)-4*y(i-2,:)+y(i-4,:)) +(0.01/2)*m*((N+1).^3)*(y(i,:)-2*y(i-2,:)+y(i-4,:))+ p*exp(15*(y(i+1,:)/(1+y(i+1,:))))*(1-y(i,:));
dydt(i+1,:) = (-0.1/2)*(N+1)*(3*y(i+1,:)-4*y(i-1,:)+y(i-3,:))+(0.01/2)*m*((N+1).^3)*(y(i+1,:)-2*y(i-1,:)+y(i-3,:)) - q*exp(15*(y(i+1,:)/(1+y(i+1,:))))*(1-y(i,:))+0.25;
end
%-------------------------------------------------------------
end %brussode
%-------------------------------------------------------------
% Subfunction -- the sparsity pattern
%
function S = jpattern(N)
% Jacobian sparsity patter
B = ones(2*N,5);
B(2:2:2*N,2) = zeros(N,1);
B(1:2:2*N-1,4) = zeros(N,1);
S = spdiags(B,-2:2,2*N,2*N);
end
%-------------------------------------------------------------

Related

Plotting the results of a Newton-Raphson solution for multiple cases

Consider the following problem:
I am now in the third part of this question. I wrote the vectorial loop equations (q=teta2, x=teta3 and y=teta4):
fval(1,1) = r2*cos(q)+r3*cos(x)-r4*cos(y)-r1;
fval(2,1) = r2*sin(q)+r3*sin(x)-r4*sin(y);
I have these 2 functions, and all variables except x and y are given. I found the roots with help of this video.
Now I need to plot graphs of q versus x and q versus y when q is at [0,2pi] with delta q of 2.5 degree. What should I do to plot the graphs?
Below is my attempt so far:
function [fval,jac] = lorenzSystem(X)
%Define variables
x = X(1);
y = X(2);
q = pi/2;
r2 = 15
r3 = 50
r4 = 45
r1 = 40
%Define f(x)
fval(1,1)=r2*cos(q)+r3*cos(x)-r4*cos(y)-r1;
fval(2,1)=r2*sin(q)+r3*sin(x)-r4*sin(y);
%Define Jacobian
jac = [-r3*sin(X(1)), r4*sin(X(2));
r3*cos(X(1)), -r4*cos(X(2))];
%% Multivariate NR
%Initial conditions:
X0 = [0.5;1];
maxIter = 50;
tolX = 1e-6;
X = X0;
Xold = X0;
for i = 1:maxIter
[f,j] = lorenzSystem(X);
X = X - inv(j)*f;
err(:,i) = abs(X-Xold);
Xold = X;
if (err(:,i)<tolX)
break;
end
end
Please take a look at my solution below, and study how it differs from your own.
function [th2,th3,th4] = q65270276()
[th2,th3,th4] = lorenzSystem();
hF = figure(); hAx = axes(hF);
plot(hAx, deg2rad(th2), deg2rad(th3), deg2rad(th2), deg2rad(th4));
xlabel(hAx, '\theta_2')
xticks(hAx, 0:pi/3:2*pi);
xticklabels(hAx, {'$0$','$\frac{\pi}{3}$','$\frac{2\pi}{3}$','$\pi$','$\frac{4\pi}{3}$','$\frac{5\pi}{3}$','$2\pi$'});
hAx.TickLabelInterpreter = 'latex';
yticks(hAx, 0:pi/6:pi);
yticklabels(hAx, {'$0$','$\frac{\pi}{6}$','$\frac{\pi}{3}$','$\frac{\pi}{2}$','$\frac{2\pi}{3}$','$\frac{5\pi}{6}$','$\pi$'});
set(hAx, 'XLim', [0 2*pi], 'YLim', [0 pi], 'FontSize', 16);
grid(hAx, 'on');
legend(hAx, '\theta_3', '\theta_4')
end
function [th2,th3,th4] = lorenzSystem()
th2 = (0:2.5:360).';
[th3,th4] = deal(zeros(size(th2)));
% Define geometry:
r1 = 40;
r2 = 15;
r3 = 50;
r4 = 45;
% Define the residual:
res = #(q,X)[r2*cosd(q)+r3*cosd(X(1))-r4*cosd(X(2))-r1; ... Δx=0
r2*sind(q)+r3*sind(X(1))-r4*sind(X(2))]; % Δy=0
% Define the Jacobian:
J = #(X)[-r3*sind(X(1)), r4*sind(X(2));
r3*cosd(X(1)), -r4*cosd(X(2))];
X0 = [acosd((45^2-25^2-50^2)/(-2*25*50)); 180-acosd((50^2-25^2-45^2)/(-2*25*45))]; % Accurate guess
maxIter = 500;
tolX = 1e-6;
for idx = 1:numel(th2)
X = X0;
Xold = X0;
err = zeros(maxIter, 1); % Preallocation
for it = 1:maxIter
% Update the guess
f = res( th2(idx), Xold );
X = Xold - J(Xold) \ f;
% X = X - pinv(J(X)) * res( q(idx), X ); % May help when J(X) is close to singular
% Determine convergence
err(it) = (X-Xold).' * (X-Xold);
if err(it) < tolX
break
end
% Update history
Xold = X;
end
% Unpack and store θ₃, θ₄
th3(idx) = X(1);
th4(idx) = X(2);
% Update X0 for faster convergence of the next case:
X0 = X;
end
end
Several notes:
All computations are performed in degrees.
The specific plotting code I used is less interesting, what matters is that I defined all θ₂ in advance, then looped over them to find θ₃ and θ₄ (without recursion, as was done in your own implementation).
The initial guess (actually, analytical solution) for the very first case (θ₂=0) can be found by solving the problem manually (i.e. "on paper") using the law of cosines. The solver also works for other guesses, but you might need to increase maxIter. Also, for certain guesses (e.g. X(1)==X(2)), the Jacobian is ill-conditioned, in which case you can use pinv.
If my computation is correct, this is the result:

Finding Percent Error of a Fourier Series

Find the error as a function of n, where the error is defined as the difference between two the voltage from the Fourier series (vF (t)) and the value from the ideal function (v(t)), normalized to the maximum magnitude (Vm ):
I am given this prompt where Vm = 1 V. Below this line is the code which I have written.
I am trying to write a function to solve this question: Plot the error versus time for n=3,n=5,n=10, and n=50. (10points). What does it look like I am doing incorrectly?
clc;
close all;
clear all;
% define the signal parameters
Vm = 1;
T = 1;
w0 = 2*pi/T;
% define the symbolic variables
syms n t;
% define the signal
v1 = Vm*sin(4*pi*t/T);
v2 = 2*Vm*sin(4*pi*t/T);
% evaluate the fourier series integral
an1 = 2/T*int(v1*cos(n*w0*t),0,T/2) + 2/T*int(v2*cos(n*w0*t),T/2,T);
bn1 = 2/T*int(v1*sin(n*w0*t),0,T/2) + 2/T*int(v2*sin(n*w0*t),T/2,T);
a0 = 1/T*int(v1,0,T/2) + 1/T*int(v2,T/2,T);
% obtain C by substituting n in c[n]
nmax = 100;
n = 1:nmax;
a = subs(an1);
b = subs(bn1);
% define the time vector
ts = 1e-2; % ts is sampling the
t = 0:ts:3*T-ts;
% directly plot the signal x(t)
t1 = 0:ts:T-ts;
v1 = Vm*sin(4*pi*t1/T).*(t1<=T/2);
v2 = 2*Vm*sin(4*pi*t1/T).*(t1>T/2).*(t1<T);
v = v1+v2;
x = repmat(v,1,3);
% Now fourier series reconstruction
N = [3];
for p = 1:length(N)
for i = 1:length(t)
for k = N(p)
x(k,i) = a(k)*cos(k*w0*t(i)) + b(k)*sin(k*w0*t(i));
end
% y(k,i) = a0+sum(x(:,i)); % Add DC term
end
end
z = a0 + sum(x);
figure(1);
plot(t,z);
%Percent error
function [per_error] = percent_error(measured, actual)
per_error = abs(( (measured - actual) ./ 1) * 100);
end
The purpose of the forum is helping with specific technical questions, not doing your homework.

Matlab ODE to solve 2DOF vibrational systems

I'm currently learning Matlab's ODE-functions to solve simple vibration-problems.
For instance mx''+cx'+kx=F*sin(wt) can be solved using
function dx = fun(t,x)
m=0.02; % Mass - kg
k=25.0; % Stiffness - N/m
c=0.0125; % System damping - Ns/m
f=10; % Frequency
F=5;
dx= [x(2); (F*sin(2*pi*f*t)-c*x(2)-k*x(1))/m]
And then calling the ode45 function to get displacement and velocity
[t,x]=ode45(#fun,[0 10],[0.0;0.0])
My question, which I have not fully understood searching the web, is if it is possible to use ODE-function for a multiple degree of freedom system? For instance, if we have two masses, springs and dampers, which we excite att mass 1, we get the following equations:
m1*x1''+c1*x1'-c2*x2'+(k1+k2)*x1-k2*x2 = f1(t)
m2*x2''-c2*x1'+(c1+c2)*x2'-k2*x1+k2*x2 = 0
Here, the displacements x1 & x2 depend on each other, my question is how one should go about to solve these ODE's in Matlab?
There is no restriction that the inputs to the function solved by ODE45 be scalar. Just pass in an input matrix and expect out an output matrix. For example here is a function that solves the position of a 6 bar mechanism.
function zdot = cp_solve(t,z)
%% Constants
g = -9.81;
L1 = .2;
m0 = 0;
I0 = 0;
m1 = 1;
I1 = (1/3) * m1 * L1^2;
%% Inputs
q = z(1:6);
qdot = z(7:12);
%% Mass Matrix
M = zeros(6,6);
M(1,1) = m0;
M(2,2) = m0;
M(3,3) = I0;
M(4,4) = m1;
M(5,5) = m1;
M(6,6) = I1;
%% Constraint Matrix
Phiq = zeros(5,6);
Phiq(1,1) = 1;
Phiq(2,2) = 1;
Phiq(3,3) = 1;
Phiq(4,1) = 1;
Phiq(4,4) = -1;
Phiq(4,6) = (-L1/2)*sin(q(6));
Phiq(5,2) = 1;
Phiq(5,5) = -1;
Phiq(5,6) = (L1/2)*cos(q(6));
%% Generalized Forces
Q = zeros(6,1);
Q(5) = m1 * g;
%% Right Side Vector
rs = zeros(5,1);
rs(4) = (L1/2) * cos(q(6)) * qdot(6)^2;
rs(5) = (L1/2) * sin(q(6)) * qdot(6)^2;
%% Coefficient Matrix
C = [M Phiq'; Phiq zeros(5,5)];
R = [Q; rs];
%% Solution
Sol = C \ R;
zdot = [qdot; Sol(1:6)];
end
The inputs are the positions and velocities of the members. The outputs are the new positions and velocities.
You use it the same way you would any ODE45 problem. Setup the initial conditions, define a time and solve the problem.
%% Constants
L1 = .2;
C1 = L1/2;
theta1 = 30*pi/180;
theta_dot1 = 0;
tspan = 0:.001:2;
%% Initial Conditions
q = zeros(6,1);
q(6) = theta1;
q(4) = C1 * cos(q(6));
q(5) = C1 * sin(q(6));
qdot = zeros(6,1);
qdot(6) = theta_dot1;
z0 = [q; qdot];
%% Solve the problem
options = odeset('RelTol', 1.0e-9, 'AbsTol', 1.0e-6);
[Tout, Zout] = ode45(#cp_solve, tspan, z0, options);
In your case you have 2 equations and 2 unknowns. Set the problem up as a matrix problem and solve it simultaneously in your function. I would recommend the modal approach for your case.

Matlab Differential Equations Euler’s method

I need help plotting a differential equation ... it keeps coming out all funky and the graph is not what it's supposed to look like.
function [dydt] = diff(y,t)
dydt = (-3*y)+(t*(exp(-3*t)));
end
tI = 0;
yI = -0.1;
tEnd = 5;
dt = 0.5;
t = tI:dt:tEnd;
y = zeros(size(t));
y(1) = yI;
for k = 2:numel(y)
yPrime = diff(t(k-1),y(k-1));
y(k) = y(k-1) + dt*yPrime;
end
plot(t,y)
grid on
title('Engr')
xlabel('Time')
ylabel('y(t)')
legend(['dt = ' num2str(dt)])
That's my code, but the graph is not anything like what it's supposed to look like. Am I missing something like an index for the for statement?
Edit
I am getting an error:
Error using diff
Difference order N must be a positive integer scalar.
Error in diff3 (line 12)
yPrime = diff(t(k-1),y(k-1));
After fixing the errors pointed out by Danil Asotsky and horchler in the comments:
avoiding name conflict with built-in function 'diff'
changing the order of arguments to t,y.
decreasing the time-step dt to 0.1
converting ODE right-hand side to an anonymous function
(and removing unnecessary parentheses in the function definition), your code could look like this:
F = #(t,y) -3*y+t*exp(-3*t);
tI = 0;
yI = -0.1;
tEnd = 5;
dt = 0.1;
t = tI:dt:tEnd;
y = zeros(size(t));
y(1) = yI;
for k = 2:numel(y)
yPrime = F(t(k-1),y(k-1));
y(k) = y(k-1) + dt*yPrime;
end
plot(t,y)
grid on
title('Engr')
xlabel('Time')
ylabel('y(t)')
legend(['dt = ' num2str(dt)])
which performs as expected:

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