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) < x(2) < ... < x(n). % % a and b are column (n-1)-vectors with the property that for i=1:n-1, the % line L(z) = a(i) + b(i)z passes though the points (x(i),y(i)) and (x(i+1),y(i+1)). n = length(x); a = y(1:n-1); b = diff(y) ./ diff(x);
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) < x(2) <...<x(n) and % z is a scalar with x(1) <= z <= x(n). % g (1<=g<=n-1) is an optional input parameter % % i is an integer such that x(i) <= z <= x(i+1). Before the general % search for i begins, the value i=g is tried. if nargin==3 % Try the initial guess. if (x(g)<=z) & (z<=x(g+1)) i = g; return end end n = length(x); if z==x(n) i = n-1; else % Binary Search Left = 1; Right = n; while Right > 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<beta. % delta is a positive scalar. % % x and y column n-vectors with the property that y(i) = f(x(i)), i=1:n. % The piecewise linear interpolant L(x) of this data satisfies % |L(z) - f(z)| <= delta for x(1) <= z <= x(n). n = max(2,ceil(1+(beta-alpha)*sqrt(M2/(8*delta)))); x = linspace(alpha,beta,n)'; y = feval(fname,x);
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);