I have a very large array with five channels and approximately 6 million entries (5 x 6000000). My goal is to sweep through the array with a 7-point window and remove "spikes" which are defined as being some scaled amount greater than the median absolute deviation (MAD).
I am testing the code by running only 10000 initial points of the time series. Currently, it takes about 3 seconds for me to run the first 10,000 points. I am running on a relatively old, 32-bit Dell laptop with 2.30 GHz processor and 4 GB of RAM. Obviously, if I was using a newer computer, I could complete the task very quickly. For example, my more powerful desktop completes the same task in 0.7 seconds. However, I need to run the code on a laptop, and cannot afford to wait 35 - 40 minutes every time I need to run the code. I am looking for help finding inefficiencies and places where I can make the code faster.
Below is the code. Any suggestions for how to improve the speed is appreciated. I've noticed that the calculation for the "MAD" is the most time consuming (requiring about 1.9 seconds, or over half of the total time).
load('data.mat') % data (approx 5 channels x 6000000 data points (int32))
nscans = length(data); %number of data points in each channel
nwide = 7; %number of data points in the window
% Rejection parameters (not so important for the question)
iscale = 50; %scale factor for MAD
minmad = 2;
mincrit = [100 100 100 500 500];
nfixed=zeros(1,5);
L = floor(nwide/2); %half of window (odd window length only)
%Padding for beginning and end of data
data = [repmat(data(:,1),[1 L]) data repmat(data(:,end),[1 L])];
nfixed = zeros(1,5); %initialize counter
tic
for n = L+1:10000
idata = data(:,n-L:n+L)'; % temporary window
% compute median of window
med=median(idata);
%compute median absolute deviation (MAD)
% Note: mad = median(abs(X - median(X)))
mad = median(abs(idata-repmat(median(idata),[nwide 1])));
mad = max([mad;minmad*ones(1,5)]); %minmad threshold added
%compute rejection threshold
icrit=max([iscale*mad;mincrit]);
for i = 1:5 %loop over channels
if abs(data(i,n)-med(i)) > icrit(i) %if threshold is exceeded
data(i,n)=med(i); %then replace with median value
nfixed(i)=nfixed(i)+1; %count number of replacements
end
end
end
toc
data = data(:,L+1:end-L)'; %remove padding
I feel like there is likely a more elegant way of doing the "repmat" command.
Any ideas are appreciated.
Cheers