


RUNMEAN - Very fast running mean (aka moving average) filter
For vectors, Y = RUNMEAN(X,M) computes a running mean (also known as
moving average) on the elements of the vector X. It uses a window of
2*M+1 datapoints. M an positive integer defining (half) the size of the
window. In pseudo code:
Y(i) = sum(X(j)) / (2*M+1), for j = (i-M):(i+M), and i=1:length(X)
For matrices, Y = RUNMEAN(X,M) or RUNMEAN(X,M,[]) operates on the first
non-singleton dimension of X. RUNMEAN(X,M,DIM) computes the running
mean along the dimension DIM.
If the total window size (2*M+1) is larger than the size in dimension
DIM, the overall average along dimension DIM is computed.
As always with filtering, the values of Y can be inaccurate at the
edges. RUNMEAN(..., MODESTR) determines how the edges are treated. MODESTR can be
one of the following strings:
'edge' : X is padded with first and last values along dimension
DIM (default)
'zero' : X is padded with zeros
'mean' : X is padded with the mean along dimension DIM
X should not contains NaNs, yielding an all NaN result. NaNs can be
replaced by using, e.g., "inpaint_nans" created by John D'Errico.
Examples
runmean([1:5],1)
% -> 1.33 2 3 4 4.67
runmean([1:5],1,'mean')
% -> 2 2 3 4 4
runmean([2:2:10],1,1) % dimension 1 is larger than 2*(M=1)+1 ...
% -> 2 4 6 8 10
runmean(ones(10,7),3,2,'zero') ; % along columns, using mode 'zero'
runmean(repmat([1 2 4 8 NaN 5 6],5,1),2,2) ;
% -> all NaN result
A = rand(10,10) ; A(2,7) = NaN ;
runmean(A,3,2) ;
% -> column 7 is all NaN
runmean(1:2:10,100) % mean
% -> 5 5 5 5 5
This is an incredibly fast implementation of a running mean, since
execution time does not depend on the size of the window.
See also MEAN, FILTER

0001 function Y = runmean(X, m, dim, modestr) ; 0002 % RUNMEAN - Very fast running mean (aka moving average) filter 0003 % For vectors, Y = RUNMEAN(X,M) computes a running mean (also known as 0004 % moving average) on the elements of the vector X. It uses a window of 0005 % 2*M+1 datapoints. M an positive integer defining (half) the size of the 0006 % window. In pseudo code: 0007 % Y(i) = sum(X(j)) / (2*M+1), for j = (i-M):(i+M), and i=1:length(X) 0008 % 0009 % For matrices, Y = RUNMEAN(X,M) or RUNMEAN(X,M,[]) operates on the first 0010 % non-singleton dimension of X. RUNMEAN(X,M,DIM) computes the running 0011 % mean along the dimension DIM. 0012 % 0013 % If the total window size (2*M+1) is larger than the size in dimension 0014 % DIM, the overall average along dimension DIM is computed. 0015 % 0016 % As always with filtering, the values of Y can be inaccurate at the 0017 % edges. RUNMEAN(..., MODESTR) determines how the edges are treated. MODESTR can be 0018 % one of the following strings: 0019 % 'edge' : X is padded with first and last values along dimension 0020 % DIM (default) 0021 % 'zero' : X is padded with zeros 0022 % 'mean' : X is padded with the mean along dimension DIM 0023 % 0024 % X should not contains NaNs, yielding an all NaN result. NaNs can be 0025 % replaced by using, e.g., "inpaint_nans" created by John D'Errico. 0026 % 0027 % Examples 0028 % runmean([1:5],1) 0029 % % -> 1.33 2 3 4 4.67 0030 % runmean([1:5],1,'mean') 0031 % % -> 2 2 3 4 4 0032 % runmean([2:2:10],1,1) % dimension 1 is larger than 2*(M=1)+1 ... 0033 % % -> 2 4 6 8 10 0034 % runmean(ones(10,7),3,2,'zero') ; % along columns, using mode 'zero' 0035 % runmean(repmat([1 2 4 8 NaN 5 6],5,1),2,2) ; 0036 % % -> all NaN result 0037 % A = rand(10,10) ; A(2,7) = NaN ; 0038 % runmean(A,3,2) ; 0039 % % -> column 7 is all NaN 0040 % runmean(1:2:10,100) % mean 0041 % % -> 5 5 5 5 5 0042 % 0043 % This is an incredibly fast implementation of a running mean, since 0044 % execution time does not depend on the size of the window. 0045 % 0046 % See also MEAN, FILTER 0047 0048 % for Matlab R13 0049 % version 3.0 (sep 2006) 0050 % Jos van der Geest 0051 % email: jos@jasen.nl 0052 0053 % History: 0054 % 1.0 (2003) created, after a snippet from Peter Acklam (?) 0055 % 1.1 (feb 2006) made suitable for the File Exchange (extended help and 0056 % documentation) 0057 % 1.2 (feb 2006) added a warning when the window size is too big 0058 % 1.3 (feb 2006) improved help section 0059 % 2.0 (sep 2006) working across a dimension of a matrix. 0060 % 3.0 (sep 2006) several treatments of the edges. 0061 0062 % Acknowledgements: (sep 2006) Thanks to Markus Hahn for the idea of 0063 % working in multi-dimensions and the way to treat edges. 0064 0065 error(nargchk(2,4,nargin)) ; 0066 0067 if ~isnumeric(m) || (numel(m) ~= 1) || (m < 0) || fix(m) ~= m, 0068 error('The window size (M) should be a positive integer') ; 0069 end 0070 0071 if nargin == 2, 0072 dim = [] ; 0073 modestr = 'edge' ; 0074 elseif nargin==3, 0075 if ischar(dim), 0076 % no dimension given 0077 modestr = dim ; 0078 dim = [] ; 0079 else 0080 modestr = 'edge' ; 0081 end 0082 end 0083 0084 modestr = lower(modestr) ; 0085 0086 % check mode specifier 0087 if ~ismember(modestr,{'edge','zero','mean'}), 0088 error('Unknown mode') ; 0089 end 0090 0091 szX = size(X) ; 0092 if isempty(dim), 0093 dim = min(find(szX>1)) ; 0094 end 0095 0096 if m == 0 || dim > ndims(X), 0097 % easy 0098 Y = X ; 0099 else 0100 mm = 2*m+1 ; 0101 if mm >= szX(dim), 0102 % if the window is larger than X, average all 0103 sz2 = ones(size(szX)) ; 0104 sz2(dim) = szX(dim) ; 0105 Y = repmat(mean(X,dim),sz2) ; 0106 else 0107 % here starts the real stuff 0108 % shift dimensions so that the desired dimensions comes first 0109 [X, nshifts] = shiftdim(X, dim-1); 0110 szX = size(X) ; 0111 % make the rest of the dimensions columns, so we have a 2D matrix 0112 % (suggested of Markus Hahn) 0113 X = reshape(X,szX(1),[]) ; 0114 % select how to pad the matrix 0115 switch (modestr), 0116 case 'edge' 0117 % pad with first and last elements 0118 Xfirst = repmat(X(1,:),m,1) ; 0119 Xlast = repmat(X(end,:),m,1) ; 0120 case 'zero' 0121 % pad with zeros 0122 Xfirst = zeros(m,1) ; 0123 Xlast= zeros(m,1) ; 0124 case 'mean', 0125 % pad with the average 0126 Xfirst = repmat(mean(X,1),m,1) ; 0127 Xlast = Xfirst ; 0128 end 0129 % pad the array 0130 Y = [zeros(1,size(X,2)) ; Xfirst ; X ; Xlast] ; 0131 % the cumsum trick (by Peter Acklam ?) 0132 Y = cumsum(Y,1) ; 0133 Y = (Y(mm+1:end,:)-Y(1:end-mm,:)) ./ mm ; 0134 0135 % reshape into original size 0136 Y = reshape(Y,szX) ; 0137 % and re-shift the dimensions 0138 Y = shiftdim(Y,ndims(Y)-nshifts) ; 0139 end 0140 end 0141 0142 % ===================== 0143 % CODE OF VERSION 1.3 0144 % ===================== 0145 0146 % function Y = runmean(X,m) ; 0147 % % RUNMEAN - Very fast running mean filter for vectors 0148 % % Y = RUNMEAN(X,M) computes a running mean on vector X using a window of 0149 % % 2*M+1 datapoints. X is a vector, and M an positive integer defining 0150 % % (half) the size of the window. In pseudo code: 0151 % % Y(i) = sum(X(j)) / (2*M+1), for j = (i-M):(i+M), and i=1:length(X) 0152 % % 0153 % % If the total window size (2M+1) is larger than the length of the vector, the overall 0154 % % average is returned. 0155 % % 0156 % % Example: 0157 % % runmean(1:10,1) % -> 0158 % % [1.3333 2 3 4 5 6 7 8 9 9.6667] 0159 % % 0160 % % This is an incredibly fast implementation of a running average, since 0161 % % execution time does not depend on the size of the window. 0162 % % 0163 % % X should not contains NaNs (a NaN will result in a all NaN result) 0164 % % At both ends the values of Y can be inaccurate, as the first and last 0165 % % values of X are used multiple times. 0166 % % 0167 % % See also MEAN 0168 % 0169 % % for Matlab R13 0170 % % version 1.3 (feb 2006) 0171 % % Jos van der Geest 0172 % % email: jos@jasen.nl 0173 % 0174 % % History: 0175 % % 1.0 (2003) created, after a snippet from Peter Acklam (?) 0176 % % 1.1 (feb 2006) made suitable for the File Exchange (extended help and 0177 % % documentation) 0178 % % 1.2 (feb 2006) added a warning when the window size is too big 0179 % % 1.3 (feb 2006) improved help section 0180 % 0181 % error(nargchk(2,2,nargin)) ; 0182 % 0183 % sz = size(X) ; 0184 % 0185 % if numel(sz) ~= 2 || (min(sz) ~= 1), 0186 % error('X should be a vector') ; 0187 % end 0188 % 0189 % if any(isnan(X)), 0190 % error('NaNs cannot be dealt with') ; 0191 % end 0192 % 0193 % if ~isnumeric(m) || (numel(m) ~= 1) || (m < 0) || fix(m) ~= m, 0194 % error('The window size (M) should be a positive integer') ; 0195 % elseif m == 0, 0196 % Y = X ; 0197 % return ; 0198 % end 0199 % 0200 % mm = 2*m+1 ; 0201 % 0202 % if mm >= prod(sz), 0203 % % if the window is larger than X, average all 0204 % warning('Window size is larger than the length of the vector.') 0205 % Y = repmat(mean(X),sz) ; 0206 % else 0207 % % the cumsum trick ... 0208 % Y = [repmat(X(1),m,1) ; X(:) ; repmat(X(end),m,1)] ; 0209 % Y = [0 ; cumsum(Y)] ; 0210 % Y = (Y(mm+1:end)-Y(1:end-mm)) / mm ; 0211 % Y = reshape(Y,sz) ; 0212 % end 0213