Finding runs of a signal where enabling conditions are met.

2 views (last 30 days)
Dear all,
I have two long data vectors which are slightly delayed.
I am trying to find the delay time each time, a third variable of TRUE (1). In the picture below a screenshot of the data, where the grey signal is slightly delayed, and the pink signal the enabling condition.
To find the delay time, I am thinking of finding the gradient of the two signals and compare them. I then want to find the maximum value of the signal and find the 63% value which will give me tau.
Finding the gradient of the signals:
signal_1_gradient = diff(signal_1)./diff(time)
signal_2_gradient = diff(signal_1)./diff(time)
For filtering the gradient signal:
b = (1/6)*ones(1,6);
a = 1;
signal_1_gradient_filt = filter(b,a,signal_1);
signal_2_gradient_filt = filter(b,a,signal_2);
And finding the index where enabling conditions are met:
index = find(enabling_conditions == 1)
signal_1_gradient_filt = signal_1_gradient_filt(index)
signal_1_gradient_filt = signal_1_gradient_filt(index)
It would be easiest for me, if I get multiple short vectors (in a structure) with all the periods where the enabling conditions were met. But I cannot find out how to split the vectors once I found the total index where enabling conditions were met.
From this I think it's not so hard to find the gradients for each phase.
Thanks a lot, and please ask me if something is not clear.

Accepted Answer

Guillaume
Guillaume on 11 May 2015
First, in your example, you don't need the find. A logical array would work just as well:
index = enabling_conditions == 0; %shouldn't it be == 1?
If I understood correctly, you want to find the start and end of each run of 1 (or is it 0?) in your enabling_conditions, and split the signals arrays into each run:
transitions = diff([0 enabling_conditions 0]); %assuming enabling_conditions is a row vector, and you want to find the runs of 1
%transitions is 1 when going from false to true and -1 when going from true to false. 0 otherwise
startruns = find(transitions == 1);
endruns = find(transitions == -1);
%because enabling_conditions was flanked with 0 in the diff, startruns and endruns are guaranteed to have the same number of elements.
%now split the signal according to start and end of each run:
subsignals_1 = arrayfun(@(s, e) signal_1_gradient_filt(s:e), startruns, endruns, 'UniformOutput', false)
subsignals_2 = arrayfun(@(s, e) signal_2_gradient_filt(s:e), startruns, endruns, 'UniformOutput', false)
Note that I put the vectors into a cell array rather than a structure. I think it makes more sense. You can convert the cell array into a structure with cell2struct but naming the fields is going to be an issue.
  2 Comments
Erik Schoof
Erik Schoof on 12 May 2015
Edited: Erik Schoof on 13 May 2015
Thanks a lot Guillaume! I wasn't aware of the 'arrayfun' function, but this does exactly what I need!
Just a short question, how is the s and e defined in the lines where you define the subsignals ? Does MATLAB automatically take the first letter of startruns and endruns ?
Guillaume
Guillaume on 13 May 2015
Edited: Guillaume on 13 May 2015
No, that's not how it works. The
@(s, e) dosomethingwith(s, e)
is an anonymous function. s and e are just variable names, i could have used any other valid name. So when I write
@(s, e) signal(s:e)
I define a function with two input arguments s and e that returns the elements s to e of signal. It would be similar as writing
function out = myfun(s, e)
out = signal(s:e); %except that a normal function does not have access to signal, so this wouldn't work
end
And calling arrayfun with:
subsignal = arrayfun(@myfun, startruns, endruns, ...)
What arrayfun does is pass the first element of each array it's given to the anonymous function, then the second element, and so on. Because I give it two arrays, the anonymous function has two inputs.
You could replace the whole arrayfun with a loop. For the first one, this would be:
assert(size(startruns) == size(endruns)); %arrayfun checks the arrays are the same size
subsignals_1 = cell(size(startruns)); %array fun does the allocation for you and creates a cell array because of the 'UniformOutput', false
for index = 1:numel(startruns)
s = startruns(index);
e = endruns(index);
subsignals_1{index} = signal_1_gradient_filt(s:e);
end
I like arrayfun and its brothers( cellfun, etc.) as it allows some functional programming in matlab. arrayfun clearly means "transform these arrays into some other(s) array(s) using this function". A for loop does not have this expressiveness.

Sign in to comment.

More Answers (0)

Categories

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

Tags

Products

Community Treasure Hunt

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

Start Hunting!