-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathinterp_fast.m
138 lines (119 loc) · 4.16 KB
/
interp_fast.m
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
function [y_mat_pts, idx] = interp_fast(x_vec, y_mat, x_vec_pts, idx)
% Extremely fast linear interpolation method.
%
% Parameters:
% x_vec - vector with the sample points (float / row vector)
% y_mat - matrix with the sample values (float / matrix)
% x_vec_pts - vector with the query points (float / row vector)
% idx - initial value for the location of the query point (integer / scalar)
%
% Returns:
% y_mat_pts - interpolated values (float / matrix)
% idx - location of the last query point (integer / scalar)
%
% Row vector are considered for the samples.
% If the sample values is a matrix, then each row contains a set of 1D values.
%
% Linear interpolation inside the domain, linear extrapolation outside.
%
% The following fast interpolation method is implemented:
% - After each query, the position (index) of the point is returned.
% - This index is used as an initial value for the next query point.
% - If no initial value is available, NaN can be provided.
%
% This method reduces the computational cost if the query points are partially sorted.
% In such cases, the complexity is reduced from O(n) to O(1).
%
% This function can be compiled to a MEX file with the MATLAB Coder.
% For reducing the computational cost, the size/type of the inputs are not checked.
%
% Thomas Guillod.
% 2021 - BSD License.
% init solution
y_mat_pts = zeros(size(y_mat, 1), size(x_vec_pts, 2));
% interpolate for each point
if isscalar(x_vec_pts)
% update the index with respect to the provided query points
idx = get_interp_idx(x_vec, x_vec_pts, idx);
% linear interpolation
y_mat_pts = get_interp_lin(x_vec, y_mat, x_vec_pts, idx);
else
for i=1:length(x_vec_pts)
% update the index with respect to the provided query points
idx = get_interp_idx(x_vec, x_vec_pts(i), idx);
% linear interpolation
y_mat_pts(:,i) = get_interp_lin(x_vec, y_mat, x_vec_pts(i), idx);
end
end
end
function idx = get_interp_init(x_vec, x_pts)
% Find the location of the query point without an initial guess.
%
% Parameters:
% x_vec - vector with the sample points (float / row vector)
% x_pts - scalar with the query point (float / scalar)
%
% Returns:
% idx - location of the query point (integer / scalar)
% find the position of the query point
x_diff_vec = x_vec-x_pts;
x_diff_vec(x_diff_vec>0) = -Inf;
[~, idx] = max(x_diff_vec);
% the number of intervals is smaller than the number of points
if idx==length(x_vec)
idx = length(x_vec)-1;
end
end
function idx = get_interp_idx(x_vec, x_pts, idx_init)
% Find the location of the query point with an initial guess.
%
% Parameters:
% x_vec - vector with the sample points (float / row vector)
% x_pts - scalar with the query point (float / scalar)
% idx_init - initial value for the location of the query point (integer / scalar)
%
% Returns:
% idx - location of the query point (integer / scalar)
% if no intial guess, find one
if isnan(idx_init)
idx_init = get_interp_init(x_vec, x_pts);
end
% default case, initial guess is correct
idx = idx_init;
% initial guess is too small
if x_pts>x_vec(idx_init+1)
for i=(idx_init+1):+1:(length(x_vec)-1)
if x_vec(i+1)>=x_pts
idx = i;
break
end
idx = length(x_vec)-1;
end
end
% initial guess is too large
if x_pts<x_vec(idx_init)
for i=(idx_init-1):-1:1
if x_vec(i)<=x_pts
idx = i;
break
end
idx = 1;
end
end
end
function y_vec_pts = get_interp_lin(x_vec, y_mat, x_pts, idx)
% Extremely fast linear interpolation method.
%
% Parameters:
% x_vec - vector with the sample points (float / row vector)
% y_mat - matrix with the sample values (float / matrix)
% x_pts - scalar with the query point (float / scalar)
% idx - location of the query point (integer / scalar)
%
% Returns:
% y_vec_pts - interpolated values (float / col vector)
% get the slope
slope = (y_mat(:,idx+1)-y_mat(:,idx))./(x_vec(idx+1)-x_vec(idx));
% interpolate
y_vec_pts = y_mat(:,idx)+slope.*(x_pts-x_vec(idx));
end