Skip to content

Neuroscan plugin #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
23 changes: 17 additions & 6 deletions bcilab_config.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,16 @@
% argument to the "bcilab" function (e.g. cd /your/path/to/bcilab; bcilab
% /your/path/to/your/bcilab_config.m)

% This file is loaded by bcilab.m -- note that you can have a version of the file in your ~/.bcilab/
% directory, which will take precedence over a file of same name placed in the bcilab folder (see
% bcilab.m), and that you can specify a custom config file to load.
%
% The options in this configuration file can also be edited via the GUI (under Settings); the GUI
% always edits the file that was used when the toolbox was loaded.

% this is your data path, i.e., where your studies and data sets are stored
data = {'/data/projects'};
data = [];
% (if empty, will default to your bcilab:/userdata folder)
data = []; % e.g., {'/data/myprojects','bcilab:/userdata','home:/mydata'};

% this is a path where results can be stored (you must have write permission)
% (if empty, it is set to equal the data path)
Expand All @@ -28,7 +35,8 @@
else
cache = [];
end
% comment out this line to enable caching of intermediate results
% comment out this line to enable caching of intermediate results in one of the above default linux
% temp folders
cache = [];

% This is the memory capacity that is being reserved for in-memory caching of intermediate results.
Expand Down Expand Up @@ -56,9 +64,14 @@
data_reuses = 3;

% this is a directory for temporary results (e.g. IC decompositions); if this is empty, it will be
% set to a directory next to your BCILAB path
% set to a directory that is your BCILAB installation path with -temp appended.
temp = [];

% if you have private plugins that you manage separately from the bcilab directory tree, you can set
% the path to these here (using the same sub-directory structure as ~/.bcilab/, see that folder for
% reference)
private = [];

% whether to show the main BCILAB menu by default (if this is set to 'separate', the menu is
% always detached from the EEGLAB main menu; otherwise it is under Tools>BCILAB)
menu = 'separate';
Expand All @@ -75,5 +88,3 @@
acquire_options = {'Hostnames',{'localhost'},'ShutdownTimeout',300};




2 changes: 1 addition & 1 deletion code/dataset_editing/set_concat.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
end
% count events, epochs and samples in each set
event_count = cellfun(@(x)length(x.event),varargin);
sample_count = cellfun(@(x)x.pnts,varargin).*epoch_count;
sample_count = cellfun(@(x)x.pnts,varargin);
% concatenate .event and .epoch fields
event = cellfun(@(x)x.event,varargin,'UniformOutput',false); result.event = [event{:}];
% shift event latencies based on cumulative sample counts
Expand Down
29 changes: 26 additions & 3 deletions code/environment/env_startup.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ function env_startup(varargin)
% (default: path/to/bcilab-temp, or path/to/cache/bcilab_temp if a cache
% directory was specified)
%
% 'private': optional private plugin directory, separate from bcilab/*; can have
% the same directory structure as ~/.bcilab/ (default: [])
%
% --- caching settings ---
%
% 'cache': Path where intermediate data sets are cached. Should be located on a fast
Expand Down Expand Up @@ -209,7 +212,7 @@ function env_startup(varargin)
disp('Note: Your version of MATLAB is not supported by BCILAB any more. You may try BCILAB version 0.9, which supports old MATLAB''s back to version 2006a.'); end

% get options
opts = hlp_varargin2struct(varargin,'data',[],'store',[],'cache',[],'temp',[],'mem_capacity',2,'data_reuses',3, ...
opts = hlp_varargin2struct(varargin,'data',[],'store',[],'cache',[],'temp',[],'private',[],'mem_capacity',2,'data_reuses',3, ...
'parallel',{'use','local'}, 'menu',true, 'configscript','', 'worker',false, 'autocompile',true, 'acquire_options',{}, ...
'show_experimental',false,'show_guru',false);

Expand All @@ -218,6 +221,8 @@ function env_startup(varargin)
env_load_dependencies(dependency_dir,opts.autocompile);
if exist(env_translatepath('home:/.bcilab/code/dependencies'),'dir')
env_load_dependencies(env_translatepath('home:/.bcilab/code/dependencies'),opts.autocompile); end
if ~isempty(opts.private) && exist(env_translatepath([opts.private '/code/dependencies']),'dir')
env_load_dependencies(env_translatepath([opts.private '/code/dependencies']),opts.autocompile); end

if ischar(opts.worker)
try
Expand Down Expand Up @@ -248,7 +253,7 @@ function env_startup(varargin)
opts.data = {opts.data}; end
for d = 1:length(opts.data)
opts.data{d} = path_normalize(opts.data{d}); end
if isempty(opts.data) || ~any(cellfun(@exist,opts.data))
if isempty(opts.data)
opts.data = {[base_dir 'userdata']}; end

% process store directory
Expand Down Expand Up @@ -297,7 +302,7 @@ function env_startup(varargin)

% set global variables
global tracking
tracking.paths = struct('bcilab_path',{base_dir(1:end-1)}, 'function_path',{function_dir}, 'data_paths',{opts.data}, 'store_path',{opts.store}, 'dependency_path',{dependency_dir},'resource_path',{resource_dir},'temp_path',{opts.temp});
tracking.paths = struct('bcilab_path',{base_dir(1:end-1)}, 'function_path',{function_dir}, 'data_paths',{opts.data}, 'store_path',{opts.store}, 'dependency_path',{dependency_dir},'resource_path',{resource_dir},'temp_path',{opts.temp}, 'private_path',{opts.private});
for d=1:length(opts.cache)
location = rmfield(opts.cache{d},'tag');
% convert GiB to bytes
Expand Down Expand Up @@ -406,6 +411,8 @@ function env_startup(varargin)
disp('cache is disabled');
end
disp(['temp is in ' opts.temp]);
if ~isempty(opts.private)
disp(['private plugins are in ' opts.private]); end
fprintf('\n');


Expand Down Expand Up @@ -463,6 +470,22 @@ function env_startup(varargin)
end
catch,end

% add private plugin directories to the path
if ~isempty(opts.private)
try
private_codedirs = {['code' filesep 'filters'],['code' filesep 'dataset_editing'], ...
['code' filesep 'machine_learning'], ['code' filesep 'paradigms'], ['code' filesep 'scripts']};
% and add the code directories to the path
for d = private_codedirs
tmpdir = env_translatepath([opts.private filesep d{1}]);
if exist(tmpdir,'dir')
addpath(genpath(tmpdir)); end
end
catch e
disp(['Could not add private code directories to path: ' e.message]);
end
end

% create a menu
if ~(isequal(opts.menu,false) || isequal(opts.menu,0))
try
Expand Down
89 changes: 51 additions & 38 deletions code/environment/env_translatepath.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
% 30])", and this in turn allows to share the same data set caches (which are indexed by expression)
% across machines and operating systems, minimizing redundant computations.
%
% Some of the path references, such as data:/, temp:/, store:/, private:/ can be set in the startup
% arguments of bcilab.m or bcilab_config.m (see documentation in those files). It is permitted to
% use other relative paths, such as home:/ when specifying those arguments (but circular references
% must be avoided).
%
% In:
% IndependentPath : platform-independent path; may contain forward and/or backward slashes
% (forward slashes generally preferred), and may refer to locations such as
Expand Down Expand Up @@ -42,7 +47,6 @@
% % resolve a reference to the resources directory
% env_translatepath('resources:/workspaces/testing.mat')
%
%
% See also:
% env_startup, io_loadset
%
Expand All @@ -51,47 +55,56 @@

global tracking;

% turn the path into a system-dependent one
filename = strrep(strrep(filename,'\',filesep),'/',filesep);
% function to sanitize file names (replace file separators by system-dependent version)
sanitize = @(filename) strrep(strrep(strrep(filename,'\',filesep),'/',filesep),[filesep filesep],filesep);

% resolve location references
if strncmp('store:',filename,6)
filename = [tracking.paths.store_path filename(1+length('store:'):end)];
elseif strncmp('resources:',filename,10)
filename = [tracking.paths.resource_path filename(1+length('resources:'):end)];
elseif strncmp('temp:',filename,5)
filename = [tracking.paths.temp_path filename(1+length('temp:'):end)];
elseif strncmp('functions:',filename,10)
filename = [tracking.paths.function_path filename(1+length('functions:'):end)];
elseif strncmp('bcilab:',filename,7)
filename = [tracking.paths.bcilab_path filename(1+length('bcilab:'):end)];
elseif strncmp('dependencies:',filename,13)
filename = [tracking.paths.dependency_path filename(1+length('dependencies:'):end)];
elseif strncmp('home:',filename,5)
filename = [hlp_homedir filename(1+length('home:'):end)];
elseif strncmp('data:',filename,5)
rest = filename(1+length('data:'):end);
bestpath = 1; bestlen = -1;
if length(tracking.paths.data_paths) > 1
fpieces = hlp_split(rest,filesep);
% find the data path that contains the longest prefix of the filename
for pidx=1:length(tracking.paths.data_paths)
p = tracking.paths.data_paths{pidx};
% for each prefix of the filename (starting with the longest one)
for k=length(fpieces):-1:0
% check if the data path plus the first k pieces of the filename exists
if exist([p sprintf([filesep '%s'],fpieces{1:k})],'file')
% found a match - check if it is a new length record among all our data paths...
if k>bestlen
bestlen = k;
bestpath = pidx;
% loop until all path references have been resolved
while true
% resolve location references
if strncmp('store:',filename,6)
filename = [tracking.paths.store_path filename(1+length('store:'):end)];
elseif strncmp('resources:',filename,10)
filename = [tracking.paths.resource_path filename(1+length('resources:'):end)];
elseif strncmp('temp:',filename,5)
filename = [tracking.paths.temp_path filename(1+length('temp:'):end)];
elseif strncmp('functions:',filename,10)
filename = [tracking.paths.function_path filename(1+length('functions:'):end)];
elseif strncmp('bcilab:',filename,7)
filename = [tracking.paths.bcilab_path filename(1+length('bcilab:'):end)];
elseif strncmp('dependencies:',filename,13)
filename = [tracking.paths.dependency_path filename(1+length('dependencies:'):end)];
elseif strncmp('private:',filename,8)
filename = [tracking.paths.private_path filename(1+length('private:'):end)];
elseif strncmp('home:',filename,5)
filename = [hlp_homedir filename(1+length('home:'):end)];
elseif strncmp('data:',filename,5)
rest = filename(1+length('data:'):end);
bestpath = 1; bestlen = -1;
if length(tracking.paths.data_paths) > 1
% find the data path that contains the longest prefix of the filename
fpieces = hlp_split(sanitize(rest),filesep);
for pidx=1:length(tracking.paths.data_paths)
p = env_translatepath(tracking.paths.data_paths{pidx});
% for each prefix of the filename (starting with the longest one)
for k=length(fpieces):-1:0
% check if the data path plus the first k pieces of the filename exists
if exist([p filesep fpieces{1:k}],'file')
% found a match - check if it is a new length record among all our data paths...
if k>bestlen
bestlen = k;
bestpath = pidx;
end
break;
end
break;
end
end
end
% resolve the reference using that data path which matches most of the filename,
% where, if multiple data paths are equally well suited, the first one of them is taken
filename = [tracking.paths.data_paths{bestpath} rest];
else
break;
end
% resolve the reference using that data path which matches most of the filename,
% where, if multiple data paths are equally well suited, the first one of them is taken
filename = [tracking.paths.data_paths{bestpath} rest];
end

filename = sanitize(filename);
4 changes: 4 additions & 0 deletions code/filters/flt_pipeline.m
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,10 @@
dir(env_translatepath('functions:/dataset_editing/set_*.m'));
dir(env_translatepath('functions:/filters/in_development/flt_*.m'));
dir(env_translatepath('functions:/dataset_editing/in_development/set_*.m'));
dir(env_translatepath('private:/code/filters/flt_*.m'));
dir(env_translatepath('private:/code/dataset_editing/set_*.m'));
dir(env_translatepath('private:/code/filters/in_development/flt_*.m'));
dir(env_translatepath('private:/code/dataset_editing/in_development/set_*.m'));
dir(env_translatepath('home:/.bcilab/code/filters/flt_*.m'));
dir(env_translatepath('home:/.bcilab/code/dataset_editing/set_*.m'))];

Expand Down
6 changes: 5 additions & 1 deletion code/gui/gui_batchanalysis.m
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ function gui_batchanalysis_OpeningFcn(hObject, eventdata, handles, varargin)
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global tracking;

% turn all large edit panes to multi-line editors
for obj = {handles.edit1,handles.edit20,handles.edit19}
Expand All @@ -93,7 +94,10 @@ function gui_batchanalysis_OpeningFcn(hObject, eventdata, handles, varargin)

% get all paradigm names
para_files = [];
for p = {'functions:/paradigms', 'home:/.bcilab/code/paradigms'}
para_paths = {'functions:/paradigms', 'functions:/paradigms/in_development', 'home:/.bcilab/code/paradigms'};
if ~isempty(tracking.paths.private_path)
para_paths = [para_paths {'private:/code/paradigms','private:/code/paradigms/in_development'}]; end
for p = para_paths
para_files = [para_files dir([env_translatepath(p{1}) filesep 'Paradigm*.m'])]; end
para_acronyms = cellfun(@(s)s(9:end-2),{para_files.name},'UniformOutput',false);

Expand Down
9 changes: 8 additions & 1 deletion code/gui/utils/gui_listapproaches.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@
{'Built-in Paradigms', {'functions:/paradigms'}}, ...
{'User Paradigms', {'home:/.bcilab/code/paradigms'}}, ...
{'Experimental Paradigms',quickif(tracking.gui.show_experimental,{'functions:/paradigms/in_development'},{})}};
if ~isempty(tracking.paths.private_path)
paradigm_locations = [paradigm_locations { ...
{'Private Paradigms', {'private:/code/paradigms'}}, ...
{'Private Experimental Paradigms',quickif(tracking.gui.show_experimental,{'private:/code/paradigms/in_development'},{})}}];
end

for loc=1:length(paradigm_locations)
if ~isempty(paradigm_locations{loc}{2})
Expand Down Expand Up @@ -68,7 +73,7 @@
for v=find(strcmp({vars.class},'cell'))
var = evalin('base',vars(v).name);
if length(var)>1 && ischar(var{1}) && ((strncmp(var{1},'Paradigm',8) && length(var{1})>8 && any(strcmp(var{1}(9:end),paradigm_names))) || any(strcmp(var{1},paradigm_names)))
approaches{end+1} = struct('paradigm',quickif(strncmp(var{1},'Paradigm',8),var{1},['Paradigm',var{1}]),'name',vars(v).name,'parameters',{var(2:end)}); end
approaches{end+1} = struct('paradigm',quickif(strncmp(var{1},'Paradigm',8),var{1},['Paradigm',var{1}]),'name',vars(v).name,'parameters',{var(2:end)},'description',''); end
end

list = [list {'From Workspace', approaches}];
Expand All @@ -77,6 +82,8 @@
% --- aggregate all approaches in the approaches directory (and the user's home directory, too) ---
approaches = {};
approach_dirs = {env_translatepath('home:/.bcilab/approaches'),env_translatepath('resources:/approaches')};
if ~isempty(tracking.paths.private_path)
approach_dirs = [approach_dirs {env_translatepath('private:/approaches')}]; end
for d = approach_dirs
approach_dir = d{1};
files = dir([approach_dir filesep '*.apr']);
Expand Down
6 changes: 5 additions & 1 deletion code/machine_learning/ml_train.m
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,14 @@

function learners = list_learners(update_list)
% list all the learning functions in code/machine_learning/
global tracking;
persistent memo;
if isempty(memo) || exist('update_list','var') && update_list
memo = {};
for p = {'functions:/machine_learning/ml_train*.m','home:/.bcilab/code/machine_learning/ml_train*.m'}
ml_paths = {'functions:/machine_learning/ml_train*.m','home:/.bcilab/code/machine_learning/ml_train*.m'};
if ~isempty(tracking.paths.private_path)
ml_paths = [ml_paths {'private:/code/machine_learning/ml_train*.m'}]; end
for p = ml_paths
modules = dir(env_translatepath(p{1}));
names = setdiff({modules.name},{'ml_train.m','ml_trainvote.m'});
tags = cellfun(@(n) n(9:end-2),names,'UniformOutput',false);
Expand Down
18 changes: 18 additions & 0 deletions code/online_plugins/Neuroscan/BCILAB.readme
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
README for Neuroscan Scan Plugin for BCILAB
Author: Visual Attention and Cognition Lab, Dan Roberts, and Nick Pe�aranda, George Mason University, Spring 2014
Released under the GPLv3, see COPYING.txt
Based on the BrainVision BCILAB plug-in by Hal Greenwald


Plugin to stream EEG data and event markers from Neuroscan Scan software to BCILAB. Has been tested with Scan 4.3 and a NuAmps 40-channel amplifier

Associated Files:

BCILAB/code/online_plugins/Neuroscan:
ns_close.m
ns_open.m
ns_parseheader.m
ns_parseinfo.m
ns_read.m
ns_sendpacket.m
run_readneuroscan.m
Loading