/* splinef.i * $Id: splinef.i,v 1.1 2007/03/04 05:13:15 dhmunro Exp $ * piecewise cubic interpolation functions */ /* Copyright (c) 2007, The Regents of the University of California. * All rights reserved. * This file is part of yorick (http://yorick.sourceforge.net). * Read the accompanying LICENSE file for details. */ /* This package extends the original spline.i functions, concentrating * on how arbitrary piecewise cubic functions may be used as a natural * extension of the piecewise linear interp() built-in function. * Given a sequence of abcissa values x(i), the corresponding function * values y(i) uniquely determine a piecewise linear function. Knowing * both the function and its first derivatives, y(i) and dydx(i), * uniquely determines a piecewise cubic function. * * Unlike a true "spline", a general piecewise cubic curve has a * discontinuous second derivative. True spline curves depend only on * the function values y(i) at x(i); the derivatives dydx(i) are * computed to force continuity of the second derivative at x(i). * The less continuous general piecewise cubic permits you to make a * more robust fit, which is still smoother than piecewise linear, at * the cost of having to provide dydx(i) values by some other means. * The splinelsq function can select y(i) and dydx(i) to have least * square residuals of the piecewise cubic from a larger set of data, * like the fitlsq function in fitlsq.i does for piecewise linear fits. * * Note that a pair of piecewise cubic curves is a Bezier curve; that is, * if x(t) and y(t) are piecewise cubic, then (x,y) is a (cubic) Bezier. * These are the curves generated by the Postscript arcto operator. * If (x0,y0) is an initial point, (x1,y1) and (x2,y2) are the Bezier * control points, and (x3,y3) is the final point, then the spline * with 00.)? grow(xl, xfit, xu) : grow(xu, xfit, xl); xl = xx(l); xu = xx(l+1); dx = xu - xl; rdx = 1./dx; ld = x-xl; lx = ld * rdx; ud = lx*lx; lx = 1.-lx; ld *= lx*lx; uf = (1.+lx+lx)*ud; ud *= -lx*dx; lf = 1.-uf; if (is_void(weight)) weight = 1.0; lfy = histogram(l, lf*y*weight, top=np1); ldy = histogram(l, ld*y*weight, top=np1); ufy = histogram(l, uf*y*weight, top=np1); udy = histogram(l, ud*y*weight, top=np1); lflf = histogram(l, lf*lf*weight, top=np1); lfld = histogram(l, lf*ld*weight, top=np1); lfuf = histogram(l, lf*uf*weight, top=np1); lfud = histogram(l, lf*ud*weight, top=np1); ldld = histogram(l, ld*ld*weight, top=np1); lduf = histogram(l, ld*uf*weight, top=np1); ldud = histogram(l, ld*ud*weight, top=np1); ufuf = histogram(l, uf*uf*weight, top=np1); ufud = histogram(l, uf*ud*weight, top=np1); udud = histogram(l, ud*ud*weight, top=np1); n = 2*numberof(xfit); rhs = array(0., n); mat = array(rhs, n); n2 = n*n; dn = 2*(n+1); mat(1:n2:dn) = lflf(2:0) + ufuf(1:-1); mat(2:n2:dn) = mat(n+1:n2:dn) = lfld(2:0) + ufud(1:-1); mat(n+2:n2:dn) = ldld(2:0) + udud(1:-1); mat(3:n2-n:dn) = mat(dn-1:n2:dn) = lfuf(2:-1); mat(4:n2-n:dn) = mat(n+dn-1:n2:dn) = lfud(2:-1); mat(n+3:n2:dn) = mat(dn:n2:dn) = lduf(2:-1); mat(n+4:n2:dn) = mat(n+dn:n2:dn) = ldud(2:-1); rhs(1:n:2) = lfy(2:0) + ufy(1:-1); rhs(2:n:2) = ldy(2:0) + udy(1:-1); if (!is_void(y0)) { if (list(1)!=1) error, "y0= keyword with no data in first interval"; rhs(1) = y0; mat(1,) = 0.0; mat(1,1) = 1.0; } if (!is_void(dydx0)) { if (list(1)!=1) error, "dydx0= keyword with no data in first interval"; rhs(2) = dydx0; mat(2,) = 0.0; mat(2,2) = 1.0; } if (!is_void(y1)) { if (list(0)!=nfit) error, "y1= keyword with no data in last interval"; rhs(-1) = y1; mat(-1,) = 0.0; mat(-1,-1) = 1.0; } if (!is_void(dydx1)) { if (list(0)!=nfit) error, "dydx1= keyword with no data in last interval"; rhs(0) = dydx1; mat(0,) = 0.0; mat(0,0) = 1.0; } if (!is_void(constrain)) constrain; fd = LUsolve(mat, rhs); xfd = xfit(-:1:3,); xfd(2,) = fd(1:0:2); xfd(3,) = fd(2:0:2); return xfd; }