Commit 6c421a0b authored by Jesse Heckman's avatar Jesse Heckman
Browse files

added substantial body back end vPrime

parent 581245b6
function handles = pb_createdir(handles)
% PB_CREATEDIR()
%
% PB_CREATEDIR() ...
%
% See also ...
% PBToolbox (2018): JJH: j.heckman@donders.ru.nl
% Creates directory and sets parameters for data storage
cfg = handles.cfg;
path = [cfg.dname filesep 'trial'];
if ~exist(path,'dir'); mkdir(path); end
cd(path);
fname = [cfg.expInitials '-' cfg.subjectid '-' cfg.datestring '-' cfg.recording '-0001.vc' ];
while exist(fname,'file')
% Check for existing recordings
quest = 'Recording already exists. Indicate how to proceed?';
answer = questdlg(quest,'Choices','Overwrite', 'Increment','Stop','Stop');
switch answer
case 'Overwrite'
break;
case 'Increment'
cfg.recording = num2str(str2double(cfg.recording)+1,'%04d');
set(handles.editRec,'string',cfg.recording);
case 'Stop'
error('Run stopped.');
end
fname = [cfg.expInitials '-' cfg.subjectid '-' cfg.datestring '-' cfg.recording '-0001.vc' ];
end
handles.cfg = cfg;
handles = pb_gethandles(handles);
end
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% %
% Part of Programmeer Beer Toolbox (PBToolbox) %
% Written by: Jesse J. Heckman (2018) %
% %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
function path = pb_datapath(path)
% PB_DATAPATH()
%
% PB_DATAPATH() ...
%
% See also ...
% PBToolbox (2018): JJH: j.heckman@donders.ru.nl
if nargin == 0; path = []; end
if isempty(path) || ~exist(path)
username = char(java.lang.System.getProperty('user.name'));
if ismac % MAC (personal // NO VC, NO TDT)
path = ['/Users/' username '/Documents/Data/Experiment'];
%path = '/Users/jjheckman/Documents/Data/PhD/Experiment/VC';
elseif isunix && ~ismac % LINUX (public // VC, NO TDT)
path = ['/home/' username '/Documents/Data'];
elseif ispc % WINDOWS (public // VC, TDT)
path = ['C:\Users\' username '\Documents\Data'];
end
end
end
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% %
% Part of Programmeer Beer Toolbox (PBToolbox) %
% Written by: Jesse J. Heckman (2018) %
% %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
function handles = pb_getblock(handles)
% PB_GETBLOCK()
%
% PB_GETBLOCK() ...
%
% See also ...
% PBToolbox (2018): JJH: j.heckman@donders.ru.nl
cfg = handles.cfg;
[block, cfg] = pb_vReadExp(cfg);
block = pb_vPrimeZ(block,cfg);
handles.block = block;
handles.cfg = cfg;
end
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% %
% Part of Programmeer Beer Toolbox (PBToolbox) %
% Written by: Jesse J. Heckman (2018) %
% %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
function handles = pb_getcfgdefaults(handles)
% PB_GETCFGDEFAULTS()
%
% PB_GETCFGDEFAULTS() ...
%
% See also ...
% PBToolbox (2018): JJH: j.heckman@donders.ru.nl
%% Default parameters
cfg.fpath = pb_datapath; % default data folder
cfg.date = date;
cd(cfg.fpath); % default data folder
d = dir;
d = d([d.isdir]);
d = d(3:end);
cfg.expinitials = {d.name};
formatOut = 'yy-mm-dd';
d = datestr(now,formatOut);
cfg.date = d;
cfg.datestring = d;
cfg.trialnumber = 1;
cfg.blocknumber = 1;
%% TDT and PLC defaults
cfg = pb_tdtglobals(cfg); % TDT defaults
%% TDT and PLC defaults
cfg.nleds = 256; % maximum number of LED configurations on PLC
cfg.calfile = which('vPrime.net');
if isempty(cfg.calfile)
cfg.calfile = which('defaultvPrime.net');
end
%% Convert experimental trial
cfg = pb_vLSCpositions(cfg); % lookup structure
%% Data filter coefficients
% Do we use this?
% cfg.Fcutoff = 80; % Cutoff Frequency (Hz)
% cfg.Order = 50;
%
% cfg.lpFilt = designfilt('lowpassfir', 'FilterOrder', cfg.Order, 'CutoffFrequency', ...
% cfg.Fcutoff, 'SampleRate', cfg.RZ6Fs, 'Window', 'hamming');
% check RZ6Fs
%% Led colours
cfg.ledcolours = {'g','r'}; % green and red
%% handles
handles.cfg = cfg;
end
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% %
% Part of Programmeer Beer Toolbox (PBToolbox) %
% Written by: Jesse J. Heckman (2018) %
% %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
function handles = pb_gethandles(handles)
% PB_GETHANDLES()
%
% PB_GETHANDLES() ...
%
% See also ...
% PBToolbox (2018): JJH: j.heckman@donders.ru.nl
cfg = handles.cfg;
expIdx = get(handles.popExperimenter,'Value');
expInitials = get(handles.popExperimenter,'String');
cfg.expInitials = expInitials{expIdx};
cfg.subjectid = get(handles.editPart,'String');
cfg.recording = get(handles.editRec,'String');
cfg.fname = [cfg.expInitials '-' sprintf('%04u',str2double(cfg.subjectid)) '-' cfg.datestring '-' sprintf('%04u',str2double(cfg.recording)) '.vc']; % file name
cfg.dname = [cfg.fpath filesep cfg.expInitials filesep 'Recordings' filesep cfg.expInitials '-' sprintf('%04u',str2double(cfg.subjectid)) '-' cfg.datestring]; % directory name
cfg.expdir = [cfg.fpath filesep cfg.expInitials filesep 'EXP' filesep]; % exp directory name
cfg.snddir = [cfg.fpath filesep cfg.expInitials filesep 'SND' filesep]; % wav directory name
% get exp and cfg files
str = [cfg.expdir filesep '*.exp'];
d = dir(str); % default exp folder
cfg.expfiles = {d.name};
if isempty(cfg.expfiles)
end
%set(handles.popupmenu_exp,'String',cfg.expfiles)
%expfileIdx = get(handles.popupmenu_exp,'Value');
%cfg.expfname = cfg.expfiles{expfileIdx};
cfg.expfname = get(handles.editLoad,'String');
% d = dir([cfg.expdir filesep '*.cfg']);
% cfg.cfgfiles = {d.name};
% set(handles.popupmenu_cfg,'String',cfg.cfgfiles);
% cfgfileIdx = get(handles.popupmenu_cfg,'Value');
% cfg.cfgfname = cfg.cfgfiles{cfgfileIdx};
handles.cfg = cfg;
end
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% %
% Part of Programmeer Beer Toolbox (PBToolbox) %
% Written by: Jesse J. Heckman (2018) %
% %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
function pb_sethandles(handles)
% PB_SETHANDLES()
%
% PB_SETHANDLES() ...
%
% See also ...
% PBToolbox (2018): JJH: j.heckman@donders.ru.nl
set(handles.popExperimenter,'String',handles.cfg.expinitials);
%set(handles.edit_date,'String',handles.cfg.date);
end
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% %
% Part of Programmeer Beer Toolbox (PBToolbox) %
% Written by: Jesse J. Heckman (2018) %
% %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
function pb_setupShow(handles)
% PB_SETUPSHOW()
%
% PB_SETUPSHOW() ...
%
% See also ...
% PBToolbox (2018): JJH: j.heckman@donders.ru.nl
axes(handles.signals);
cla; hold on;
axis([0 120 -50 50]);
box off
axes(handles.hTrace);
cla; hold on;
axis([0 2.5 0 300]);
box off
axes(handles.eTrace);
cla; hold on;
axis([0 2.5 0 300]);
box off
end
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% %
% Part of Programmeer Beer Toolbox (PBToolbox) %
% Written by: Jesse J. Heckman (2018) %
% %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
function cfg = pb_vLSCpositions(cfg,varargin)
% PB_VLOOKUP()
%
% PB_VLOOKUP() ...
%
% See also ...
% PBToolbox (2018): JJH: j.heckman@donders.ru.nl
if nargin<1
cfg = [];
end
%% Optional arguments
dspFlag = pb_keyval('display',varargin,false);
if dspFlag; close all; end
%% File
fname = which('vPrime Measurement.xlsx');
N = xlsread(fname,'Values');
channel = N(:,1);
%% Transform to Cartesian
% To be checked
% actual spherical azimuth, elevation
az = -N(:,4)+90;
el = N(:,5);
az = pa_deg2rad(az);
el = pa_deg2rad(el);
R = 1;
[X,Y,Z] = sph2cart(az,el,R);
[X,Y,Z] = pitch(X,Y,Z,90);
% desired double-polar azimuth and elevation
daz = N(:,2);
del = N(:,3);
% [dX,dY,dZ] = azel2cart(daz,del,R);
%% Transform to double-polar coordinate system
% actual double-polar azimuth, elevation
[X,Y,Z] = yaw(X,Y,Z,-90);
[aazel] = xyz2azel(X,Y,Z);
aaz = aazel(:,1);
ael = aazel(:,2);
sel = daz>90;
aaz(sel) = 90+(90-aaz(sel));
sel = daz<-90;
aaz(sel) = -90+(-90-aaz(sel));
sel = del>90;
ael(sel) = 90+(90-ael(sel));
cfg.lookup = [aaz ael channel];
end
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% %
% Part of Programmeer Beer Toolbox (PBToolbox) %
% Written by: Jesse J. Heckman (2018) %
% %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
function cfg = pb_vLookup(cfg,varargin)
% PB_VLOOKUP()
%
% PB_VLOOKUP() ...
%
% See also ...
% PBToolbox (2018): JJH: j.heckman@donders.ru.nl
if nargin<1
cfg = [];
end
%% LED connections
% [Azimuth (deg) Elevation (deg) LED #]
% azimuths and elevations were measured by Sebastian Ausili in June 2015
cfg = pb_vLSCpositions(cfg);
cfg.nstimchan = 2^5; % number of PLC and MUX channels
cfg.nspeakers = 17; % actual number of speakers
cfg.stimchan = (1:cfg.nstimchan)-1;
%% Add missing channels
n = size(cfg.lookup,1);
cfg.lookup = [cfg.lookup; NaN(cfg.nstimchan-n,3)]; % add missing channel data as NaNs
sel = ismember(cfg.stimchan,cfg.lookup(:,3)); % lookup existing channels
cfg.missingchan = cfg.stimchan(~sel); % get missing channels
sel = isnan(cfg.lookup(:,3)); % search for missing channels in lookup-table
cfg.lookup(sel,3) = cfg.missingchan; % put missing channel numbers in lookup-table
cfg.lookup = sortrows(cfg.lookup,[3 1 2]); % sort lookup-table by channel number
%% Speakers
cfg.nMUX = 2; % 2 multiplexers
cfg.nMUXbit = 16; % 16 bits per MUX
cfg.MUXind = 1:cfg.nMUX;
cfg.MUXbit = 1:cfg.nMUXbit;
LookUp(:,1) = cfg.stimchan; % Stimulus channel 0-31
idx = LookUp(:,1)+1;
LookUp(:,2) = ceil(idx/(2^4));% MUX number
idx = mod(idx,2^4);
idx(idx==0) = 2^4;
LookUp(:,3) = idx; % TDT bit
%% Combine
% [PLC-Chan# RP2# MUX# BIT# AZ EL]
cfg.lookup = [cfg.lookup(:,3) LookUp(:,2:3) cfg.lookup(:,1) cfg.lookup(:,2)];
cfg.lookuplabel = {'Channel' 'MUX' 'Bit' 'Azimuth' 'Elevation'};
% cfg.lookuplabel = {'Channel' 'RP2' 'MUX' 'Bit' 'Azimuth' 'Elevation'};
%% Interpolant
x = cfg.lookup(:,4);
y = cfg.lookup(:,5);
z = cfg.lookup(:,1);
sel = ~isnan(x);
x = x(sel);
y = y(sel);
z = z(sel);
cfg.interpolant = scatteredInterpolant(x,y,z,'nearest');
end
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% %
% Part of Programmeer Beer Toolbox (PBToolbox) %
% Written by: Jesse J. Heckman (2018) %
% %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
function block = pb_vPrimeZ(block,cfg)
% PB_VPRIMEZ()
%
% PB_VPRIMEZ() ...
%
% See also ...
% PBToolbox (2018): JJH: j.heckman@donders.ru.nl
cfg;
for iBlck = 1:cfg.Blocks
ntrls = length(block(iBlck).trial);
for iTrl = 1:ntrls
nstms = length(block(iBlck).trial(iTrl).stim);
for iStm = 1:nstms
X = block(iBlck).trial(iTrl).stim(iStm);
if ~isempty(X)
ZI = cfg.interpolant(block(iBlck).trial(iTrl).stim(iStm).azimuth,block(iBlck).trial(iTrl).stim(iStm).elevation);
block(iBlck).trial(iTrl).stim(iStm).Z = ZI;
block(iBlck).trial(iTrl).stim(iStm).azimuth = cfg.lookup(ZI+1,4);
block(iBlck).trial(iTrl).stim(iStm).elevation = cfg.lookup(ZI+1,5);
end
end
end
end
end
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% %
% Part of Programmeer Beer Toolbox (PBToolbox) %
% Written by: Jesse J. Heckman (2018) %
% %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
function [Dat,profile,dur] = pb_vSignalVC(h,block,iBlock) function [Dat,profile,dur] = pb_vSignalVC(handles,block,iBlock)
% PB_VSIGNALVC() % PB_VSIGNALVC()
% %
% PB_VSIGNALVC() ... % PB_VSIGNALVC() ...
...@@ -30,24 +30,30 @@ function [Dat,profile,dur] = pb_vSignalVC(h,block,iBlock) ...@@ -30,24 +30,30 @@ function [Dat,profile,dur] = pb_vSignalVC(h,block,iBlock)
dur = max([signal(1).duration signal(2).duration])+5; % add 5 extra seconds for delay of the system dur = max([signal(1).duration signal(2).duration])+5; % add 5 extra seconds for delay of the system
%% FEEDBACK GUI %% FEEDBACK GUI
updateBlock(h,iBlock,signal); updateBlock(handles,iBlock,signal);
axes(h.signals); cla; hold on; handles = pb_gethandles(handles);
h.signals.YLim = [-50 50];
cb = handles.cfg.blocknumber;
dur = max([handles.block(cb).signal.ver.duration handles.block(cb).signal.hor.duration]);
axes(handles.signals); cla; hold on;
handles.signals.YLim = [-50 50];
handles.signals.XLim = [0 dur];
plot(Dat.v.t,Dat.v.x,'k'); plot(Dat.v.t,Dat.v.x,'k');
plot(Dat.h.t,Dat.h.x,'b'); plot(Dat.h.t,Dat.h.x,'b');
end end
function updateBlock(h, iBlock, signal) function updateBlock(handles, iBlock, signal)
% Updates the block information to the GUI % Updates the block information to the GUI
bn = pb_sentenceCase(num2str(iBlock,'%03d')); % count block bn = pb_sentenceCase(num2str(iBlock,'%03d')); % count block
set(h.Bn,'string',bn); set(handles.Bn,'string',bn);
vs = ['V = ' pb_sentenceCase(signal(1).type) ... % VC stim vs = ['V = ' pb_sentenceCase(signal(1).type) ... % VC stim
', H = ' pb_sentenceCase(signal(2).type)]; ', H = ' pb_sentenceCase(signal(2).type)];
set(h.Vs,'string',vs); set(handles.Vs,'string',vs);
end end
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
......
function cnt = pb_vInitialize(h, initialize) function handles = pb_vInitialize(handles, initialize)
% PB_VREADYEXP(h,initialize) % PB_VREADYEXP(h,initialize)
% %
% PB_VREADYEXP() interacts with GUI during check in/out experiment. % PB_VREADYEXP() interacts with GUI during check in/out experiment.
...@@ -9,20 +9,15 @@ function cnt = pb_vInitialize(h, initialize) ...@@ -9,20 +9,15 @@ function cnt = pb_vInitialize(h, initialize)
if initialize; initialize = 'off'; else; initialize = 'on'; end if initialize; initialize = 'off'; else; initialize = 'on'; end
set(h.buttonClose, 'Enable', initialize) % avoid closing GUI during executing run function set(handles.buttonClose, 'Enable', initialize) % avoid closing GUI during executing run function
set(h.buttonRun, 'Enable', initialize) set(handles.buttonRun, 'Enable', initialize)
set(h.buttonLoad, 'Enable', initialize) set(handles.buttonLoad, 'Enable', initialize)
if strcmp(initialize,'off') if strcmp(initialize,'off')
% Ready feedback plots % test
axes(h.signals); cla;
axes(h.eTrace); cla; h.eTrace.YLim = [0 300]; h.eTrace.XLim = [0 2.5];
axes(h.hTrace); cla; h.hTrace.YLim = [0 300]; h.hTrace.XLim = [0 2.5];
else else
disp([newline newline 'Experiment finished!']); disp([newline newline 'Experiment finished!']);
end end
if nargout == 1; cnt = 0; end
end end
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
......
function [block,cfg] = pb_vReadExp(expfile) function [block,cfg] = pb_vReadExp(cfg)
% PB_VREADEXP(expfile) % PB_VREADEXP(expfile)
% %
% PB_VREADEXP() reads experimental data from expfile and loads BLOCK and % PB_VREADEXP() reads experimental data from expfile and loads BLOCK and
...@@ -10,13 +10,12 @@ function [block,cfg] = pb_vReadExp(expfile) ...@@ -10,13 +10,12 @@ function [block,cfg] = pb_vReadExp(expfile)
%% INITIALIZE %% INITIALIZE
expfile = cfg.expfname;
if ~pb_fexist(expfile); return; end if ~pb_fexist(expfile); return; end
fid = fopen(expfile,'r'); fid = fopen(expfile,'r');
%% HEADER %% HEADER
cfg = struct;
cfg.comment = checkcomment(fid); cfg.comment = checkcomment(fid);
cfg = hread(fid,cfg); cfg = hread(fid,cfg);
n = cfg.Blocks; n = cfg.Blocks;
...@@ -116,10 +115,50 @@ function [block,cfg] = pb_vReadExp(expfile) ...@@ -116,10 +115,50 @@ function [block,cfg] = pb_vReadExp(expfile)
block(bn).trial(tn).stim(sn).onevent = par(1); block(bn).trial(tn).stim(sn).onevent = par(1);
block(bn).trial(tn).stim(sn).ondelay = par(2); block(bn).trial(tn).stim(sn).ondelay = par(2);
end end