-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmovingslope.m
More file actions
219 lines (208 loc) · 6.31 KB
/
movingslope.m
File metadata and controls
219 lines (208 loc) · 6.31 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
function Dvec = movingslope(vec,supportlength,modelorder,dt)
% movingslope: estimate local slope for a sequence of points, using a sliding window
% usage: Dvec = movingslope(vec)
% usage: Dvec = movingslope(vec,supportlength)
% usage: Dvec = movingslope(vec,supportlength,modelorder)
% usage: Dvec = movingslope(vec,supportlength,modelorder,dt)
%
%
% movingslope uses filter to determine the slope of a curve stored
% as an equally (unit) spaced sequence of points. A patch is applied
% at each end where filter will have problems. A non-unit spacing
% can be supplied.
%
% Note that with a 3 point window and equally spaced data sequence,
% this code should be similar to gradient. However, with wider
% windows this tool will be more robust to noisy data sequences.
%
%
% arguments: (input)
% vec - row of column vector, to be differentiated. vec must be of
% length at least 2.
%
% supportlength - (OPTIONAL) scalar integer - defines the number of
% points used for the moving window. supportlength may be no
% more than the length of vec.
%
% supportlength must be at least 2, but no more than length(vec)
%
% If supportlength is an odd number, then the sliding window
% will be central. If it is an even number, then the window
% will be slid backwards by one element. Thus a 2 point window
% will result in a backwards differences used, except at the
% very first point, where a forward difference will be used.
%
% DEFAULT: supportlength = 3
%
% modelorder - (OPTIONAL) - scalar - Defines the order of the windowed
% model used to estimate the slope. When model order is 1, the
% model is a linear one. If modelorder is less than supportlength-1.
% then the sliding window will be a regression one. If modelorder
% is equal to supportlength-1, then the window will result in a
% sliding Lagrange interpolant.
%
% modelorder must be at least 1, but not exceeding
% min(10,supportlength-1)
%
% DEFAULT: modelorder = 1
%
% dt - (OPTIONAL) - scalar - spacing for sequences which do not have
% a unit spacing.
%
% DEFAULT: dt = 1
%
% arguments: (output)
% Dvec = vector of derivative estimates, Dvec will be of the same size
% and shape as is vec.
%
%
% Example:
% Estimate the first derivative using a 7 point window with first through
% fourth order models in the sliding window. Note that the higher order
% approximations provide better accuracy on this curve with no noise.
%
% t = 0:.1:1;
% vec = exp(t);
%
% Dvec = movingslope(vec,7,1,.1)
% Dvec =
% Columns 1 through 7
% 1.3657 1.3657 1.3657 1.3657 1.5093 1.668 1.8435
% Columns 8 through 11
% 2.0373 2.0373 2.0373 2.0373
%
% Dvec = movingslope(vec,7,2,.1)
% Dvec =
% Columns 1 through 7
% 0.95747 1.0935 1.2296 1.3657 1.5093 1.668 1.8435
% Columns 8 through 11
% 2.0373 2.2403 2.4433 2.6463
%
% Dvec = movingslope(vec,7,3,.1)
% Dvec =
% Columns 1 through 7
% 1.0027 1.1049 1.2206 1.3498 1.4918 1.6487 1.8221
% Columns 8 through 11
% 2.0137 2.2268 2.4602 2.7138
%
% Dvec = movingslope(vec,7,4,.1)
% Dvec =
% Columns 1 through 7
% 0.99988 1.1052 1.2214 1.3498 1.4918 1.6487 1.8221
% Columns 8 through 11
% 2.0137 2.2255 2.4597 2.7181
%
%
% Example:
% Estimate the slope of a noisy curve, using a locally quadratic
% approximation. In this case, use a straight line so that we know
% the true slope should be 1. Use a wide window, since we have
% noisy data.
%
% t = 0:100;
% vec = t + randn(size(t));
% Dvec = movingslope(vec,10,2,1)
% mean(Dvec)
% ans =
% 1.0013
% std(Dvec)
% ans =
% 0.10598
%
% By way of comparison, gradient gives a much noisier estimate
% of the slope of this curve.
%
% std(gradient(vec))
% ans =
% 0.69847
%
%
% Example:
% As a time test, generate random data vector of length 500000.
% Compute the slopes using a window of width 10.
%
% vec = rand(1,500000);
% tic
% Dvec = movingslope(vec,10,2);
% toc
%
% Elapsed time is 0.626021 seconds.
%
%
% See also: gradient
%
%
% Author: John D'Errico
% e-mail: woodchips@rochester.rr.com
% Release: 1.0
% Release date: 10/19/07
% how long is vec? is it a vector?
if (nargin==0)
help movingslope
return
end
if ~isvector(vec)
error('vec must be a row or column vector')
end
n = length(vec);
% supply defaults
if (nargin<4) || isempty(dt)
dt = 1;
end
if (nargin<3) || isempty(modelorder)
modelorder = 1;
end
if (nargin<2) || isempty(supportlength)
supportlength = 3;
end
% check the parameters for problems
if (length(supportlength)~=1) || (supportlength<=1) || (supportlength>n) || (supportlength~=floor(supportlength))
error('supportlength must be a scalar integer, >= 2, and no more than length(vec)')
end
if (length(modelorder)~=1) || (modelorder<1) || (modelorder>min(10,supportlength-1)) || (modelorder~=floor(modelorder))
error('modelorder must be a scalar integer, >= 1, and no more than min(10,supportlength-1)')
end
if (length(dt)~=1) || (dt<0)
error('dt must be a positive scalar numeric variable')
end
% now build the filter coefficients to estimate the slope
if mod(supportlength,2) == 1
parity = 1; % odd parity
else
parity = 0;
end
s = (supportlength-parity)/2;
t = ((-s+1-parity):s)';
coef = getcoef(t,supportlength,modelorder);
% Apply the filter to the entire vector
f = filter(-coef,1,vec);
Dvec = zeros(size(vec));
Dvec(s+(1:(n-supportlength+1))) = f(supportlength:end);
% patch each end
vec = vec(:);
for i = 1:s
% patch the first few points
t = (1:supportlength)' - i;
coef = getcoef(t,supportlength,modelorder);
Dvec(i) = coef*vec(1:supportlength);
% patch the end points
if i<(s + parity)
t = (1:supportlength)' - supportlength + i - 1;
coef = getcoef(t,supportlength,modelorder);
Dvec(n - i + 1) = coef*vec(n + (0:(supportlength-1)) + 1 - supportlength);
end
end
% scale by the supplied spacing
Dvec = Dvec/dt;
% all done
end % mainline end
% =========================================================
% subfunction, used to compute the filter coefficients
function coef = getcoef(t,supportlength,modelorder)
% Note: bsxfun would have worked here as well, but some people
% might not yet have that release of matlab.
A = repmat(t,1,modelorder+1).^repmat(0:modelorder,supportlength,1);
pinvA = pinv(A);
% we only need the linear term
coef = pinvA(2,:);
end % nested function end