Filter data into different Phases using multiple conditions.

3 views (last 30 days)
Hi all,
I have got data which looks like C=[0,3 0,8 0,3 1,3 0,6 1,1 3,1 5,1 3,1 0,5]. I want to split this data into 2 Phases. Phase 1 will start when >1 (condition1) AND 3 spots after this point it must be > 3(condition2). Phase 1 will end when <1. D should eventually look like [0 0 0 0 0 1 1 1 1 0].
Condition 1 can easily be tested by D=C>1. But I can't figure out how to expand the filter by condition 2? How can I achieve this?
Many Thanks, Daan

Accepted Answer

arich82
arich82 on 23 Sep 2015
Edited: arich82 on 24 Sep 2015
I think you can achieve this by a variation on run length encoding. First, encode the data based on condition 1, then use condition 2 to modify the decoding. (Note that I'm interpretting condition 2 to mean '**still** greater than 1' for three spots; let me know if this is correct).
% data
C=[0.3 0.8 0.3 1.3 0.6 1.1 3.1 5.1 3.1 0.5];
% make data nontrivial
C = [C, C]
% apply condition 1
L = C > 1
% get index of the start of each phase change
%
% note: the first index is always the start of the first phase, so
% we begin the mask with true
mask = [true, logical(diff(L))]
idx = find(mask)
% compute the run-length of each phase
%
% note: an 'extra' index is appended to the end of the data,
% (essentially a 'phantom' phase starting past the end of the data)
% in order to get the correct length of the last phase
rl = diff([idx, numel(C)+1])
% extract the values associated with the run-length encoding
v = L(mask)
% apply condition 2
% i.e. require all '1' phases to also have a run-length > 3
v = v & (rl > 3)
% decode the rle
D = v(cumsum(mask))
The input C and output D are (printed columnwise for easier comparison)
>> [num2str(C(:)), repmat(' ', numel(C), 1), num2str(D(:))]
ans =
0.3 0
0.8 0
0.3 0
1.3 0
0.6 0
1.1 1
3.1 1
5.1 1
3.1 1
0.5 0
0.3 0
0.8 0
0.3 0
1.3 0
0.6 0
1.1 1
3.1 1
5.1 1
3.1 1
0.5 0
Please accept this answer if it helps, or leave a note in the comments if I've missed something.
  7 Comments
Daan
Daan on 25 Sep 2015
Thank you so much. There is one typo in your last script (nposts = 3 should be nspots = 3). But it works great! Thank you for all the help!
arich82
arich82 on 25 Sep 2015
I corrected the typo.
I'm glad it helps.
I still might play around with it over the weekend...

Sign in to comment.

More Answers (1)

Thorsten
Thorsten on 23 Sep 2015
The indices three positions after C is > 1 can be found using
ind = find(C > 1) + 3;
Ensure that the indices are not larger than the number of elements in C
ind = ind(ind < numel(C));
Start of phase 1
i1 = ind(find(C(ind) > 1, 1, 'first'))
Start of phase 2
ind2 = find(C < 1);
i2 = ind2(find(ind2 - i1 > 0, 1, 'first'));
phase1 = zeros(size(C));
phase1(i1:i2) = 1;
  3 Comments
Thorsten
Thorsten on 24 Sep 2015
i = 1;
while numel(C) > 1
%insert algorithm from above
phase1{i} = C(i1:i2);
i = i + 1;
if i2 == numel(C), C = []; else, C = C(i2+1:end); end
end
Daan
Daan on 24 Sep 2015
Thanks for helping me. The following script gives me the error but I can't figure out what is the problem?
??? Cell contents assignment to a non-cell array object.
Error in ==> DetermineMeansRecoveryPushFase at 112 phase1{i} = C(i1:i2);*
while numel(C) > 1
ind = find(C> 1) + 3;
ind = ind(ind < numel(C));
i1 = ind(find(C(ind) > 3, 1, 'first'));
ind2 = find(C < 1);
i2 = ind2(find(ind2 - i1 > 0, 1, 'first'));
phase1 = zeros(size(C));
phase1(i1:i2) = 1;
phase1{i} = C(i1:i2);
i = i + 1;
if i2 == numel(C), C = []; else, C = C(i2+1:end); end
end

Sign in to comment.

Products

Community Treasure Hunt

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

Start Hunting!