function yi = interp1qr(x,y,xi)
%% Quicker 1D linear interpolation
% Performs 1D linear interpolation of 'xi' points using 'x' and 'y',
% resulting in 'yi', following the formula yi = y1 + (y2-y1)/(x2-x1)*(xi-x1).
% Returns NaN for values of 'xi' out of range of 'x', and when 'xi' is NaN.
%
% 'x'  is column vector [m x 1], monotonically increasing.
% 'y'  is matrix [m x n], corresponding to 'x'.
% 'xi' is column vector [p x 1], in any order.
% 'yi' is matrix [p x n], corresponding to 'xi'.
%
% Copyright (c) 2013 Jose M. Mier
%

%% Full function description
% Quicker 1D linear interpolation: 'interp1qr'
% Performs 1D linear interpolation of 'xi' points using 'x' and 'y',
% resulting in 'yi', following the formula yi = y1 + (y2-y1)/(x2-x1)*(xi-x1).
%
% It has same functionality as built-in MATLAB function 'interp1q' (see
% MATLAB help for details).
%
% It runs at least 3x faster than 'interp1q' and 8x faster than 'interp1',
% and more than 10x faster as m=length(x) increases (see attached performance
% graph).
%
% As with 'interp1q', this function does no input checking. To work properly
% user has to be aware of the following:
%  - 'x'  must be a monotonically increasing column vector.
%  - 'y'  must be a column vector or matrix with m=length(x) rows.
%  - 'xi' must be a column vector.
%
% As with 'interp1q', if 'y' is a matrix, then the interpolation is performed
% for each column of 'y', in which case 'yi' is p=length(xi) by n=size(y,2).
%
% As with 'interp1q', this function returns NaN for any values of 'xi' that
% lie outside the coordinates in 'x', and when 'xi' is NaN.
%
% This function uses the approach given by Loren Shure (The MathWorks) in
% http://blogs.mathworks.com/loren/2008/08/25/piecewise-linear-interpolation/
%  - Uses the function 'histc' to get the 'xi_pos' vector.
%  - Also uses a small trick to rearrange the linear operation, such that
%    yi = y1 + s*(xi-x1), where s = (y2-y1)/(x2-x1), now becomes
%    yi = y1 + t*(y2-y1), where t = (xi-x1)/(x2-x1), which reduces the need
%    for replicating a couple of matrices and the right hand division
%    operation for 't' is simpler than it was for 's' because it takes place
%    only in one dimension (both 'x' and 'xi' are column vectors).
%
% Acknowledgements: Nils Oberg, Blake Landry, Marcelo H. Garcia,
% the University of Illinois (USA), and the University of Cantabria (Spain).
%
% Author:   Jose M. Mier
% Contact:  jmierlo2@illinois.edu
% Date:     August 2013
% Version:  4
%

%% Function begins

% Size of 'x' and 'y'
m = size(x,1);
n = size(y,2);

% For each 'xi', get the position of the 'x' element bounding it on the left [p x 1]
[~,xi_pos] = histc(xi,x);
xi_pos = max(xi_pos,1);     % To avoid index=0 when xi < x(1)
xi_pos = min(xi_pos,m-1);   % To avoid index=m+1 when xi > x(end).

% 't' matrix [p x 1]
dxi = xi-x(xi_pos);
dx = x(xi_pos+1)-x(xi_pos);
t = dxi./dx;

% Get 'yi'
yi = y(xi_pos,:) + t(:,ones(1,n)).*(y(xi_pos+1,:)-y(xi_pos,:));

% Give NaN to the values of 'yi' corresponding to 'xi' out of the range of 'x'
yi(xi<x(1) | xi>x(end),:) = NaN;

end
