My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
spline.cpp
Go to the documentation of this file.
1 /*
2  * spline.cpp - spline class implementation
3  *
4  * Copyright (C) 2005, 2006, 2009 Stefan Jahn <stefan@lkcc.org>
5  *
6  * This is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This software is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this package; see the file COPYING. If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  * $Id: spline.cpp 1825 2011-03-11 20:42:14Z ela $
22  *
23  */
24 
25 #if HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33 
34 #include "logging.h"
35 #include "complex.h"
36 #include "object.h"
37 #include "vector.h"
38 #include "poly.h"
39 #include "tvector.h"
40 #include "tridiag.h"
41 #include "spline.h"
42 
43 // Constructor creates an instance of the spline class.
45  x = f0 = f1 = f2 = f3 = NULL;
46  d0 = dn = 0;
47  n = 0;
48  boundary = SPLINE_BC_NATURAL;
49 }
50 
51 // Constructor creates an instance of the spline class with given boundary.
53  x = f0 = f1 = f2 = f3 = NULL;
54  d0 = dn = 0;
55  n = 0;
56  boundary = b;
57 }
58 
59 // Constructor creates an instance of the spline class with vector data given.
61  x = f0 = f1 = f2 = f3 = NULL;
62  d0 = dn = 0;
63  n = 0;
64  boundary = SPLINE_BC_NATURAL;
65  vectors (y, t);
66  construct ();
67 }
68 
69 // Constructor creates an instance of the spline class with tvector data given.
71  x = f0 = f1 = f2 = f3 = NULL;
72  d0 = dn = 0;
73  n = 0;
74  boundary = SPLINE_BC_NATURAL;
75  vectors (y, t);
76  construct ();
77 }
78 
79 #define t_ (t)
80 #define y_ (y)
81 
82 // Pass interpolation datapoints as vectors.
84  int i = t.getSize ();
85  assert (y.getSize () == i && i >= 3);
86 
87  // create local copy of f(x)
88  realloc (i);
89  for (i = 0; i <= n; i++) {
90  f0[i] = real (y_(i)); x[i] = real (t_(i));
91  }
92 }
93 
94 // Pass interpolation datapoints as tvectors.
96  int i = t.getSize ();
97  assert (y.getSize () == i && i >= 3);
98 
99  // create local copy of f(x)
100  realloc (i);
101  for (i = 0; i <= n; i++) {
102  f0[i] = y_(i); x[i] = t_(i);
103  }
104 }
105 
106 // Pass interpolation datapoints as pointers.
107 void spline::vectors (nr_double_t * y, nr_double_t * t, int len) {
108  int i = len;
109  assert (i >= 3);
110 
111  // create local copy of f(x)
112  realloc (i);
113  for (i = 0; i <= n; i++) {
114  f0[i] = y[i]; x[i] = t[i];
115  }
116 }
117 
118 // Reallocate vector data if necessary.
119 void spline::realloc (int size) {
120  if (n != size - 1) {
121  n = size - 1;
122  if (f0) delete[] f0;
123  f0 = new nr_double_t[n+1];
124  if (x) delete[] x;
125  x = new nr_double_t[n+1];
126  }
127  if (f1) { delete[] f1; f1 = NULL; }
128  if (f2) { delete[] f2; f2 = NULL; }
129  if (f3) { delete[] f3; f3 = NULL; }
130 }
131 
132 // Construct cubic spline interpolation coefficients.
133 void spline::construct (void) {
134 
135  // calculate first derivative h = f'(x)
136  int i;
137  nr_double_t * h = new nr_double_t[n+1];
138  for (i = 0; i < n; i++) {
139  h[i] = x[i+1] - x[i];
140  if (h[i] == 0.0) {
141  logprint (LOG_ERROR, "ERROR: Duplicate points in spline: %g, %g\n",
142  x[i], x[i+1]);
143  }
144  }
145 
146  // first kind of cubic splines
147  if (boundary == SPLINE_BC_NATURAL || boundary == SPLINE_BC_CLAMPED) {
148 
149  // setup right hand side
150  nr_double_t * b = new nr_double_t[n+1]; // b as in Ax = b
151  for (i = 1; i < n; i++) {
152  nr_double_t _n = f0[i+1] * h[i-1] - f0[i] * (h[i] + h[i-1]) +
153  f0[i-1] * h[i];
154  nr_double_t _d = h[i-1] * h[i];
155  b[i] = 3 * _n / _d;
156  }
157  if (boundary == SPLINE_BC_NATURAL) {
158  // natural boundary condition
159  b[0] = 0;
160  b[n] = 0;
161  } else if (boundary == SPLINE_BC_CLAMPED) {
162  // start and end derivatives given
163  b[0] = 3 * ((f0[1] - f0[0]) / h[0] - d0);
164  b[n] = 3 * (dn - (f0[n] - f0[n-1]) / h[n-1]);
165  }
166 
167  nr_double_t * u = new nr_double_t[n+1];
168  nr_double_t * z = b; // reuse storage
169  if (boundary == SPLINE_BC_NATURAL) {
170  u[0] = 0;
171  z[0] = 0;
172  } else if (boundary == SPLINE_BC_CLAMPED) {
173  u[0] = h[0] / (2 * h[0]);
174  z[0] = b[0] / (2 * h[0]);
175  }
176 
177  for (i = 1; i < n; i++) {
178  nr_double_t p = 2 * (h[i] + h[i-1]) - h[i-1] * u[i-1]; // pivot
179  u[i] = h[i] / p;
180  z[i] = (b[i] - z[i-1] * h[i-1]) / p;
181  }
182  if (boundary == SPLINE_BC_NATURAL) {
183  z[n] = 0;
184  } else if (boundary == SPLINE_BC_CLAMPED) {
185  nr_double_t p = h[n-1] * (2 - u[n-1]);
186  z[n] = (b[n] - z[n-1] * h[n-1]) / p;
187  }
188 
189  // back substitution
190  f1 = u; // reuse storage
191  f2 = z;
192  f3 = h;
193  f2[n] = z[n];
194  f3[n] = 0;
195  for (i = n - 1; i >= 0; i--) {
196  f2[i] = z[i] - u[i] * f2[i+1];
197  f1[i] = (f0[i+1] - f0[i]) / h[i] - h[i] * (f2[i+1] + 2 * f2[i]) / 3;
198  f3[i] = (f2[i+1] - f2[i]) / (3 * h[i]);
199  }
200 
201  // set up last slot for extrapolation above
202  if (boundary == SPLINE_BC_NATURAL) {
203  f1[n] = f1[n-1] + (x[n] - x[n-1]) * f2[n-1];
204  } else if (boundary == SPLINE_BC_CLAMPED) {
205  f1[n] = dn;
206  }
207  f2[n] = 0;
208  f3[n] = 0;
209  }
210 
211  // second kind of cubic splines
212  else if (boundary == SPLINE_BC_PERIODIC) {
213  // non-trigdiagonal equations - periodic boundary condition
214  nr_double_t * z = new nr_double_t[n+1];
215  if (n == 2) {
216  nr_double_t B = h[0] + h[1];
217  nr_double_t A = 2 * B;
218  nr_double_t b[2], det;
219  b[0] = 3 * ((f0[2] - f0[1]) / h[1] - (f0[1] - f0[0]) / h[0]);
220  b[1] = 3 * ((f0[1] - f0[2]) / h[0] - (f0[2] - f0[1]) / h[1]);
221  det = 3 * B * B;
222  z[1] = ( A * b[0] - B * b[1]) / det;
223  z[2] = (-B * b[0] + A * b[1]) / det;
224  z[0] = z[2];
225  }
226  else {
228  tvector<nr_double_t> o (n);
229  tvector<nr_double_t> d (n);
231  b.setData (&z[1], n);
232  for (i = 0; i < n - 1; i++) {
233  o(i) = h[i+1];
234  d(i) = 2 * (h[i+1] + h[i]);
235  b(i) = 3 * ((f0[i+2] - f0[i+1]) / h[i+1] - (f0[i+1] - f0[i]) / h[i]);
236  }
237  o(i) = h[0];
238  d(i) = 2 * (h[0] + h[i]);
239  b(i) = 3 * ((f0[1] - f0[i+1]) / h[0] - (f0[i+1] - f0[i]) / h[i]);
240  sys.setDiagonal (&d);
241  sys.setOffDiagonal (&o);
242  sys.setRHS (&b);
244  sys.solve ();
245  z[0] = z[n];
246  }
247 
248  f1 = new nr_double_t[n+1];
249  f2 = z; // reuse storage
250  f3 = h;
251  for (i = n - 1; i >= 0; i--) {
252  f1[i] = (f0[i+1] - f0[i]) / h[i] - h[i] * (z[i+1] + 2 * z[i]) / 3;
253  f3[i] = (z[i+1] - z[i]) / (3 * h[i]);
254  }
255  f1[n] = f1[0];
256  f2[n] = f2[0];
257  f3[n] = f3[0];
258  }
259 }
260 
261 // Returns pointer to the first value greater than the given one.
262 nr_double_t * spline::upper_bound (nr_double_t * first, nr_double_t * last,
263  nr_double_t value) {
264  int half, len = last - first;
265  nr_double_t * centre;
266 
267  while (len > 0) {
268  half = len >> 1;
269  centre = first;
270  centre += half;
271  if (value < *centre)
272  len = half;
273  else {
274  first = centre;
275  ++first;
276  len = len - half - 1;
277  }
278  }
279  return first;
280 }
281 
282 // Evaluates the spline at the given position.
283 poly spline::evaluate (nr_double_t t) {
284 
285 #ifndef PERIOD_DISABLED
286  if (boundary == SPLINE_BC_PERIODIC) {
287  // extrapolation easy: periodically
288  nr_double_t period = x[n] - x[0];
289  while (t > x[n]) t -= period;
290  while (t < x[0]) t += period;
291  }
292 #endif /* PERIOD_DISABLED */
293 
294  nr_double_t * here = upper_bound (x, x+n+1, t);
295  nr_double_t y0, y1, y2;
296  if (here == x) {
297  nr_double_t dx = t - x[0];
298  y0 = f0[0] + dx * f1[0];
299  y1 = f1[0];
300  return poly (t, y0, y1);
301  }
302  else {
303  int i = here - x - 1;
304  nr_double_t dx = t - x[i];
305  // value
306  y0 = f0[i] + dx * (f1[i] + dx * (f2[i] + dx * f3[i]));
307  // first derivative
308  y1 = f1[i] + dx * (2 * f2[i] + 3 * dx * f3[i]);
309  // second derivative
310  y2 = 2 * f2[i] + 6 * dx * f3[i];
311  return poly (t, y0, y1, y2);
312  }
313 }
314 
315 // Destructor deletes an instance of the spline class.
317  if (x) delete[] x;
318  if (f0) delete[] f0;
319  if (f1) delete[] f1;
320  if (f2) delete[] f2;
321  if (f3) delete[] f3;
322 }