-
Notifications
You must be signed in to change notification settings - Fork 2
/
findReversals.m
executable file
·95 lines (94 loc) · 4.79 KB
/
findReversals.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
function [revStartInd, revDuration, untrackedRevEnds, interRevTime, incompleteInterRev] =...
findReversals(signedSpeed, worm_index, minPathLength, frameRate,minSpeedPerFrame)
% finds reversals based on worm tracking data features file
if nargin<4
frameRate = 9;
if nargin<3
minPathLength = eps(0);
end
end
minSpeed = minSpeedPerFrame*frameRate;
% define reversal starting events as when sign of speed changes from + to -
revStartInd = find(signedSpeed(1:end-1)>minSpeed&signedSpeed(2:end)<-minSpeed);
% reversals end when sign of speed changes from - to + (but there could
% be more or fewer of these than reversal start times)
revEndInd = 1+find(signedSpeed(1:end-1)<-minSpeed&signedSpeed(2:end)>minSpeed);
% match up reversal end times with starts
revEndIndMatched = NaN(size(revStartInd));
untrackedRevEnds = false(size(revStartInd));
revDisplacement = zeros(size(revStartInd)); % to calculate displacement length of reversal, for filtering
nRevs = length(revStartInd);
for revCtr = 1:nRevs
if revStartInd(revCtr)<max(revEndInd)
revEndIndMatched(revCtr) = revEndInd(find(revEndInd>revStartInd(revCtr),1,'first'));
if worm_index(revStartInd(revCtr)) ~= worm_index(revEndIndMatched(revCtr))
% reversal 'end' is actually from a different worm, which means
% that the reversal end is not tracked (at least not under the
% same identity)
[revStartInd(revCtr), revEndIndMatched(revCtr)] = findLastTracked(revStartInd(revCtr),...
revEndIndMatched(revCtr),worm_index,signedSpeed);
untrackedRevEnds(revCtr) = true;
end
% it can happen that the end of the reversal is not tracked, and
% that another reversal has started before the matched end
if revCtr<nRevs&&revEndIndMatched(revCtr)>revStartInd(revCtr+1)&&~isnan(revStartInd(revCtr))
[revStartInd(revCtr), revEndIndMatched(revCtr)] = findLastTracked(revStartInd(revCtr),...
revEndIndMatched(revCtr),worm_index,signedSpeed);
untrackedRevEnds(revCtr) = true;
end
if ~isnan(revStartInd(revCtr))
revDisplacement(revCtr) = sum(abs(signedSpeed((revStartInd(revCtr)+1):revEndIndMatched(revCtr))))/frameRate;
% here we divide by frameRate as the speed is unit of
% microns/s, do to get the displacement per frame (which we
% want to sum up to get the path length), we need to convert
% back to microns/frame
end
else % reversal still ongoing when tracking ends
[revStartInd(revCtr), revEndIndMatched(revCtr)] = findLastTracked(revStartInd(revCtr),...
numel(signedSpeed),worm_index,signedSpeed);
untrackedRevEnds(revCtr) = true;
end
end
% cut-out any reversals that had been misidentified as such
keepLogInd = ~isnan(revStartInd);
% cut-out any reversals that are shorter than minDisplacement
keepLogInd = keepLogInd&revDisplacement>=minPathLength;
revEndIndMatched = revEndIndMatched(keepLogInd);
revStartInd = revStartInd(keepLogInd);
untrackedRevEnds = untrackedRevEnds(keepLogInd);
% calculate duration and interrevtime
revDuration = revEndIndMatched - revStartInd;
try
interRevTime = [diff(revStartInd); ...
find(worm_index==worm_index(revStartInd(end)),1,'last') - revStartInd(end)]; % the last reversal has a censored interrev time until the end of tracking
catch
1;
end
incompleteInterRev = false(size(interRevTime));
incompleteInterRev(end) = true;
% censor those inter-reversal times where the worm_index changes
wormChangeInd = find(worm_index(revStartInd)~=worm_index(revStartInd+interRevTime));
for wcCtr = wormChangeInd'
interRevTime(wcCtr) = find(worm_index==worm_index(revStartInd(wcCtr)),1,'last') - revStartInd(wcCtr);
end
incompleteInterRev(wormChangeInd) = true;
end
function [firstTracked, lastTracked] = findLastTracked(currentStartInd,wrongEndInd,worm_index,midbody_speed)
firstTwoEntriesWithPositiveSpeed = find(worm_index(currentStartInd:wrongEndInd)==worm_index(currentStartInd)...
&midbody_speed(currentStartInd:wrongEndInd)>0,2,'first'); % check in case we have multiple zero crossings with missing data
if numel(firstTwoEntriesWithPositiveSpeed)>1
wrongEndInd = currentStartInd - 1 + firstTwoEntriesWithPositiveSpeed(end);
end
lastTracked = currentStartInd - 1 + find(worm_index(currentStartInd:wrongEndInd)==worm_index(currentStartInd)...
&midbody_speed(currentStartInd:wrongEndInd)<0,1,'last');
if isempty(lastTracked) % in case we now think it's no reversal at all
lastTracked = wrongEndInd;
firstTracked = NaN;
else
firstTracked = currentStartInd;
end
if lastTracked>=wrongEndInd&&~isnan(firstTracked) % check that the last time the reversal was tracked is before the end of the next reversal
warning('lastTracked was after a change in worm index')
lastTracked = wrongEndInd;
end
end