Chapter 3 M-Files
Script File Index
| ShowPWL1 | Illustrates pwL and pwLEval. |
| ShowPWL2 | Compares pwLStatic and pwLAdapt. |
| ShowHermite | Illustrates the Hermite interpolation idea. |
| ShowpwCH | Illustrates pwC and pwCEval. |
| ShowSpline | Illustrates CubicSpline. |
| ShowSplineErr | Explores the not-a-knot spline interpolant error. |
| ShowSplineTools | Illustrates \Matlab spline tools. |
Function File Index
| pwL | Sets up a piecewise linear interpolant. |
| Locate | Determines the subinterval in a mesh that houses a given x-value. |
| pwLEval | Evaluates a piecewise linear function. |
| pwLStatic | A priori determination of a mesh for a pwL approximation. |
| pwLAdapt | Dynamic determination of a mesh for a pwL approximation. |
| HCubic | Constructs the cubic Hermite interpolant. |
| pwC | Sets up a piecewise cubic Hermite interpolant. |
| pwCEval | Evaluates a piecewise cubic function. |
| CubicSpline | Constructs complete, natural, or not-a-knot spline. |
% Script File: ShowPWL1
% Convergence of the piecewise linear interpolant to
% humps(x) on [0,3]
close all
z = linspace(0,3,200)';
fvals = humps(z);
for n = [5 10 25 50]
figure
x = linspace(0,3,n)';
y = humps(x);
[a,b] = pwL(x,y);
Lvals = pwLEval(a,b,x,z);
plot(z,Lvals,z,fvals,'--',x,y,'o');
title(sprintf('Interpolation of humps(x) with pwL, n = %2.0f',n))
end
% Script File: ShowPWL2
% Compares pwLStatic and pwLAdapt on [0,3] using the function
%
% humps(x) = 1/((x-.3)^2 + .01) + 1/((x-.9)^2+.04)
%
close all
% Second derivative estimate based on divided differences
z = linspace(0,1,101);
humpvals = humps(z);
M2 = max(abs(diff(humpvals,2)/(.01)^2));
for delta = [1 .5 .1 .05 .01]
figure
[x,y] = pwLStatic('humps',M2,0,3,delta);
subplot(1,2,1)
plot(x,y,'.');
title(sprintf('delta = %8.4f Static n= %2.0f',delta,length(x)))
[x,y] = pwLAdapt('humps',0,humps(0),3,humps(3),delta,.001);
subplot(1,2,2)
plot(x,y,'.');
title(sprintf('delta = %8.4f Adapt n= %2.0f',delta,length(x)))
end
% Script File: ShowHermite
% Plots a succession of cubic interpolants to cos(x).
% x(2) converges to x(1) = 0 and x(3) converges to x(4) = 3pi/2.
close all
z = linspace(-pi/2,2*pi,100);
CosValues = cos(z);
for d = [1 .5 .3 .1 .05 .001]
figure
xvals = [0;d;(3*pi/2)-d;3*pi/2];
yvals = cos(xvals);
c = InterpN(xvals,yvals);
CubicValues = HornerN(c,xvals,z);
plot(z,CosValues,z,CubicValues,'--',xvals,yvals,'*')
axis([-.5 5 -1.5 1.5])
title(sprintf('Interpolation of cos(x). Separation = %5.3f',d))
end
% Script File: ShowPWCH
% Convergence of the piecewise cubic hermite interpolant to
% exp(-2x)sin(10*pi*x) on [0,1].)
close all
z = linspace(0,1,200)';
fvals = exp(-2*z).*sin(10*pi*z);
for n = [4 8 16 24]
x = linspace(0,1,n)';
y = exp(-2*x).*sin(10*pi*x);
s = 10*pi*exp(-2*x).*cos(10*pi*x)-2*y;
[a,b,c,d] = pwC(x,y,s);
Cvals = pwCEval(a,b,c,d,x,z);
figure
plot(z,fvals,z,Cvals,'--',x,y,'*');
title(sprintf('Interpolation of exp(-2x)sin(10pi*x) with pwCH, n = %2.0f',n))
end
legend('e^{-2z}sin(10\pi z)','The pwC interpolant')
% Script File: ShowSpline
% Illustrates CubicSpline with various end conditions, some not so good.
close all
xvals = linspace(0,4*pi,100);
yvals = sin(xvals);
for n = 4:3:16
x = linspace(0,4*pi,n)';
y = sin(x);
[a,b,c,d] = CubicSpline(x,y,1,1,1);
svals = pwCEval(a,b,c,d,x,xvals);
figure
plot(xvals,yvals,xvals,svals,'--')
title(sprintf('''Good'' Complete spline interpolant of sin(x) with %2.0f subintervals',n-1))
end
for n = 4:3:16
x = linspace(0,4*pi,n)';
y = sin(x);
[a,b,c,d] = CubicSpline(x,y,1,-1,-1);
svals = pwCEval(a,b,c,d,x,xvals);
figure
plot(xvals,yvals,xvals,svals,'--')
title(sprintf('''Bad'' Complete spline interpolant of sin(x) with %2.0f subintervals',n-1))
end
for n = 4:3:16
x = linspace(0,4*pi,n)';
y = sin(x);
[a,b,c,d] = CubicSpline(x,y,2,0,0);
svals = pwCEval(a,b,c,d,x,xvals);
figure
plot(xvals,yvals,xvals,svals,'--')
title(sprintf('Natural spline interpolant of sin(x) with %2.0f subintervals',n-1))
end
for n = 4:3:16
x = linspace(0,4*pi,n)';
y = sin(x);
[a,b,c,d] = CubicSpline(x,y);
svals = pwCEval(a,b,c,d,x,xvals);
figure
plot(xvals,yvals,xvals,svals,'--')
title(sprintf('Not-a-Knot spline interpolant of sin(x) with %2.0f subintervals',n-1))
end
% Script File: ShowSplineErr
% Examines error in the not-a-knot spline interpolant of
% sin(2pi*x) across the interval [0,1]. Two equally-spaced knot
% cases are plotted: h =.05 and h = .005.
close all
z = linspace(0,1,500)';
SinVals = sin(2*pi*z);
k=0;
for n=[21 201 ]
x = linspace(0,1,n)';
y = sin(2*pi*x);
[a,b,c,d] = CubicSpline(x,y);
Svals = pwCEval(a,b,c,d,x,z);
k=k+1;
subplot(1,2,k)
semilogy(z,abs(SinVals-Svals)+eps);
axis([0 1 10^(-12) 10^(-3)])
xlabel(sprintf('Knot Spacing = %5.3f',1/(n-1)))
end
% Script File: ShowSplineTools
% Illustrates the Matlab functions spline, ppval, mkpp, unmkpp
close all
% Set Up Data:
n = 9;
x = linspace(-5,5,n);
y = atan(x);
% Compute the spline interpolant and its derivative:
S = spline(x,y);
[x,rho,L,k] = unmkpp(S);
drho = [3*rho(:,1) 2*rho(:,2) rho(:,3)];
dS = mkpp(x,drho);
% Evaluate S and dS:
z = linspace(-5,5);
Svals = ppval(S,z);
dSvals = ppval(dS,z);
% Plot:
atanvals = atan(z);
figure
plot(z,atanvals,z,Svals,x,y,'*');
title(sprintf('n = %2.0f Spline Interpolant of atan(x)',n))
datanvals = ones(size(z))./(1 + z.*z);
figure
plot(z,datanvals,z,dSvals)
title(sprintf('Derivative of n = %2.0f Spline Interpolant of atan(x)',n))
function [a,b] = pwL(x,y) % [a,b] = pwL(x,y) % % Generates the piecewise linear interpolant of the data specified by the % column n-vectors x and y. It is assumed that x(1)
function i = Locate(x,z,g) % i = Locate(x,z,g) % Locates z in a partition x. % % x is column n-vector with x(1)Left+1 % x(Left) <= z <="x(Right)" mid="floor((Left+Right)/2);" if z < x(mid) Right="mid;" else Left="mid;" end end i="Left;" end
function LVals = pwLEval(a,b,x,zVals) % LVals = pwLEval(a,b,x,zvals) % Evaluates the piecewise linear polynomial defined by the column (n-1)-vectors % a and b and the column n-vector x. It is assumed that x(1) <... < x(n). % zVals is a column m-vector with each component in [x(1),x(n)]. % % LVals is a column m-vector with the property that LVals(j)="L(zVals(j))" % for j="1:m" where L(z)="a(i)" + b(i)(z-x(i)) for x(i)<="z<=x(i+1)." m="length(zVals);" LVals="zeros(m,1);" g="1;" for j="1:m" i="Locate(x,zVals(j),g);" LVals(j)="a(i)" + b(i)*(zVals(j)-x(i)); g="i;" end
function [x,y] = pwLStatic(fname,M2,alpha,beta,delta) % [x,y] = pwLStatic(fname,M2,alpha,beta,delta) % Generates interpolation points for a piecewise linear approximation of % prescribed accuracy. % % fname is string that names an available function f(x). % Assume that f can take vector arguments. % M2 is an upper bound for|f"(x)| on [alpha,beta]. % alpha and beta are scalars with alpha
function [x,y] = pwLAdapt(fname,xL,fL,xR,fR,delta,hmin) % [x,y] = pwLAdapt(fname,xL,fL,xR,fR,delta,hmin) % Adaptively determines interpolation points for a piecewise linear % approximation of a specified function. % % fname is a string that specifies a function of the form y = f(u). % xL and xR are real scalars and fL = f(xL) and fR = f(xR). % delta and hmin are positive real scalars that determine accuracy. % % x and y are column n-vector with the property that % xL = x(1) <... < x(n)="xR" % and y(i)="f(x(i))," i="1:n." Each subinterval [x(i),x(i+1)] is % either <="hmin" in length or has the property that at its midpoint m, % |f(m) L(m)| <="delta" where L(x) is the line that connects (x(i),y(i)) % and (x(i+1),y(i+1)). if (xR-xL) <="hmin" % Subinterval is acceptable x="[xL;xR];" y="[fL;fR];" else mid="(xL+xR)/2;" fmid="feval(fname,mid);" if (abs(((fL+fR)/2) fmid) <="delta" ) % Subinterval accepted. x="[" xL;xR]; y="[fL;fR];" else % Produce left and right partitions, then synthesize. [xLeft,yLeft]="pwLAdapt(fname,xL,fL,mid,fmid,delta,hmin);" [xRight,yRight]="pwLAdapt(fname,mid,fmid,xR,fR,delta,hmin);" x="[" xLeft;xRight(2:length(xRight))]; y="[" yLeft;yRight(2:length(yRight))]; end end
function [a,b,c,d] = HCubic(xL,yL,sL,xR,yR,sR) % [a,b,c,d] = HCubic(xL,yL,sL,xR,yR,sR) % Cubic Hermite interpolation % % (xL,yL,sL) and (xR,yR,sR) are x-y-slope triplets with xL and xR distinct. % a,b,c,d are real numbers with the property that if % p(z) = a + b(z-xL) + c(z-xL)^2 + d(z-xL)^2(z-xR) % then p(xL)=yL, p'(xL)=sL, p(xR)=yR, and p'(xR)=sR. a = yL; b = sL; delx = xR - xL; yp = (yR - yL)/delx; c = (yp - sL)/delx; d = (sL - 2*yp + sR)/(delx*delx);
function [a,b,c,d] = pwC(x,y,s) % [a,b,c,d] = pwC(x,y,s) % Piecewise cubic Hermite interpolation. % % x,y,s column n-vectors with x(1) <... < x(n) % % a,b,c,d column (n-1)-vectors that define a continuous, piecewise % cubic polynomial q(z) with the property that for i="1:n," % % q(x(i))="y(i)" and q'(x(i))="s(i)." % % On the interval [x(i),x(i+1)], % % q(z)="a(i)" + b(i)(z-x(i)) + c(i)(z-x(i))^2 + d(i)(z-x(i))^2(z-x(i+1)). n="length(x);" a="y(1:n-1);" b="s(1:n-1);" Dx="diff(x);" Dy="diff(y);" yp="Dy" ./ Dx; c="(yp" s(1:n-1)) ./ Dx; d="(s(2:n)" + s(1:n-1) 2*yp) ./ (Dx.* Dx);
function Cvals = pwCEval(a,b,c,d,x,zVals) % Cvals = pwCEval(a,b,c,d,x,zVals) % % Evaluates the piecewise cubic polynomial defined by the column (n-1)-vectors a,b,c, and % d and the column n-vector x. It is assumed that x(1) <... < x(n). % zVals is a column m-vector with each component in [x(1),x(n)]. % % CVals is a column m-vector with the property that CVals(j)="C(zVals(j))" % for j="1:m" where on the interval [x(i),x(i+1)] % % C(z)="a(i)" + b(i)(z-x(i)) + c(i)(z-x(i))^2 + d(i)(z-x(i))^2(z-x(i+1)) m="length(zVals);" Cvals="zeros(m,1);" g="1;" for j="1:m" i="Locate(x,zVals(j),g);" Cvals(j)="d(i)*(zVals(j)-x(i+1))" + c(i); Cvals(j)="Cvals(j)*(zVals(j)-x(i))" + b(i); Cvals(j)="Cvals(j)*(zVals(j)-x(i))" + a(i); g="i;" end
function [a,b,c,d] = CubicSpline(x,y,derivative,muL,muR) % [a,b,c,d] = CubicSpline(x,y,derivative,muL,muR) % Cubic spline interpolation with prescribed end conditions. % % x,y are column n-vectors. It is assumed that n >= 4 and x(1) <... x(n). % derivative is an integer (1 or 2) that specifies the order of the endpoint derivatives. % muL and muR are the endpoint values of this derivative. % % a,b,c, and d are column (n-1)-vectors that define the spline S(z). On [x(i),x(i+1)], % % S(z)="a(i)" + b(i)(z-x(i)) + c(i)(z-x(i))^2 + d(i)(z-x(i))^2(z-x(i+1). % % Usage: % [a,b,c,d]="CubicSpline(x,y,1,muL,muR)" S'(x(1))="muL," S'(x(n))="muR" % [a,b,c,d]="CubicSpline(x,y,2,muL,muR)" S''(x(1))="muL," S''(x(n))="muR" % [a,b,c,d]="CubicSpline(x,y)" S'''(z) continuous at x(2) and x(n-1) % First, set up all but the first and last equations that % define the vector of interior knot slopes s(2:n-1). n="length(x);" Dx="diff(x);" yp="diff(y)" ./ Dx; T="zeros(n-2,n-2);" r="zeros(n-2,1);" for i="2:n-3" T(i,i)="2*(Dx(i)" + Dx(i+1)); T(i,i-1)="Dx(i+1);" T(i,i+1)="Dx(i);" r(i)="3*(Dx(i+1)*yp(i)" + Dx(i)*yp(i+1)); end % For each of the 3 cases, finish setting up the linear system, % solve the system, and set s(1:n) to be the vector of slopes. if nargin="=5" %Derivative information available. if derivative="=1" % End values for S'(z) specified. T(1,1)="2*(Dx(1)" + Dx(2)); T(1,2)="Dx(1);" r(1)="3*(Dx(2)*yp(1)+Dx(1)*yp(2))" Dx(2)*muL; T(n-2,n-2)="2*(Dx(n-2)+Dx(n-1));" T(n-2,n-3)="Dx(n-1);" r(n-2)="3*(Dx(n-1)*yp(n-2)" + Dx(n-2)*yp(n-1)) Dx(n-2)*muR; s="[muL;" T\r; muR]; end if derivative="=2" % End values for S''(z) specified. T(1,1)="2*Dx(1)" + 1.5*Dx(2); T(1,2)="Dx(1);" r(1)="1.5*Dx(2)*yp(1)" + 3*Dx(1)*yp(2) + Dx(1)*Dx(2)*muL/4; T(n-2,n-2)="1.5*Dx(n-2)+2*Dx(n-1);" T(n-2,n-3)="Dx(n-1);" r(n-2)="3*Dx(n-1)*yp(n-2)" + 1.5*Dx(n-2)*yp(n-1)-Dx(n-1)*Dx(n-2)*muR/4; stilde="T\r;" s1="(3*yp(1)" stilde(1) muL*Dx(1)/2)/2; sn="(3*yp(n-1)" stilde(n-2) + muR*Dx(n-1)/2)/2; s="[s1;stilde;sn];" end; else % No derivative information. Compute the not-a-knot spline. q="Dx(1)*Dx(1)/Dx(2);" T(1,1)="2*Dx(1)" +Dx(2) + q; T(1,2)="Dx(1)" + q; r(1)="Dx(2)*yp(1)" + Dx(1)*yp(2)+2*yp(2)*(q+Dx(1)); q="Dx(n-1)*Dx(n-1)/Dx(n-2);" T(n-2,n-2)="2*Dx(n-1)" + Dx(n-2)+q; T(n-2,n-3)="Dx(n-1)+q;" r(n-2)="Dx(n-1)*yp(n-2)" + Dx(n-2)*yp(n-1) +2*yp(n-2)*(Dx(n-1)+q); stilde="T\r;" s1="-stilde(1)+2*yp(1);" s1="s1" + ((Dx(1)/Dx(2))^2)*(stilde(1)+stilde(2)-2*yp(2)); sn="-stilde(n-2)" +2*yp(n-1); sn="sn+((Dx(n-1)/Dx(n-2))^2)*(stilde(n-3)+stilde(n-2)-2*yp(n-2));" s="[s1;stilde;sn];" end % Compute the a,b,c,d vectors. a="y(1:n-1);" b="s(1:n-1);" c="(yp" s(1:n-1)) ./ Dx; d="(s(2:n)" + s(1:n-1) 2*yp) ./ (Dx.* Dx);