From c31cb036ae22c9260fdadf137b04068919762ce0 Mon Sep 17 00:00:00 2001 From: okba bekhelifi Date: Thu, 2 Feb 2017 00:41:47 +0100 Subject: [PATCH] Added data format conversion recorded using other frameworks: - BCI2000 - OpenVibe new file: misc/BCI2000_BBCI_convert_to_mat.m new file: misc/OV_BBCI_convert_to_mat.m new file: misc/utils_BCI2000_getmrk.m --- misc/BCI2000_BBCI_convert_to_mat.m | 66 +++++++++++++++++++++++++++ misc/OV_BBCI_convert_to_mat.m | 72 ++++++++++++++++++++++++++++++ misc/utils_BCI2000_getmrk.m | 51 +++++++++++++++++++++ 3 files changed, 189 insertions(+) create mode 100644 misc/BCI2000_BBCI_convert_to_mat.m create mode 100644 misc/OV_BBCI_convert_to_mat.m create mode 100644 misc/utils_BCI2000_getmrk.m diff --git a/misc/BCI2000_BBCI_convert_to_mat.m b/misc/BCI2000_BBCI_convert_to_mat.m new file mode 100644 index 0000000..84d84f9 --- /dev/null +++ b/misc/BCI2000_BBCI_convert_to_mat.m @@ -0,0 +1,66 @@ +function BCI2000_BBCI_convert_to_mat(folder) +%BCI2000_CONVERT_TO_MAT - convert BCI2000 .dat files to BBCI format +% +%Synopsis: +% BCI2000_BBCI_convert_to_mat(folder) +% +% +%Arguments: +% folder - folder name containing .dat files +% +%Returns: +% creates folder and saves the converted +% .mat files in BTB.MatDir/Mat/BCI2000/folder +% Note: +% Requires load_bcidat mex function delivred with BCI2000 package +% +% Okba Bekhelifi, LARESI, USTO-MB +% 02-2017 +global BTB + +% check if 'load_bcidat' is added in the path +if exist('load_bcidat','file') == 0 + error('BCI2000 load function is not found'); +end + +if exist('BTB','var') == 0 + if exist('init_bbci','file') == 2 +% the author's own script to run BBCI + init_bbci; + else + error('run BBCI with startup_bbci_toolbox first'); + end +end + +foldertmp = fullfile(BTB.DataDir, 'Raw', ['BCI2000\' folder]); +files = dir([foldertmp '\*.dat']); +eegFiles = {files.name}; +eegFiles = cellfun(@(s) strsplit(s, '.dat'), eegFiles, 'UniformOutput', false); + +for file = 1:length(eegFiles) + + filepath = [foldertmp '\' eegFiles{file}{1,1}]; + [signal, states, parameters, total_samples] = load_bcidat(filepath); +% cnt + cnt.clab = parameters.ChannelNames.Value'; + cnt.fs = parameters.SamplingRate.NumericValue; +% this value need to be changed for other BCI paradigms + cnt.title = 'P300-Speller'; + cnt.T = total_samples; + cnt.yUnit = 'µV'; + cnt.origClab = cnt.clab; + cnt.file = filepath; + cnt.x = signal; + cnt.history = ''; +% format states from .dat to a conveniet mrk structure +% usinge function thutils_BCI20000_getmrk + mrk = utils_BCI2000_getmrk(parameters, states); +% create mnt + mnt = mnt_setElectrodePositions(cnt.clab); + mnt = mnt_setGrid(mnt, 'XXL'); + % save in matlab format + file_saving_name = fullfile(BTB.DataDir, 'Mat', ['BCI2000\' folder '\' eegFiles{file}{1,1}]); + file_saveMatlab(file_saving_name, cnt, mrk, mnt); +end +end + diff --git a/misc/OV_BBCI_convert_to_mat.m b/misc/OV_BBCI_convert_to_mat.m new file mode 100644 index 0000000..b445e69 --- /dev/null +++ b/misc/OV_BBCI_convert_to_mat.m @@ -0,0 +1,72 @@ +function OV_BBCI_convert_to_mat(folder) +%OV_BBCI_CONVERT_TO_MAT - convert vhdr files recorded using OpenVibe +% to BBCI mat format +% +%Synopsis: +% OV_BBCI_convert_to_mat(folder) +% +% +%Arguments: +% folder - folder name containing .vhdr files +% +%Returns: +% creates folder and saves the converted +% .mat files in BTB.MatDir/Mat/OV/folder +% Note: +% Requires running ov2vhdr scenario in OpenVibe at first in order to convert +% .ov files to vhdr format +% +% Okba Bekhelifi, LARESI, USTO-MB +% 02-2017 + +global BTB + +if exist('BTB','var') == 0 + if exist('init_bbci','file') == 2 +% the author's own script to run BBCI + init_bbci; + else + error('run BBCI with startup_bbci_toolbox first'); + end +end + + +foldertmp = fullfile(BTB.DataDir, 'Raw', ['OV\' folder]); +files = dir([foldertmp '\*.vhdr']); +eegFiles = {files.name}; +eegFiles = cellfun(@(s) strsplit(s, '.vhdr'), eegFiles, 'UniformOutput', false); + +for file = 1:length(eegFiles) + + filepath = [foldertmp '/' eegFiles{file}{1,1}]; + [cnt, mrk_orig, hdr] = file_readBV(filepath); + % OpenVibe's stimuli code: + % target, nontarget + if (isempty(cell2mat(strfind(mrk_orig.className,'S 11')))) + stimDef = {33285,33286;'target', 'nontarget'}; + else + % Pyff ERP feedback markers style + % current definition hold 8 stimuli + % change it to your number of stimuli + stimDef= {31:38, 11:18; 'target', 'nontarget'}; + end + + mrk = mrk_defineClasses(mrk_orig, stimDef); + mrk.orig = mrk_orig; + mnt = mnt_setElectrodePositions(cnt.clab); + mnt = mnt_setGrid(mnt, 'XXL'); + + % save in matlab format + % default OpenVibe recorded files has date & time format containing + % points, removing points from the file name before constructing + % a new .mat filename + str = eegFiles{file}{1,1}; + point_idx = strfind(str,'.'); + if ~isempty(point_idx) + str(point_idx)=[]; + end + file_saving_name = fullfile(BTB.DataDir, 'Mat', ['OV\' folder '\' str]); + file_saveMatlab(file_saving_name, cnt, mrk, mnt, 'Vars','hdr'); +end + +end \ No newline at end of file diff --git a/misc/utils_BCI2000_getmrk.m b/misc/utils_BCI2000_getmrk.m new file mode 100644 index 0000000..b31e9c2 --- /dev/null +++ b/misc/utils_BCI2000_getmrk.m @@ -0,0 +1,51 @@ +function [mrk] = utils_BCI2000_getmrk(parameters, states) +% UTILS_BCI2000_GETMRK - create a mrk conveient struct +% +%Synopsis: +% mrk = utils_BCI2000_getmrk(parameters, states) +% +% +%Arguments: +% parameters - BCI2000 session parameters such as SamplingRate etc... +% states - BCI2000 session states such StimulusCode etc... +%Returns: +% creates folder and saves the converted +% MRK - mrk struct +% .time - defines the time points of events in msec (DOUBLE [1 #events]) +% .event - structure of further information; +% each field of mrk.event provides information that is specified +% for each event, given in arrays that index the events in their first +% dimension. +% .y - class labels (DOUBLE [#classes #events]) +% .className - class names (CELL {1 #classes}) +% .desiredPhrase - text to spell +% Okba Bekhelifi, LARESI, USTO-MB +% 02-2017 + +% +targetSamples = states.StimulusType==1; +target = states.StimulusCode(targetSamples); +target = unique(target); +% +stimlutationDuration = (parameters.StimulusDuration.NumericValue / 10^3) * parameters.SamplingRate.NumericValue; +stimulationStart = find(states.StimulusCode ~=0); +stimulationStart = stimulationStart(1:stimlutationDuration:end); +% +mrk.time = stimulationStart'; +desc = states.StimulusCode(stimulationStart); +targetIndices = find(desc==target(1) | desc==target(2)); +desc(targetIndices) = desc(targetIndices) + 10; +mrk.event.desc = desc; +% +y = zeros(2,length(desc)); +targetIndices = desc >10; +nontargetIndices = ~targetIndices; +y(1,targetIndices) = 1; +y(2,nontargetIndices) = 1; +mrk.y = y; +% +mrk.className = {'target', 'nontarget'}; +% +mrk.desiredPhrase = parameters.TextToSpell.Value; +end +