From 26bf518bd7514496aa499bef377550fcccec340c Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 14 Sep 2020 09:50:13 +0200 Subject: [PATCH 01/19] refactor preTrialSetup --- subfun/doDotMo.m | 5 +---- subfun/preTrialSetup.m | 21 +++++++++++++++++++++ visualLocTranslational.m | 8 ++------ 3 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 subfun/preTrialSetup.m diff --git a/subfun/doDotMo.m b/subfun/doDotMo.m index 5978421..19f6f80 100644 --- a/subfun/doDotMo.m +++ b/subfun/doDotMo.m @@ -1,4 +1,4 @@ -function [onset, duration] = doDotMo(cfg, thisEvent) +function [onset, duration] = doDotMo(cfg, thisEvent, thisFixation) % Draws the stimulation of static/moving in 4 directions dots or static % % DIRECTIONS @@ -46,9 +46,6 @@ apertureTexture('draw', cfg, thisEvent); - % If this frame shows a target we change the color of the cross - thisFixation.fixation = cfg.fixation; - thisFixation.screen = cfg.screen; if thisEvent.target(1) && GetSecs < (onset + cfg.target.duration) thisFixation.fixation.color = cfg.fixation.colorTarget; end diff --git a/subfun/preTrialSetup.m b/subfun/preTrialSetup.m new file mode 100644 index 0000000..4a0e4a8 --- /dev/null +++ b/subfun/preTrialSetup.m @@ -0,0 +1,21 @@ +function varargout = preTrialSetup(varargin) + % varargout = postInitializatinSetup(varargin) + + % generic function to finalize some set up after psychtoolbox has been + % initialized + + [cfg, iBlock, iEvent] = deal(varargin{:}); + + % set direction, speed of that event and if it is a target + thisEvent.trial_type = cfg.design.blockNames{iBlock}; + thisEvent.direction = cfg.design.directions(iBlock, iEvent); + thisEvent.speed = cfg.design.speeds(iBlock, iEvent); + thisEvent.target = cfg.design.fixationTargets(iBlock, iEvent); + + % If this frame shows a target we change the color of the cross + thisFixation.fixation = cfg.fixation; + thisFixation.screen = cfg.screen; + + varargout = {thisEvent, thisFixation}; + +end \ No newline at end of file diff --git a/visualLocTranslational.m b/visualLocTranslational.m index 0951228..6954203 100644 --- a/visualLocTranslational.m +++ b/visualLocTranslational.m @@ -79,11 +79,7 @@ % 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 = cfg.design.blockNames{iBlock}; - thisEvent.direction = cfg.design.directions(iBlock, iEvent); - thisEvent.speed = cfg.design.speeds(iBlock, iEvent); - thisEvent.target = cfg.design.fixationTargets(iBlock, iEvent); + [thisEvent, thisFixation] = preTrialSetup(cfg, iBlock, iEvent); % we wait for a trigger every 2 events if cfg.pacedByTriggers.do && mod(iEvent, 2) == 1 @@ -95,7 +91,7 @@ end % play the dots and collect onset and duraton of the event - [onset, duration] = doDotMo(cfg, thisEvent); + [onset, duration] = doDotMo(cfg, thisEvent, thisFixation); thisEvent.event = iEvent; thisEvent.block = iBlock; From 698708ec01603f9336c48aa27b081bd5e474c55d Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 14 Sep 2020 10:49:47 +0200 Subject: [PATCH 02/19] factor out preSaveSetup --- subfun/preSaveSetup.m | 28 ++++++++++++++++++++++++++++ visualLocTranslational.m | 21 +-------------------- 2 files changed, 29 insertions(+), 20 deletions(-) create mode 100644 subfun/preSaveSetup.m diff --git a/subfun/preSaveSetup.m b/subfun/preSaveSetup.m new file mode 100644 index 0000000..4290ef8 --- /dev/null +++ b/subfun/preSaveSetup.m @@ -0,0 +1,28 @@ +function varargout = preSaveSetup(varargin) + % varargout = postInitializatinSetup(varargin) + + % generic function to prepare structures before saving + + [thisEvent, iBlock, iEvent, duration, onset, cfg, logFile] = deal(varargin{:}); + + thisEvent.event = iEvent; + thisEvent.block = iBlock; + thisEvent.keyName = 'n/a'; + thisEvent.duration = duration; + thisEvent.onset = onset - cfg.experimentStart; + + % % this value should be in degrees / second in the log file + % % highlights that the way speed is passed around could be + % % simplified. + % % + % thisEvent.speed + % % + + % Save the events txt logfile + % we save event by event so we clear this variable every loop + thisEvent.fileID = logFile.fileID; + thisEvent.extraColumns = logFile.extraColumns; + + varargout = thisEvent; + +end \ No newline at end of file diff --git a/visualLocTranslational.m b/visualLocTranslational.m index 6954203..ad9526b 100644 --- a/visualLocTranslational.m +++ b/visualLocTranslational.m @@ -93,28 +93,9 @@ % play the dots and collect onset and duraton of the event [onset, duration] = doDotMo(cfg, thisEvent, thisFixation); - thisEvent.event = iEvent; - thisEvent.block = iBlock; - thisEvent.keyName = 'n/a'; - thisEvent.duration = duration; - thisEvent.onset = onset - cfg.experimentStart; - - % % this value should be in degrees / second in the log file - % % highlights that the way speed is passed around could be - % % simplified. - % % - % thisEvent.speed - % % - - % Save the events txt logfile - % we save event by event so we clear this variable every loop - thisEvent.fileID = logFile.fileID; - thisEvent.extraColumns = logFile.extraColumns; - + thisEvent = preSaveSetup(thisEvent, iBlock, iEvent, duration, onset, cfg, logFile); saveEventsFile('save', cfg, thisEvent); - clear thisEvent; - % collect the responses and appends to the event structure for % saving in the tsv file responseEvents = getResponse('check', cfg.keyboard.responseBox, cfg, ... From 3a85ab7c0741d88f4f5f52b0140fd080360d91e6 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 14 Sep 2020 13:18:11 +0200 Subject: [PATCH 03/19] factor out getDesigInput --- subfun/expDesign.m | 12 +++--------- subfun/getDesignInput.m | 6 ++++++ 2 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 subfun/getDesignInput.m diff --git a/subfun/expDesign.m b/subfun/expDesign.m index 912915e..6f790b6 100644 --- a/subfun/expDesign.m +++ b/subfun/expDesign.m @@ -62,7 +62,7 @@ fprintf('\n\nCreating design.\n\n'); - [NB_BLOCKS, NB_REPETITIONS, NB_EVENTS_PER_BLOCK, MAX_TARGET_PER_BLOCK] = getInput(cfg); + [NB_BLOCKS, NB_REPETITIONS, NB_EVENTS_PER_BLOCK, MAX_TARGET_PER_BLOCK] = getDesignInput(cfg); [~, STATIC_INDEX, MOTION_INDEX] = assignConditions(cfg); if mod(NB_REPETITIONS, MAX_TARGET_PER_BLOCK) ~= 0 @@ -128,7 +128,7 @@ [MOTION_DIRECTIONS, STATIC_DIRECTIONS] = getDirectionBaseVectors(cfg); - [NB_BLOCKS, NB_REPETITIONS, NB_EVENTS_PER_BLOCK] = getInput(cfg); + [NB_BLOCKS, NB_REPETITIONS, NB_EVENTS_PER_BLOCK] = getDesignInput(cfg); [~, STATIC_INDEX, MOTION_INDEX] = assignConditions(cfg); @@ -169,16 +169,10 @@ end -function [nbBlocks, nbRepet, nbEventsBlock, maxTargBlock] = getInput(cfg) - nbRepet = cfg.design.nbRepetitions; - nbEventsBlock = cfg.design.nbEventsPerBlock; - maxTargBlock = cfg.target.maxNbPerBlock; - nbBlocks = length(cfg.design.names) * nbRepet; -end function [conditionNamesVector, STATIC_INDEX, MOTION_INDEX] = assignConditions(cfg) - [~, nbRepet] = getInput(cfg); + [~, nbRepet] = getDesignInput(cfg); conditionNamesVector = repmat(cfg.design.names, nbRepet, 1); diff --git a/subfun/getDesignInput.m b/subfun/getDesignInput.m new file mode 100644 index 0000000..2975944 --- /dev/null +++ b/subfun/getDesignInput.m @@ -0,0 +1,6 @@ +function [nbBlocks, nbRepet, nbEventsBlock, maxTargBlock] = getDesignInput(cfg) + nbRepet = cfg.design.nbRepetitions; + nbEventsBlock = cfg.design.nbEventsPerBlock; + maxTargBlock = cfg.target.maxNbPerBlock; + nbBlocks = length(cfg.design.names) * nbRepet; +end \ No newline at end of file From 67ee48dbe2826f769873f1dd7f7c7c8867d27f7e Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 14 Sep 2020 13:47:36 +0200 Subject: [PATCH 04/19] use preTrialSetup to prepare MT and MST trials --- subfun/preTrialSetup.m | 24 ++++++++++++++++++++---- visualLocTranslational.m | 2 +- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/subfun/preTrialSetup.m b/subfun/preTrialSetup.m index 4a0e4a8..382328c 100644 --- a/subfun/preTrialSetup.m +++ b/subfun/preTrialSetup.m @@ -1,8 +1,7 @@ function varargout = preTrialSetup(varargin) % varargout = postInitializatinSetup(varargin) - % generic function to finalize some set up after psychtoolbox has been - % initialized + % generic function to prepare some structure before each trial [cfg, iBlock, iEvent] = deal(varargin{:}); @@ -10,12 +9,29 @@ thisEvent.trial_type = cfg.design.blockNames{iBlock}; thisEvent.direction = cfg.design.directions(iBlock, iEvent); thisEvent.speed = cfg.design.speeds(iBlock, iEvent); - thisEvent.target = cfg.design.fixationTargets(iBlock, iEvent); + thisEvent.target = cfg.design.fixationTargets(iBlock, iEvent); % If this frame shows a target we change the color of the cross thisFixation.fixation = cfg.fixation; thisFixation.screen = cfg.screen; + + switch thisEvent.trial_type + case 'fixation_right' + cfg.aperture.xPosPix = -abs(cfg.aperture.xPosPix); + + thisFixation.fixation.xDisplacement = cfg.aperture.xPos; + thisFixation = initFixation(thisFixation); + + case 'fixation_left' + cfg.aperture.xPosPix = +abs(cfg.aperture.xPosPix); + + thisFixation.fixation.xDisplacement = -cfg.aperture.xPos; + thisFixation = initFixation(thisFixation); + + end + + varargout = {thisEvent, thisFixation, cfg}; + - varargout = {thisEvent, thisFixation}; end \ No newline at end of file diff --git a/visualLocTranslational.m b/visualLocTranslational.m index ad9526b..83c0f27 100644 --- a/visualLocTranslational.m +++ b/visualLocTranslational.m @@ -79,7 +79,7 @@ % Check for experiment abortion from operator checkAbort(cfg, cfg.keyboard.keyboard); - [thisEvent, thisFixation] = preTrialSetup(cfg, iBlock, iEvent); + [thisEvent, thisFixation, cfg] = preTrialSetup(cfg, iBlock, iEvent); % we wait for a trigger every 2 events if cfg.pacedByTriggers.do && mod(iEvent, 2) == 1 From 48afb0389d6b677004f8c1e8b1a57d169e871079 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 14 Sep 2020 13:49:01 +0200 Subject: [PATCH 05/19] prepare setParameters for MT and MST --- setParameters.m | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/setParameters.m b/setParameters.m index 6179c47..1a34af4 100644 --- a/setParameters.m +++ b/setParameters.m @@ -41,10 +41,15 @@ % cfg.design.motionType = 'translation'; % cfg.design.motionType = 'radial'; cfg.design.motionType = 'translation'; + cfg.design.motionDirections = [0 0 180 180]; cfg.design.names = {'static'; 'motion'}; cfg.design.nbRepetitions = 8; cfg.design.nbEventsPerBlock = 12; % DO NOT CHANGE + + if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') + cfg.design.names = {'fixation_right'; 'fixation_left'}; + end %% Timing @@ -103,6 +108,12 @@ cfg.aperture.type = 'none'; cfg.aperture.width = []; % if left empty it will take the screen height cfg.aperture.xPos = 0; + + if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') + cfg.aperture.type = 'circle'; + cfg.aperture.width = 3; % if left empty it will take the screen height + cfg.aperture.xPos = 4; + end %% Task(s) From cef527d769266fcdbba8100c06fb9c709656ee40 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 14 Sep 2020 13:58:34 +0200 Subject: [PATCH 06/19] update submodules to latest commit --- 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 962c947..7f276cb 160000 --- a/lib/CPP_BIDS +++ b/lib/CPP_BIDS @@ -1 +1 @@ -Subproject commit 962c947fe38094da9561eeba5daa44993505f2c0 +Subproject commit 7f276cbf9b6eb06b78bc00f7946485a501106679 diff --git a/lib/CPP_PTB b/lib/CPP_PTB index e7be247..c33ae7f 160000 --- a/lib/CPP_PTB +++ b/lib/CPP_PTB @@ -1 +1 @@ -Subproject commit e7be247a039cfe5ed95122d5045328f770023935 +Subproject commit c33ae7ffa7d8ffb7c0b6c92e3ffb7e2625b191cb From 760a10c6136fd5b097bfb138059342b62dc78cb5 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 14 Sep 2020 14:03:11 +0200 Subject: [PATCH 07/19] fix some varargout cell issues --- subfun/postInitializationSetup.m | 2 +- subfun/preSaveSetup.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/subfun/postInitializationSetup.m b/subfun/postInitializationSetup.m index 1bbaa4e..000de7a 100644 --- a/subfun/postInitializationSetup.m +++ b/subfun/postInitializationSetup.m @@ -22,6 +22,6 @@ cfg.dot.number = round(cfg.dot.density * ... (cfg.dot.matrixWidth / cfg.screen.ppd)^2); - varargout = cfg; + varargout = {cfg}; end diff --git a/subfun/preSaveSetup.m b/subfun/preSaveSetup.m index 4290ef8..db50015 100644 --- a/subfun/preSaveSetup.m +++ b/subfun/preSaveSetup.m @@ -23,6 +23,6 @@ thisEvent.fileID = logFile.fileID; thisEvent.extraColumns = logFile.extraColumns; - varargout = thisEvent; + varargout = {thisEvent}; end \ No newline at end of file From 12bbbac6801e5a1549517772237fc1f9be996b6f Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 14 Sep 2020 14:03:45 +0200 Subject: [PATCH 08/19] add some placeholder READMEs --- docs/README.md | 1 + lib/README.md | 1 + subfun/doDotMo.m | 4 +++- tests/README.md | 5 +++++ 4 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 docs/README.md create mode 100644 lib/README.md create mode 100644 tests/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..7d8b3af --- /dev/null +++ b/docs/README.md @@ -0,0 +1 @@ +# Documentation \ No newline at end of file diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 0000000..ca16653 --- /dev/null +++ b/lib/README.md @@ -0,0 +1 @@ +# External libraries and dependencies \ No newline at end of file diff --git a/subfun/doDotMo.m b/subfun/doDotMo.m index 19f6f80..f165ec7 100644 --- a/subfun/doDotMo.m +++ b/subfun/doDotMo.m @@ -30,12 +30,14 @@ [dots] = updateDots(dots, cfg); %% Center the dots + % We assumed that zero is at the top left, but we want it to be % in the center, so shift the dots up and left, which just means - % adding half of the screen width in pixel to both the x and y direction. + % adding half of the screen width in pixel to both the x and y direction. thisEvent.dot.positions = (dots.positions - cfg.dot.matrixWidth / 2)'; %% make textures + dotTexture('make', cfg, thisEvent); apertureTexture('make', cfg, thisEvent); diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..da470b5 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,5 @@ +# Unit tests folder + +To be run using mox unit. + +Code coverage can be estimated with Mocov. \ No newline at end of file From 4bbb574204d47685c8e8426a216cac173c604d9e Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 14 Sep 2020 14:24:17 +0200 Subject: [PATCH 09/19] fix bugs for basic run of MT / MST localizer --- lib/CPP_BIDS | 2 +- lib/CPP_PTB | 2 +- setParameters.m | 8 +- subfun/doDotMo.m | 2 +- subfun/expDesignMtMst.m | 172 +++++++++++++++++++++++++++++++++++++++ visualLocTranslational.m | 6 +- 6 files changed, 185 insertions(+), 7 deletions(-) create mode 100644 subfun/expDesignMtMst.m diff --git a/lib/CPP_BIDS b/lib/CPP_BIDS index 7f276cb..bfa76ac 160000 --- a/lib/CPP_BIDS +++ b/lib/CPP_BIDS @@ -1 +1 @@ -Subproject commit 7f276cbf9b6eb06b78bc00f7946485a501106679 +Subproject commit bfa76acd7ad6796dbe2d353a097c9c1db94cade9 diff --git a/lib/CPP_PTB b/lib/CPP_PTB index c33ae7f..a8d5558 160000 --- a/lib/CPP_PTB +++ b/lib/CPP_PTB @@ -1 +1 @@ -Subproject commit c33ae7ffa7d8ffb7c0b6c92e3ffb7e2625b191cb +Subproject commit a8d5558b1bf12127d4b3116a337cd673bc2df652 diff --git a/setParameters.m b/setParameters.m index 1a34af4..ba57474 100644 --- a/setParameters.m +++ b/setParameters.m @@ -37,6 +37,8 @@ cfg.pacedByTriggers.do = true; %% Experiment Design + + cfg.design.localizer = 'MT_MST'; % cfg.design.motionType = 'translation'; % cfg.design.motionType = 'radial'; @@ -111,8 +113,8 @@ if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') cfg.aperture.type = 'circle'; - cfg.aperture.width = 3; % if left empty it will take the screen height - cfg.aperture.xPos = 4; + cfg.aperture.width = 7; % if left empty it will take the screen height + cfg.aperture.xPos = 7; end %% Task(s) @@ -126,7 +128,7 @@ cfg.fixation.type = 'cross'; cfg.fixation.colorTarget = cfg.color.red; cfg.fixation.color = cfg.color.white; - cfg.fixation.width = .5; + cfg.fixation.width = .25; cfg.fixation.lineWidthPix = 3; cfg.fixation.xDisplacement = 0; cfg.fixation.yDisplacement = 0; diff --git a/subfun/doDotMo.m b/subfun/doDotMo.m index f165ec7..6aa1713 100644 --- a/subfun/doDotMo.m +++ b/subfun/doDotMo.m @@ -66,7 +66,7 @@ %% Erase last dots - drawFixation(cfg); + drawFixation(thisFixation); Screen('DrawingFinished', cfg.screen.win); diff --git a/subfun/expDesignMtMst.m b/subfun/expDesignMtMst.m new file mode 100644 index 0000000..53476db --- /dev/null +++ b/subfun/expDesignMtMst.m @@ -0,0 +1,172 @@ +function [cfg] = expDesignMtMst(cfg) + % Creates the sequence of blocks and the events in them + % + % The conditions are consecutive static and motion blocks + % (Gives better results than randomised). + % + % Style guide: constants are in SNAKE_UPPER_CASE + % + % EVENTS + % The numEventsPerBlock should be a multiple of the number of "base" + % listed in the MOTION_DIRECTIONS and STATIC_DIRECTIONS (4 at the moment). + % MOTION_DIRECTIONS = [0 90 180 270]; + % + % Pseudorandomization rules: + % (1) Directions are all present in random orders in `numEventsPerBlock/nDirections` + % consecutive chunks. This evenly distribute the directions across the + % block. + % (2) No same consecutive direction + % + % + % TARGETS + % + % Pseudorandomization rules: + % (1) If there are more than 1 target per block we make sure that they are at least 2 + % events apart. + % (2) Targets cannot be on the first or last event of a block. + % (3) Targets can not be present more than NB_REPETITIONS - 1 times in the same event + % position across blocks. + % + % Input: + % - cfg: parameters returned by setParameters + % - displayFigs: a boolean to decide whether to show the basic design + % matrix of the design + % + % Output: + % - ExpParameters.designBlockNames = cell array (nr_blocks, 1) with the + % name for each block + % + % - cfg.designDirections = array (nr_blocks, numEventsPerBlock) + % with the direction to present in a given block + % - 0 90 180 270 indicate the angle + % - -1 indicates static + % + % - cfg.designSpeeds = array (nr_blocks, numEventsPerBlock) * speedEvent; + % + % - cfg.designFixationTargets = array (nr_blocks, numEventsPerBlock) + % showing for each event if it should be accompanied by a target + % + + %% Check inputs + + % Set variables here for a dummy test of this function + if nargin < 1 || isempty(cfg) + error('give me something to work with'); + end + + fprintf('\n\nCreating design.\n\n'); + + [NB_BLOCKS, NB_REPETITIONS, NB_EVENTS_PER_BLOCK, MAX_TARGET_PER_BLOCK] = ... + getDesignInput(cfg); + [~, FIX_RIGHT_INDEX, FIX_LEFT_INDEX] = assignConditions(cfg); + + if mod(NB_REPETITIONS, MAX_TARGET_PER_BLOCK) ~= 0 + error('number of repetitions must be a multiple of max number of targets'); + end + + RANGE_TARGETS = 1:MAX_TARGET_PER_BLOCK; + targetPerCondition = repmat(RANGE_TARGETS, 1, NB_REPETITIONS / MAX_TARGET_PER_BLOCK); + + numTargetsForEachBlock = zeros(1, NB_BLOCKS); + numTargetsForEachBlock(FIX_RIGHT_INDEX) = shuffle(targetPerCondition); + numTargetsForEachBlock(FIX_LEFT_INDEX) = shuffle(targetPerCondition); + + %% Give the blocks the names with condition and design the task in each event + while 1 + + fixationTargets = zeros(NB_BLOCKS, NB_EVENTS_PER_BLOCK); + + for iBlock = 1:NB_BLOCKS + + % Set target + % - if there are 2 targets per block we make sure that they are at least + % 2 events apart + % - targets cannot be on the first or last event of a block + % - no more than 2 target in the same event order + + nbTarget = numTargetsForEachBlock(iBlock); + + chosenPosition = setTargetPositionInSequence( ... + NB_EVENTS_PER_BLOCK, ... + nbTarget, ... + [1 NB_EVENTS_PER_BLOCK]); + + fixationTargets(iBlock, chosenPosition) = 1; + + end + + % Check rule 3 + if max(sum(fixationTargets)) < NB_REPETITIONS - 1 + break + end + + end + + %% Now we do the easy stuff + cfg.design.blockNames = assignConditions(cfg); + + cfg.design.nbBlocks = NB_BLOCKS; + + cfg = setDirections(cfg); + + speeds = ones(NB_BLOCKS, NB_EVENTS_PER_BLOCK) * cfg.dot.speedPixPerFrame; + cfg.design.speeds = speeds; + + cfg.design.fixationTargets = fixationTargets; + +end + +function cfg = setDirections(cfg) + + [FIX_RIGHT_DIRECTIONS, FIX_LEFT_DIRECTIONS] = getDirectionBaseVectors(cfg); + + [NB_BLOCKS, NB_REPETITIONS, NB_EVENTS_PER_BLOCK] = getDesignInput(cfg); + + [~, FIX_RIGHT_INDEX, FIX_LEFT_INDEX] = assignConditions(cfg); + + if mod(NB_EVENTS_PER_BLOCK, length(FIX_RIGHT_DIRECTIONS)) ~= 0 + error('Number of events/block not a multiple of number of motion/static direction'); + end + + % initialize + directions = zeros(NB_BLOCKS, NB_EVENTS_PER_BLOCK); + + % Create a vector for the static condition + NB_REPEATS_BASE_VECTOR = NB_EVENTS_PER_BLOCK / length(FIX_LEFT_DIRECTIONS); + + for iMotionBlock = 1:NB_REPETITIONS + + % Set motion direction and static order + directions(FIX_LEFT_INDEX(iMotionBlock), :) = ... + repeatShuffleConditions(FIX_LEFT_DIRECTIONS, NB_REPEATS_BASE_VECTOR); + + directions(FIX_RIGHT_INDEX(iMotionBlock), :) = ... + repeatShuffleConditions(FIX_RIGHT_DIRECTIONS, NB_REPEATS_BASE_VECTOR); + + end + + cfg.design.directions = directions; + +end + +function [FIX_RIGHT_DIRECTIONS, FIX_LEFT_DIRECTIONS] = getDirectionBaseVectors(cfg) + + % CONSTANTS + % Set directions for both blocks condition + + FIX_RIGHT_DIRECTIONS = cfg.design.motionDirections; + FIX_LEFT_DIRECTIONS = cfg.design.motionDirections; + +end + +function [conditionNamesVector, FIX_RIGHT_INDEX, FIX_LEFT_INDEX] = assignConditions(cfg) + + [~, nbRepet] = getDesignInput(cfg); + + conditionNamesVector = repmat(cfg.design.names, nbRepet, 1); + + % Get the index of each condition + FIX_RIGHT_INDEX = find(strcmp(conditionNamesVector, 'fixation_right')); + FIX_LEFT_INDEX = find(strcmp(conditionNamesVector, 'fixation_left')); + +end \ No newline at end of file diff --git a/visualLocTranslational.m b/visualLocTranslational.m index 83c0f27..fbc6b04 100644 --- a/visualLocTranslational.m +++ b/visualLocTranslational.m @@ -37,7 +37,11 @@ [el] = eyeTracker('Calibration', cfg); - [cfg] = expDesign(cfg); + if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') + [cfg] = expDesignMtMst(cfg); + else + [cfg] = expDesign(cfg); + end % Prepare for the output logfiles with all logFile.extraColumns = cfg.extraColumns; From 9d99a1b06de84dc74a312da6512f15665ccb96f8 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 14 Sep 2020 15:11:26 +0200 Subject: [PATCH 10/19] force drawing fixation cross for baseline --- setParameters.m | 21 +++++++++++++++------ visualLocTranslational.m | 11 +++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/setParameters.m b/setParameters.m index ba57474..3f93d53 100644 --- a/setParameters.m +++ b/setParameters.m @@ -71,15 +71,19 @@ cfg.timing.onsetDelay = 0; % Number of seconds after the end all the stimuli before ending the run cfg.timing.endDelay = 3.6; - + + if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') + cfg.timing.IBI = 3.6; + end + % reexpress those in terms of repetition time if cfg.pacedByTriggers.do - + cfg.pacedByTriggers.quietMode = true; cfg.pacedByTriggers.nbTriggers = 1; - + cfg.timing.eventDuration = cfg.mri.repetitionTime / 2 - 0.04; % second - + % Time between blocs in secs cfg.timing.IBI = 0; % Time between events in secs @@ -88,10 +92,15 @@ cfg.timing.onsetDelay = 0; % Number of seconds after the end all the stimuli before ending the run cfg.timing.endDelay = 2; + + if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') + cfg.timing.IBI = 2; + end + end - + %% Visual Stimulation - + % Speed in visual angles / second cfg.dot.speed = 15; % Coherence Level (0-1) diff --git a/visualLocTranslational.m b/visualLocTranslational.m index fbc6b04..32743ef 100644 --- a/visualLocTranslational.m +++ b/visualLocTranslational.m @@ -113,6 +113,17 @@ end eyeTracker('StopRecordings', cfg); + + % "prepare" cross for the baseline block + % if MT / MST this allows us to set the cross at the position of the next block + if iBlock < cfg.design.nbBlocks + nextBlock = iBlock+1; + else + nextBlock = cfg.design.nbBlocks; + end + [~, thisFixation] = preTrialSetup(cfg, nextBlock, 1); + drawFixation(thisFixation); + Screen('Flip', cfg.screen.win); waitFor(cfg, cfg.timing.IBI); From 58a59b1319baab4fdb315e3db4d3a409619c6c46 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 14 Sep 2020 15:24:47 +0200 Subject: [PATCH 11/19] mh fix --- lib/CPP_PTB | 2 +- setParameters.m | 22 +++++++++++----------- subfun/doDotMo.m | 6 +++--- subfun/expDesign.m | 1 - subfun/expDesignMtMst.m | 2 +- subfun/getDesignInput.m | 2 +- subfun/preSaveSetup.m | 16 ++++++++-------- subfun/preTrialSetup.m | 18 ++++++++---------- visualLocTranslational.m | 4 ++-- 9 files changed, 35 insertions(+), 38 deletions(-) diff --git a/lib/CPP_PTB b/lib/CPP_PTB index a8d5558..f0a8024 160000 --- a/lib/CPP_PTB +++ b/lib/CPP_PTB @@ -1 +1 @@ -Subproject commit a8d5558b1bf12127d4b3116a337cd673bc2df652 +Subproject commit f0a80248eed772f8f787b049c3ac9d1bcb620d50 diff --git a/setParameters.m b/setParameters.m index 3f93d53..b632374 100644 --- a/setParameters.m +++ b/setParameters.m @@ -71,19 +71,19 @@ cfg.timing.onsetDelay = 0; % Number of seconds after the end all the stimuli before ending the run cfg.timing.endDelay = 3.6; - + if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') cfg.timing.IBI = 3.6; end - + % reexpress those in terms of repetition time if cfg.pacedByTriggers.do - + cfg.pacedByTriggers.quietMode = true; cfg.pacedByTriggers.nbTriggers = 1; - + cfg.timing.eventDuration = cfg.mri.repetitionTime / 2 - 0.04; % second - + % Time between blocs in secs cfg.timing.IBI = 0; % Time between events in secs @@ -92,15 +92,15 @@ cfg.timing.onsetDelay = 0; % Number of seconds after the end all the stimuli before ending the run cfg.timing.endDelay = 2; - + if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') cfg.timing.IBI = 2; end - + end - + %% Visual Stimulation - + % Speed in visual angles / second cfg.dot.speed = 15; % Coherence Level (0-1) @@ -112,14 +112,14 @@ % proportion of dots killed per frame cfg.dot.proportionKilledPerFrame = 0; % Dot Size (dot width) in visual angles. - cfg.dot.size = .1; + cfg.dot.size = .2; cfg.dot.color = cfg.color.white; % Diameter/length of side of aperture in Visual angles cfg.aperture.type = 'none'; cfg.aperture.width = []; % if left empty it will take the screen height cfg.aperture.xPos = 0; - + if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') cfg.aperture.type = 'circle'; cfg.aperture.width = 7; % if left empty it will take the screen height diff --git a/subfun/doDotMo.m b/subfun/doDotMo.m index 6aa1713..72e54c7 100644 --- a/subfun/doDotMo.m +++ b/subfun/doDotMo.m @@ -30,14 +30,14 @@ [dots] = updateDots(dots, cfg); %% Center the dots - + % We assumed that zero is at the top left, but we want it to be % in the center, so shift the dots up and left, which just means - % adding half of the screen width in pixel to both the x and y direction. + % adding half of the screen width in pixel to both the x and y direction. thisEvent.dot.positions = (dots.positions - cfg.dot.matrixWidth / 2)'; %% make textures - + dotTexture('make', cfg, thisEvent); apertureTexture('make', cfg, thisEvent); diff --git a/subfun/expDesign.m b/subfun/expDesign.m index 6f790b6..95e18af 100644 --- a/subfun/expDesign.m +++ b/subfun/expDesign.m @@ -169,7 +169,6 @@ end - function [conditionNamesVector, STATIC_INDEX, MOTION_INDEX] = assignConditions(cfg) [~, nbRepet] = getDesignInput(cfg); diff --git a/subfun/expDesignMtMst.m b/subfun/expDesignMtMst.m index 53476db..3332a88 100644 --- a/subfun/expDesignMtMst.m +++ b/subfun/expDesignMtMst.m @@ -169,4 +169,4 @@ FIX_RIGHT_INDEX = find(strcmp(conditionNamesVector, 'fixation_right')); FIX_LEFT_INDEX = find(strcmp(conditionNamesVector, 'fixation_left')); -end \ No newline at end of file +end diff --git a/subfun/getDesignInput.m b/subfun/getDesignInput.m index 2975944..01310ad 100644 --- a/subfun/getDesignInput.m +++ b/subfun/getDesignInput.m @@ -3,4 +3,4 @@ nbEventsBlock = cfg.design.nbEventsPerBlock; maxTargBlock = cfg.target.maxNbPerBlock; nbBlocks = length(cfg.design.names) * nbRepet; -end \ No newline at end of file +end diff --git a/subfun/preSaveSetup.m b/subfun/preSaveSetup.m index db50015..3788d21 100644 --- a/subfun/preSaveSetup.m +++ b/subfun/preSaveSetup.m @@ -1,28 +1,28 @@ function varargout = preSaveSetup(varargin) % varargout = postInitializatinSetup(varargin) - + % generic function to prepare structures before saving - + [thisEvent, iBlock, iEvent, duration, onset, cfg, logFile] = deal(varargin{:}); - + thisEvent.event = iEvent; thisEvent.block = iBlock; thisEvent.keyName = 'n/a'; thisEvent.duration = duration; thisEvent.onset = onset - cfg.experimentStart; - + % % this value should be in degrees / second in the log file % % highlights that the way speed is passed around could be % % simplified. % % % thisEvent.speed % % - + % Save the events txt logfile % we save event by event so we clear this variable every loop thisEvent.fileID = logFile.fileID; thisEvent.extraColumns = logFile.extraColumns; - + varargout = {thisEvent}; - -end \ No newline at end of file + +end diff --git a/subfun/preTrialSetup.m b/subfun/preTrialSetup.m index 382328c..852a511 100644 --- a/subfun/preTrialSetup.m +++ b/subfun/preTrialSetup.m @@ -9,29 +9,27 @@ thisEvent.trial_type = cfg.design.blockNames{iBlock}; thisEvent.direction = cfg.design.directions(iBlock, iEvent); thisEvent.speed = cfg.design.speeds(iBlock, iEvent); - thisEvent.target = cfg.design.fixationTargets(iBlock, iEvent); - + thisEvent.target = cfg.design.fixationTargets(iBlock, iEvent); + % If this frame shows a target we change the color of the cross thisFixation.fixation = cfg.fixation; thisFixation.screen = cfg.screen; - + switch thisEvent.trial_type case 'fixation_right' cfg.aperture.xPosPix = -abs(cfg.aperture.xPosPix); - + thisFixation.fixation.xDisplacement = cfg.aperture.xPos; thisFixation = initFixation(thisFixation); - + case 'fixation_left' cfg.aperture.xPosPix = +abs(cfg.aperture.xPosPix); - + thisFixation.fixation.xDisplacement = -cfg.aperture.xPos; thisFixation = initFixation(thisFixation); - + end varargout = {thisEvent, thisFixation, cfg}; - - -end \ No newline at end of file +end diff --git a/visualLocTranslational.m b/visualLocTranslational.m index 32743ef..20b6327 100644 --- a/visualLocTranslational.m +++ b/visualLocTranslational.m @@ -113,11 +113,11 @@ end eyeTracker('StopRecordings', cfg); - + % "prepare" cross for the baseline block % if MT / MST this allows us to set the cross at the position of the next block if iBlock < cfg.design.nbBlocks - nextBlock = iBlock+1; + nextBlock = iBlock + 1; else nextBlock = cfg.design.nbBlocks; end From 42753f1c740b4d49049d756f54f3319ac698e623 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 14 Sep 2020 15:30:00 +0200 Subject: [PATCH 12/19] mh fix --- setParameters.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setParameters.m b/setParameters.m index b632374..9b87b6a 100644 --- a/setParameters.m +++ b/setParameters.m @@ -37,18 +37,18 @@ cfg.pacedByTriggers.do = true; %% Experiment Design - + cfg.design.localizer = 'MT_MST'; % cfg.design.motionType = 'translation'; % cfg.design.motionType = 'radial'; cfg.design.motionType = 'translation'; - + cfg.design.motionDirections = [0 0 180 180]; cfg.design.names = {'static'; 'motion'}; cfg.design.nbRepetitions = 8; cfg.design.nbEventsPerBlock = 12; % DO NOT CHANGE - + if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') cfg.design.names = {'fixation_right'; 'fixation_left'}; end From 674fd7c5522c0b76ee11e5d5c89cb8aac9dbb437 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 14 Sep 2020 15:44:13 +0200 Subject: [PATCH 13/19] update README --- README.md | 67 ++++++++++++++++++++++++++----------------------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 44a5abf..4691521 100644 --- a/README.md +++ b/README.md @@ -5,33 +5,30 @@ [![Build Status](https://travis-ci.com/cpp-lln-lab/localizer_visual_motion.svg?branch=master)](https://travis-ci.com/cpp-lln-lab/localizer_visual_motion) - - -- 1. [Requirements](#Requirements) -- 2. [Installation](#Installation) -- 3. [Structure and function details](#Structureandfunctiondetails) - _ 3.1. [visualLocTranslational](#visualLocTranslational) - _ 3.2. [setParameters](#setParameters) - _ 3.3. [subfun/doDotMo](#subfundoDotMo) - _ 3.3.1. [Input:](#Input:) - _ 3.3.2. [Output:](#Output:) - _ 3.4. [subfun/expDesign](#subfunexpDesign) - _ 3.4.1. [EVENTS](#EVENTS) - _ 3.4.2. [TARGETS:](#TARGETS:) - _ 3.4.3. [Input:](#Input:-1) - _ 3.4.4. [Output:](#Output:-1) - - - + +- [fMRI localizers for visual motion](#fmri-localizers-for-visual-motion) + - [Translational Motion](#translational-motion) + - [Requirements](#requirements) + - [Installation](#installation) + - [Structure and function details](#structure-and-function-details) + - [visualLocTranslational](#visualloctranslational) + - [setParameters](#setparameters) + - [Let the scanner pace the experiment](#let-the-scanner-pace-the-experiment) + - [subfun/doDotMo](#subfundodotmo) + - [Input](#input) + - [Output](#output) + - [subfun/expDesign](#subfunexpdesign) + - [EVENTS](#events) + - [TARGETS](#targets) + - [Input](#input-1) + - [Output](#output-1) + # fMRI localizers for visual motion -# Translational Motion +## Translational Motion -## 1. Requirements +## Requirements Make sure that the following toolboxes are installed and added to the matlab / octave path. @@ -45,7 +42,7 @@ For instructions see the following links: | [Matlab](https://www.mathworks.com/products/matlab.html) | >=2017 | | or [octave](https://www.gnu.org/software/octave/) | >=4.? | -## 2. Installation +## Installation The CPP_BIDS and CPP_PTB dependencies are already set up as submodule to this repository. You can install it all with git by doing. @@ -54,9 +51,9 @@ You can install it all with git by doing. git clone --recurse-submodules https://github.com/cpp-lln-lab/localizer_visual_motion.git ``` -## 3. Structure and function details +## Structure and function details -### 3.1. visualLocTranslational +### visualLocTranslational Running this script will show blocks of motion dots (soon also moving gratings) and static dots. Motion blocks will show dots(/gratings) moving in one of four directions (up-, down-, left-, and right-ward) @@ -64,7 +61,7 @@ By default it is run in `Debug mode` meaning that it does not run care about sub Any details of the experiment can be changed in `setParameters.m` (e.g., experiment mode, motion stimuli details, exp. design, etc.) -### 3.2. setParameters +### setParameters `setParameters.m` is the core engine of the experiment. It contains the following tweakable sections: @@ -105,40 +102,40 @@ if cfg.pacedByTriggers.do end ``` -### 3.3. subfun/doDotMo +### subfun/doDotMo -#### 3.3.1. Input: +#### Input - `cfg`: PTB/machine configurations returned by `setParameters` and `initPTB` - `expParameters`: parameters returned by `setParameters` - `logFile`: structure that stores the experiment logfile to be saved -#### 3.3.2. Output: +#### Output - Event `onset` - Event `duration` The dots are drawn on a square that contains the round aperture, then any dots outside of the aperture is turned into a NaN so effectively the actual number of dots on the screen at any given time is not the one that you input but a smaller number (nDots / Area of aperture) on average. -### 3.4. subfun/expDesign +### subfun/expDesign Creates the sequence of blocks and the events in them. The conditions are consecutive static and motion blocks (Gives better results than randomised). It can be run as a stand alone without inputs to display a visual example of possible design. -#### 3.4.1. EVENTS +#### EVENTS The `numEventsPerBlock` should be a multiple of the number of "base" listed in the `motionDirections` and `staticDirections` (4 at the moment). -#### 3.4.2. TARGETS: +#### TARGETS - If there are 2 targets per block we make sure that they are at least 2 events apart. - Targets cannot be on the first or last event of a block -#### 3.4.3. Input: +#### Input - `expParameters`: parameters returned by `setParameters` - `displayFigs`: a boolean to decide whether to show the basic design matrix of the design -#### 3.4.4. Output: +#### Output - `expParameters.designBlockNames` is a cell array `(nr_blocks, 1)` with the name for each block - `expParameters.designDirections` is an array `(nr_blocks, numEventsPerBlock)` with the direction to present in a given block From f8d34139714e46e698e6472d3d3ec1fc3aab5cec Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 14 Sep 2020 15:49:27 +0200 Subject: [PATCH 14/19] add task name to setParameters --- setParameters.m | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/setParameters.m b/setParameters.m index 9b87b6a..5e66d5b 100644 --- a/setParameters.m +++ b/setParameters.m @@ -16,14 +16,14 @@ cfg.debug.do = false; % 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 = false; % To test with trasparent full size screen + cfg.debug.transpWin = true; % To test with trasparent full size screen cfg.verbose = false; %% Engine parameters cfg.testingDevice = 'mri'; - cfg.eyeTracker.do = true; + cfg.eyeTracker.do = false; cfg.audio.do = false; cfg = setMonitor(cfg); @@ -34,7 +34,7 @@ % MRI settings cfg = setMRI(cfg); - cfg.pacedByTriggers.do = true; + cfg.pacedByTriggers.do = false; %% Experiment Design @@ -129,6 +129,9 @@ %% Task(s) cfg.task.name = 'visual localizer'; + if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') + cfg.task.name = 'mt mst localizer'; + end % Instruction cfg.task.instruction = '1-Detect the RED fixation cross\n \n\n'; @@ -167,7 +170,7 @@ function cfg = setMRI(cfg) % letter sent by the trigger to sync stimulation and volume acquisition cfg.mri.triggerKey = 't'; - cfg.mri.triggerNb = 5; + cfg.mri.triggerNb = 1; cfg.mri.repetitionTime = 1.8; From 10b7afd09cd19a0dca54d558ddbbccfe56fa517b Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 23 Sep 2020 10:50:28 +0200 Subject: [PATCH 15/19] make log collect information about cross and aperture position --- setParameters.m | 12 ++++++++++-- subfun/preSaveSetup.m | 5 ++++- visualLocTranslational.m | 8 +++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/setParameters.m b/setParameters.m index 5e66d5b..f8b544d 100644 --- a/setParameters.m +++ b/setParameters.m @@ -148,7 +148,15 @@ cfg.target.maxNbPerBlock = 1; cfg.target.duration = 0.05; % In secs - cfg.extraColumns = {'direction', 'speed', 'target', 'event', 'block', 'keyName'}; + cfg.extraColumns = { ... + 'direction', ... + 'speed', ... + 'target', ... + 'event', ... + 'block', ... + 'keyName', ... + 'fixationPosition', ... + 'aperturePosition'}; end @@ -157,7 +165,7 @@ cfg.keyboard.responseKey = { ... 'r', 'g', 'y', 'b', ... 'd', 'n', 'z', 'e', ... - 't'}; % dnze rgyb + 't'}; cfg.keyboard.keyboard = []; cfg.keyboard.responseBox = []; diff --git a/subfun/preSaveSetup.m b/subfun/preSaveSetup.m index 3788d21..f7b71f4 100644 --- a/subfun/preSaveSetup.m +++ b/subfun/preSaveSetup.m @@ -3,13 +3,16 @@ % generic function to prepare structures before saving - [thisEvent, iBlock, iEvent, duration, onset, cfg, logFile] = deal(varargin{:}); + [thisEvent, thisFixation, iBlock, iEvent, duration, onset, cfg, logFile] = ... + deal(varargin{:}); thisEvent.event = iEvent; thisEvent.block = iBlock; thisEvent.keyName = 'n/a'; thisEvent.duration = duration; thisEvent.onset = onset - cfg.experimentStart; + thisEvent.fixationPosition = thisFixation.fixation.xDisplacement; + thisEvent.aperturePosition = cfg.aperture.xPos * sign(cfg.aperture.xPosPix); % % this value should be in degrees / second in the log file % % highlights that the way speed is passed around could be diff --git a/visualLocTranslational.m b/visualLocTranslational.m index 20b6327..733dbe0 100644 --- a/visualLocTranslational.m +++ b/visualLocTranslational.m @@ -97,7 +97,13 @@ % play the dots and collect onset and duraton of the event [onset, duration] = doDotMo(cfg, thisEvent, thisFixation); - thisEvent = preSaveSetup(thisEvent, iBlock, iEvent, duration, onset, cfg, logFile); + thisEvent = preSaveSetup( ... + thisEvent, ... + thisFixation, ... + iBlock, iEvent, ... + duration, onset, ... + cfg, ... + logFile); saveEventsFile('save', cfg, thisEvent); % collect the responses and appends to the event structure for From 1fe86ef52f98b272d878ba318fed45588f3f9b1f Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 23 Sep 2020 12:16:09 +0200 Subject: [PATCH 16/19] add copyright --- initEnv.m | 31 ++++++++++++++++--------------- miss_hit.cfg | 4 +++- setParameters.m | 2 ++ subfun/doDotMo.m | 3 +++ subfun/expDesign.m | 2 ++ subfun/expDesignMtMst.m | 2 ++ subfun/getDesignInput.m | 2 ++ subfun/postInitializationSetup.m | 2 ++ subfun/preSaveSetup.m | 2 ++ subfun/preTrialSetup.m | 2 ++ visualLocTranslational.m | 11 ++++------- 11 files changed, 40 insertions(+), 23 deletions(-) diff --git a/initEnv.m b/initEnv.m index bf4ec9c..9880ce2 100644 --- a/initEnv.m +++ b/initEnv.m @@ -1,18 +1,19 @@ -% -% 1 - Check if version requirements -% are satisfied and the packages are -% are installed/loaded: -% Octave > 4 -% - image -% - optim -% - struct -% - statistics -% -% MATLAB >= R2015b -% -% 2 - Add project to the O/M path +% (C) Copyright 2020 Agah Karakuzu +% (C) Copyright 2019 CPP BIDS SPM-pipeline developpers function initEnv + % 1 - Check if version requirements + % are satisfied and the packages are + % are installed/loaded: + % Octave > 4 + % - image + % - optim + % - struct + % - statistics + % + % MATLAB >= R2015b + % + % 2 - Add project to the O/M path octaveVersion = '4.0.3'; matlabVersion = '8.6.0'; @@ -56,8 +57,8 @@ if numel(dir(libDirectory)) <= 2 % Means that the external is empty error(['Git submodules are not cloned!', ... - 'Try this in your terminal:', ... - ' git submodule update --recursive ']); + 'Try this in your terminal:', ... + ' git submodule update --recursive ']); else addDependencies(); end diff --git a/miss_hit.cfg b/miss_hit.cfg index 5a5f311..df98a43 100644 --- a/miss_hit.cfg +++ b/miss_hit.cfg @@ -1,8 +1,10 @@ # style guide (https://florianschanda.github.io/miss_hit/style_checker.html) line_length: 100 regex_function_name: "[a-z]+(([A-Z]){1}[A-Za-z]+)*" -suppress_rule: "copyright_notice" exclude_dir: "lib" +copyright_entity: "Mohamed Rezk" +copyright_entity: "Agah Karakuzu" +copyright_entity: "CPP visual motion localizer developpers" # metrics limit for the code quality (https://florianschanda.github.io/miss_hit/metrics.html) metric "cnest": limit 4 diff --git a/setParameters.m b/setParameters.m index f8b544d..027d28e 100644 --- a/setParameters.m +++ b/setParameters.m @@ -1,3 +1,5 @@ +% (C) Copyright 2020 CPP visual motion localizer developpers + function [cfg] = setParameters() % VISUAL LOCALIZER diff --git a/subfun/doDotMo.m b/subfun/doDotMo.m index 72e54c7..4a4a312 100644 --- a/subfun/doDotMo.m +++ b/subfun/doDotMo.m @@ -1,3 +1,6 @@ +% (C) Copyright 2018 Mohamed Rezk +% (C) Copyright 2020 CPP visual motion localizer developpers + function [onset, duration] = doDotMo(cfg, thisEvent, thisFixation) % Draws the stimulation of static/moving in 4 directions dots or static % diff --git a/subfun/expDesign.m b/subfun/expDesign.m index 95e18af..e7a9f8d 100644 --- a/subfun/expDesign.m +++ b/subfun/expDesign.m @@ -1,3 +1,5 @@ +% (C) Copyright 2020 CPP visual motion localizer developpers + function [cfg] = expDesign(cfg, displayFigs) % Creates the sequence of blocks and the events in them % diff --git a/subfun/expDesignMtMst.m b/subfun/expDesignMtMst.m index 3332a88..74671a5 100644 --- a/subfun/expDesignMtMst.m +++ b/subfun/expDesignMtMst.m @@ -1,3 +1,5 @@ +% (C) Copyright 2020 CPP visual motion localizer developpers + function [cfg] = expDesignMtMst(cfg) % Creates the sequence of blocks and the events in them % diff --git a/subfun/getDesignInput.m b/subfun/getDesignInput.m index 01310ad..7e177bc 100644 --- a/subfun/getDesignInput.m +++ b/subfun/getDesignInput.m @@ -1,3 +1,5 @@ +% (C) Copyright 2020 CPP visual motion localizer developpers + function [nbBlocks, nbRepet, nbEventsBlock, maxTargBlock] = getDesignInput(cfg) nbRepet = cfg.design.nbRepetitions; nbEventsBlock = cfg.design.nbEventsPerBlock; diff --git a/subfun/postInitializationSetup.m b/subfun/postInitializationSetup.m index 000de7a..5ddb12b 100644 --- a/subfun/postInitializationSetup.m +++ b/subfun/postInitializationSetup.m @@ -1,3 +1,5 @@ +% (C) Copyright 2020 CPP visual motion localizer developpers + function varargout = postInitializationSetup(varargin) % varargout = postInitializatinSetup(varargin) diff --git a/subfun/preSaveSetup.m b/subfun/preSaveSetup.m index f7b71f4..d13c65f 100644 --- a/subfun/preSaveSetup.m +++ b/subfun/preSaveSetup.m @@ -1,3 +1,5 @@ +% (C) Copyright 2020 CPP visual motion localizer developpers + function varargout = preSaveSetup(varargin) % varargout = postInitializatinSetup(varargin) diff --git a/subfun/preTrialSetup.m b/subfun/preTrialSetup.m index 852a511..2c8a49a 100644 --- a/subfun/preTrialSetup.m +++ b/subfun/preTrialSetup.m @@ -1,3 +1,5 @@ +% (C) Copyright 2020 CPP visual motion localizer developpers + function varargout = preTrialSetup(varargin) % varargout = postInitializatinSetup(varargin) diff --git a/visualLocTranslational.m b/visualLocTranslational.m index 733dbe0..d73568a 100644 --- a/visualLocTranslational.m +++ b/visualLocTranslational.m @@ -1,17 +1,14 @@ -%% Visual hMT localizer using translational motion in four directions -% (up- down- left and right-ward) +% (C) Copyright 2018 Mohamed Rezk +% (C) Copyright 2020 CPP visual motion localizer developpers -% by Mohamed Rezk 2018 -% adapted by MarcoB and RemiG 2020 - -%% +%% Visual motion localizer getOnlyPress = 1; more off; % Clear all the previous stuff -% clc; clear; +clc; if ~ismac close all; clear Screen; From d91b235791a1f527239269a818c5d45c38bf440c Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 23 Sep 2020 12:26:05 +0200 Subject: [PATCH 17/19] refactor expDesign --- subfun/assignConditions.m | 20 ++++ subfun/diplayDesign.m | 81 ++++++++++++++ subfun/expDesign.m | 143 +------------------------ subfun/expDesignMtMst.m | 174 ------------------------------- subfun/getDirectionBaseVectors.m | 17 +++ subfun/setDirections.m | 52 +++++++++ 6 files changed, 173 insertions(+), 314 deletions(-) create mode 100644 subfun/assignConditions.m create mode 100644 subfun/diplayDesign.m delete mode 100644 subfun/expDesignMtMst.m create mode 100644 subfun/getDirectionBaseVectors.m create mode 100644 subfun/setDirections.m diff --git a/subfun/assignConditions.m b/subfun/assignConditions.m new file mode 100644 index 0000000..74ef6ae --- /dev/null +++ b/subfun/assignConditions.m @@ -0,0 +1,20 @@ +% (C) Copyright 2020 CPP visual motion localizer developpers + +function [conditionNamesVector, CONDITON1_INDEX, CONDITON2_INDEX] = assignConditions(cfg) + + [~, nbRepet] = getDesignInput(cfg); + + conditionNamesVector = repmat(cfg.design.names, nbRepet, 1); + + % Get the index of each condition + nameCondition1 = 'static'; + nameCondition2 = 'motion'; + if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') + nameCondition1 = 'fixation_right'; + nameCondition2 = 'fixation_left'; + end + + CONDITON1_INDEX = find(strcmp(conditionNamesVector, nameCondition1)); + CONDITON2_INDEX = find(strcmp(conditionNamesVector, nameCondition2)); + +end diff --git a/subfun/diplayDesign.m b/subfun/diplayDesign.m new file mode 100644 index 0000000..34929bb --- /dev/null +++ b/subfun/diplayDesign.m @@ -0,0 +1,81 @@ +% (C) Copyright 2020 CPP visual motion localizer developpers + +function diplayDesign(cfg, displayFigs) + + %% Visualize the design matrix + if displayFigs + + close all; + + figure(1); + + % Shows blocks (static and motion) and events (motion direction) order + directions = cfg.design.directions; + directions(directions == -1) = -90; + + subplot(3, 1, 1); + imagesc(directions); + + labelAxesBlock(); + + caxis([-90 - 37, 270 + 37]); + myColorMap = lines(5); + colormap(myColorMap); + + title('Block (static and motion) & Events (motion direction)'); + + % Shows the fixation targets design in each event (1 or 0) + fixationTargets = cfg.design.fixationTargets; + + subplot(3, 1, 2); + imagesc(fixationTargets); + labelAxesBlock(); + title('Fixation Targets design'); + colormap(gray); + + % Shows the fixation targets position distribution in the block across + % the experimet + [~, itargetPosition] = find(fixationTargets == 1); + + subplot(3, 1, 3); + hist(itargetPosition); + labelAxesFreq(); + title('Fixation Targets position distribution'); + + figure(2); + + [motionDirections] = getDirectionBaseVectors(cfg); + motionDirections = unique(motionDirections); + + for iMotion = 1:length(motionDirections) + + [~, position] = find(directions == motionDirections(iMotion)); + + subplot(2, 2, iMotion); + hist(position); + scaleAxes(); + labelAxesFreq(); + title(num2str(motionDirections(iMotion))); + + end + + end + +end + +function labelAxesBlock() + % an old viking saying because they really cared about their axes + ylabel('Block seq.', 'Fontsize', 8); + xlabel('Events', 'Fontsize', 8); +end + +function labelAxesFreq() + % an old viking saying because they really cared about their axes + ylabel('Number of targets', 'Fontsize', 8); + xlabel('Events', 'Fontsize', 8); +end + +function scaleAxes() + xlim([1 12]); + ylim([0 5]); +end diff --git a/subfun/expDesign.m b/subfun/expDesign.m index e7a9f8d..b334fe0 100644 --- a/subfun/expDesign.m +++ b/subfun/expDesign.m @@ -65,7 +65,7 @@ fprintf('\n\nCreating design.\n\n'); [NB_BLOCKS, NB_REPETITIONS, NB_EVENTS_PER_BLOCK, MAX_TARGET_PER_BLOCK] = getDesignInput(cfg); - [~, STATIC_INDEX, MOTION_INDEX] = assignConditions(cfg); + [~, CONDITON1_INDEX, CONDITON2_INDEX] = assignConditions(cfg); if mod(NB_REPETITIONS, MAX_TARGET_PER_BLOCK) ~= 0 error('number of repetitions must be a multiple of max number of targets'); @@ -75,8 +75,8 @@ targetPerCondition = repmat(RANGE_TARGETS, 1, NB_REPETITIONS / MAX_TARGET_PER_BLOCK); numTargetsForEachBlock = zeros(1, NB_BLOCKS); - numTargetsForEachBlock(STATIC_INDEX) = shuffle(targetPerCondition); - numTargetsForEachBlock(MOTION_INDEX) = shuffle(targetPerCondition); + numTargetsForEachBlock(CONDITON1_INDEX) = shuffle(targetPerCondition); + numTargetsForEachBlock(CONDITON2_INDEX) = shuffle(targetPerCondition); %% Give the blocks the names with condition and design the task in each event while 1 @@ -125,140 +125,3 @@ diplayDesign(cfg, displayFigs); end - -function cfg = setDirections(cfg) - - [MOTION_DIRECTIONS, STATIC_DIRECTIONS] = getDirectionBaseVectors(cfg); - - [NB_BLOCKS, NB_REPETITIONS, NB_EVENTS_PER_BLOCK] = getDesignInput(cfg); - - [~, STATIC_INDEX, MOTION_INDEX] = assignConditions(cfg); - - if mod(NB_EVENTS_PER_BLOCK, length(MOTION_DIRECTIONS)) ~= 0 - error('Number of events/block not a multiple of number of motion/static direction'); - end - - % initialize - directions = zeros(NB_BLOCKS, NB_EVENTS_PER_BLOCK); - - % Create a vector for the static condition - NB_REPEATS_BASE_VECTOR = NB_EVENTS_PER_BLOCK / length(STATIC_DIRECTIONS); - - static_directions = repmat( ... - STATIC_DIRECTIONS, ... - 1, NB_REPEATS_BASE_VECTOR); - - for iMotionBlock = 1:NB_REPETITIONS - - % Set motion direction and static order - directions(MOTION_INDEX(iMotionBlock), :) = ... - repeatShuffleConditions(MOTION_DIRECTIONS, NB_REPEATS_BASE_VECTOR); - directions(STATIC_INDEX(iMotionBlock), :) = static_directions; - - end - - cfg.design.directions = directions; - -end - -function [MOTION_DIRECTIONS, STATIC_DIRECTIONS] = getDirectionBaseVectors(cfg) - - % CONSTANTS - % Set directions for static and motion condition - - MOTION_DIRECTIONS = cfg.design.motionDirections; - STATIC_DIRECTIONS = repmat(-1, size(MOTION_DIRECTIONS)); - -end - -function [conditionNamesVector, STATIC_INDEX, MOTION_INDEX] = assignConditions(cfg) - - [~, nbRepet] = getDesignInput(cfg); - - conditionNamesVector = repmat(cfg.design.names, nbRepet, 1); - - % Get the index of each condition - STATIC_INDEX = find(strcmp(conditionNamesVector, 'static')); - MOTION_INDEX = find(strcmp(conditionNamesVector, 'motion')); - -end - -function diplayDesign(cfg, displayFigs) - - %% Visualize the design matrix - if displayFigs - - close all; - - figure(1); - - % Shows blocks (static and motion) and events (motion direction) order - directions = cfg.design.directions; - directions(directions == -1) = -90; - - subplot(3, 1, 1); - imagesc(directions); - - labelAxesBlock(); - - caxis([-90 - 37, 270 + 37]); - myColorMap = lines(5); - colormap(myColorMap); - - title('Block (static and motion) & Events (motion direction)'); - - % Shows the fixation targets design in each event (1 or 0) - fixationTargets = cfg.design.fixationTargets; - - subplot(3, 1, 2); - imagesc(fixationTargets); - labelAxesBlock(); - title('Fixation Targets design'); - colormap(gray); - - % Shows the fixation targets position distribution in the block across - % the experimet - [~, itargetPosition] = find(fixationTargets == 1); - - subplot(3, 1, 3); - hist(itargetPosition); - labelAxesFreq(); - title('Fixation Targets position distribution'); - - figure(2); - - [motionDirections] = getDirectionBaseVectors(cfg); - motionDirections = unique(motionDirections); - - for iMotion = 1:length(motionDirections) - - [~, position] = find(directions == motionDirections(iMotion)); - - subplot(2, 2, iMotion); - hist(position); - scaleAxes(); - labelAxesFreq(); - title(num2str(motionDirections(iMotion))); - - end - - end - -end - -function labelAxesBlock() - % an old viking saying because they really cared about their axes - ylabel('Block seq.', 'Fontsize', 8); - xlabel('Events', 'Fontsize', 8); -end - -function labelAxesFreq() - % an old viking saying because they really cared about their axes - ylabel('Number of targets', 'Fontsize', 8); - xlabel('Events', 'Fontsize', 8); -end - -function scaleAxes() - xlim([1 12]); - ylim([0 5]); -end diff --git a/subfun/expDesignMtMst.m b/subfun/expDesignMtMst.m deleted file mode 100644 index 74671a5..0000000 --- a/subfun/expDesignMtMst.m +++ /dev/null @@ -1,174 +0,0 @@ -% (C) Copyright 2020 CPP visual motion localizer developpers - -function [cfg] = expDesignMtMst(cfg) - % Creates the sequence of blocks and the events in them - % - % The conditions are consecutive static and motion blocks - % (Gives better results than randomised). - % - % Style guide: constants are in SNAKE_UPPER_CASE - % - % EVENTS - % The numEventsPerBlock should be a multiple of the number of "base" - % listed in the MOTION_DIRECTIONS and STATIC_DIRECTIONS (4 at the moment). - % MOTION_DIRECTIONS = [0 90 180 270]; - % - % Pseudorandomization rules: - % (1) Directions are all present in random orders in `numEventsPerBlock/nDirections` - % consecutive chunks. This evenly distribute the directions across the - % block. - % (2) No same consecutive direction - % - % - % TARGETS - % - % Pseudorandomization rules: - % (1) If there are more than 1 target per block we make sure that they are at least 2 - % events apart. - % (2) Targets cannot be on the first or last event of a block. - % (3) Targets can not be present more than NB_REPETITIONS - 1 times in the same event - % position across blocks. - % - % Input: - % - cfg: parameters returned by setParameters - % - displayFigs: a boolean to decide whether to show the basic design - % matrix of the design - % - % Output: - % - ExpParameters.designBlockNames = cell array (nr_blocks, 1) with the - % name for each block - % - % - cfg.designDirections = array (nr_blocks, numEventsPerBlock) - % with the direction to present in a given block - % - 0 90 180 270 indicate the angle - % - -1 indicates static - % - % - cfg.designSpeeds = array (nr_blocks, numEventsPerBlock) * speedEvent; - % - % - cfg.designFixationTargets = array (nr_blocks, numEventsPerBlock) - % showing for each event if it should be accompanied by a target - % - - %% Check inputs - - % Set variables here for a dummy test of this function - if nargin < 1 || isempty(cfg) - error('give me something to work with'); - end - - fprintf('\n\nCreating design.\n\n'); - - [NB_BLOCKS, NB_REPETITIONS, NB_EVENTS_PER_BLOCK, MAX_TARGET_PER_BLOCK] = ... - getDesignInput(cfg); - [~, FIX_RIGHT_INDEX, FIX_LEFT_INDEX] = assignConditions(cfg); - - if mod(NB_REPETITIONS, MAX_TARGET_PER_BLOCK) ~= 0 - error('number of repetitions must be a multiple of max number of targets'); - end - - RANGE_TARGETS = 1:MAX_TARGET_PER_BLOCK; - targetPerCondition = repmat(RANGE_TARGETS, 1, NB_REPETITIONS / MAX_TARGET_PER_BLOCK); - - numTargetsForEachBlock = zeros(1, NB_BLOCKS); - numTargetsForEachBlock(FIX_RIGHT_INDEX) = shuffle(targetPerCondition); - numTargetsForEachBlock(FIX_LEFT_INDEX) = shuffle(targetPerCondition); - - %% Give the blocks the names with condition and design the task in each event - while 1 - - fixationTargets = zeros(NB_BLOCKS, NB_EVENTS_PER_BLOCK); - - for iBlock = 1:NB_BLOCKS - - % Set target - % - if there are 2 targets per block we make sure that they are at least - % 2 events apart - % - targets cannot be on the first or last event of a block - % - no more than 2 target in the same event order - - nbTarget = numTargetsForEachBlock(iBlock); - - chosenPosition = setTargetPositionInSequence( ... - NB_EVENTS_PER_BLOCK, ... - nbTarget, ... - [1 NB_EVENTS_PER_BLOCK]); - - fixationTargets(iBlock, chosenPosition) = 1; - - end - - % Check rule 3 - if max(sum(fixationTargets)) < NB_REPETITIONS - 1 - break - end - - end - - %% Now we do the easy stuff - cfg.design.blockNames = assignConditions(cfg); - - cfg.design.nbBlocks = NB_BLOCKS; - - cfg = setDirections(cfg); - - speeds = ones(NB_BLOCKS, NB_EVENTS_PER_BLOCK) * cfg.dot.speedPixPerFrame; - cfg.design.speeds = speeds; - - cfg.design.fixationTargets = fixationTargets; - -end - -function cfg = setDirections(cfg) - - [FIX_RIGHT_DIRECTIONS, FIX_LEFT_DIRECTIONS] = getDirectionBaseVectors(cfg); - - [NB_BLOCKS, NB_REPETITIONS, NB_EVENTS_PER_BLOCK] = getDesignInput(cfg); - - [~, FIX_RIGHT_INDEX, FIX_LEFT_INDEX] = assignConditions(cfg); - - if mod(NB_EVENTS_PER_BLOCK, length(FIX_RIGHT_DIRECTIONS)) ~= 0 - error('Number of events/block not a multiple of number of motion/static direction'); - end - - % initialize - directions = zeros(NB_BLOCKS, NB_EVENTS_PER_BLOCK); - - % Create a vector for the static condition - NB_REPEATS_BASE_VECTOR = NB_EVENTS_PER_BLOCK / length(FIX_LEFT_DIRECTIONS); - - for iMotionBlock = 1:NB_REPETITIONS - - % Set motion direction and static order - directions(FIX_LEFT_INDEX(iMotionBlock), :) = ... - repeatShuffleConditions(FIX_LEFT_DIRECTIONS, NB_REPEATS_BASE_VECTOR); - - directions(FIX_RIGHT_INDEX(iMotionBlock), :) = ... - repeatShuffleConditions(FIX_RIGHT_DIRECTIONS, NB_REPEATS_BASE_VECTOR); - - end - - cfg.design.directions = directions; - -end - -function [FIX_RIGHT_DIRECTIONS, FIX_LEFT_DIRECTIONS] = getDirectionBaseVectors(cfg) - - % CONSTANTS - % Set directions for both blocks condition - - FIX_RIGHT_DIRECTIONS = cfg.design.motionDirections; - FIX_LEFT_DIRECTIONS = cfg.design.motionDirections; - -end - -function [conditionNamesVector, FIX_RIGHT_INDEX, FIX_LEFT_INDEX] = assignConditions(cfg) - - [~, nbRepet] = getDesignInput(cfg); - - conditionNamesVector = repmat(cfg.design.names, nbRepet, 1); - - % Get the index of each condition - FIX_RIGHT_INDEX = find(strcmp(conditionNamesVector, 'fixation_right')); - FIX_LEFT_INDEX = find(strcmp(conditionNamesVector, 'fixation_left')); - -end diff --git a/subfun/getDirectionBaseVectors.m b/subfun/getDirectionBaseVectors.m new file mode 100644 index 0000000..b63d0ea --- /dev/null +++ b/subfun/getDirectionBaseVectors.m @@ -0,0 +1,17 @@ +% (C) Copyright 2020 CPP visual motion localizer developpers + +function [CONDITION1_DIRECTIONS, CONDITION2_DIRECTIONS] = getDirectionBaseVectors(cfg) + + % CONSTANTS + + % Set directions for static and motion condition + CONDITION1_DIRECTIONS = cfg.design.motionDirections; + CONDITION2_DIRECTIONS = repmat(-1, size(CONDITION1_DIRECTIONS)); % static + + % for for the MT / MST localizer + if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') + CONDITION1_DIRECTIONS = cfg.design.motionDirections; + CONDITION2_DIRECTIONS = cfg.design.motionDirections; + end + +end diff --git a/subfun/setDirections.m b/subfun/setDirections.m new file mode 100644 index 0000000..f45bb5b --- /dev/null +++ b/subfun/setDirections.m @@ -0,0 +1,52 @@ +% (C) Copyright 2020 CPP visual motion localizer developpers + +function cfg = setDirections(cfg) + + [CONDITION1_DIRECTIONS, CONDITION2_DIRECTIONS] = getDirectionBaseVectors(cfg); + + [NB_BLOCKS, NB_REPETITIONS, NB_EVENTS_PER_BLOCK] = getDesignInput(cfg); + + [~, CONDITON1_INDEX, CONDITON2_INDEX] = assignConditions(cfg); + + if mod(NB_EVENTS_PER_BLOCK, length(CONDITION1_DIRECTIONS)) ~= 0 + error('Number of events/block not a multiple of number of motion/static direction'); + end + + % initialize + directions = zeros(NB_BLOCKS, NB_EVENTS_PER_BLOCK); + + % Create a vector for the static condition + NB_REPEATS_BASE_VECTOR = NB_EVENTS_PER_BLOCK / length(CONDITION2_DIRECTIONS); + + static_directions = repmat( ... + CONDITION2_DIRECTIONS, ... + 1, NB_REPEATS_BASE_VECTOR); + + for iMotionBlock = 1:NB_REPETITIONS + + if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') + + % Set motion direction for MT/MST localizer + + directions(CONDITON1_INDEX(iMotionBlock), :) = ... + repeatShuffleConditions(CONDITION1_DIRECTIONS, NB_REPEATS_BASE_VECTOR); + + directions(CONDITON2_INDEX(iMotionBlock), :) = ... + repeatShuffleConditions(CONDITION1_DIRECTIONS, NB_REPEATS_BASE_VECTOR); + + else + + % Set motion direction and static order + + directions(CONDITON2_INDEX(iMotionBlock), :) = ... + repeatShuffleConditions(CONDITION1_DIRECTIONS, NB_REPEATS_BASE_VECTOR); + + directions(CONDITON1_INDEX(iMotionBlock), :) = static_directions; + + end + + end + + cfg.design.directions = directions; + +end From 6a79476fd1a5128dcf6e45505fa67738bbccdc97 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 23 Sep 2020 12:26:35 +0200 Subject: [PATCH 18/19] mh fix --- lib/CPP_PTB | 2 +- setParameters.m | 7 +++---- subfun/saveResponsesAndTriggers.m | 2 ++ visualLocTranslational.m | 10 +++++----- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/CPP_PTB b/lib/CPP_PTB index f0a8024..0334054 160000 --- a/lib/CPP_PTB +++ b/lib/CPP_PTB @@ -1 +1 @@ -Subproject commit f0a80248eed772f8f787b049c3ac9d1bcb620d50 +Subproject commit 03340548820285460bde9e27396a2595bb2e54af diff --git a/setParameters.m b/setParameters.m index 027d28e..a4d91bf 100644 --- a/setParameters.m +++ b/setParameters.m @@ -40,9 +40,8 @@ %% Experiment Design - cfg.design.localizer = 'MT_MST'; + % cfg.design.localizer = 'MT_MST'; - % cfg.design.motionType = 'translation'; % cfg.design.motionType = 'radial'; cfg.design.motionType = 'translation'; @@ -110,9 +109,9 @@ % Number of dots per visual angle square. cfg.dot.density = 1; % Dot life time in seconds - cfg.dot.lifeTime = 10; + cfg.dot.lifeTime = .15; % proportion of dots killed per frame - cfg.dot.proportionKilledPerFrame = 0; + cfg.dot.proportionKilledPerFrame = 0.005; % Dot Size (dot width) in visual angles. cfg.dot.size = .2; cfg.dot.color = cfg.color.white; diff --git a/subfun/saveResponsesAndTriggers.m b/subfun/saveResponsesAndTriggers.m index 61f8e5a..bca56bd 100644 --- a/subfun/saveResponsesAndTriggers.m +++ b/subfun/saveResponsesAndTriggers.m @@ -1,3 +1,5 @@ +% (C) Copyright 2020 CPP visual motion localizer developpers + function saveResponsesAndTriggers(responseEvents, cfg, logFile, triggerString) if isfield(responseEvents(1), 'onset') && ~isempty(responseEvents(1).onset) diff --git a/visualLocTranslational.m b/visualLocTranslational.m index d73568a..5d23655 100644 --- a/visualLocTranslational.m +++ b/visualLocTranslational.m @@ -34,11 +34,11 @@ [el] = eyeTracker('Calibration', cfg); - if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') - [cfg] = expDesignMtMst(cfg); - else - [cfg] = expDesign(cfg); - end + % if isfield(cfg.design, 'localizer') && strcmpi(cfg.design.localizer, 'MT_MST') + % [cfg] = expDesignMtMst(cfg); + % else + [cfg] = expDesign(cfg); + % end % Prepare for the output logfiles with all logFile.extraColumns = cfg.extraColumns; From db8c02b8ed1e145f482975b8daf9f0cb076a95c4 Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Wed, 23 Sep 2020 12:34:24 +0200 Subject: [PATCH 19/19] mh fix --- initEnv.m | 4 ++-- setParameters.m | 26 +++++++++++++------------- subfun/expDesign.m | 6 +++--- subfun/postInitializationSetup.m | 2 +- subfun/setDirections.m | 4 ++-- tests/test_expDesign.m | 10 ++++++---- visualLocTranslational.m | 24 ++++++++++++------------ 7 files changed, 39 insertions(+), 37 deletions(-) diff --git a/initEnv.m b/initEnv.m index 9880ce2..0420ce7 100644 --- a/initEnv.m +++ b/initEnv.m @@ -57,8 +57,8 @@ if numel(dir(libDirectory)) <= 2 % Means that the external is empty error(['Git submodules are not cloned!', ... - 'Try this in your terminal:', ... - ' git submodule update --recursive ']); + 'Try this in your terminal:', ... + ' git submodule update --recursive ']); else addDependencies(); end diff --git a/setParameters.m b/setParameters.m index a4d91bf..7714aeb 100644 --- a/setParameters.m +++ b/setParameters.m @@ -11,8 +11,8 @@ % setParamters.m file is % change that if you want the data to be saved somewhere else cfg.dir.output = fullfile( ... - fileparts(mfilename('fullpath')), '..', ... - 'output'); + fileparts(mfilename('fullpath')), '..', ... + 'output'); %% Debug mode settings @@ -150,23 +150,23 @@ cfg.target.duration = 0.05; % In secs cfg.extraColumns = { ... - 'direction', ... - 'speed', ... - 'target', ... - 'event', ... - 'block', ... - 'keyName', ... - 'fixationPosition', ... - 'aperturePosition'}; + 'direction', ... + 'speed', ... + 'target', ... + 'event', ... + 'block', ... + 'keyName', ... + 'fixationPosition', ... + 'aperturePosition'}; end function cfg = setKeyboards(cfg) cfg.keyboard.escapeKey = 'ESCAPE'; cfg.keyboard.responseKey = { ... - 'r', 'g', 'y', 'b', ... - 'd', 'n', 'z', 'e', ... - 't'}; + 'r', 'g', 'y', 'b', ... + 'd', 'n', 'z', 'e', ... + 't'}; cfg.keyboard.keyboard = []; cfg.keyboard.responseBox = []; diff --git a/subfun/expDesign.m b/subfun/expDesign.m index b334fe0..1678d83 100644 --- a/subfun/expDesign.m +++ b/subfun/expDesign.m @@ -94,9 +94,9 @@ nbTarget = numTargetsForEachBlock(iBlock); chosenPosition = setTargetPositionInSequence( ... - NB_EVENTS_PER_BLOCK, ... - nbTarget, ... - [1 NB_EVENTS_PER_BLOCK]); + NB_EVENTS_PER_BLOCK, ... + nbTarget, ... + [1 NB_EVENTS_PER_BLOCK]); fixationTargets(iBlock, chosenPosition) = 1; diff --git a/subfun/postInitializationSetup.m b/subfun/postInitializationSetup.m index 5ddb12b..fdafac3 100644 --- a/subfun/postInitializationSetup.m +++ b/subfun/postInitializationSetup.m @@ -22,7 +22,7 @@ % dots are displayed on a square with a length in visual angle equal to the % field of view cfg.dot.number = round(cfg.dot.density * ... - (cfg.dot.matrixWidth / cfg.screen.ppd)^2); + (cfg.dot.matrixWidth / cfg.screen.ppd)^2); varargout = {cfg}; diff --git a/subfun/setDirections.m b/subfun/setDirections.m index f45bb5b..c6c4a04 100644 --- a/subfun/setDirections.m +++ b/subfun/setDirections.m @@ -19,8 +19,8 @@ NB_REPEATS_BASE_VECTOR = NB_EVENTS_PER_BLOCK / length(CONDITION2_DIRECTIONS); static_directions = repmat( ... - CONDITION2_DIRECTIONS, ... - 1, NB_REPEATS_BASE_VECTOR); + CONDITION2_DIRECTIONS, ... + 1, NB_REPEATS_BASE_VECTOR); for iMotionBlock = 1:NB_REPETITIONS diff --git a/tests/test_expDesign.m b/tests/test_expDesign.m index a224c55..5ef89da 100644 --- a/tests/test_expDesign.m +++ b/tests/test_expDesign.m @@ -28,8 +28,9 @@ function test_exDesignBasic() % make sure that we have the right number of blocks of the right length assertTrue(all(size(cfg.design.directions) == [ ... - cfg.design.nbRepetitions * numel(cfg.design.names), ... - cfg.design.nbEventsPerBlock])); + cfg.design.nbRepetitions * ... + numel(cfg.design.names), ... + cfg.design.nbEventsPerBlock])); % check that we do not have more than the required number of targets per % block @@ -62,8 +63,9 @@ function test_exDesignBasicOtherSetUp() % make sure that we have the right number of blocks of the right length assertTrue(all(size(cfg.design.directions) == [ ... - cfg.design.nbRepetitions * numel(cfg.design.names), ... - cfg.design.nbEventsPerBlock])); + cfg.design.nbRepetitions * ... + numel(cfg.design.names), ... + cfg.design.nbEventsPerBlock])); % check that we do not have more than the required number of targets per % block diff --git a/visualLocTranslational.m b/visualLocTranslational.m index 5d23655..4e40173 100644 --- a/visualLocTranslational.m +++ b/visualLocTranslational.m @@ -85,28 +85,28 @@ % we wait for a trigger every 2 events if cfg.pacedByTriggers.do && mod(iEvent, 2) == 1 waitForTrigger( ... - cfg, ... - cfg.keyboard.responseBox, ... - cfg.pacedByTriggers.quietMode, ... - cfg.pacedByTriggers.nbTriggers); + cfg, ... + cfg.keyboard.responseBox, ... + cfg.pacedByTriggers.quietMode, ... + cfg.pacedByTriggers.nbTriggers); end % play the dots and collect onset and duraton of the event [onset, duration] = doDotMo(cfg, thisEvent, thisFixation); thisEvent = preSaveSetup( ... - thisEvent, ... - thisFixation, ... - iBlock, iEvent, ... - duration, onset, ... - cfg, ... - logFile); + thisEvent, ... + thisFixation, ... + iBlock, iEvent, ... + duration, onset, ... + cfg, ... + logFile); saveEventsFile('save', cfg, thisEvent); % collect the responses and appends to the event structure for % saving in the tsv file responseEvents = getResponse('check', cfg.keyboard.responseBox, cfg, ... - getOnlyPress); + getOnlyPress); triggerString = ['trigger_' cfg.design.blockNames{iBlock}]; saveResponsesAndTriggers(responseEvents, cfg, logFile, triggerString); @@ -132,7 +132,7 @@ % trigger monitoring triggerEvents = getResponse('check', cfg.keyboard.responseBox, cfg, ... - getOnlyPress); + getOnlyPress); triggerString = 'trigger_baseline'; saveResponsesAndTriggers(triggerEvents, cfg, logFile, triggerString);