interpol.pro
8.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
; $Id: //depot/Release/ENVI52_IDL84/idl/idldir/lib/interpol.pro#1 $
;
; Copyright (c) 1982-2014, Exelis Visual Information Solutions, Inc. All
; rights reserved. Unauthorized reproduction is prohibited.
Function ls2fit, xx, y, xm
COMPILE_OPT idl2, hidden
x = xx - xx[0] ;Normalize to preserve significance.
ndegree = 2L
n = n_elements(xx)
corrm = fltarr(ndegree+1, ndegree+1) ;Correlation matrix
b = fltarr(ndegree+1)
corrm[0,0] = n ;0 - Form the normal equations
b[0] = total(y)
z = x ;1
b[1] = total(y*z)
corrm[[0,1],[1,0]] = total(z)
z = z * x ;2
b[2] = total(y*z)
corrm[[0,1,2], [2,1,0]] = total(z)
z = z * x ;3
corrm[[1,2],[2,1]] = total(z)
corrm[2,2] = total(z*x) ;4
c = b # invert(corrm)
xm0 = xm - xx[0]
return, c[0] + c[1] * xm0 + c[2] * xm0^2
end
;+
; NAME:
; INTERPOL
;
; PURPOSE:
; Linearly interpolate vectors with a regular or irregular grid.
; Quadratic or a 4 point least-square fit to a quadratic
; interpolation may be used as an option.
;
; CATEGORY:
; E1 - Interpolation
;
; CALLING SEQUENCE:
; Result = INTERPOL(V, N) ;For regular grids.
;
; Result = INTERPOL(V, X, XOUT) ;For irregular grids.
;
; INPUTS:
; V: The input vector can be any type except string.
;
; For regular grids:
; N: The number of points in the result when both input and
; output grids are regular.
;
; Irregular grids:
; X: The absicissae values for V. This vector must have same # of
; elements as V. The values MUST be monotonically ascending
; or descending.
;
; XOUT: The absicissae values for the result. The result will have
; the same number of elements as XOUT. XOUT does not need to be
; monotonic. If XOUT is outside the range of X, then the
; closest two endpoints of (X,V) are linearly extrapolated.
;
; Keyword Input Parameters:
; NAN = if set, then filter out NaN values before interpolating.
; The default behavior is to include the NaN values - by including NaN's
; the output will contain NaN's in locations where the interpolation
; result is undefined.
;
; LSQUADRATIC = if set, interpolate using a least squares
; quadratic fit to the equation y = a + bx + cx^2, for each 4
; point neighborhood (x[i-1], x[i], x[i+1], x[i+2]) surrounding
; the interval, x[i] <= XOUT < x[i+1].
;
; QUADRATIC = if set, interpolate by fitting a quadratic
; y = a + bx + cx^2, to the three point neighborhood (x[i-1],
; x[i], x[i+1]) surrounding the interval x[i] <= XOUT < x[i+1].
;
; SPLINE = if set, interpolate by fitting a cubic spline to the
; 4 point neighborhood (x[i-1], x[i], x[i+1], x[i+2]) surrounding
; the interval, x[i] <= XOUT < x[i+1].
;
; Note: if LSQUADRATIC or QUADRATIC or SPLINE is not set, the
; default linear interpolation is used.
;
; OUTPUTS:
; INTERPOL returns a floating-point vector of N points determined
; by interpolating the input vector by the specified method.
;
; If the input vector is double or complex, the result is double
; or complex.
;
; COMMON BLOCKS:
; None.
;
; SIDE EFFECTS:
; None.
;
; RESTRICTIONS:
; None.
;
; PROCEDURE:
; For linear interpolation,
; Result(i) = V(x) + (x - FIX(x)) * (V(x+1) - V(x))
;
; where x = i*(m-1)/(N-1) for regular grids.
; m = # of elements in V, i=0 to N-1.
;
; For irregular grids, x = XOUT(i).
; m = number of points of input vector.
;
; For QUADRATIC interpolation, the equation y=a+bx+cx^2 is
; solved explicitly for each three point interval, and is then
; evaluated at the interpolate.
; For LSQUADRATIC interpolation, the coefficients a, b, and c,
; from the above equation are found, for the four point
; interval surrounding the interpolate using a least square
; fit. Then the equation is evaluated at the interpolate.
; For SPLINE interpolation, a cubic spline is fit over the 4
; point interval surrounding each interpolate, using the routine
; SPL_INTERP().
;
; MODIFICATION HISTORY:
; Written, DMS, October, 1982.
; Modified, Rob at NCAR, February, 1991. Made larger arrays possible
; and correct by using long indexes into the array instead of
; integers.
; Modified, DMS, August, 1998. Now use binary intervals which
; speed things up considerably when XOUT is random.
; DMS, May, 1999. Use new VALUE_LOCATE function to find intervals,
; which speeds things up by a factor of around 100, when
; interpolating from large arrays. Also added SPLINE,
; QUADRATIC, and LSQUADRATIC keywords.
; CT, VIS, Feb 2009: CR54942: Automatically filter out NaN values.
; Clean up code.
; CT, VIS, Feb 2010: CR57403: Back out previous change.
; Add NAN keyword to control filtering out of NaN's
;-
;
FUNCTION INTERPOL, VV, XX, XOUT, $
SPLINE=spline, LSQUADRATIC=ls2, QUADRATIC=quad, NAN=nan
COMPILE_OPT idl2
on_error,2 ;Return to caller if an error occurs
regular = n_params(0) eq 2
; Make a copy so we don't overwrite the input arguments.
v = vv
x = xx
m = N_elements(v) ;# of input pnts
if (regular) then nOut = LONG(x)
; Filter out NaN values in both the V and X arguments.
if (KEYWORD_SET(nan)) then begin
isNAN = FINITE(v, /NAN)
if (~regular) then isNAN or= FINITE(x, /NAN)
if (~ARRAY_EQUAL(isNAN, 0)) then begin
good = WHERE(~isNAN, ngood)
if (ngood gt 0 && ngood lt m) then begin
v = v[good]
if (regular) then begin
; We supposedly had a regular grid, but some of the values
; were NaN (missing). So construct the irregular grid.
regular = 0b
x = LINDGEN(m)
xout = FINDGEN(nOut) * ((m-1.0) / ((nOut-1.0) > 1.0)) ;Grid points
endif
x = x[good]
endif
endif
endif
; get the number of input points again, in case some NaN's got filtered
m = N_elements(v)
type = SIZE(v, /TYPE)
if regular && $ ;Simple regular case?
((keyword_set(ls2) || keyword_set(quad) || keyword_set(spline)) eq 0) $
then begin
xout = findgen(nOut)*((m-1.0)/((nOut-1.0) > 1.0)) ;Grid points in V
xoutInt = long(xout) ;Cvt to integer
case (type) of
1: diff = v[1:*] - FIX(v)
12: diff = v[1:*] - LONG(v)
13: diff = v[1:*] - LONG64(v)
15: diff = LONG64(v[1:*]) - LONG64(v)
else: diff = v[1:*] - v
endcase
return, V[xoutInt] + (xout-xoutInt)*diff[xoutInt] ;interpolate
endif
if regular then begin ;Regular intervals??
xout = findgen(nOut) * ((m-1.0) / ((nOut-1.0) > 1.0)) ;Grid points
s = long(xout) ;Subscripts
endif else begin ;Irregular
if n_elements(x) ne m then $
message, 'V and X arrays must have same # of elements'
s = VALUE_LOCATE(x, xout) > 0L < (m-2) ;Subscript intervals.
endelse
; Clip interval, which forces extrapolation.
; XOUT[i] is between x[s[i]] and x[s[i]+1].
CASE (1) OF
KEYWORD_SET(ls2): BEGIN ;Least square fit quadratic, 4 points
s = s > 1L < (m-3) ;Make in range.
p = replicate(v[0]*1.0, n_elements(s)) ;Result
for i=0L, n_elements(s)-1 do begin
s0 = s[i]-1
p[i] = ls2fit(regular ? s0+findgen(4) : x[s0:s0+3], v[s0:s0+3], xout[i])
endfor
END
KEYWORD_SET(quad): BEGIN ;Quadratic.
s = s > 1L < (m-2) ;In range
x1 = regular ? float(s) : x[s]
x0 = regular ? x1-1.0 : x[s-1]
x2 = regular ? x1+1.0 : x[s+1]
p = v[s-1] * (xout-x1) * (xout-x2) / ((x0-x1) * (x0-x2)) + $
v[s] * (xout-x0) * (xout-x2) / ((x1-x0) * (x1-x2)) + $
v[s+1] * (xout-x0) * (xout-x1) / ((x2-x0) * (x2-x1))
END
KEYWORD_SET(spline): BEGIN
s = s > 1L < (m-3) ;Make in range.
p = replicate(v[0], n_elements(s)) ;Result
sold = -1
for i=0L, n_elements(s)-1 do begin
s0 = s[i]-1
if sold ne s0 then begin
x0 = regular ? s0+findgen(4): x[s0: s0+3]
v0 = v[s0: s0+3]
q = spl_init(x0, v0)
sold = s0
endif
p[i] = spl_interp(x0, v0, q, xout[i])
endfor
END
ELSE: begin ;Linear, not regular
case (type) of
1: diff = v[s+1] - FIX(v[s])
12: diff = v[s+1] - LONG(v[s])
13: diff = v[s+1] - LONG64(v[s])
15: diff = LONG64(v[s+1]) - LONG64(v[s])
else: diff = v[s+1] - v[s]
endcase
p = (xout-x[s])*diff/(x[s+1] - x[s]) + v[s]
end
ENDCASE
RETURN, p
end