From d695d501e311fdf970c8553b48da09db490cfd77 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 29 Jul 2020 16:36:44 +0200 Subject: [PATCH 1/3] update to new cfg structure --- setParameters.m | 128 ++++++++++++++++++++-------------------- subfun/doDotMo.m | 44 +++++++------- subfun/expDesign.m | 46 +++++++-------- visualLocTanslational.m | 83 +++++++++++++------------- 4 files changed, 151 insertions(+), 150 deletions(-) diff --git a/setParameters.m b/setParameters.m index 7091395..854a346 100644 --- a/setParameters.m +++ b/setParameters.m @@ -1,95 +1,95 @@ -function [cfg, expParameters] = setParameters(); +function [cfg] = setParameters() % Initialize the parameters and general configuration variables - expParameters = struct(); cfg = struct(); - - % by default the data will be stored in an output folder created where the % setParamters.m file is % change that if you want the data to be saved somewhere else - expParameters.outputDir = fullfile( ... + cfg.dir.output = fullfile( ... fileparts(mfilename('fullpath')), '..', ... 'output'); %% Debug mode settings - cfg.debug = true; % To test the script out of the scanner, skip PTB sync - cfg.testingSmallScreen = false; % To test on a part of the screen, change to 1 - cfg.testingTranspScreen = true; % To test with trasparent full size screen + cfg.debug.do = true; % To test the script out of the scanner, skip PTB sync + cfg.debug.smallWin = false; % To test on a part of the screen, change to 1 + cfg.debug.transpWin = true; % To test with trasparent full size screen - expParameters.verbose = true; + cfg.verbose = false; %% Engine parameters cfg.testingDevice = 'pc'; - cfg.eyeTracker = false; - cfg.initAudio = false; + cfg.eyeTracker.do = false; + cfg.audio.do = false; - [cfg, expParameters] = setMonitor(cfg, expParameters); + cfg = setMonitor(cfg, cfg); % Keyboards - [cfg, expParameters] = setKeyboards(cfg, expParameters); + cfg = setKeyboards(cfg, cfg); % MRI settings - [cfg, expParameters] = setMRI(cfg, expParameters); + cfg = setMRI(cfg, cfg); %% Experiment Design - expParameters.names = {'static', 'motion'}; - expParameters.possibleDirections = [-1 1]; % 1 motion , -1 static - expParameters.numBlocks = size(expParameters.possibleDirections, 2); - expParameters.numRepetitions = 1; % AT THE MOMENT IT IS NOT SET IN THE MAIN SCRIPT - expParameters.IBI = 0; % 8; + cfg.names = {'static', 'motion'}; + cfg.possibleDirections = [-1 1]; % 1 motion , -1 static + cfg.numBlocks = size(cfg.possibleDirections, 2); + cfg.numRepetitions = 1; % AT THE MOMENT IT IS NOT SET IN THE MAIN SCRIPT + cfg.IBI = 0; % 8; % Time between events in secs - expParameters.ISI = 0.1; + cfg.ISI = 0.1; % Number of seconds before the motion stimuli are presented - expParameters.onsetDelay = 5; + cfg.onsetDelay = 5; % Number of seconds after the end all the stimuli before ending the run - expParameters.endDelay = 1; + cfg.endDelay = 1; %% Visual Stimulation - % speed in visual angles - expParameters.speedEvent = 8; + % Number of events per block (should not be changed) - expParameters.numEventsPerBlock = 12; - expParameters.eventDuration = 1; + cfg.numEventsPerBlock = 12; + cfg.eventDuration = 1; % second + + % speed in visual angles + cfg.dot.speed = 8; % Coherence Level (0-1) - expParameters.coh = 1; + cfg.dot.coh = 1; % Maximum number dots per frame - expParameters.maxDotsPerFrame = 300; + cfg.dot.maxNbPerFrame = 300; % Dot life time in seconds - expParameters.dotLifeTime = 1; + cfg.dot.lifeTime = 1; % Dot Size (dot width) in visual angles. - expParameters.dotSize = 0.1; - expParameters.dotColor = cfg.white; - expParameters.dontClear = 0; + cfg.dot.size = 0.1; + cfg.dot.color = cfg.color.white; + cfg.dot.dontClear = 0; + % Diameter/length of side of aperture in Visual angles cfg.diameterAperture = 8; %% Task(s) - - expParameters.task = 'visualLocalizer'; + + cfg.task.name = 'visual localizer'; % Instruction - expParameters.taskInstruction = '1-Detect the RED fixation cross\n \n\n'; + cfg.task.instruction = '1-Detect the RED fixation cross\n \n\n'; % Fixation cross (in pixels) % Set the length of the lines of the fixation cross - expParameters.fixCrossDimPix = 10; + cfg.fixation.dimensionPix = 10; % Set the line width for our fixation cross - expParameters.lineWidthPix = 4; - expParameters.maxNumFixationTargetPerBlock = 2; - expParameters.targetDuration = 0.15; % In secs - - expParameters.xDisplacementFixCross = 0; % Manual displacement of the fixation cross - expParameters.yDisplacementFixCross = 0; % Manual displacement of the fixation cross - expParameters.fixationCrossColor = cfg.white; - expParameters.fixationCrossColorTarget = cfg.red; - - expParameters.extraColumns = {'direction', 'speed', 'target', 'event', 'block'}; + cfg.fixation.lineWidthPix = 4; + cfg.fixation.xDisplacement = 0; % Manual displacement of the fixation cross + cfg.fixation.yDisplacement = 0; % Manual displacement of the fixation cross + cfg.fixation.color = cfg.color.white; + cfg.fixation.colorTarget = cfg.color.red; + + cfg.target.maxNbPerBlock = 2; + cfg.target.duration = 0.15; % In secs + + cfg.extraColumns = {'direction', 'speed', 'target', 'event', 'block'}; end -function [cfg, expParameters] = setKeyboards(cfg, expParameters) +function cfg = setKeyboards(cfg) cfg.keyboard.escapeKey = 'ESCAPE'; cfg.keyboard.responseKey = {'space'}; cfg.keyboard.keyboard = []; @@ -101,34 +101,34 @@ end end -function [cfg, expParameters] = setMRI(cfg, expParameters) +function cfg = setMRI(cfg) % letter sent by the trigger to sync stimulation and volume acquisition - cfg.triggerKey = 't'; - cfg.numTriggers = 4; + cfg.mri.triggerKey = 't'; + cfg.mri.triggerNb = 4; - expParameters.bids.MRI.RepetitionTime = 2; + cfg.mri.repetitionTime = 2; - expParameters.bids.MRI.Instructions = 'Detect the RED fixation cross'; - expParameters.bids.MRI.TaskDescription = []; + cfg.bids.MRI.Instructions = 'Detect the RED fixation cross'; + cfg.bids.MRI.TaskDescription = []; end -function [cfg, expParameters] = setMonitor(cfg, expParameters) +function cfg = setMonitor(cfg) % Monitor parameters for PTB - cfg.white = [255 255 255]; - cfg.black = [0 0 0]; - cfg.red = [255 0 0]; - cfg.grey = mean([cfg.black; cfg.white]); - cfg.backgroundColor = cfg.black; - cfg.textColor = cfg.white; + cfg.color.white = [255 255 255]; + cfg.color.black = [0 0 0]; + cfg.color.red = [255 0 0]; + cfg.color.grey = mean([cfg.color.black; cfg.color.white]); + cfg.color.background = cfg.color.black; + cfg.text.color = cfg.color.white; % Monitor parameters - cfg.monitorWidth = 42; % in cm - cfg.screenDistance = 134; % distance from the screen in cm + cfg.screen.monitorWidth = 42; % in cm + cfg.screen.monitorDistance = 134; % distance from the screen in cm if strcmpi(cfg.testingDevice, 'mri') - cfg.monitorWidth = 42; - cfg.screenDistance = 134; + cfg.screen.monitorWidth = 42; + cfg.screen.monitorDistance = 134; end end diff --git a/subfun/doDotMo.m b/subfun/doDotMo.m index 414a969..8bcd721 100644 --- a/subfun/doDotMo.m +++ b/subfun/doDotMo.m @@ -1,4 +1,4 @@ -function [onset, duration] = doDotMo(cfg, expParameters, thisEvent) +function [onset, duration] = doDotMo(cfg, thisEvent) % Draws the stimulation of static/moving in 4 directions dots or static % % DIRECTIONS @@ -18,19 +18,19 @@ % smaller number (nDots / Area of aperture) on average. %% Get parameters - dontClear = expParameters.dontClear; + dontClear = cfg.dot.dontClear; direction = thisEvent.direction(1); isTarget = thisEvent.target(1); speed = thisEvent.speed(1); - coh = expParameters.coh; - ndots = expParameters.maxDotsPerFrame; - dotSizePix = expParameters.dotSizePix; - dotLifeTime = expParameters.dotLifeTime; - dotColor = expParameters.dotColor; + coh = cfg.dot.coh; + ndots = cfg.dot.maxNbPerFrame; + dotSizePix = cfg.dot.sizePix; + dotLifeTime = cfg.dot.lifeTime; + dotColor = cfg.dot.color; - targetDuration = expParameters.targetDuration; + targetDuration = cfg.target.duration; % thisEvent = deg2Pix('speed', thisEvent, cfg); % dotSpeedPix = logFile.iEventSpeedPix; @@ -45,7 +45,7 @@ speed = 0; - dotLifeTime = expParameters.eventDuration; + dotLifeTime = cfg.eventDuration; end %% initialize variables @@ -59,7 +59,7 @@ % Set a N x 2 matrix that gives jump size in pixels % pix/sec * sec/frame = pix / frame dxdy = repmat( ... - speed * 10 / (diamAperture * 10) * (3 / cfg.monRefresh) * ... + speed * 10 / (diamAperture * 10) * (3 / cfg.screen.monitorRefresh) * ... [cos(pi * direction / 180.0) -sin(pi * direction / 180.0)], ndots, 1); % dxdy = repmat(... @@ -71,13 +71,13 @@ dotTime = ones(size(xy, 1), 1); % Set for how many frames to show the dots - continueShow = floor(expParameters.eventDuration / cfg.ifi); + continueShow = floor(cfg.eventDuration / cfg.screen.ifi); % Covert the dotLifeTime from seconds to frames - dotLifeTime = ceil(dotLifeTime / cfg.ifi); + dotLifeTime = ceil(dotLifeTime / cfg.screen.ifi); %% Start the dots presentation - vbl = Screen('Flip', cfg.win, 0, dontClear); + vbl = Screen('Flip', cfg.screen.win, 0, dontClear); onset = vbl; while continueShow @@ -124,19 +124,19 @@ %% PTB draws the dots stimulation % Draw the fixation cross - color = expParameters.fixationCrossColor; + color = cfg.fixation.color; % If this frame shows a target we change the color if GetSecs < (onset + targetDuration) && isTarget == 1 - color = expParameters.fixationCrossColorTarget; + color = cfg.fixation.colorTarget; end - drawFixationCross(cfg, expParameters, color); + drawFixationCross(cfg, color); % Draw the dots - Screen('DrawDots', cfg.win, xy_pix, dotSizePix, dotColor, cfg.center, 2); + Screen('DrawDots', cfg.screen.win, xy_pix, dotSizePix, dotColor, cfg.screen.center, 2); - Screen('DrawingFinished', cfg.win, dontClear); + Screen('DrawingFinished', cfg.screen.win, dontClear); - vbl = Screen('Flip', cfg.win, vbl + cfg.ifi, dontClear); + vbl = Screen('Flip', cfg.screen.win, vbl + cfg.screen.ifi, dontClear); %% Update counters @@ -150,11 +150,11 @@ %% Erase last dots - drawFixationCross(cfg, expParameters, expParameters.fixationCrossColor); + drawFixationCross(cfg, cfg.fixation.color); - Screen('DrawingFinished', cfg.win, dontClear); + Screen('DrawingFinished', cfg.screen.win, dontClear); - vbl = Screen('Flip', cfg.win, vbl + cfg.ifi, dontClear); + vbl = Screen('Flip', cfg.screen.win, vbl + cfg.screen.ifi, dontClear); duration = vbl - onset; diff --git a/subfun/expDesign.m b/subfun/expDesign.m index d846fdd..dffad21 100644 --- a/subfun/expDesign.m +++ b/subfun/expDesign.m @@ -1,4 +1,4 @@ -function [expParameters] = expDesign(expParameters, displayFigs) +function [cfg] = expDesign(cfg, displayFigs) % Creates the sequence of blocks and the events in them % % The conditions are consecutive static and motion blocks @@ -43,12 +43,12 @@ %% Check inputs % Set variables here for a dummy test of this function - if nargin < 1 || isempty(expParameters) - expParameters.names = {'static', 'motion'}; - expParameters.numRepetitions = 4; - expParameters.speedEvent = 4; - expParameters.numEventsPerBlock = 12; - expParameters.maxNumFixationTargetPerBlock = 2; + if nargin < 1 || isempty(cfg) + cfg.names = {'static', 'motion'}; + cfg.numRepetitions = 4; + cfg.dot.speed = 4; + cfg.numEventsPerBlock = 12; + cfg.target.maxNbPerBlock = 2; end % Set to 1 for a visualtion of the trials design order @@ -57,11 +57,11 @@ end % Get the parameters - names = expParameters.names; - numRepetitions = expParameters.numRepetitions; - speedEvent = expParameters.speedEvent; - numEventsPerBlock = expParameters.numEventsPerBlock; - maxNumFixTargPerBlock = expParameters.maxNumFixationTargetPerBlock; + names = cfg.names; + numRepetitions = cfg.numRepetitions; + speedEvent = cfg.dot.speed; + numEventsPerBlock = cfg.numEventsPerBlock; + maxNumFixTargPerBlock = cfg.target.maxNbPerBlock; if mod(numEventsPerBlock, length(motionDirections)) ~= 0 warning('Number of events/block not a multiple of number of motion/static direction'); @@ -91,15 +91,15 @@ %% Give the blocks the names with condition - expParameters.designBlockNames = cell(nrBlocks, 1); - expParameters.designDirections = zeros(nrBlocks, numEventsPerBlock); - expParameters.designSpeeds = ones(nrBlocks, numEventsPerBlock) * speedEvent; - expParameters.designFixationTargets = zeros(nrBlocks, numEventsPerBlock); + cfg.design.blockNames = cell(nrBlocks, 1); + cfg.design.directions = zeros(nrBlocks, numEventsPerBlock); + cfg.design.speeds = ones(nrBlocks, numEventsPerBlock) * speedEvent; + cfg.design.fixationTargets = zeros(nrBlocks, numEventsPerBlock); for iMotionBlock = 1:numRepetitions - expParameters.designDirections(motionIndex(iMotionBlock), :) = Shuffle(motionDirections); - expParameters.designDirections(staticIndex(iMotionBlock), :) = Shuffle(staticDirections); + cfg.design.directions(motionIndex(iMotionBlock), :) = Shuffle(motionDirections); + cfg.design.directions(staticIndex(iMotionBlock), :) = Shuffle(staticDirections); end @@ -112,7 +112,7 @@ case 'motion' thisBlockName = {'motion'}; end - expParameters.designBlockNames(iBlock) = thisBlockName; + cfg.design.blockNames(iBlock) = thisBlockName; % set target % if there are 2 targets per block we make sure that they are at least @@ -140,20 +140,20 @@ end - expParameters.designFixationTargets(iBlock, chosenTarget) = 1; + cfg.design.fixationTargets(iBlock, chosenTarget) = 1; end %% Visualize the design matrix if displayFigs - uniqueNames = unique(expParameters.designBlockNames) ; + uniqueNames = unique(cfg.design.blockNames) ; - Ind = zeros(length(expParameters.designBlockNames), length(uniqueNames)) ; + Ind = zeros(length(cfg.design.blockNames), length(uniqueNames)) ; for i = 1:length(uniqueNames) CondInd(:, i) = find( ... - strcmp(expParameters.designBlockNames, uniqueNames{i})) ; %#ok<*AGROW> + strcmp(cfg.design.blockNames, uniqueNames{i})) ; %#ok<*AGROW> Ind(CondInd(:, i), i) = 1 ; end diff --git a/visualLocTanslational.m b/visualLocTanslational.m index 9b4ee65..5d61be9 100644 --- a/visualLocTanslational.m +++ b/visualLocTanslational.m @@ -8,6 +8,8 @@ getOnlyPress = 1; +more off; + % Clear all the previous stuff % clc; clear; if ~ismac @@ -18,20 +20,19 @@ % make sure we got access to all the required functions and inputs initEnv(); -[cfg, expParameters] = setParameters; - % set and load all the parameters to run the experiment -expParameters = userInputs(cfg, expParameters); -[cfg, expParameters] = createFilename(cfg, expParameters); +cfg = setParameters; +cfg = userInputs(cfg); +cfg = createFilename(cfg); -disp(expParameters); disp(cfg); +% REFACTOR % Prepare for fixation Cross -cfg.xCoords = [-expParameters.fixCrossDimPix expParameters.fixCrossDimPix 0 0] + ... - expParameters.xDisplacementFixCross; -cfg.yCoords = [0 0 -expParameters.fixCrossDimPix expParameters.fixCrossDimPix] + ... - expParameters.yDisplacementFixCross; +cfg.xCoords = [-cfg.fixation.dimensionPix cfg.fixation.dimensionPix 0 0] + ... + cfg.fixation.xDisplacement; +cfg.yCoords = [0 0 -cfg.fixation.dimensionPix cfg.fixation.dimensionPix] + ... + cfg.fixation.yDisplacement; cfg.allCoords = [cfg.xCoords; cfg.yCoords]; %% Experiment @@ -44,17 +45,17 @@ % Convert some values from degrees to pixels cfg = degToPix('diameterAperture', cfg, cfg); - expParameters = degToPix('dotSize', expParameters, cfg); + cfg.dot = degToPix('size', cfg.dot, cfg); - [el] = eyeTracker('Calibration', cfg, expParameters); + [el] = eyeTracker('Calibration', cfg); % % % REFACTOR THIS FUNCTION - [expParameters] = expDesign(expParameters); + [cfg] = expDesign(cfg); % % % % Prepare for the output logfiles with all - logFile.extraColumns = expParameters.extraColumns; - logFile = saveEventsFile('open', expParameters, logFile); + logFile.extraColumns = cfg.extraColumns; + logFile = saveEventsFile('open', cfg, logFile); % Wait for space key to be pressed pressSpaceForMe(); @@ -64,44 +65,44 @@ getResponse('start', cfg.keyboard.responseBox); % Show instructions - DrawFormattedText(cfg.win, expParameters.taskInstruction, ... - 'center', 'center', cfg.textColor); - Screen('Flip', cfg.win); + DrawFormattedText(cfg.screen.win, cfg.task.instruction, ... + 'center', 'center', cfg.text.color); + Screen('Flip', cfg.screen.win); % Wait for Trigger from Scanner waitForTrigger(cfg); % Show the fixation cross - drawFixationCross(cfg, expParameters, expParameters.fixationCrossColor); - Screen('Flip', cfg.win); + drawFixationCross(cfg, cfg.fixation.color); + Screen('Flip', cfg.screen.win); %% Experiment Start cfg.experimentStart = GetSecs; - WaitSecs(expParameters.onsetDelay); + WaitSecs(cfg.onsetDelay); %% For Each Block - for iBlock = 1:expParameters.numBlocks + for iBlock = 1:cfg.numBlocks fprintf('\n - Running Block %.0f \n', iBlock); - eyeTracker('StartRecording', cfg, expParameters); + eyeTracker('StartRecording', cfg); % For each event in the block - for iEvent = 1:expParameters.numEventsPerBlock + for iEvent = 1:cfg.numEventsPerBlock % Check for experiment abortion from operator checkAbort(cfg, cfg.keyboard.keyboard); % set direction, speed of that event and if it is a target thisEvent.trial_type = 'dummy'; - thisEvent.direction = expParameters.designDirections(iBlock, iEvent); - thisEvent.speed = expParameters.designSpeeds(iBlock, iEvent); - thisEvent.target = expParameters.designFixationTargets(iBlock, iEvent); + thisEvent.direction = cfg.design.directions(iBlock, iEvent); + thisEvent.speed = cfg.design.speeds(iBlock, iEvent); + thisEvent.target = cfg.design.fixationTargets(iBlock, iEvent); % play the dots and collect onset and duraton of the event - [onset, duration] = doDotMo(cfg, expParameters, thisEvent); + [onset, duration] = doDotMo(cfg, thisEvent); thisEvent.event = iEvent; thisEvent.block = iBlock; @@ -113,58 +114,58 @@ thisEvent.fileID = logFile.fileID; thisEvent.extraColumns = logFile.extraColumns; - saveEventsFile('save', expParameters, thisEvent); - + saveEventsFile('save', cfg, thisEvent); + clear thisEvent; % collect the responses and appends to the event structure for % saving in the tsv file - responseEvents = collectAndSaveResponses(cfg, logFile, experimentStart); - + responseEvents = collectAndSaveResponses(cfg, logFile, cfg.experimentStart); + responseEvents = getResponse('check', cfg.keyboard.responseBox, cfg, getOnlyPress); if isfield(responseEvents(1), 'onset') && ~isempty(responseEvents(1).onset) for iResp = 1:size(responseEvents, 1) - + responseEvents(iResp).event = iEvent; responseEvents(iResp).block = iBlock; end - saveEventsFile('save', expParameters, responseEvents); + saveEventsFile('save', cfg, responseEvents); end % wait for the inter-stimulus interval - WaitSecs(expParameters.ISI); + WaitSecs(cfg.ISI); getResponse('flush', cfg.keyboard.responseBox); end - eyeTracker('StopRecordings', cfg, expParameters); + eyeTracker('StopRecordings', cfg); - WaitSecs(expParameters.IBI); + WaitSecs(cfg.IBI); end % End of the run for the BOLD to go down - WaitSecs(expParameters.endDelay); + WaitSecs(cfg.endDelay); % Close the logfiles - saveEventsFile('close', expParameters, logFile); + saveEventsFile('close', cfg, logFile); getResponse('stop', cfg.keyboard.responseBox); getResponse('release', cfg.keyboard.responseBox); totalExperimentTime = GetSecs - cfg.experimentStart; - eyeTracker('Shutdown', cfg, expParameters); + eyeTracker('Shutdown', cfg); % save the whole workspace matFile = fullfile( ... - expParameters.outputDir, ... - strrep(expParameters.fileName.events, 'tsv', 'mat')); + cfg.dir.output, ... + strrep(cfg.fileName.events, 'tsv', 'mat')); if IsOctave save(matFile, '-mat7-binary'); else From b65cedc24c596a89fb3ee303f0e4118464e63d8f Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 29 Jul 2020 16:37:02 +0200 Subject: [PATCH 2/3] mh lint --- setParameters.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setParameters.m b/setParameters.m index 854a346..15094a1 100644 --- a/setParameters.m +++ b/setParameters.m @@ -49,7 +49,7 @@ % Number of events per block (should not be changed) cfg.numEventsPerBlock = 12; cfg.eventDuration = 1; % second - + % speed in visual angles cfg.dot.speed = 8; % Coherence Level (0-1) @@ -62,7 +62,7 @@ cfg.dot.size = 0.1; cfg.dot.color = cfg.color.white; cfg.dot.dontClear = 0; - + % Diameter/length of side of aperture in Visual angles cfg.diameterAperture = 8; From d24611fcfe399b5ce3fbfd329e6bbca9774efa16 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 29 Jul 2020 16:52:48 +0200 Subject: [PATCH 3/3] update submodules --- lib/CPP_BIDS | 2 +- lib/CPP_PTB | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/CPP_BIDS b/lib/CPP_BIDS index c1cd48c..b5e6c7a 160000 --- a/lib/CPP_BIDS +++ b/lib/CPP_BIDS @@ -1 +1 @@ -Subproject commit c1cd48c536f5f377d9a347e42280f7c2c79f6b51 +Subproject commit b5e6c7af678ec288bdfc6117ee52f1c82cabac84 diff --git a/lib/CPP_PTB b/lib/CPP_PTB index 241ef89..a7653ed 160000 --- a/lib/CPP_PTB +++ b/lib/CPP_PTB @@ -1 +1 @@ -Subproject commit 241ef89942fb92858dd572ed052d0b31934bd127 +Subproject commit a7653ed5055ea7ae591450d49804f074e6e76edd