Previous Contents Next

Chapter 6  Data Fitting

6.1  Interpolation:

6.1.1  The Basics:

The basic idea here is the following. We are given a set of data points
x1
···
xn
 
y1
···
yn

for some positive integer n. This data will be interpreted as the ordered pairs corresponding to some function f which must pss through each of these data point pairs. Hence, our basic condition is that for all relevant indices i, we have
f(xi) = yi

6.1.2  The Vandermonde Approach:

The first choice for f is to use a polynomial of of degree one less than the number of data points. Hence, we seek a polynomial p of the form
p(x) = a1 + a2 x + a3 x2 + ... + an xn-1

satisfying
a1 + a2 x1 + a3 x12 + ... + an x1n-1 = y1
a1 + a2 x2 + a3 x22 + ... + an x2n-1 = y2
  ···  
a1 + a2 xn + a3 xn2 + ... + an xnn-1 = yn

this can be reorganized into a matrix equation
1 x1 x12 ... x1n-1
1 x2 x22 ... x2n-1
··· ··· ··· ··· ···
1 xn xn2 ... xnn-1
a1
···
an
=
y1
···
yn

The Matrix above is the Vandermonde matrix which is generally called V.

VanderMonde Matlab Code:

Now to see an easy way to set up the Vandermonde matrix, consider the 3 × 3 case. Start with all ones:
1 1 1
1 1 1
1 1 1

Note that we can get column 2 of the Vandermonde matrix V by pointwise column vector multiplication of the data vector x and the first column of V:
x1
x2
x3
1
1
1
=
x1
x2
x3

This sets the second column of V. Using it, we do another pointwise column vector multiplication of the data x and the new second column of V to create the third column of V.
x1
x2
x3
x1
x2
x3
=
x12
x22
x32

which completes the calculation of the Vandermonde 3 × 3 matrix. So to do this in Matlab is actually easy. We just use the new operator
.*
to indicate we want to do pointwise column vector multiplication. Consider the following code:

Vander.m
 1 function a = Vander(x,y)
 2 %
 3 % x  column vector of domain data points
 4 % y  column vector of range data points
 5 %
 6 % a  column vector of coefficients for the
 7 %    interpolating polynomial p
 8 %
 9 n = length(x);
10 V = ones(n,n);
11 for j=2:n
12   %Set up column j
13   V(:,j) = x.*V(:,j-1);
14 end
15 %Use the built in
16 c = V\y 
17 %Do Each Step Explicitly
18 [L,U,P] = lu(V);
19 z = LTriSol(L,P*y);
20 a = UTriSol(U,z);
21 
22    


syntax highlighted by Code2HTML, v. 0.8.8b

In this code, we have inserted two ways to do the required linear system calculations. These are the built in
%Use the built in
c = V\y 
which is the same as the explicit steps
%Do Each Step Explicitly
[L,U,P] = lu(V);
z = LTriSol(L,P*y);
a = UTriSol(U,z);
You'll note that c and a are the same.

Run Time Output:

Vander.prompts
 1 >> x = [0.0; 0.5; 1.0; 6.0; 7.0; 9.0]
 2 
 3 x =
 4 
 5          0
 6     0.5000
 7     1.0000
 8     6.0000
 9     7.0000
10     9.0000
11 
12 >> y = [0.0; 1.6; 2.0; 2.0; 1.5; 0.0]
13 
14 y =
15 
16          0
17     1.6000
18     2.0000
19     2.0000
20     1.5000
21          0
22 
23 >> a = Vander(x,y);
24 
25 c =
26 
27          0
28     4.8643
29    -3.8559
30     1.1208
31    -0.1348
32     0.0057
33 
34 >> a
35 
36 a =
37 
38          0
39     4.8643
40    -3.8559
41     1.1208
42    -0.1348
43     0.0057


syntax highlighted by Code2HTML, v. 0.8.8b

Evaluating the Interpolating Polynomial:

Now that we have the desired coefficients a, we need efficient ways to evaluate the polynomial p. We'll use Horner's method.

Horner's Method in Matlab:

HornerV.m
 1 function pval = HornerV(a,z)
 2 %
 3 % a    column vector of polynomial coefficients
 4 % z    column vector of domain points to evaluate
 5 %      the polynomial at.
 6 %
 7 % pval column vector of same size at z.
 8 %      pval(i) = polynomial(z(i))
 9 %
10 n = length(a);
11 m = length(z);
12 pval = a(n)*ones(m,1);
13 for k=n-1:-1:1
14   pval = z.*pval + a(k);
15 end


syntax highlighted by Code2HTML, v. 0.8.8b

Run Time Output:

Here we show that if evaluate our newly created Vandermonde polynomial at the original data x we get back y.

HornerV.prompts
 1 >> w = HornerV(a,x)
 2 
 3 w =
 4 
 5          0
 6     1.6000
 7     2.0000
 8     2.0000
 9     1.5000
10    -0.0000


syntax highlighted by Code2HTML, v. 0.8.8b

Now to see what our polynomial looks like, let's plot it on the interval -1,10].

Plot.prompts
1 >> close all
2 >> x0 = linspace(-1,10,110)';
3 >> y0 = HornerV(a,x0);
4 >> plot(x0,y0);
5 >> print -deps plot1 


syntax highlighted by Code2HTML, v. 0.8.8b

We saved the plot to a file called plot1.eps so we can include it in both our web page and our printed document. The plot looks like this:



6.1.3  Cubic Hermite Interpolation:

This special cubic intepolates both the functions values and the derivative values of the function.

Just One Interval:

Given an interval [[xL, xR], we wish to fit a cubic polynomial to the data (xL,yL,SL) and (xR,yR,sR) where the data represents the domain values, xL and xR; the function values, f(xL) = yL and f(xR) = yR; and derivative values f' (xL) = sL and f' (xR) = sR for some function f we wish to interpolate. Write the general cubic we seek in the following form:
p(x) = a + b(x-xL) + c(x-xL)2 + d(x-xL)2(x-xR)

This is the Hermite cubic polynomial form. Note that this then implies that
p' (x) = b + 2c(x-xL) + 2d(x-xl)(x-xR) + d(x-xl)2

Now let h denote the difference xR - xL and apply the constraints:
p(xL) = yL ® a = yL
p' (xL) = sL ® b = sL
p(xR) = yR ® a + bh + ch2 = yL
p' (xR) = sR ® b + 2ch + dh2 = sL

In matrix form this gives
1 0 0 0
0 1 0 0
1 h h2 0
0 1 2h h2
a
b
c
d
=
yL
sl
yR
sR

Letting D be yr - yL/h, we see this can easily be solved to give:
a = yL
b = sL
c =
yR - yL - sLh
h2
  =
D - sL
h
d =
sL + sR - 2 D
h2

The General Problem: n Intervals:

So how do we do the general problem? We start with the data triples
{(x1,y1,s1), ..., (xn,yn,sn) }

and define a function p which is a cubic of the form we used above on each subinterval [xi, xi+1] for all indices i from 1 to n-1. Hence, p is defined piecewise as
p(x) =
q1(x) x1 £ x £ x2
q2(x) x2 £ x £ x3
··· ···
qn-1(x) xn-1 £ x £ xn

and each qi has the form
qi(x) = ai + bi(x-xi) + ci(x-xi)2 + di(x-xi)2(x-xi+1)

To find these n-1 Hermite cubic polynomials, we apply the results from above for the case of one interval. Instead of using h and D like before, we will use
hi = xi+1 - xi
Di =
yi+1 - yi
hi

We know that the solution is given by
ai = yi
bi = si
ci =
Di - si
hi
di =
si + si+1 - 2 Di
hi2

The Basic Matlab Code:

First, we start with the code which implements the Hermite Cubic Spline idea:

pwC.m
 1 function [a,b,c,d] = pwC(x,y,s)
 2 %
 3 % x,y,s      column vectors of data of size n
 4 % a,b,c,d    column vectors of size n-1 that hold
 5 %            hermite polynomial coeficients
 6 %
 7 n = length(x);
 8 a = y(1:n-1);
 9 b = s(1:n-1);
10 Dx = diff(x);
11 Dy = diff(y);
12 D = Dy ./ Dx;
13 c = (D - s(1:n-1)) ./ Dx;
14 d = (s(2:n) + s(1:n-1) - 2*D) ./ (Dx .* Dx);


syntax highlighted by Code2HTML, v. 0.8.8b

Locating a Point in the Interval:

Now that we can compute the piecewise Hermite polynomial interploant, we need to evaluate the resulting funtion p at a point z: here is the code to locate where z is in the interval [x1,xn] using binary search:

Locate.m
 1 function i = Locate(x,z,g)
 2 %
 3 % x     column vector of size n which is the 
 4 %       partition x_1 < x_2 < ... < x_n
 5 % z     scalar value which is in the interval
 6 %       [x_1,x_n]
 7 % g     optional third argument which is an
 8 %       index between 1 and n-1
 9 %
10 % i     the interval that z belongs to
11 %
12 if nargin==3
13   %Try initial guess
14   if(x(g)<=z) & (z<=x(g+1))
15     i=g;
16     return;
17   end
18 end
19 
20 n = length(x);
21 if z==x(n)
22   i = n-1;
23 else
24   % Use Binary Search
25   Left = 1;
26   Right = n;
27   while Right > Left +1
28     % x(Left) <= z <= x(Right)
29     mid = floor((Left + Right)/2);
30     if z < x(mid)
31      Right = mid;
32     else
33       Left = mid;
34     end
35   end
36   i = Left;
37 end


syntax highlighted by Code2HTML, v. 0.8.8b

Evaluating a Piecewise Cubic:

Here is the code to evaluate p(z) once z has been located:

pwCEval.m
 1 function CVals = pwCEval(a,b,c,d,x,z)
 2 %
 3 % a,b,c,d     column vectors of size n-1 that store
 4 %             Hermite cubic polynomial interpolation
 5 % x           column vector of size n which is
 6 %             the partition x_1 < x_2 < ... < x_n
 7 % z           column vector of size m with each
 8 %             value $z_i$ lying in the interval
 9 %             [x_1,x_n]
10 %
11 % CVals       column vector of size m which stores the
12 %             m values of the interpolating fucntion  p,
13 %             p(z_1),...,p(z_m)
14 %
15 m = length(z);
16 CVals = zeros(m,1);
17 g = 1;
18 for j = 1:m
19   i = Locate(x,z(j),g);
20   %Use a Hormer Mutliply Method
21   CVals(j) = d(i)*(z(j)-x(i+1)) + c(i);
22   CVals(j) = CVals(j)*(z(j)-x(i)) + b(i);
23   CVals(j) = CVals(j)*(z(j) - x(i)) + a(i);
24   g = i;
25 end


syntax highlighted by Code2HTML, v. 0.8.8b

Some Run Time Results:

A function that occurs in many places in the sigmoid curve given by
s(x) =
0.5(1 + tanh(
x-x0
g
)

where x0 determines the location of the inflection point of s and g determines the slope at x0. We will use the piecewise Hermite polynomials to approximate s for x0 = 0 and g = 0.5 on the interval [-2,2].

Here is the run time code:

Sigmoid.prompts
 1 >> z = linspace(-2,2,200)';
 2 >> fvals = 0.5+0.5*tanh(2*z);
 3 >> n = 4;
 4 >> x = linspace(-2,2,n)';
 5 >> y = 0.5+0.5*tanh(2*x);
 6 >> s = sech(2*x).*sech(2*x);
 7 >> [a,b,c,d] = pwC(x,y,s);
 8 >> Cvals = pwCEval(a,b,c,d,x,z);
 9 >> plot(z,fvals,z,Cvals,x,y,'*');
10 >> print -deps sigmoid1


syntax highlighted by Code2HTML, v. 0.8.8b

and you can see the results in the plot

We saved the plot to a file called plot1.eps so we can include it in both our web page and our printed document. The plot looks like this:



Now we will use the piecewise Hermite polynomials to approximate s for x0 = 0 and g = 0.2 on the interval [-2,2].

Here is the run time code:

Sigmoid2.prompts
1 >> fvals = 0.5 + 0.5*tanh(5*z);
2 >> y = 0.5+0.5*tanh(5*x);
3 >> s = 2.5*sech(5*x).*sech(5*x);
4 >> [a,b,c,d] = pwC(x,y,s);
5 >> Cvals = pwCEval(a,b,c,d,x,z);
6 >> plot(z,fvals,z,Cvals,x,y,'*');
7 >> print -deps sigmoid2


syntax highlighted by Code2HTML, v. 0.8.8b

and you can see the results in the plot:



This one is not so good!

Exercises:

Consider the following function which has two rather high humps:
f(x) +
1
(x - 0.3)2 + 0.01
+
1
(x - 0.9)2 + 0.04
- 6
  1. Let's construct the piecewise Hermite cubic polynomial to this function on the interval [0,3] for the cases n = 4, n = 8 and n = 16. Use uniformly spaced points like we have done in our Matlab code examples in this section.
  2. Let's construct the piecewise Hermite cubic polynomial to this function on the interval [0,3] using nonuniformly spaced points n = 4, n = 8 and n = 16. Use your judgement on how to space the points and comment on how and why you are choosing them. Discuss any thoughts you might have on how to automate this procedure: how could you infer from data that you are trying to interpolate a function with high humps? Provide a plot for each case of course!

6.1.4  General Cubic Splines:

The Hermite cubic splines interpolate both function and function derivative data. This makes the resulting interpolating function continuous and makes its derivative continuous too. But we don't know that the function's second derivative is continous. Another approach is to think of the points {s1, ..., sn} as parameters to be chosen so that the interpolating function is continuous through its second derivative. Of course, in this approach we don't match derivative data.

The Basics:

The general problem still concerns the triples
{(x1,y1,s1), ..., (xn,yn,sn) }

and we still define a function p which is a Hermite cubic on each subinterval [xi, xi+1] for all indices i from 1 to n-1. Hence, p is defined piecewise as
p(x) =
q1(x) x1 £ x £ x2
q2(x) x2 £ x £ x3
··· ···
qn-1(x) xn-1 £ x £ xn

and each qi has the form
qi(x) = ai + bi(x-xi) + ci(x-xi)2 + d(x-xi)2(x-xi+1)

The solutions we have derived for the Hermite cubics then give us
ai = yi
bi = si
ci =
Di - si
hi
di =
si + si+1 - 2 Di
hi2

The only difference here is that the points si are now being though of as parameters to be chosen. We still find the form of qi is as follows:
qi(x) =
yi + si(x-xi) + (
Di - si
hi
)(x-xi)2
   
+ (
si + si+1 - 2 Di
hi2
) (x-xi)2(x-xi+1)
qi' (x) =
si + 2(
Di - si
hi
)(x-xi) + 2(
si + si+1 - 2 Di
hi2
) (x-xi)(x-xi+1)
   
+ (
si + si+1 - 2 Di
hi2
)(x-xi)2
qi' ' (x) =
2(
Di - si
hi
) + 2(
si + si+1 - 2 Di
hi2
)(x-xi+1)
   
+ 4(
si + si+1 - 2 Di
hi2
) (x-xi)
  =
2(
Di - si
hi
)
   
+ (
si + si+1 - 2 Di
hi2
) (4(x-xi)) + 2(x-xi+1)

A similar calculation gives us the second derivative of qi+1
qi+1(x) =
yi+1 + si+1(x-xi+1) + (
Di+1 - si+1
hi+1
)(x-xi+1)2
 
+ (
si+1 + si+2 - 2 Di+1
hi+12
) (x-xi+1)2(x-xi+2)
qi+1' (x) =
si+1 + 2(
Di+1 - si+1
hi+1
)(x-xi+1) + 2(
si+1 + si+2 - 2 Di+1
hi+12
) (x-xi+1)(x-xi+2)
 
+ (
si+1 + si+2 - 2 Di+1
hi+12
) (x-xi+1)2
qi+1' ' (x) =
2(
Di+1 - si+1
hi+1
)
 
+ (
si+1 + si+2 - 2 Di+1
hi+12
) (4(x-xi+1) + 2(x-xi+2)

To get second continuity of these two cubics, it is enough to force continuity at the point that they share, xi+1. This gives
qi' ' (xi+1) =
2(
Di - si
hi
) + 4hi(
si + si+1 - 2 Di
hi2
)
qi+1' ' (xi+1) =
2(
Di+1 - si+1
hi+1
) + -2hi+1(
si+1 + si+2 - 2 Di+1
hi+12
)

Equating we get
2(
Di - si
hi
) + 4hi(
si + si+1 - 2 Di
hi2
)
=
2(
Di+1 - si+1
hi+1
) - 2hi+1(
si+1 + si+2 - 2 Di+1
hi+12
)

or
2
hi
(si + 2si+1 - - 3Di)
=
2
hi+1
(-2si+1 - si+2 - + 3Di+1)

This simplifies to
hi+1si + 2(hi + hi+1)si+1 + hi sI+1 = 3(hi Di+1 + hi+1Di)

Now these equations are satisfied for n = 1 to n-2. If we choose {s1, ..., sn } so satisfy the above equations, then the resulting interpolant function will have a continuous second derivative. Note we have n-2 equations in n unknowns, so there are two unresolved degress of freedom.

We get these equations:
h2 s1 + 2(h1 + h2) s2 + h1 s3 = 3(h1 D2 + h2 D1)
h3 s2 + 2(h2 + h3) s3 + h2 s4 = 3(h2 D3 + h3 D2)
··· = ···
hn-1 sn-2 + 2(hn-2 + hn-1) sn-1 + hn-2 sn = 3(hn-2 Dn-1 + hn-1 Dn-2)

It is traditional to treat the parameters s1 and sn are the free parameters. Move these over to the right hand side and we get
2(h1 + h2) s2 + h1 s3 = 3(h1 D2 + h2 D1) - h2 s1
h3 s2 + 2(h2 + h3) s3 + h2 s4 = 3(h2 D3 + h3 D2)
··· = ···
hn-1 sn-2 + 2(hn-2 + hn-1) sn-1 = 3(hn-2 Dn-1 + hn-1 Dn-2) - hn-2 sn

The resulting n-2 by n-2 system then looks like this in matrix form:
2(h1 + h2) h1 0 0 0 ··· 0
h3 2(h2 + h3) h2 0 ··· 0
0 h4 2(h3 + h4) h3 0 ··· 0
··· ··· ··· ··· ··· ··· ···
0 0 ··· ··· 0 hn-1 2(hn-2 + hn-1)
s2
s3
···
sn-1
=  
3(h1 D2 + h2 D1) - h2 s1
3(h2 D3 + h3 D2)
···
3(hn-3 Dn-2 + hn-2 Dn-3)
3(hn-2 Dn-1 + hn-1 Dn-2) - hn-2 sn
 

EndPoint Conditions:

We can set the values of s1 and sn a lot of ways and the resulting interpolants we find will have different sorts of properties.

Exercises:

Let's repeat the exercises for the Hermite Cubic interpolants using these new splines.

Again, we consider the following function which has two rather high humps:
f(x) +
1
(x - 0.3)2 + 0.01
+
1
(x - 0.9)2 + 0.04
- 6
  1. Let's construct the Natural Spline interpolants to this function on the interval [0,3] for the cases n = 4, n = 8 and n = 16. Use uniformly spaced points like we have done in our Matlab code examples in this section. You will need to look at the Matlab code provided in Van Loan on page 115 and on page 116. The Matlab fragments will set up the matrix you need to solve to find the natural cubic spline interpolant. You will need to modify, if necessary, the Matlab code for Location and Evaluation of the resulting function. Then plot the true function and the interpolants on the same graph like before.
  2. This is the same except let's set A to be 1 and B to be -1 just for grins. Do the same thing as the first part. What do you think of this new choice of A and B? In general, do you think you could find a better choice of A and B than the natural spline choice?

Previous Contents Next