comparison main/general/interp1.m @ 0:6b33357c7561 octave-forge

Initial revision
author pkienzle
date Wed, 10 Oct 2001 19:54:49 +0000
parents
children e6b6904a399e
comparison
equal deleted inserted replaced
-1:000000000000 0:6b33357c7561
1 ## Copyright (C) 2000 Paul Kienzle
2 ##
3 ## This program is free software; you can redistribute it and/or modify
4 ## it under the terms of the GNU General Public License as published by
5 ## the Free Software Foundation; either version 2 of the License, or
6 ## (at your option) any later version.
7 ##
8 ## This program is distributed in the hope that it will be useful,
9 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 ## GNU General Public License for more details.
12 ##
13 ## You should have received a copy of the GNU General Public License
14 ## along with this program; if not, write to the Free Software
15 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
17 ## usage: yi = interp1(x, y, xi [, 'method' [, 'extrap']])
18 ##
19 ## Interpolate the function y=f(x) at the points xi. The sample
20 ## points x must be strictly monotonic. If y is a matrix with
21 ## length(x) rows, yi will be a matrix of size rows(xi) by columns(y),
22 ## or its transpose if xi is a row vector.
23 ##
24 ## Method is one of:
25 ## 'nearest': return nearest neighbour.
26 ## 'linear': linear interpolation from nearest neighbours
27 ## 'pchip': piece-wise cubic hermite interpolating polynomial
28 ## 'cubic': cubic interpolation from four nearest neighbours
29 ## 'spline': cubic spline interpolation--smooth first and second
30 ## derivatives throughout the curve
31 ## ['*' method]: same as method, but assumes x is uniformly spaced
32 ## only uses x(1) and x(2); usually faster, never slower
33 ##
34 ## Method defaults to 'linear'.
35 ##
36 ## If extrap is the string 'extrap', then extrapolate values beyond
37 ## the endpoints. If extrap is a number, replace values beyond the
38 ## endpoints with that number. If extrap is missing, assume NaN.
39 ##
40 ## Example:
41 ## xf=[0:0.05:10]; yf = sin(2*pi*xf/5);
42 ## xp=[0:10]; yp = sin(2*pi*xp/5);
43 ## lin=interp1(xp,yp,xf);
44 ## spl=interp1(xp,yp,xf,'spline');
45 ## cub=interp1(xp,yp,xf,'cubic');
46 ## near=interp1(xp,yp,xf,'nearest');
47 ## plot(xf,yf,';original;',xf,lin,';linear;',xf,spl,';spline;',...
48 ## xf,cub,';cubic;',xf,near,';nearest;',xp,yp,'*;;');
49 ##
50 ## See also: interp
51
52 ## 2000-03-25 Paul Kienzle
53 ## added 'nearest' as suggested by Kai Habel
54 ## 2000-07-17 Paul Kienzle
55 ## added '*' methods and matrix y
56 ## check for proper table lengths
57
58 function yi = interp1(x, y, xi, method, extrap)
59
60 if nargin<3 || nargin>5
61 usage("yi = interp1(x, y, xi [, 'method' [, 'extrap']])");
62 endif
63
64 if nargin < 4,
65 method = 'linear';
66 else
67 method = tolower(method);
68 endif
69
70 if nargin < 5
71 extrap = NaN;
72 endif
73
74 ## reshape matrices for convenience
75 x = x(:);
76 if size(y,1)==1, y=y(:); endif
77 transposed = (size(xi,1)==1);
78 xi = xi(:);
79
80 ## determine sizes
81 nx = size(x,1);
82 [ny, nc] = size(y);
83 if (nx < 2 || ny < 2)
84 error ("interp1: table too short");
85 endif
86
87 ## determine which values are out of range and set them to extrap,
88 ## unless extrap=='extrap' in which case, extrapolate them like we
89 ## should have done in the first place.
90 minx = x(1);
91 if (method(1) == '*')
92 dx = x(2) - x(1);
93 maxx = minx + (ny-1)*dx;
94 else
95 maxx = x(nx);
96 endif
97 if strcmp(extrap,"extrap")
98 range=1:nx;
99 else
100 range = find(xi >= minx & xi <= maxx);
101 yi = extrap*ones(size(xi,1), size(y,2));
102 if isempty(range),
103 if transposed, yi = yi.'; endif
104 return;
105 endif
106 xi = xi(range);
107 endif
108
109 if strcmp(method, 'nearest')
110 idx = lookup(0.5*(x(1:nx-1)+x(2:nx)), xi)+1;
111 yi(range,:) = y(idx,:);
112
113 elseif strcmp(method, '*nearest')
114 idx = floor((xi-minx)/dx+1.5);
115 yi(range,:) = y(idx,:);
116
117 elseif strcmp(method, 'linear')
118 ## find the interval containing the test point
119 idx = lookup (x(2:nx-1), xi)+1;
120 # 2:n-1 so that anything beyond the ends
121 # gets dumped into an interval
122
123 ## use the endpoints of the interval to define a line
124 dy = y(2:ny,:) - y(1:ny-1,:);
125 dx = x(2:nx) - x(1:nx-1);
126 s = (xi - x(idx))./dx(idx);
127 yi(range,:) = s(:,ones(1,nc)).*dy(idx,:) + y(idx,:);
128
129 elseif strcmp(method, '*linear')
130 ## find the interval containing the test point
131 t = (xi - minx)/dx + 1;
132 idx = floor(t);
133
134 ## use the endpoints of the interval to define a line
135 dy = [y(2:ny,:) - y(1:ny-1,:); zeros(1,nc)];
136 s = (t - idx)./dx;
137 yi(range,:) = s(:,ones(1,nc)).*dy(idx,:) + y(idx,:);
138
139 elseif strcmp(method, 'pchip')
140 if (nx == 2) x = linspace(minx, maxx, ny); endif
141 yi(range,:) = pchip(x, y, xi);
142
143 elseif strcmp(method, 'cubic')
144 if (nx < 4 || ny < 4)
145 error ("interp1: table too short");
146 endif
147 idx = lookup(x(3:nx-2), xi) + 1;
148
149 ## Construct cubic equations for each interval using divided
150 ## differences (computation of c and d don't use divided differences
151 ## but instead solve 2 equations for 2 unknowns). Perhaps
152 ## reformulating this as a lagrange polynomial would be more efficient.
153 i=1:nx-3;
154 J = ones(1,nc);
155 dx = diff(x);
156 dx2 = x(i+1).^2 - x(i).^2;
157 dx3 = x(i+1).^3 - x(i).^3;
158 a=diff(y,3)./dx(i,J).^3/6;
159 b=(diff(y(1:nx-1,:),2)./dx(i,J).^2 - 6*a.*x(i+1,J))/2;
160 c=(diff(y(1:nx-2,:),1) - a.*dx3(:,J) - b.*dx2(:,J))./dx(i,J);
161 d=y(i,:) - ((a.*x(i,J) + b).*x(i,J) + c).*x(i,J);
162 yi(range,:) = ((a(idx,:).*xi(:,J) + b(idx,:)).*xi(:,J) ...
163 + c(idx,:)).*xi(:,J) + d(idx,:);
164
165 elseif strcmp(method, '*cubic')
166 if (nx < 4 || ny < 4)
167 error ("interp1: table too short");
168 endif
169
170 ## From: Miloje Makivic
171 ## http://www.npac.syr.edu/projects/nasa/MILOJE/final/node36.html
172 t = (xi - minx)/dx + 1;
173 idx = max(min(floor(t), ny-2), 2);
174 t = t - idx;
175 t2 = t.*t;
176 tp = 1 - 0.5*t;
177 a = (1 - t2).*tp;
178 b = (t2 + t).*tp;
179 c = (t2 - t).*tp/3;
180 d = (t2 - 1).*t/6;
181 J = ones(1,nc);
182 yi(range,:) = a(:,J) .* y(idx,:) + b(:,J) .* y(idx+1,:) ...
183 + c(:,J) .* y(idx-1,:) + d(:,J) .* y(idx+2,:);
184
185 elseif strcmp(method, 'spline') || strcmp(method, '*spline')
186 if (nx == 2) x = linspace(minx, maxx, ny); endif
187 yi(range,:) = spline(x, y, xi);
188
189 else
190 error(["interp1 doesn't understand method '", method, "'"]);
191 endif
192 if transposed, yi=yi.'; endif
193
194 endfunction
195
196 %!demo
197 %! xf=0:0.05:10; yf = sin(2*pi*xf/5);
198 %! xp=0:10; yp = sin(2*pi*xp/5);
199 %! lin=interp1(xp,yp,xf,'linear');
200 %! spl=interp1(xp,yp,xf,'spline');
201 %! cub=interp1(xp,yp,xf,'pchip');
202 %! near=interp1(xp,yp,xf,'nearest');
203 %! plot(xf,yf,';original;',xf,near,';nearest;',xf,lin,';linear;',...
204 %! xf,cub,';pchip;',xf,spl,';spline;',xp,yp,'*;;');
205 %! %--------------------------------------------------------
206 %! % confirm that interpolated function matches the original
207
208 %!demo
209 %! xf=0:0.05:10; yf = sin(2*pi*xf/5);
210 %! xp=0:10; yp = sin(2*pi*xp/5);
211 %! lin=interp1(xp,yp,xf,'*linear');
212 %! spl=interp1(xp,yp,xf,'*spline');
213 %! cub=interp1(xp,yp,xf,'*cubic');
214 %! near=interp1(xp,yp,xf,'*nearest');
215 %! plot(xf,yf,';*original;',xf,near,';*nearest;',xf,lin,';*linear;',...
216 %! xf,cub,';*cubic;',xf,spl,';*spline;',xp,yp,'*;;');
217 %! %--------------------------------------------------------
218 %! % confirm that interpolated function matches the original
219
220 %!shared xp, yp, xi, style
221 %! xp=0:5; yp = sin(2*pi*xp/5);
222 %! xi = sort([-1, max(xp)*rand(1,6), max(xp)+1]);
223
224 %!test style = 'nearest';
225 %!assert (interp1(xp, yp, [-1, max(xp)]), [NaN, NaN]);
226 %!assert (interp1(xp,yp,xp,style), yp, 100*eps);
227 %!assert (interp1(xp,yp,xp',style), yp', 100*eps);
228 %!assert (interp1(xp',yp',xp',style), yp', 100*eps);
229 %!assert (interp1(xp',yp',xp,style), yp, 100*eps);
230 %!assert (isempty(interp1(xp',yp',[],style)));
231 %!assert (isempty(interp1(xp,yp,[],style)));
232 %!assert (interp1(xp,[yp',yp'],xi(:),style),...
233 %! [interp1(xp,yp,xi(:),style),interp1(xp,yp,xi(:),style)]);
234 %!assert (interp1(xp,[yp',yp'],xi,style),
235 %! interp1(xp,[yp',yp'],xi,["*",style]));
236
237 %!test style = 'linear';
238 %!assert (interp1(xp, yp, [-1, max(xp)+1]), [NaN, NaN]);
239 %!assert (interp1(xp,yp,xp,style), yp, 100*eps);
240 %!assert (interp1(xp,yp,xp',style), yp', 100*eps);
241 %!assert (interp1(xp',yp',xp',style), yp', 100*eps);
242 %!assert (interp1(xp',yp',xp,style), yp, 100*eps);
243 %!assert (isempty(interp1(xp',yp',[],style)));
244 %!assert (isempty(interp1(xp,yp,[],style)));
245 %!assert (interp1(xp,[yp',yp'],xi(:),style),...
246 %! [interp1(xp,yp,xi(:),style),interp1(xp,yp,xi(:),style)]);
247 %!assert (interp1(xp,[yp',yp'],xi,style),
248 %! interp1(xp,[yp',yp'],xi,["*",style]),100*eps);
249
250 %!test style = 'cubic';
251 %!assert (interp1(xp, yp, [-1, max(xp)+1]), [NaN, NaN]);
252 %!assert (interp1(xp,yp,xp,style), yp, 100*eps);
253 %!assert (interp1(xp,yp,xp',style), yp', 100*eps);
254 %!assert (interp1(xp',yp',xp',style), yp', 100*eps);
255 %!assert (interp1(xp',yp',xp,style), yp, 100*eps);
256 %!assert (isempty(interp1(xp',yp',[],style)));
257 %!assert (isempty(interp1(xp,yp,[],style)));
258 %!assert (interp1(xp,[yp',yp'],xi(:),style),...
259 %! [interp1(xp,yp,xi(:),style),interp1(xp,yp,xi(:),style)]);
260 %!assert (interp1(xp,[yp',yp'],xi,style),
261 %! interp1(xp,[yp',yp'],xi,["*",style]),1000*eps);
262
263 %!test style = 'spline';
264 %!assert (interp1(xp, yp, [-1, max(xp) + 1]), [NaN, NaN]);
265 %!assert (interp1(xp,yp,xp,style), yp, 100*eps);
266 %!assert (interp1(xp,yp,xp',style), yp', 100*eps);
267 %!assert (interp1(xp',yp',xp',style), yp', 100*eps);
268 %!assert (interp1(xp',yp',xp,style), yp, 100*eps);
269 %!assert (isempty(interp1(xp',yp',[],style)));
270 %!assert (isempty(interp1(xp,yp,[],style)));
271 %!assert (interp1(xp,[yp',yp'],xi(:),style),...
272 %! [interp1(xp,yp,xi(:),style),interp1(xp,yp,xi(:),style)]);
273 %!assert (interp1(xp,[yp',yp'],xi,style),
274 %! interp1(xp,[yp',yp'],xi,["*",style]),10*eps);
275
276 %!error interp1
277 %!error interp1(1:2,1:2,1,'bogus')
278
279 %!error interp1(1,1,1, 'nearest');
280 %!assert (interp1(1:2,1:2,1.4,'nearest'),1);
281 %!error interp1(1,1,1, 'linear');
282 %!assert (interp1(1:2,1:2,1.4,'linear'),1.4);
283 %!error interp1(1:3,1:3,1, 'cubic');
284 %!assert (interp1(1:4,1:4,1.4,'cubic'),1.4);
285 %!error interp1(1:2,1:2,1, 'spline');
286 %!assert (interp1(1:3,1:3,1.4,'spline'),1.4);
287
288 %!error interp1(1,1,1, '*nearest');
289 %!assert (interp1(1:2,1:2,1.4,'*nearest'),1);
290 %!error interp1(1,1,1, '*linear');
291 %!assert (interp1(1:2,1:2,1.4,'*linear'),1.4);
292 %!error interp1(1:3,1:3,1, '*cubic');
293 %!assert (interp1(1:4,1:4,1.4,'*cubic'),1.4);
294 %!error interp1(1:2,1:2,1, '*spline');
295 %!assert (interp1(1:3,1:3,1.4,'*spline'),1.4);