001 package edu.nrao.sss.math; 002 003 import java.awt.geom.Point2D; 004 import java.util.ArrayList; 005 import java.util.List; 006 007 /** 008 * An interpolated value calculator that uses cubic spline interpolation. 009 * <p> 010 * <b>Version Info:</b> 011 * <table style="margin-left:2em"> 012 * <tr><td>$Revision: 568 $</td></tr> 013 * <tr><td>$Date: 2007-04-27 16:53:09 -0600 (Fri, 27 Apr 2007) $</td></tr> 014 * <tr><td>$Author: dharland $</td></tr> 015 * </table></p> 016 * 017 * @author David M. Harland 018 * @since 2007-04-24 019 */ 020 public class CubicSpline 021 extends AbsInterp 022 { 023 private List<Cubic> splines; 024 025 /** Creates a new instance. */ 026 public CubicSpline() 027 { 028 super(); 029 030 splines = new ArrayList<Cubic>(); 031 } 032 033 /* (non-Javadoc) 034 * @see edu.nrao.sss.math.AbsInterp#getComputedValueFor(double) 035 */ 036 @Override 037 public double getComputedValueFor(double x) 038 { 039 return getSplineFor(x).evaluate(x); 040 } 041 042 /** Returns the appropriate spline for x. */ 043 private Cubic getSplineFor(double x) 044 { 045 //This code assumes: 046 // 1. x is in domain 047 // 2. splines are sorted 048 049 Cubic spline = null; 050 051 for (int s=splines.size()-1; s >= 0; s--) 052 { 053 Cubic candidate = splines.get(s); 054 055 if (x >= candidate.X) 056 { 057 spline = candidate; 058 break; 059 } 060 } 061 062 return spline; 063 } 064 065 /* (non-Javadoc) 066 * @see edu.nrao.sss.math.AbsInterp#compute() 067 */ 068 @Override 069 void runAlgorithm() 070 { 071 //TODO Think about also coding clamped spline. In order to calc a clamped 072 // spline, we need the value of the derivate at x[0] and x[n]. 073 // If the points are evenly spaced, there are ways to estimate 074 // these values. 075 computeNaturalSplines(); 076 } 077 078 /** 079 * Calculates the natural splines for this interpolator. 080 * "Natural" means the second derivatives at the endpoints are taken to be 0. 081 * 082 * This algorithm was take from section 3.6 of <u>Numerical Analysis, Fourth 083 * Edition</u> by Burden & Faires, p 131. 084 * The variable names in this method are, as much as possible, the same as 085 * those in the book. 086 */ 087 private void computeNaturalSplines() 088 { 089 int n = this.size() - 1; 090 091 double[] a = new double[n+1]; //term of order 0, also = f(x[i]) 092 double[] b = new double[n]; //term of order 1 093 double[] c = new double[n+1]; //term of order 2 (see step 5 for why n+1) 094 double[] d = new double[n]; //term of order 3 095 double[] x = new double[n+1]; 096 097 //INPUT 098 for (int i=0; i < n+1; i++) 099 { 100 Point2D point = getPoint(i); 101 102 x[i] = point.getX(); 103 a[i] = point.getY(); 104 } 105 106 //STEP 1 107 double[] h = new double[n]; 108 for (int i=0; i < n; i++) 109 h[i] = x[i+1] - x[i]; 110 111 //STEP 2 112 double[] alpha = new double[n]; 113 alpha[0] = 0.0; 114 for (int i=1; i < n; i++) 115 { 116 alpha[i] = 117 3 * (a[i+1]*h[i-1] - a[i]*(x[i+1]-x[i-1]) + a[i-1]*h[i]) / (h[i-1]*h[i]); 118 } 119 120 //STEP 3 121 double[] l = new double[n+1]; 122 double[] mu = new double[n+1]; 123 double[] z = new double[n+1]; 124 125 l[0] = 1.0; mu[0] = 0.0; z[0] = 0.0; 126 127 //STEP 4 128 for (int i=1; i < n; i++) 129 { 130 l[i] = 2*(x[i+1]-x[i-1]) - h[i-1]*mu[i-1]; 131 mu[i] = h[i] / l[i]; 132 z[i] = (alpha[i] - h[i-1]*z[i-1]) / l[i]; 133 } 134 135 //STEP 5 136 l[n] = 1.0; z[n] = 0.0; c[n] = 0; 137 138 //STEP 6 139 for (int j=n-1; j >= 0; j--) 140 { 141 c[j] = z[j] - mu[j]*c[j+1]; 142 b[j] = (a[j+1]-a[j])/h[j] - h[j]*(c[j+1]+2*c[j])/3.0; 143 d[j] = (c[j+1]-c[j])/(3.0*h[j]); 144 } 145 146 //STEP 7 147 splines.clear(); 148 for (int j=0; j < n; j++) 149 { 150 Cubic spline = new Cubic(); 151 152 spline.X = x[j]; 153 spline.a = a[j]; 154 spline.b = b[j]; 155 spline.c = c[j]; 156 spline.d = d[j]; 157 158 splines.add(spline); 159 } 160 } 161 162 /** 163 * A single cubic equation of form 164 * f(x) = a + b*(x-X) + c*(x-X)^2 + d*(x-X)^3. 165 */ 166 private class Cubic 167 { 168 double a, b, c, d, X; 169 170 double evaluate(double x) 171 { 172 double delta = x - X; 173 174 return a + b * delta + c * delta * delta + d * delta * delta * delta; 175 } 176 } 177 }