forked from debapratimsaha/PacedStroopTest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
runStroopTestWtimerWresults.m
211 lines (184 loc) · 8.63 KB
/
runStroopTestWtimerWresults.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
function t=runStroopTestWtimerWresults(totalRunTime,sPortObj,Congruence,FigHdl)
%% Produce a figure running the Stroop Test
%
% Description
% A figure appears every 3s for a total of "totalRunTime" seconds, that runs
% the Stroop Test. The user has to speak/choose the color of the word
% irrespective of the word that they can see.
%
% If this file is run stand-alone (i.e. without calling the main function),
% then you have to issue a start command to the timerObj that is output
% from this function. For example -
% t=runStroopTestWtimerWresults(totalRunTime,[OPTIONAL]);
% start(t);
%
% Inputs
% totalRunTime : Total time (in s) this test needs to run
% sPortObj : *OPTIONAL*
% : This object can be used for passing any serial
% object, which can be killed when the timer StopFcn
% is executed
% Congruence : [OPTIONAL][String]
% (as mentioned in parentheses)
% If this arguement is provided, based on this value
% Congruent (C) or Incongruent(IC) or Randomised(R)
% Stroop Test will run.
% FigHdl : *OPTIONAL*
% : This is the figure handle for the test figures
% Outputs
% t : Timer Object Handle if the code is in execution
% (in case you need to kill the timer)
% : UserData Structure if the execution has ended
% -------------------------------------------------------------------------
% Copyright (c) 13-Nov-2014
% Deba Pratim Saha,
% Electrical Engineer, M.S.,
% Ph.D. Student, ECE Virginia Tech.
% Email: [email protected]
% -------------------------------------------------------------------------
%% Argument Checking and Global Vars
if nargin>4
error('err:ArgChk','This function takes 4 inputs, the 2nd,3rd and 4th inputs are optional');
end
if nargin<4
FigHdl = 1;
end
if nargin<3
Congruence = 'IC';
end
if nargin<2
sPortObj = {};
end
%% Define the words and colors
global words;
words = ['YELLOW ';'MAGENTA';'CYAN ';'RED ';'GREEN ';'BLUE ';'BLACK ']; %1
global colors;
colors = [1 1 0;1 0 1;0 1 1;1 0 0;0 1 0;0 0 1;0 0 0]; %2
global randomStroopArray;
randomStroopArray = repmat([false false true true false true false true true false],1,6);
global stroopFigHdl;
switch Congruence
case 'C'
Congruence = true; %Congruent stroop test flag
randomStroopFlag = false; %Randomised stroop test flag
case 'IC'
Congruence = false; %InCongruent stroop test flag
randomStroopFlag = false; %Randomised stroop test flag
case 'R'
Congruence = randomStroopArray(1); %InCongruent stroop test flag
randomStroopFlag = true; %Randomised stroop test flag
end
% Set figure userdata based on the congruence props
FigHdl = figure(FigHdl); set(FigHdl,'Visible','Off');
fUserdata = get(FigHdl,'UserData');
fUserdata.('randomStroopFlag') = randomStroopFlag;
set(FigHdl,'UserData',fUserdata);
global dataDirPath;
global congruenceFlagSet;
%% Create Timer
secondsFigureChange = 3;
secondsCongruenceInterval = ceil(totalRunTime/3);
propCongruence = Congruence;
t = timer;
t.UserData = struct('Congruence',propCongruence,...
'tCongruenceCount',0,...
'tEntryCount',0,...
'CongruenceInterval',secondsCongruenceInterval,...
'testData',{{'DUMMY'}});
t.StartFcn = @phaseTimerStart;
t.TimerFcn = @nextFigure;
t.StopFcn = @phaseTimerCleanup;
t.Period = secondsFigureChange;
t.StartDelay = secondsFigureChange;
t.TasksToExecute = ceil(totalRunTime/secondsFigureChange);
t.ExecutionMode = 'fixedSpacing';
% start(t);
%% Run the test
function phaseTimerStart(mTimer,~)
tUserdata = mTimer.UserData;
% fprintf('Starting StroopTest with Congruence = %d\n',tUserdata.Congruence);
[stroopFigHdl] = StroopTest(words,colors,tUserdata.Congruence,1,FigHdl);
end
function nextFigure(mTimer,~)
tUserdata = mTimer.UserData;
tUserdata.tCongruenceCount = tUserdata.tCongruenceCount + 1; % Var to determine congruence change
tUserdata.tEntryCount = tUserdata.tEntryCount + 1; % Timer callback entry count
tUserdata.testData{tUserdata.tEntryCount,:} = get(stroopFigHdl,'UserData'); % Append the user's test data
% Figure Modification starts for next cycle
delete(findobj(stroopFigHdl,'Tag','StroopString')); % Delete the StroopString by finding the text
btnGrpObj = findobj(stroopFigHdl,'Tag','existingBtnGrp'); % Find the buttongroup object
set(get(btnGrpObj,'Children'),'Enable','Inactive'); % Deactivate the buttons until next figures appears
% Check the user choice and display RIGHT/WRONG
colorShown = tUserdata.testData{tUserdata.tEntryCount,1}.inputColor;
userChoiceString = tUserdata.testData{tUserdata.tEntryCount,1}.choice;
colorIndex = find(ismember(words,userChoiceString,'rows'));
colorEvaluation = isequal(colors(colorIndex,:),colorShown);
if ~isempty(findobj(stroopFigHdl,'Tag','evalMsg')) % delete any previous msg
delete(findobj(stroopFigHdl,'Tag','evalMsg')); end
if colorEvaluation
disp('correct');
text(stroopFigHdl.Number,0.1,0.1,'Correct Choice!!','Tag','evalMsg');
else
disp('wrong');
text(stroopFigHdl.Number,0.1,0.1,'Wrong Choice','Tag','evalMsg');
end
% Check Stroop Test version - Random or Planned
if tUserdata.testData{tUserdata.tEntryCount,1}.randomStroopFlag
tUserdata.Congruence = randomStroopArray(tUserdata.tEntryCount);
end
% Check whether to change the Congruence value
if ~congruenceFlagSet
if (tUserdata.tCongruenceCount * (mTimer.Period)...
>= tUserdata.CongruenceInterval)
tUserdata.Congruence = ~ tUserdata.Congruence;
tUserdata.tCongruenceCount = 0;
end
end
mTimer.UserData = tUserdata;
% fprintf('Next Stroop Figure with EntryCount = %d and Congruence = %d\n',...
% tUserdata.tCongruenceCount,tUserdata.Congruence);
[stroopFigHdl] = StroopTest(words,colors,tUserdata.Congruence,1,stroopFigHdl);
end
function phaseTimerCleanup(mTimer,~)
disp('Clearing Timer and all figures');
close(stroopFigHdl);
% Save the Stroop Test Data
tUserdata = mTimer.UserData;
delete(mTimer);
stroopDataDump = evalin('base','{}'); % Create an empty var in base WS
assignin('base','stroopDataDump',tUserdata.testData); % Assign value to var
stroopDataDump = evalin('base','stroopDataDump'); % Get the updated value from base WS
% Close the serial port object, if valid obj was passed from main
if exist('sPortObj','var') && ~isempty(sPortObj)
serialDataDump = evalin('base','serialDataDump'); % Get the value from base workspace
if isvalid(sPortObj)
fclose(sPortObj);
delete(sPortObj);
clear sPortObj;
end
end
% Choose to save test data
saveQuestion = questdlg('Do you want to save all test data?','Save Test Data');
switch saveQuestion
case 'Yes'
folderName = strcat(dataDirPath,'user_',stroopDataDump{end}.userID);
disp(folderName);
if ~exist(folderName,'dir')
mkdir(strcat(folderName,'\stroop'));
end
fileName = strcat(folderName,'\stroop','\user_',stroopDataDump{end}.userID,'_phase_',stroopDataDump{end}.PhaseNum,'_',datestr(clock,30),'.mat');
fileID = fopen(fileName,'w');
if exist('sPortObj','var') && ~isempty(sPortObj)
% Save both physio and stroop data variables
save (fileName,'stroopDataDump','serialDataDump');
else
% Save only stroop data variables
save (fileName,'stroopDataDump');
end
fclose(fileID);
case 'No'
disp('YOUR DATA IS NOT SAVED');
case 'Cancel'
end
end
end