Skip to content

Commit

Permalink
Process entire event channel instead of blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
rcassani committed May 20, 2022
1 parent a54ac2a commit 549410a
Showing 1 changed file with 131 additions and 106 deletions.
237 changes: 131 additions & 106 deletions toolbox/process/functions/process_evt_read.m
Original file line number Diff line number Diff line change
Expand Up @@ -262,147 +262,172 @@
% Process by blocks (if not: out of memory)
totalLength = (samplesBounds(2) - samplesBounds(1) + 1);
nbBlocks = ceil(totalLength / blockLength);
% Progress bar
% Progress bar, channels
isProgressBar = bst_progress('isVisible');
bst_progress('start', 'Import events', 'Reading events channels...', 0, nbBlocks);
bst_progress('start', 'Import events', 'Reading events channels...', 0, length(iChannels));

trackPrev = [];
nTooShort = 0;
% For each block
for iBlock = 1:nbBlocks
tracks_name = {};
tracks_vals = {};
tracks_smps = {};
% Process each channel
for iChannel = 1 : length(iChannels)
% Increment progress bar
bst_progress('inc', 1);
track_prev = [];
track_vals = [];
track_smps = [];
% Progress bar, blocks
isProgressBar = bst_progress('isVisible');
bst_progress('start', 'Import events', ['Reading events in channel ' StimChan{iChannel} ' ...'], 0, nbBlocks);
for iBlock = 1:nbBlocks
% Increment progress bar
bst_progress('inc', 1);
% === READ BLOCK ===
% Get samples indices for this block
samplesBlock = samplesBounds(1) + [(iBlock - 1) * blockLength, iBlock * blockLength - 1];
samplesBlock(2) = min(samplesBlock(2), samplesBounds(2));
% Read block of data
[track, ~] = in_fread(sFile, ChannelMat, 1, samplesBlock, iChannels(iChannel));
% Round values
track = fix(track);
% Keep only track changes
if iBlock == 1
track_smps(1) = 1;
track_vals(1) = track(1);
track_prev = track(1);
end
% === KEEP ALL CHANGES ===
ixDiffTrack = find(diff([track_prev, track]));
track_vals = [track_vals, track(ixDiffTrack)];
track_smps = [track_smps, samplesBlock(1) + ixDiffTrack];
% Saving ending state for next block
track_prev = track(end);
end
% Close progress bar
if ~isProgressBar
bst_progress('stop');
end

% === READ BLOCK ===
% Get samples indices for this block
samplesBlock = samplesBounds(1) + [(iBlock - 1) * blockLength, iBlock * blockLength - 1];
samplesBlock(2) = min(samplesBlock(2), samplesBounds(2));
% Read block of data
[tracks, times] = in_fread(sFile, ChannelMat, 1, samplesBlock, iChannels);

% === BLOCK EDITED 16-JUN-2021 ===
% Round values
tracks = fix(tracks);
% CTF: Read separately Upper and Lower bytes
if ismember(sFile.format, {'CTF', 'CTF-CONTINUOUS'})
% Events are read as int32, while they are actually uint32: fix negative values
tracks(tracks<0) = tracks(tracks<0) + 2^32;
track_vals(track_vals<0) = track_vals(track_vals<0) + 2^32;
% Keep only upper or lower bytes
if isCtfUp
tracks = fix(tracks / 2^16);
track_vals = fix(track_vals / 2^16);
elseif isCtfLow
tracks = double(bitand(uint32(tracks), 2^16-1));
track_vals = double(bitand(uint32(track_vals), 2^16-1));
end
% Other formats
else
% Old code: Might be useless and/or detrimental to the reading of the events
% tracks = reshape(double(typecast(int16(tracks(:)), 'uint16')), size(tracks));
% Use the same fix as for CTF files
tracks(tracks<0) = tracks(tracks<0) + 2^32;
track_vals(track_vals<0) = track_vals(track_vals<0) + 2^32;
end
% =================================

% === ADD INITIAL STATE ===
% Add the initial status of the tracks
if isempty(trackPrev)
tracks = [tracks(:,1), tracks];
else
tracks = [trackPrev, tracks];
end
% Saving ending state for next block
trackPrev = tracks(:,end);

% === SEPARATE TRACKS ===
% Each bit of each channel is interpreted as a track
switch lower(EventsTrackMode)
case 'bit'
tracks_tmp = [];
tracks_name = {};
for iTrack = 1:size(tracks, 1)
% Convert track in binary values
track_bin = double(fliplr(dec2bin(tracks(iTrack, :)))');
track_bin(track_bin == '0') = 0;
track_bin(track_bin == '1') = 1;
% Add those binary tracks to the list
tracks_tmp = [tracks_tmp; track_bin];
% Save name of the tracks
for iBit = 1:size(track_bin, 1)
if (length(StimChan) > 1)
tracks_name{end+1} = sprintf('%s_%d', StimChan{iTrack}, iBit);
else
tracks_name{end+1} = sprintf('%d', iBit);
end
% Convert track in binary values
track_bin = double(fliplr(dec2bin(track_vals))');
track_bin(track_bin == '0') = 0;
track_bin(track_bin == '1') = 1;
nBit = size(track_bin, 1);
tracks_bit_name = cell(1, nBit);
tracks_bit_vals = cell(1, nBit);
tracks_bit_smps = cell(1, nBit);
% Data for each binary track
for iBit = 1 : nBit
if (length(StimChan) > 1)
tracks_bit_name{iBit} = sprintf('%s_%d', StimChan{iChannel}, iBit);
else
tracks_bit_name{iBit} = sprintf('%d', iBit);
end
% Keep changes in each binary tracks
ixDiffTrackBit = find(diff([track_prev, track_bin(iBit, :)]));
tracks_bit_vals{iBit} = track_bin(iBit, ixDiffTrackBit);
tracks_bit_smps{iBit} = track_smps(ixDiffTrackBit);
end
tracks = tracks_tmp;
% Append to other tracks
tracks_name = [tracks_name, tracks_bit_name];
tracks_vals = [tracks_vals, tracks_bit_vals];
tracks_smps = [tracks_smps, tracks_bit_smps];
case 'value'
tracks_name = StimChan;
tracks_name{end+1} = StimChan{iChannel};
tracks_vals{end+1} = track_vals;
tracks_smps{end+1} = track_smps;
case {'ttl', 'rttl'}
tracks_name = StimChan;
tracks = abs(round(tracks));
tracks(tracks ~= 0) = 1;
tracks_name{end+1} = StimChan{iChannel};
track_vals = abs(round(track_vals));
track_vals(track_vals ~= 0) = 1;
tracks_vals{end+1} = track_vals;
tracks_smps{end+1} = track_smps;
end
end

% === GET EVENTS ===
% Get the changes on each track
diffTrack = diff(tracks, [], 2);
% Remove intial state from tracks
tracks(:,1) = [];
% Process each track separately
for iTrack = 1:size(tracks, 1)
% Get the samples where something happens
if strcmpi(EventsTrackMode, 'rttl')
iSmp = find((diffTrack(iTrack,:) ~= 0) & ((tracks(iTrack,:) == 0)));
elseif isAcceptZero
iSmp = find((diffTrack(iTrack,:) ~= 0));
else
iSmp = find((diffTrack(iTrack,:) ~= 0) & ((tracks(iTrack,:) ~= 0)));
end
% Process each change individually
for i = 1:length(iSmp)
% === PROCESS EACH TRACK SEPARATELY ===
nTooShort = 0;
for iTrack = 1:length(tracks_name)
% Get the indices where something happens
if strcmpi(EventsTrackMode, 'rttl')
ixs = find(tracks_vals{iTrack} == 0);
elseif isAcceptZero
ixs = 1 : length(tracks_vals{iTrack});
else
ixs = find(tracks_vals{iTrack} ~= 0);
end
% Process each change individually
for i = 1:length(ixs)
if i < length(ixs)
% Skip if shorter than MinDuration
if (MinDuration > 0) && ((length(tracks) - iSmp(i) < MinDuration) || ~all(tracks(iSmp(i):iSmp(i)+MinDuration) == tracks(iSmp(i))))
duration_i = tracks_smps{iTrack}(i+1) - tracks_smps{iTrack}(i);
if (MinDuration > 0) && (duration_i < MinDuration)
nTooShort = nTooShort + 1;
% Pass start sample to next event longer than MinDuration
tracks_smps{iTrack}(i+1) = tracks_smps{iTrack}(i);
continue;
end
% Build event name
switch lower(EventsTrackMode)
case 'bit'
label = tracks_name{iTrack};
case 'value'
value = tracks(iTrack, iSmp(i));
if (length(StimChan) > 1)
label = sprintf('%s_%d', StimChan{iTrack}, value);
else
label = sprintf('%d', value);
end
case {'ttl', 'rttl'}
label = StimChan{iTrack};
end
% Find this event in list of events
if ~isempty(events)
iEvent = find(strcmpi({events.label}, label));
else
iEvent = [];
end
% If event does not exist yet: add it
if isempty(iEvent)
iEvent = length(events) + 1;
events(iEvent).label = label;
events(iEvent).epochs = [];
events(iEvent).times = [];
events(iEvent).reactTimes = [];
events(iEvent).select = 1;
events(iEvent).channels = {};
events(iEvent).notes = {};
end
% Add occurrence of this event
iOcc = length(events(iEvent).times) + 1;
events(iEvent).epochs(iOcc) = 1;
events(iEvent).times(iOcc) = (iSmp(i) + samplesBlock(1) - 1) ./ sFile.prop.sfreq;
events(iEvent).channels{iOcc} = {};
events(iEvent).notes{iOcc} = [];
end
% Build event name
switch lower(EventsTrackMode)
case 'bit'
label = tracks_name{iTrack};
case 'value'
value = tracks_vals{iTrack}(ixs(i));
if (length(StimChan) > 1)
label = sprintf('%s_%d', tracks_name{iTrack}, value);
else
label = sprintf('%d', value);
end
case {'ttl', 'rttl'}
label = tracks_name{iTrack};
end
% Find this event in list of events
if ~isempty(events)
iEvent = find(strcmpi({events.label}, label));
else
iEvent = [];
end
% If event does not exist yet: add it
if isempty(iEvent)
iEvent = length(events) + 1;
events(iEvent).label = label;
events(iEvent).epochs = [];
events(iEvent).times = [];
events(iEvent).reactTimes = [];
events(iEvent).select = 1;
events(iEvent).channels = {};
events(iEvent).notes = {};
end
% Add occurrence of this event
iOcc = length(events(iEvent).times) + 1;
events(iEvent).epochs(iOcc) = 1;
events(iEvent).times(iOcc) = (tracks_smps{iTrack}(ixs(i))-1) ./ sFile.prop.sfreq;
events(iEvent).channels{iOcc} = {};
events(iEvent).notes{iOcc} = [];
end
end
% Display warning with removed events
Expand Down

0 comments on commit 549410a

Please sign in to comment.