Clear Filters
Clear Filters

Loop step size issue

7 views (last 30 days)
Swisslog
Swisslog on 22 Jan 2013
Hoping there is a very simple solution to this but being new to matlab can't quite see where I'm going wrong:
for i = 10:5:100;
sums = conv(S, ones(1, i), 'valid');
Output(i) = nnz(sums>2 & sums<3);
end
where S is a column vector of values The code searches for instances where the sum of a block of data contained in window (i) is either >2 or <3 and counts them.
I was expecting the Output to return 19 values based on the step size of 5. Instead I get 100 values. I only want to return the counts for window sizes equal to i. Any thoughts would be much appreciated.
  1 Comment
Image Analyst
Image Analyst on 22 Jan 2013
That's because conv() moves the window over 1 element at a time. If you want to move in "jumps" of the window size, you need to use blockproc().

Sign in to comment.

Answers (3)

Walter Roberson
Walter Roberson on 22 Jan 2013
Edited: Walter Roberson on 22 Jan 2013
ivals = 10:5:100;
ni = length(ivals);
for K = 1 : ni
i = ivals(K);
sums = conv(S, ones(1, i), 'valid');
Output(K) = nnz(sums>2 & sums<3);
end
  2 Comments
Swisslog
Swisslog on 22 Jan 2013
Thanks, this works fine I think. Still slow, I don't suppose there is any way to get this vectorised is there?
Matt J
Matt J on 22 Jan 2013
Edited: Matt J on 22 Jan 2013
I don't think there's a way to vectorize fully, but if the S(i) are all non-negative, you should be sure to bail out of the loop once any(sums<3)==0. Enlarging the window from that point on will not change the result.
ivals = 10:5:100;
ni = length(ivals);
Output=zeros(ni,1);
flag=false;
for K = 1 : ni
i = ivals(K);
sums = conv(S, ones(1, i), 'valid');
Usums=sums<3;
if ~any(Usums)
break
end
Lsums=sums>2;
Output(K) = sum(Usums&Lsums);
end

Sign in to comment.


Thorsten
Thorsten on 22 Jan 2013
Edited: Thorsten on 22 Jan 2013
Walter's solution is more efficient. If you want to do it quick
Output = nan(1, 100);
% your code here
Output = Output(Output(~isnan(Output));

Thorsten
Thorsten on 22 Jan 2013
This runs about 4 times faster on my machine:
cS = cumsum(S);
for K = 1 : ni
sums = cS(ivals(K):end) - [0 cS(1:end-ivals(K))];
Output(K) = nnz(sums>2 & sums<3);
end
  2 Comments
Matt J
Matt J on 22 Jan 2013
Edited: Matt J on 22 Jan 2013
Not on mine.
S=rand(1,1e6);
ivals = 10:5:100;
ni = length(ivals);
Output=zeros(ni,1);
tic
for K = 1 : ni
i = ivals(K);
sums = conv(S, ones(1, i), 'valid');
Output(K) = nnz(sums>2 & sums<3);
end
toc
%Elapsed time is 0.313358 seconds.
tic;
cS = cumsum(S);
for K = 1 : ni
sums = cS(ivals(K):end) - [0 cS(1:end-ivals(K))];
Output(K) = sum(sums>2 & sums<3);
end
toc;
%Elapsed time is 0.437812 seconds.
Matt J
Matt J on 22 Jan 2013
I really do think the CUMSUM approach should be the better one, though. A MEX is probably needed to avoid repeated memory allocation operations in
sums = cS(ivals(K):end) - [0 cS(1:end-ivals(K))];

Sign in to comment.

Categories

Find more on Loops and Conditional Statements in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!