Loop step size issue

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 commentaire

Image Analyst
Image Analyst le 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().

Connectez-vous pour commenter.

Réponses (3)

Walter Roberson
Walter Roberson le 22 Jan 2013
Modifié(e) : Walter Roberson le 22 Jan 2013

0 votes

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 commentaires

Swisslog
Swisslog le 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 le 22 Jan 2013
Modifié(e) : Matt J le 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

Connectez-vous pour commenter.

Thorsten
Thorsten le 22 Jan 2013
Modifié(e) : Thorsten le 22 Jan 2013

0 votes

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 le 22 Jan 2013

0 votes

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 commentaires

Matt J
Matt J le 22 Jan 2013
Modifié(e) : Matt J le 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 le 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))];

Connectez-vous pour commenter.

Question posée :

le 22 Jan 2013

Community Treasure Hunt

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

Start Hunting!

Translated by