@@ -1485,6 +1485,139 @@ def load(fname,comments='%',delimiter=None, converters=None,skiprows=0,
14851485 if unpack : return transpose (X )
14861486 else : return X
14871487
1488+ def slopes (x ,y ):
1489+ """
1490+ SLOPES calculate the slope y'(x) Given data vectors X and Y SLOPES
1491+ calculates Y'(X), i.e the slope of a curve Y(X). The slope is
1492+ estimated using the slope obtained from that of a parabola through
1493+ any three consecutive points.
1494+
1495+ This method should be superior to that described in the appendix
1496+ of A CONSISTENTLY WELL BEHAVED METHOD OF INTERPOLATION by Russel
1497+ W. Stineman (Creative Computing July 1980) in at least one aspect:
1498+
1499+ Circles for interpolation demand a known aspect ratio between x-
1500+ and y-values. For many functions, however, the abscissa are given
1501+ in different dimensions, so an aspect ratio is completely
1502+ arbitrary.
1503+
1504+ The parabola method gives very similar results to the circle
1505+ method for most regular cases but behaves much better in special
1506+ cases
1507+
1508+ Norbert Nemec, Institute of Theoretical Physics, University or
1509+ Regensburg, April 2006 Norbert.Nemec at physik.uni-regensburg.de
1510+
1511+ (inspired by a original implementation by Halldor Bjornsson,
1512+ Icelandic Meteorological Office, March 2006 halldor at vedur.is)
1513+ """
1514+ # Cast key variables as float.
1515+ x = nx .asarray (x , nx .Float )
1516+ y = nx .asarray (y , nx .Float )
1517+
1518+ yp = nx .zeros (y .shape , nx .Float )
1519+
1520+ dx = x [1 :] - x [:- 1 ]
1521+ dy = y [1 :] - y [:- 1 ]
1522+ dydx = dy / dx
1523+ yp [1 :- 1 ] = (dydx [:- 1 ] * dx [1 :] + dydx [1 :] * dx [:- 1 ])/ (dx [1 :] + dx [:- 1 ])
1524+ yp [0 ] = 2.0 * dy [0 ]/ dx [0 ] - yp [1 ]
1525+ yp [- 1 ] = 2.0 * dy [- 1 ]/ dx [- 1 ] - yp [- 2 ]
1526+ return yp
1527+
1528+
1529+ def stineman_interp (xi ,x ,y ,yp = None ):
1530+ """
1531+ STINEMAN_INTERP Well behaved data interpolation. Given data
1532+ vectors X and Y, the slope vector YP and a new abscissa vector XI
1533+ the function stineman_interp(X,Y,YP,XI) uses Stineman
1534+ interpolation to calculate a vector YI corresponding to XI.
1535+
1536+ Here's an example that generates a coarse sine curve, then
1537+ interpolates over a finer abscissa:
1538+
1539+ x = linspace(0,2*pi,20); y = sin(x); yp = cos(x)
1540+ xi = linspace(0,2*pi,40);
1541+ yi = stineman_interp(x,y,yp,xi);
1542+ plot(x,y,'o',xi,yi)
1543+
1544+ The interpolation method is described in the article A
1545+ CONSISTENTLY WELL BEHAVED METHOD OF INTERPOLATION by Russell
1546+ W. Stineman. The article appeared in the July 1980 issue of
1547+ Creative computing with a note from the editor stating that while
1548+ they were
1549+
1550+ not an academic journal but once in a while something serious
1551+ and original comes in adding that this was
1552+ "apparently a real solution" to a well known problem.
1553+
1554+ For yp=None, the routine automatically determines the slopes using
1555+ the "slopes" routine.
1556+
1557+ X is assumed to be sorted in increasing order
1558+
1559+ For values xi[j] < x[0] or xi[j] > x[-1], the routine tries a
1560+ extrapolation. The relevance of the data obtained from this, of
1561+ course, questionable...
1562+
1563+ original implementation by Halldor Bjornsson, Icelandic
1564+ Meteorolocial Office, March 2006 halldor at vedur.is
1565+
1566+ completely reworked and optimized for Python by Norbert Nemec,
1567+ Institute of Theoretical Physics, University or Regensburg, April
1568+ 2006 Norbert.Nemec at physik.uni-regensburg.de
1569+
1570+ """
1571+
1572+ # Cast key variables as float.
1573+ x = nx .asarray (x , nx .Float )
1574+ y = nx .asarray (y , nx .Float )
1575+ assert x .shape == y .shape
1576+ N = len (y )
1577+
1578+ if yp is None :
1579+ yp = slopes (x ,y )
1580+ else :
1581+ yp = nx .asarray (yp , nx .Float )
1582+
1583+ xi = nx .asarray (xi , nx .Float )
1584+ yi = nx .zeros (xi .shape , nx .Float )
1585+
1586+ # calculate linear slopes
1587+ dx = x [1 :] - x [:- 1 ]
1588+ dy = y [1 :] - y [:- 1 ]
1589+ s = dy / dx #note length of s is N-1 so last element is #N-2
1590+
1591+ # find the segment each xi is in
1592+ # this line actually is the key to the efficiency of this implementation
1593+ idx = nx .searchsorted (x [1 :- 1 ], xi )
1594+
1595+ # now we have generally: x[idx[j]] <= xi[j] <= x[idx[j]+1]
1596+ # except at the boundaries, where it may be that xi[j] < x[0] or xi[j] > x[-1]
1597+
1598+ # the y-values that would come out from a linear interpolation:
1599+ sidx = nx .take (s , idx )
1600+ xidx = nx .take (x , idx )
1601+ yidx = nx .take (y , idx )
1602+ xidxp1 = nx .take (x , idx + 1 )
1603+ yo = yidx + sidx * (xi - xidx )
1604+
1605+ # the difference that comes when using the slopes given in yp
1606+ dy1 = (nx .take (yp , idx )- sidx ) * (xi - xidx ) # using the yp slope of the left point
1607+ dy2 = (nx .take (yp , idx + 1 )- sidx ) * (xi - xidxp1 ) # using the yp slope of the right point
1608+
1609+ dy1dy2 = dy1 * dy2
1610+ # The following is optimized for Python. The solution actually
1611+ # does more calculations than necessary but exploiting the power
1612+ # of numpy, this is far more efficient than coding a loop by hand
1613+ # in Python
1614+ yi = yo + dy1dy2 * nx .choose (nx .array (nx .sign (dy1dy2 ), nx .Int32 )+ 1 ,
1615+ ((2 * xi - xidx - xidxp1 )/ ((dy1 - dy2 )* (xidxp1 - xidx )),
1616+ 0.0 ,
1617+ 1 / (dy1 + dy2 ),))
1618+
1619+ return yi
1620+
14881621### the following code was written and submitted by Fernando Perez
14891622### from the ipython numutils package under a BSD license
14901623"""
0 commit comments