Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Singlecp dev #21

Draft
wants to merge 78 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
c7d3c27
Fail to implement 4AFC set-up
aernesto Oct 1, 2019
b761990
rename Adrian's version of ReversingDots
aernesto Oct 1, 2019
a85037a
update class name for topsTreeNodeTaskReversingDots4AFC
aernesto Oct 1, 2019
e150564
debug session for 4AFC -- dataset 2019_10_03_12_55
aernesto Oct 3, 2019
c2923d9
4AFC task runs -- with bugs for targets and response keys
aernesto Oct 3, 2019
19eee8f
silence console output in dotsDrawableDotKinetogram.m
aernesto Oct 7, 2019
9552eb7
targets and keys behave ok
aernesto Oct 7, 2019
65f4d57
task runs with tbUseProject('Lab_Matlab_Control')
aernesto Oct 7, 2019
6bdccef
improving metadata
aernesto Oct 7, 2019
f139a23
conditional stop
aernesto Oct 8, 2019
4384d46
numeric stop condition works
aernesto Oct 8, 2019
3119559
only dump non-empty FIRA
aernesto Oct 8, 2019
f210e75
experimenter specifies whether first session of day or not
aernesto Oct 8, 2019
a093fdd
get Quest threshold dynamically
aernesto Oct 8, 2019
e9936db
Fail at Quest block
aernesto Oct 8, 2019
3638156
no pb anymore\?
aernesto Oct 8, 2019
c628325
produce test data 2019_10_08_17_17
aernesto Oct 8, 2019
0abf89f
successfull second run of singlecp()
aernesto Oct 8, 2019
d7da8ca
fix opening message task block
aernesto Oct 8, 2019
f13e84d
improve readability of singlecp xpt launching script
aernesto Oct 10, 2019
dbe9991
produce 2019_10_10_16_04 for test 1
aernesto Oct 10, 2019
cd14c7c
ensure all blocks have similar dots stimulus
aernesto Oct 10, 2019
f9c6b64
condition feedback screen on showFeedback setting
aernesto Oct 10, 2019
0eba68a
run test 2
aernesto Oct 10, 2019
d481e4d
run test 3
aernesto Oct 10, 2019
7251b03
set up config for booth
Oct 24, 2019
2da0290
correct xml config file
Oct 24, 2019
46c6a5c
prepare for first test run in booth
Oct 24, 2019
468da2e
test 1 in booth
Oct 25, 2019
1c4ad86
prepare for test 2
Oct 25, 2019
054f0d0
test 2 fails because of pb with keyboard and gamepad
Oct 25, 2019
a4903a9
gamepad interface + keyboard work
Oct 25, 2019
2a49c7d
new dots drawable settings
Oct 28, 2019
6f0f201
task DOES NOT RUN
Oct 28, 2019
dc90d9f
TASK DOES NOT RUN
Oct 28, 2019
894942e
TASK DOES NOT RUN
Oct 29, 2019
3143992
Quest task runs, but on 4AFC task cp choice state never entered
Oct 29, 2019
5b16080
FAIL TO RUN TASK
Oct 29, 2019
1e51817
Revert "FAIL TO RUN TASK"
Oct 29, 2019
024c176
cp choice never recorded
Oct 29, 2019
5790389
holdFixation and nocpResponse events are NOT READ
Oct 29, 2019
9f90036
getting better. Last bug look at 10_29_12_04 roughly
Oct 29, 2019
72c6ab4
TASK RUNS -- CP instructions missing
Oct 29, 2019
aeb012f
text for CP instructions does not show up 2019_10_29_12_43
Oct 29, 2019
536f5ae
cp screen instructions still invisible
Oct 29, 2019
769964c
TASK RUNS -- 2019_10_29_13_04
Oct 29, 2019
2bfed4b
simplify singlecp
Nov 5, 2019
a5c9e87
add true task blocks
Nov 5, 2019
79b0479
tweak feedback
Nov 5, 2019
c80ca5f
prepare test run with S10
Nov 5, 2019
a4a6460
session 1 S11
Nov 5, 2019
6e8fbb1
randomize trial order in task
aernesto Nov 6, 2019
155899d
lengthen training_1.csv
Nov 6, 2019
df668d2
I tried a quick fix for the gamepad eventDefinitions bug
Nov 7, 2019
67fd605
add function to compute extra pay rate
Nov 11, 2019
89dd2b1
Extend Quest block to 120 trials
Nov 13, 2019
aa02c70
fix reproducibility bug in dots
Nov 25, 2019
4c73138
reproduce_dots() crashes
aernesto Nov 25, 2019
3e60f4d
reproduce_dots() does not crash anymore
aernesto Nov 25, 2019
3b2ae87
add finalCPTime property
aernesto Nov 25, 2019
33565ba
comment out console prints in dotsDrawableDotKinetogramDebug
aernesto Nov 29, 2019
7be90ea
render randSeedBase unique to every trial
Dec 11, 2019
23e74c3
fix seed in dotsDrawableDotKinetogramDebug
aernesto Dec 12, 2019
93fdc46
set flipDir to true by default
Dec 13, 2019
ecd459d
store more timestamps from dots in task + dDDK
Dec 18, 2019
746a5b1
prepare for test run dDDK
Dec 18, 2019
c9bdbe9
use now instead of clock
Dec 18, 2019
87dca83
reset dDDK counters at trialStart
Dec 18, 2019
ecf81f7
enforce sequential trial order for test
Dec 18, 2019
61c6864
re-run test with dDDKDebug
Dec 18, 2019
032f714
re-run test second time with dDDK
Dec 19, 2019
20aa8a4
Revert "re-run test second time with dDDK"
Dec 30, 2019
29aaee9
preparing for another dots reproducibility test dDDKDebug
Dec 30, 2019
7df8320
cleanup
Jan 2, 2020
c75d9af
randomize trial sequence
Jan 2, 2020
6ff2c00
Revert to task version that doesn't store the dots
Jan 2, 2020
9a3ad0b
default to Quest block first in singlecp.m
Jan 2, 2020
d76be4b
really randomize seed for every trial
Jan 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
*.DS_Store
modularTasks/tasks/AdrianTests/trials_post_expt/*
modularTasks/tasks/AdrianTests/trials_pre_expt/training_3.csv
modularTasks/tasks/AdrianTests/trials_pre_expt/training_4.csv
modularTasks/tasks/AdrianTests/trials_pre_expt/training_5.csv
modularTasks/tasks/AdrianTests/trials_pre_expt/training_6.csv
modularTasks/tasks/AdrianTests/trials_pre_expt/training_7.csv
modularTasks/tasks/AdrianTests/trials_pre_expt/training_8.csv
*.png
31 changes: 31 additions & 0 deletions configuration/dots_PsychophysicsMacMini_MachineConfig.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<dotsMachineConfig>
<defaults>
<clockFunction>@mglGetSecs</clockFunction>
<dOutClassName>['dotsDOut1208FS']</dOutClassName>
<dataPath>['/Users/joshuagold/Users/Adrian']</dataPath>
<imagesPath>[true ]</imagesPath>
<soundsPath>['~']</soundsPath>
<tasksPath>['~']</tasksPath>
</defaults>
<dotsTheMessenger>
<ackTimeout>[ 1.0000000000]</ackTimeout>
<defaultClientIP>['127.0.0.1']</defaultClientIP>
<defaultClientPort>[ 49200.0000000000]</defaultClientPort>
<defaultServerIP>['127.0.0.1']</defaultServerIP>
<defaultServerPort>[ 49201.0000000000]</defaultServerPort>
<receiveTimeout>[ 0.0000000000]</receiveTimeout>
<sendRetries>[ 10.0000000000]</sendRetries>
<socketClassName>['dotsSocketPnet']</socketClassName>
</dotsTheMessenger>
<dotsTheScreen>
<backgroundColor>[ 0.0000000000, 0.0000000000, 0.0000000000]</backgroundColor>
<bitDepth>[]</bitDepth>
<displayIndex>[ 2.0000000000]</displayIndex>
<distance>[ 70.0000000000]</distance>
<foregroundColor>[ 1.0000000000, 1.0000000000, 1.0000000000]</foregroundColor>
<height>[ 33.6550000000]</height>
<multisample>[ 1.0000000000]</multisample>
<width>[ 59.69000000000]</width>
</dotsTheScreen>
</dotsMachineConfig>
41 changes: 0 additions & 41 deletions configuration/dots_example_MachineConfig.xml

This file was deleted.

30 changes: 30 additions & 0 deletions modularTasks/tasks/AdrianTests/Lab_Matlab_Control_Adrian_Fork.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[
{
"name": "Lab_Matlab_Control_Adrian_Fork",
"type": "git",
"update": "never",
"url": "https://github.com/aernesto/Lab_Matlab_Control.git",
"pathPlacement": "append"
},
{
"name": "Lab_Matlab_Utilities",
"flavor": "5d8a529991e7d1db7bd9560078e886ca3f9a818d",
"type": "git",
"pathPlacement": "append",
"url": "https://github.com/TheGoldLab/Lab_Matlab_Utilities.git"
},
{
"name": "mgl",
"type": "git",
"flavor": "85153d66e0935b0c78a5447494e212c0e8592afe",
"url": "https://github.com/justingardner/mgl.git",
"pathPlacement": "append"
},
{
"name": "mQUESTPlus",
"pathPlacement": "append",
"flavor": "bd3673db5d3e47699bdb1820dcfe068262d8b609",
"type": "git",
"url": "https://github.com/brainardlab/mQUESTPlus.git"
}
]
24 changes: 24 additions & 0 deletions modularTasks/tasks/AdrianTests/payrate.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
function payrate(timestamp)
% compute extra pay for subject
% ARGS:
% timestamp - string like '2019_11_06_12_43'

% max_rate - integer. maximum rate a subject can get. E.g. 10 $/hour
max_rate=10;

% th_perf - percent correct above which max pay rate is reached.
% Between 0 and 1
th_perf=0.75;

pre= 'completed4AFCtrials_task100_date_';
post='.csv';
filename = which([pre, timestamp, post]);
t1=readtable(filename);
coh1 = t1(t1.coherence==100,:);
refdim = size(coh1);
dims=size(coh1(coh1.dirCorrect & coh1.cpCorrect, :));
perf = dims(1) / refdim(1);
%th_perf = .75;
payrate = min(perf/th_perf, 1); % dollars per hour
disp(['additional payrate: ', num2str( ceil(payrate * max_rate)), '$/hour'])
end
247 changes: 247 additions & 0 deletions modularTasks/tasks/AdrianTests/singlecp.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
function singlecp(subject_code, probCP)
% function to launch single CP Reversing Dots task
%
% ARGS:
% subject_code -- string that identifies subject uniquely, e.g. 'S4'
% first_block_of_day -- true or false
% probCP -- numeric value
% dump_folder -- e.g '/Users/joshuagold/Documents/MATLAB/projects/Lab_M
% atlab_Control_Adrian_Fork/modularTasks/tasks/AdrianTests/'
% quest_task_topsDataLog -- full path to topsDataLog containing the Quest
% task (can be '' if no prior Quest task is
% required)

%-------------------------- DEFAULT ARGS
dump_folder = '/Users/joshuagold/Documents/MATLAB/projects/Lab_Matlab_Control_Adrian_Fork/modularTasks/tasks/AdrianTests/trials_post_expt/';


first_block_of_day = true; % if true, Quest block is added

% the following variable should hold the full path to a topsDataLog.mat
% file where a valid Quest block was run. This is when one wants to skip
% the Quest block presently, and thus use the threshold estimated from a
% prior Quest block.
% An example path would be:
% '/Users/joshuagold/Users/Adrian/oneCP/raw/2019_12_13_13_37/2019_12_13_13_37_topsDataLog.mat'
% It is okay to leave the following variable as an empty string if
% first_block_of_day is set to true above.
quest_task_topsDataLog = '';


%-------------------------- DOTS STIMULUS PROPERTIES
ddots.Density = 150;
ddots.Speed = 5;
ddots.PixelSize = 6;
ddots.Diameter = 8;
ddots.CoherenceSTD = 10;

function newStruct = setDotsParams(dots, someStruct)
someStruct.density = dots.Density;
someStruct.speed = dots.Speed;
someStruct.diameter = dots.Diameter;
someStruct.pixelSize = dots.PixelSize;
someStruct.coherenceSTD = dots.CoherenceSTD;
newStruct = someStruct;
end


%-------------------------- CREATE TOPNODE
topNode = topsTreeNodeTopNode('oneCP');

function ts = extract_timestamp(tn)
% returns the timestamp as a string 'YYYY_MM_DD_HH_mm' associated
% with the topsTreeNodeTopNode object tn
ts = regexprep(tn.filename, ...
'[^[0-9]{4}_[0-9]{2}_[0-9]{2}_[0-9]{2}_[0-9]{2}]', '');
ts = ts(1:16);
end
timestamp = extract_timestamp(topNode);


%-------------------------- TURN DIARY ON (LOG CONSOLE OUTPUT TO FILE)
diary([dump_folder, 'session_console_',timestamp,'.log'])


%-------------------------- SET TOPNODE UP
topNode.addHelpers('screenEnsemble', ...
'displayIndex', 2, ...
'remoteDrawing', false, ...
'topNode', topNode);
%topNode.addReadable('dotsReadableHIDKeyboard');
topNode.addReadable('dotsReadableHIDGamepad');
% -1 means wait for keypress -- see topsTreeNode.pauseBeforeTask
pauseBeforeTask = -1;

function add_block(topnode, taskID, task_name, trials_file, ...
stop_cond, block_description)
% add a task to the topnode object
t = topsTreeNodeTaskReversingDots4AFC(task_name);
t.taskID = taskID;
t.independentVariables=trials_file;
% t.trialIterationMethod='sequential';
t.randomizeWhenRepeating = false;
t.pauseBeforeTask = pauseBeforeTask;
t.stopCondition = stop_cond;

% must be numeric
t.subject = str2double(regexprep(subject_code,'[^0-9]',''));
t.date = str2double(regexprep(timestamp,'_','')); % must be numeric
t.probCP = probCP;

t.message.message.Instructions.text = {...
block_description ...
};

% DOTS PROPERTIES
oldDots = t.drawable.stimulusEnsemble.dots;
t.drawable.stimulusEnsemble.dots = setDotsParams(ddots, oldDots);

topnode.addChild(t);
end

function add_training_block(tid, name, condstop)
add_block(topNode, tid, name, [name,'.csv'], condstop, ...
{'training block',num2str(tid)})
end


%-------------------------- ADD TRAINING BLOCKS TO TOPNODE
num_training_blocks=2;

stop_conditions = {...
7, 'button' ...
};

for jj = 1:num_training_blocks
if jj == 2
if probCP < .5
add_training_block(jj, 'training_2_lowprob', stop_conditions{jj})
else
add_training_block(jj, 'training_2_highprob', stop_conditions{jj})
end
else
add_training_block(jj, ['training_',num2str(jj)], stop_conditions{jj})
end
end



%-------------------------- ADD OPTIONAL QUEST BLOCK TO TOPNODE
% only put Quest block if this is the first block of the day
if first_block_of_day
questTask = topsTreeNodeTaskRTDots('Quest');
questTask.taskID = 99;
questTask.trialIterations = 60;
questTask.timing.dotsDuration = 0.4;
questTask.timing.showFeedback = 0;
questTask.pauseBeforeTask = pauseBeforeTask;
questTask.message.message.Instructions.text = {{'Quest block', ...
'There are no switches'}};
% DOTS PROPERTIES
oldieDots = questTask.drawable.stimulusEnsemble.dots;
questTask.drawable.stimulusEnsemble.dots = ...
setDotsParams(ddots, oldieDots);
topNode.addChild(questTask);

else
% extract timestamp from full path
ts = regexprep(quest_task_topsDataLog, ...
'[^[0-9]{4}_[0-9]{2}_[0-9]{2}_[0-9]{2}_[0-9]{2}]', '');
ts = ts(1:16);


% get questTask from first topsDataLog of the day
% right now, stops at first Quest block found
[oldTopNode, ~] = topsTreeNodeTopNode.loadRawData('oneCP', ts);


for tt = 1:length(oldTopNode.children)
task_child = oldTopNode.children{tt};
if strcmp(task_child.name,'Quest')
questTask = task_child;
break
end
end
end



%-------------------------- ADD TASK BLOCKS (4 by default)


ttt = topsTreeNodeTaskReversingDots4AFC('TASK');
ttt.timing.showFeedback = 0;
ttt.taskID = 100;

if probCP < 0.5
task_file = 'Block1.csv';
ttt.message.message.Instructions.text = {...
{'REAL TASK', 'RARE SWITCHES'} ...
};
else
task_file = 'Block0.csv';
ttt.message.message.Instructions.text = {...
{'REAL TASK', 'FREQUENT SWITCHES'} ...
};
end

ttt.independentVariables=task_file;
% ttt.trialIterationMethod='sequential';
ttt.randomizeWhenRepeating = false;
ttt.pauseBeforeTask = pauseBeforeTask;
ttt.stopCondition = 'button';

% subject, date and probCP must be numeric
ttt.subject = str2double(regexprep(subject_code,'[^0-9]',''));
ttt.date = str2double(regexprep(timestamp,'_',''));
ttt.probCP = probCP;

% set theshold coherence obtained from Quest
if ~first_block_of_day
threshold = questTask.getQuestThreshold();
if (threshold <= 0) || (100 <= threshold)
error(['invalid threshold of', num2str(threshold)])
else
ttt.questThreshold = threshold;
end
else
% if threshold hasn't been estimated yet, pass the Quest task instead
ttt.questThreshold = questTask;
end

% DOTS PROPERTIES
oldieDots = ttt.drawable.stimulusEnsemble.dots;
ttt.drawable.stimulusEnsemble.dots = ...
setDotsParams(ddots, oldieDots);

topNode.addChild(ttt);


%-------------------------- RUN TOPNODE

topNode.run();


%-------------------------- DUMP FIRA INFO (ONE FILE PER BLOCK)

function dumpFIRA(topnode, child)
task = topnode.children{child};
csvfile = ...
[dump_folder, 'completed4AFCtrials_task', ...
num2str(task.taskID), '_date_', ...
timestamp,'.csv'];
task.saveTrials(csvfile, 'all');
end

num_children = length(topNode.children);

for c = 1:num_children
if numel(topNode.children{c}.trialData)
dumpFIRA(topNode, c)
end
end

%-------------------------- TURN OFF DIARY
disp(['file with timestamp ', timestamp, ' produced'])
diary off
end
9 changes: 9 additions & 0 deletions modularTasks/tasks/AdrianTests/test_battery.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
High level description
======================
run 3 training + Quest + 1 task (low probCP)
run 3 training + noQuest + 1 task (low probCP)
run 3 training + noQuest + 1 task (low probCP)

Aggregate all FIRA data for this subject into single .csv

Perform basic analysis
Loading