rmeddis@28
|
1 function varargout = subjGUI_MT(varargin)
|
rmeddis@28
|
2
|
rmeddis@28
|
3 % Begin initialization code - DO NOT EDIT
|
rmeddis@28
|
4 gui_Singleton = 1;
|
rmeddis@28
|
5 gui_State = struct('gui_Name', mfilename, ...
|
rmeddis@28
|
6 'gui_Singleton', gui_Singleton, ...
|
rmeddis@28
|
7 'gui_OpeningFcn', @subjGUI_MT_OpeningFcn, ...
|
rmeddis@28
|
8 'gui_OutputFcn', @subjGUI_MT_OutputFcn, ...
|
rmeddis@28
|
9 'gui_LayoutFcn', [] , ...
|
rmeddis@28
|
10 'gui_Callback', []);
|
rmeddis@28
|
11 if nargin && isstr(varargin{1})
|
rmeddis@28
|
12 gui_State.gui_Callback = str2func(varargin{1});
|
rmeddis@28
|
13 end
|
rmeddis@28
|
14
|
rmeddis@28
|
15 if nargout
|
rmeddis@28
|
16 [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
|
rmeddis@28
|
17 else
|
rmeddis@28
|
18 gui_mainfcn(gui_State, varargin{:});
|
rmeddis@28
|
19 end
|
rmeddis@28
|
20 % End initialization code - DO NOT EDIT
|
rmeddis@28
|
21
|
rmeddis@28
|
22 % --- Executes just before subjGUI_MT is made visible.
|
rmeddis@28
|
23 function subjGUI_MT_OpeningFcn(hObject, eventdata, handles, varargin)
|
rmeddis@28
|
24
|
rmeddis@28
|
25 % Choose default command line output for subjGUI_MT
|
rmeddis@28
|
26 handles.output = hObject;
|
rmeddis@28
|
27 initializeGUI(handles)
|
rmeddis@28
|
28 guidata(hObject, handles);
|
rmeddis@28
|
29
|
rmeddis@28
|
30 function varargout = subjGUI_MT_OutputFcn(hObject, eventdata, handles)
|
rmeddis@28
|
31 % Get default command line output from handles structure
|
rmeddis@28
|
32 varargout{1} = handles.output;
|
rmeddis@28
|
33
|
rmeddis@28
|
34 % -----------------------------------------------------initializeGUI
|
rmeddis@28
|
35 function initializeGUI(handles)
|
rmeddis@28
|
36 global experiment
|
rmeddis@28
|
37 global subjectGUIHandles expGUIhandles
|
rmeddis@28
|
38 addpath (['..' filesep 'MAP'], ['..' filesep 'utilities'], ...
|
rmeddis@28
|
39 ['..' filesep 'parameterStore'], ['..' filesep 'wavFileStore'],...
|
rmeddis@28
|
40 ['..' filesep 'testPrograms'])
|
rmeddis@28
|
41
|
rmeddis@28
|
42 dbstop if error
|
rmeddis@28
|
43
|
rmeddis@28
|
44 % subjectGUI size and location % [left bottom width height]
|
rmeddis@28
|
45 scrnsize=get(0,'screensize');
|
rmeddis@28
|
46 set(0, 'units','pixels')
|
rmeddis@28
|
47 switch experiment.ear
|
rmeddis@28
|
48 % use default size unless...
|
rmeddis@28
|
49 case {'MAPmodel', 'MAPmodelMultich', 'MAPmodelSingleCh', ...
|
rmeddis@28
|
50 'statsModelLogistic','statsModelRareEvent'}
|
rmeddis@28
|
51 % subjectGUI not needed for modelling so minimize subject GUI
|
rmeddis@28
|
52 set(gcf, 'units','pixels')
|
rmeddis@28
|
53 y=[0*scrnsize(3) 0.8*scrnsize(4) 0.1*scrnsize(3) 0.2*scrnsize(4)];
|
rmeddis@28
|
54 set(gcf,'position',y, 'color',[.871 .961 .996])
|
rmeddis@28
|
55
|
rmeddis@28
|
56
|
rmeddis@28
|
57
|
rmeddis@28
|
58 case 'MAPmodelListen',
|
rmeddis@28
|
59 % subjectGUI is needed for display purposes. Make it large
|
rmeddis@28
|
60 set(gcf, 'units','pixels')
|
rmeddis@28
|
61 y=[.665*scrnsize(3) 0.02*scrnsize(4) ...
|
rmeddis@28
|
62 0.33*scrnsize(3) 0.5*scrnsize(4)]; % alongside
|
rmeddis@28
|
63 set(gcf,'position',y, 'color',[.871 .961 .996])
|
rmeddis@28
|
64 end
|
rmeddis@28
|
65
|
rmeddis@28
|
66 switch experiment.ear
|
rmeddis@28
|
67 case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'}
|
rmeddis@28
|
68 % Look to see if the button box exists and, if so, initialise it
|
rmeddis@28
|
69 buttonBoxIntitialize % harmless if no button box attached
|
rmeddis@28
|
70 end
|
rmeddis@28
|
71
|
rmeddis@28
|
72 % function varargout = subjGUI_MT(varargin)
|
rmeddis@28
|
73 %
|
rmeddis@28
|
74 % % Begin initialization code - DO NOT EDIT
|
rmeddis@28
|
75 % gui_Singleton = 1;
|
rmeddis@28
|
76 % gui_State = struct('gui_Name', mfilename, ...
|
rmeddis@28
|
77 % 'gui_Singleton', gui_Singleton, ...
|
rmeddis@28
|
78 % 'gui_OpeningFcn', @subjGUI_MT_OpeningFcn, ...
|
rmeddis@28
|
79 % 'gui_OutputFcn', @subjGUI_MT_OutputFcn, ...
|
rmeddis@28
|
80 % 'gui_LayoutFcn', [] , ...
|
rmeddis@28
|
81 % 'gui_Callback', []);
|
rmeddis@28
|
82 % if nargin && isstr(varargin{1})
|
rmeddis@28
|
83 % gui_State.gui_Callback = str2func(varargin{1});
|
rmeddis@28
|
84 % end
|
rmeddis@28
|
85 %
|
rmeddis@28
|
86 % if nargout
|
rmeddis@28
|
87 % [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
|
rmeddis@28
|
88 % else
|
rmeddis@28
|
89 % gui_mainfcn(gui_State, varargin{:});
|
rmeddis@28
|
90 % end
|
rmeddis@28
|
91 % % End initialization code - DO NOT EDIT
|
rmeddis@28
|
92 %
|
rmeddis@28
|
93 % % --- Executes just before subjGUI_MT is made visible.
|
rmeddis@28
|
94 % function subjGUI_MT_OpeningFcn(hObject, eventdata, handles, varargin)
|
rmeddis@28
|
95 %
|
rmeddis@28
|
96 % % Choose default command line output for subjGUI_MT
|
rmeddis@28
|
97 % handles.output = hObject;
|
rmeddis@28
|
98 % initializeGUI(handles)
|
rmeddis@28
|
99 % guidata(hObject, handles);
|
rmeddis@28
|
100 %
|
rmeddis@28
|
101 % function varargout = subjGUI_MT_OutputFcn(hObject, eventdata, handles)
|
rmeddis@28
|
102 % % Get default command line output from handles structure
|
rmeddis@28
|
103 % varargout{1} = handles.output;
|
rmeddis@28
|
104 %
|
rmeddis@28
|
105 % % -----------------------------------------------------initializeGUI
|
rmeddis@28
|
106 % function initializeGUI(handles)
|
rmeddis@28
|
107 % global experiment
|
rmeddis@28
|
108 % global subjectGUIHandles expGUIhandles
|
rmeddis@28
|
109 %
|
rmeddis@28
|
110 % dbstop if error
|
rmeddis@28
|
111 %
|
rmeddis@28
|
112 % % subjectGUI size and location % [left bottom width height]
|
rmeddis@28
|
113 % scrnsize=get(0,'screensize');
|
rmeddis@28
|
114 % set(0, 'units','pixels')
|
rmeddis@28
|
115 % switch experiment.ear
|
rmeddis@28
|
116 % % use default size unless...
|
rmeddis@28
|
117 % case {'MAPmodel', 'MAPmodelMultiCh','MAPmodelSingleCh', ...
|
rmeddis@28
|
118 % 'statsModelLogistic','statsModelRareEvent'}
|
rmeddis@28
|
119 % % subjectGUI not needed for modelling so minimize subject GUI
|
rmeddis@28
|
120 % set(gcf, 'units','pixels')
|
rmeddis@28
|
121 % y=[0*scrnsize(3) 0.8*scrnsize(4) 0.1*scrnsize(3) 0.2*scrnsize(4)];
|
rmeddis@28
|
122 % set(gcf,'position',y, 'color',[.871 .961 .996])
|
rmeddis@28
|
123 %
|
rmeddis@28
|
124 % case 'MAPmodelListen',
|
rmeddis@28
|
125 % % subjectGUI is needed for display purposes. Make it large
|
rmeddis@28
|
126 % set(gcf, 'units','pixels')
|
rmeddis@28
|
127 % y=[.665*scrnsize(3) 0.02*scrnsize(4) ...
|
rmeddis@28
|
128 % 0.33*scrnsize(3) 0.5*scrnsize(4)]; % alongside
|
rmeddis@28
|
129 % set(gcf,'position',y, 'color',[.871 .961 .996])
|
rmeddis@28
|
130 % end
|
rmeddis@28
|
131 %
|
rmeddis@28
|
132 % switch experiment.ear
|
rmeddis@28
|
133 % case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'}
|
rmeddis@28
|
134 % % Look to see if the button box exists and, if so, initialise it
|
rmeddis@28
|
135 % buttonBoxIntitialize % harmless if no button box attached
|
rmeddis@28
|
136 % end
|
rmeddis@28
|
137
|
rmeddis@28
|
138 % clear display of previous mean values. This is a new measurement series
|
rmeddis@28
|
139 axes(expGUIhandles.axes4), cla
|
rmeddis@28
|
140 reset (expGUIhandles.axes4)
|
rmeddis@28
|
141
|
rmeddis@28
|
142 % handles needed in non-callback routines below
|
rmeddis@28
|
143 subjectGUIHandles=handles;
|
rmeddis@28
|
144
|
rmeddis@28
|
145 % start immediately
|
rmeddis@28
|
146 startNewExperiment(handles, expGUIhandles)
|
rmeddis@28
|
147 % This is the end of the experiment. Exit here and return to ExpGUI.
|
rmeddis@28
|
148
|
rmeddis@28
|
149 % ----------------------------------------------------- startNewExperiment
|
rmeddis@28
|
150 function startNewExperiment(handles, expGUIhandles)
|
rmeddis@28
|
151 % An experiment consists of a series of 'runs'.
|
rmeddis@28
|
152 % Resets all relevant variables at the beginning of a new experiment.
|
rmeddis@28
|
153 global experiment stimulusParameters betweenRuns
|
rmeddis@28
|
154
|
rmeddis@28
|
155 % 'start new experiment' button is the only valid action now
|
rmeddis@28
|
156 experiment.status='waitingForStart';
|
rmeddis@28
|
157
|
rmeddis@28
|
158 switch experiment.threshEstMethod
|
rmeddis@28
|
159 % add appropriate labels to subject GUI buttons
|
rmeddis@28
|
160 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@28
|
161 set(handles.pushbutton3,'string','')
|
rmeddis@28
|
162 set(handles.pushbutton2,'string','2')
|
rmeddis@28
|
163 set(handles.pushbutton1,'string','1')
|
rmeddis@28
|
164 set(handles.pushbutton0,'string','0')
|
rmeddis@28
|
165 case {'MaxLikelihood', 'oneIntervalUpDown'}
|
rmeddis@28
|
166 if stimulusParameters.includeCue
|
rmeddis@28
|
167 set(handles.pushbutton3,'string','')
|
rmeddis@28
|
168 set(handles.pushbutton2,'string','2')
|
rmeddis@28
|
169 set(handles.pushbutton1,'string','1')
|
rmeddis@28
|
170 set(handles.pushbutton0,'string','0')
|
rmeddis@28
|
171 else
|
rmeddis@28
|
172 set(handles.pushbutton3,'string','')
|
rmeddis@28
|
173 set(handles.pushbutton2,'string','YES')
|
rmeddis@28
|
174 set(handles.pushbutton1,'string','NO')
|
rmeddis@28
|
175 set(handles.pushbutton0,'string','')
|
rmeddis@28
|
176 end
|
rmeddis@28
|
177 end
|
rmeddis@28
|
178
|
rmeddis@28
|
179 switch experiment.paradigm
|
rmeddis@28
|
180 case 'discomfort'
|
rmeddis@28
|
181 set(handles.pushbutton3,'string','')
|
rmeddis@28
|
182 set(handles.pushbutton2,'string','uncomfortable')
|
rmeddis@28
|
183 set(handles.pushbutton1,'string','loud')
|
rmeddis@28
|
184 set(handles.pushbutton0,'string','comfortable')
|
rmeddis@28
|
185 experiment.allowCatchTrials=0;
|
rmeddis@28
|
186 end
|
rmeddis@28
|
187
|
rmeddis@28
|
188 % experiment.subjGUIfontSize is set on expGUI
|
rmeddis@28
|
189 set(handles.pushbutton3,'FontSize',experiment.subjGUIfontSize)
|
rmeddis@28
|
190 set(handles.pushbutton2,'FontSize',experiment.subjGUIfontSize)
|
rmeddis@28
|
191 set(handles.pushbutton1,'FontSize',experiment.subjGUIfontSize)
|
rmeddis@28
|
192 set(handles.pushbutton0,'FontSize',experiment.subjGUIfontSize)
|
rmeddis@28
|
193 set(handles.pushbuttoNotSure,'FontSize',experiment.subjGUIfontSize)
|
rmeddis@28
|
194 set(handles.pushbuttonGO,'FontSize',experiment.subjGUIfontSize)
|
rmeddis@28
|
195 set(handles.textMSG,'FontSize',experiment.subjGUIfontSize)
|
rmeddis@28
|
196
|
rmeddis@28
|
197 set(handles.pushbutton19,'visible','off') % unused button
|
rmeddis@28
|
198
|
rmeddis@28
|
199 % start command window summary of progress
|
rmeddis@28
|
200 fprintf(' \n ----------- NEW MEASUREMENTS\n')
|
rmeddis@28
|
201 disp(['paradigm: ' experiment.paradigm])
|
rmeddis@28
|
202 cla(expGUIhandles.axes1)
|
rmeddis@28
|
203 cla(expGUIhandles.axes2)
|
rmeddis@28
|
204 cla(expGUIhandles.axes4)
|
rmeddis@28
|
205 cla(expGUIhandles.axes5)
|
rmeddis@28
|
206
|
rmeddis@28
|
207 experiment.stop=0; % status of 'stop' button
|
rmeddis@28
|
208 experiment.pleaseRepeat=0; % status of 'repeat' button
|
rmeddis@28
|
209 experiment.buttonBoxStatus='not busy';
|
rmeddis@28
|
210
|
rmeddis@28
|
211 % date and time and replace ':' with '_'
|
rmeddis@28
|
212 date=datestr(now);idx=findstr(':',date);date(idx)='_';
|
rmeddis@28
|
213 experiment.date=date;
|
rmeddis@28
|
214 timeNow=clock; betweenRuns.timeNow= timeNow;
|
rmeddis@28
|
215 experiment.timeAtStart=[num2str(timeNow(4)) ':' num2str(timeNow(5))];
|
rmeddis@28
|
216 experiment.minElapsed=0;
|
rmeddis@28
|
217
|
rmeddis@28
|
218 % unpack catch trial rates. The rate declines from the start rate
|
rmeddis@28
|
219 % to the base rate using a time constant.
|
rmeddis@28
|
220 stimulusParameters.catchTrialRate=stimulusParameters.catchTrialRates(1);
|
rmeddis@28
|
221 stimulusParameters.catchTrialBaseRate=...
|
rmeddis@28
|
222 stimulusParameters.catchTrialRates(2);
|
rmeddis@28
|
223 stimulusParameters.catchTrialTimeConstant=...
|
rmeddis@28
|
224 stimulusParameters.catchTrialRates(3);
|
rmeddis@28
|
225 if stimulusParameters.catchTrialBaseRate==0
|
rmeddis@28
|
226 stimulusParameters.catchTrialRate=0;
|
rmeddis@28
|
227 end
|
rmeddis@28
|
228
|
rmeddis@28
|
229 % for human measurements only, identify the start catch trial rate
|
rmeddis@28
|
230 switch experiment.ear
|
rmeddis@28
|
231 case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'}
|
rmeddis@28
|
232 fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
|
rmeddis@28
|
233 stimulusParameters.catchTrialRate)
|
rmeddis@28
|
234 end
|
rmeddis@28
|
235
|
rmeddis@28
|
236 % Reset betweenRuns parameters. this occurs only at experiment start
|
rmeddis@28
|
237 % withinRuns values are reset in 'startNewRun'
|
rmeddis@28
|
238 % this approach creates a more readable structure summary printout.
|
rmeddis@28
|
239 betweenRuns.thresholds=[];
|
rmeddis@28
|
240 betweenRuns.thresholds_mean=[];
|
rmeddis@28
|
241 betweenRuns.thresholds_median=[];
|
rmeddis@28
|
242 betweenRuns.forceThresholds=[];
|
rmeddis@28
|
243 betweenRuns.observationCount=[];
|
rmeddis@28
|
244 betweenRuns.catchTrials=[];
|
rmeddis@28
|
245 betweenRuns.timesOfFirstReversals=[];
|
rmeddis@28
|
246 betweenRuns.bestThresholdTracks=[];
|
rmeddis@28
|
247 betweenRuns.levelTracks=[];
|
rmeddis@28
|
248 betweenRuns.responseTracks=[];
|
rmeddis@28
|
249 betweenRuns.slopeKTracks=[];
|
rmeddis@28
|
250 betweenRuns.gainTracks=[];
|
rmeddis@28
|
251 betweenRuns.VminTracks=[];
|
rmeddis@28
|
252 betweenRuns.bestGain=[];
|
rmeddis@28
|
253 betweenRuns.bestVMin=[];
|
rmeddis@28
|
254 betweenRuns.bestPaMin=[];
|
rmeddis@28
|
255 betweenRuns.bestLogisticM=[];
|
rmeddis@28
|
256 betweenRuns.bestLogisticK=[];
|
rmeddis@28
|
257 betweenRuns.resets=0;
|
rmeddis@28
|
258 betweenRuns.runNumber=0;
|
rmeddis@28
|
259
|
rmeddis@28
|
260 % Up to two parameters can be changed between runs
|
rmeddis@28
|
261 % Find the variable parameters and randomize them
|
rmeddis@28
|
262 % e.g. 'variableList1 = stimulusParameters.targetFrequency;'
|
rmeddis@28
|
263 eval(['variableList1=stimulusParameters.' betweenRuns.variableName1 ';']);
|
rmeddis@28
|
264 eval(['variableList2=stimulusParameters.' betweenRuns.variableName2 ';']);
|
rmeddis@28
|
265 nVar1=length(variableList1);
|
rmeddis@28
|
266 nVar2=length(variableList2);
|
rmeddis@28
|
267
|
rmeddis@28
|
268 % Create two sequence vectors to represent the sequence of var1 and var2
|
rmeddis@28
|
269 % values. 'var1' changes most rapidly.
|
rmeddis@28
|
270 switch betweenRuns.randomizeSequence
|
rmeddis@28
|
271 case 'fixed sequence'
|
rmeddis@28
|
272 var1Sequence=repmat(betweenRuns.variableList1, 1,nVar2);
|
rmeddis@28
|
273 var2Sequence=reshape(repmat(betweenRuns.variableList2, ...
|
rmeddis@28
|
274 nVar1,1),1,nVar1*nVar2);
|
rmeddis@28
|
275 case 'randomize within blocks'
|
rmeddis@28
|
276 % the blocks are not randomized
|
rmeddis@28
|
277 var1Sequence=betweenRuns.variableList1;
|
rmeddis@28
|
278 ranNums=rand(1, length(var1Sequence)); [x idx]=sort(ranNums);
|
rmeddis@28
|
279 var1Sequence=var1Sequence(idx);
|
rmeddis@28
|
280 betweenRuns.variableList1=variableList1(idx);
|
rmeddis@28
|
281 var1Sequence=repmat(var1Sequence, 1,nVar2);
|
rmeddis@28
|
282 var2Sequence=reshape(repmat(betweenRuns.variableList2, nVar1,1)...
|
rmeddis@28
|
283 ,1,nVar1*nVar2);
|
rmeddis@28
|
284 case 'randomize across blocks'
|
rmeddis@28
|
285 var1Sequence=repmat(betweenRuns.variableList1, 1,nVar2);
|
rmeddis@28
|
286 var2Sequence=reshape(repmat(betweenRuns.variableList2, nVar1,1),...
|
rmeddis@28
|
287 1,nVar1*nVar2);
|
rmeddis@28
|
288 ranNums=rand(1, nVar1*nVar2);
|
rmeddis@28
|
289 [x idx]=sort(ranNums);
|
rmeddis@28
|
290 var1Sequence=var1Sequence(idx);
|
rmeddis@28
|
291 var2Sequence=var2Sequence(idx);
|
rmeddis@28
|
292 % there should be one start value for every combination
|
rmeddis@28
|
293 % of var1/ var2. In principle this allows these values to be
|
rmeddis@28
|
294 % programmed. Not currently in use.
|
rmeddis@28
|
295 stimulusParameters.WRVstartValues=...
|
rmeddis@28
|
296 stimulusParameters.WRVstartValues(idx);
|
rmeddis@28
|
297 end
|
rmeddis@28
|
298 betweenRuns.var1Sequence=var1Sequence;
|
rmeddis@28
|
299 betweenRuns.var2Sequence=var2Sequence;
|
rmeddis@28
|
300
|
rmeddis@28
|
301 % caught out vector needs to be linked to the length of the whole sequence
|
rmeddis@28
|
302 betweenRuns.caughtOut=zeros(1,length(var1Sequence));
|
rmeddis@28
|
303
|
rmeddis@28
|
304 disp('planned sequence:')
|
rmeddis@28
|
305 if min(var1Sequence)>1
|
rmeddis@28
|
306 % use decidaml places only if necessary
|
rmeddis@28
|
307 disp([betweenRuns.variableName1 ': ' num2str(var1Sequence,'%6.0f') ])
|
rmeddis@28
|
308 else
|
rmeddis@28
|
309 disp([betweenRuns.variableName1 ': ' num2str(var1Sequence,'%8.3f') ])
|
rmeddis@28
|
310 end
|
rmeddis@28
|
311 if min(var1Sequence)>1
|
rmeddis@28
|
312 disp([betweenRuns.variableName2 ': ' num2str(var2Sequence,'%6.0f') ])
|
rmeddis@28
|
313 else
|
rmeddis@28
|
314 disp([betweenRuns.variableName2 ': ' num2str(var2Sequence,'%8.3f') ])
|
rmeddis@28
|
315 end
|
rmeddis@28
|
316
|
rmeddis@28
|
317 fprintf('\nvariable1 \t variable2\t \n')
|
rmeddis@28
|
318 fprintf('%s \t %s\t Threshold \n',betweenRuns.variableName1,...
|
rmeddis@28
|
319 betweenRuns.variableName2)
|
rmeddis@28
|
320
|
rmeddis@28
|
321 % Light up 'GO' on subjGUI and advise.
|
rmeddis@28
|
322 set(handles.editdigitInput,'visible','off')
|
rmeddis@28
|
323 switch experiment.ear
|
rmeddis@28
|
324 case {'statsModelLogistic', 'statsModelRareEvent',...
|
rmeddis@28
|
325 'MAPmodel', 'MAPmodelMultiCh','MAPmodelSingleCh'}
|
rmeddis@28
|
326 % no changes required if model used
|
rmeddis@28
|
327 otherwise
|
rmeddis@28
|
328 set(handles.pushbuttonGO,'backgroundcolor','y')
|
rmeddis@28
|
329 set(handles.pushbuttonGO,'visible','on')
|
rmeddis@28
|
330 set(handles.frame1,'visible','off')
|
rmeddis@28
|
331 set(handles.textMSG,'backgroundcolor', 'w')
|
rmeddis@28
|
332 msg=[{'Ready to start new Experiment'}, {' '}, {'Please, click on the GO button'}];
|
rmeddis@28
|
333 set(handles.textMSG,'string', msg)
|
rmeddis@28
|
334
|
rmeddis@28
|
335 set(handles.pushbuttoNotSure,'visible','off')
|
rmeddis@28
|
336 set(handles.pushbuttonWrongButton,'visible','off')
|
rmeddis@28
|
337 set(handles.pushbutton3,'visible','off')
|
rmeddis@28
|
338 set(handles.pushbutton2,'visible','off')
|
rmeddis@28
|
339 set(handles.pushbutton1,'visible','off')
|
rmeddis@28
|
340 set(handles.pushbutton0,'visible','off')
|
rmeddis@28
|
341 pause(.1) % to allow display to be drawn
|
rmeddis@28
|
342 end
|
rmeddis@28
|
343
|
rmeddis@28
|
344 % Selecting the 'GO' button is the only valid operation action now
|
rmeddis@28
|
345 experiment.status='waitingForGO'; % i.e. waiting for new run
|
rmeddis@28
|
346
|
rmeddis@28
|
347 % control is now either manual, model (MAP) or randomization
|
rmeddis@28
|
348 switch experiment.ear
|
rmeddis@28
|
349 case {'MAPmodel','MAPmodelMultiCh','MAPmodelSingleCh','MAPmodelListen'} % MAP model is now the subject
|
rmeddis@28
|
350 stimulusParameters.calibrationdB=0; % Pascals required!
|
rmeddis@28
|
351 MAPmodelRunsGUI(handles)
|
rmeddis@28
|
352 % model is now the subject
|
rmeddis@28
|
353 case {'statsModelLogistic', 'statsModelRareEvent'}
|
rmeddis@28
|
354 % no catch trials for the statistical model
|
rmeddis@28
|
355 stimulusParameters.catchTrialBaseRate=0;
|
rmeddis@28
|
356 stimulusParameters.catchTrialRate=0;
|
rmeddis@28
|
357 statsModelRunsGUI(handles)
|
rmeddis@28
|
358 otherwise
|
rmeddis@28
|
359 %manual operation; wait for user to click on 'GO'
|
rmeddis@28
|
360 end
|
rmeddis@28
|
361
|
rmeddis@28
|
362 % Experiment complete (after MAP or randomization)
|
rmeddis@28
|
363 % return to 'initializeGUI' and then back to expGUI
|
rmeddis@28
|
364 % Manual control finds its own way home. Program control assumed when
|
rmeddis@28
|
365 % the user hits the GO button
|
rmeddis@28
|
366
|
rmeddis@28
|
367 % ----------------------------------------------------------------- startNewRun
|
rmeddis@28
|
368 function startNewRun(handles)
|
rmeddis@28
|
369 % There are many ways to arrive here.
|
rmeddis@28
|
370 % Under manual control this is achieved by hitting the GO button
|
rmeddis@28
|
371 % either via the button box or a mouse click
|
rmeddis@28
|
372 % MAP and randomization methods call this too
|
rmeddis@28
|
373
|
rmeddis@28
|
374 global experiment stimulusParameters betweenRuns withinRuns expGUIhandles
|
rmeddis@28
|
375 global LevittControl rareEvent
|
rmeddis@28
|
376
|
rmeddis@28
|
377 figure(handles.figure1) % guarantee subject GUI visibility
|
rmeddis@28
|
378
|
rmeddis@28
|
379 % ignore call if program is not ready
|
rmeddis@28
|
380 if ~strcmp(experiment.status,'waitingForGO'), return, end
|
rmeddis@28
|
381
|
rmeddis@28
|
382 set(handles.pushbuttonGO,'visible','off')
|
rmeddis@28
|
383
|
rmeddis@28
|
384 % append message to expGUI message box to alert experimenter that the user
|
rmeddis@28
|
385 % is active
|
rmeddis@28
|
386 addToMsg('Starting new trial',0)
|
rmeddis@28
|
387
|
rmeddis@28
|
388 cla(expGUIhandles.axes1), title(''); % stimulus
|
rmeddis@28
|
389 cla(expGUIhandles.axes2), title(''); % WRV track
|
rmeddis@28
|
390 drawnow
|
rmeddis@28
|
391
|
rmeddis@28
|
392 betweenRuns.runNumber=betweenRuns.runNumber + 1;
|
rmeddis@28
|
393
|
rmeddis@28
|
394 withinRuns.trialNumber=1;
|
rmeddis@28
|
395 withinRuns.variableValue=...
|
rmeddis@28
|
396 stimulusParameters.WRVstartValues(betweenRuns.runNumber);
|
rmeddis@28
|
397 % add random jitter to start level
|
rmeddis@28
|
398 if ~experiment.singleShot
|
rmeddis@28
|
399 % SS or single shot allows the user to precisely set the WRV
|
rmeddis@28
|
400 withinRuns.variableValue=withinRuns.variableValue +...
|
rmeddis@28
|
401 (rand-0.5)*stimulusParameters.jitterStartdB;
|
rmeddis@28
|
402 end
|
rmeddis@28
|
403
|
rmeddis@28
|
404 withinRuns.peaks=[];
|
rmeddis@28
|
405 withinRuns.troughs=[];
|
rmeddis@28
|
406 withinRuns.levelList=[];
|
rmeddis@28
|
407 withinRuns.meanEstTrack=[];
|
rmeddis@28
|
408 withinRuns.bestSlopeK=[];
|
rmeddis@28
|
409 withinRuns.bestGain=[];
|
rmeddis@28
|
410 withinRuns.bestVMin=[];
|
rmeddis@28
|
411 withinRuns.forceThreshold=NaN;
|
rmeddis@28
|
412 withinRuns.responseList=[];
|
rmeddis@28
|
413 withinRuns.caughtOut=0;
|
rmeddis@28
|
414 withinRuns.wrongButton=0;
|
rmeddis@28
|
415 withinRuns.catchTrialCount=0;
|
rmeddis@28
|
416 withinRuns.thresholdEstimateTrack=[];
|
rmeddis@28
|
417
|
rmeddis@28
|
418 withinRuns.beginningOfPhase2=0;
|
rmeddis@28
|
419 withinRuns.nowInPhase2=0;
|
rmeddis@28
|
420 withinRuns.thisIsRepeatTrial=0;
|
rmeddis@28
|
421
|
rmeddis@28
|
422 rareEvent.Euclid=NaN;
|
rmeddis@28
|
423 rareEvent.bestGain=NaN;
|
rmeddis@28
|
424 rareEvent.bestVMin=NaN;
|
rmeddis@28
|
425 rareEvent.thresholddB=0;
|
rmeddis@28
|
426 rareEvent.bestPaMindB=NaN;
|
rmeddis@28
|
427 rareEvent.predictionLevels=[];
|
rmeddis@28
|
428 rareEvent.predictionsRE=[];
|
rmeddis@28
|
429
|
rmeddis@28
|
430 LevittControl.sequence=[];
|
rmeddis@28
|
431
|
rmeddis@28
|
432 % on-screen count of number of runs still to complete
|
rmeddis@28
|
433 trialsToGo=length(betweenRuns.var1Sequence)-betweenRuns.runNumber;
|
rmeddis@28
|
434 set(handles.toGoCounter,'string', trialsToGo);
|
rmeddis@28
|
435
|
rmeddis@28
|
436 switch experiment.threshEstMethod
|
rmeddis@28
|
437 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@28
|
438 % For 2I2AFC the buttons need to be on the screen ab initio
|
rmeddis@28
|
439 Levitt2 % inititalize Levitt2 procedure
|
rmeddis@28
|
440 end
|
rmeddis@28
|
441
|
rmeddis@28
|
442 switch experiment.ear
|
rmeddis@28
|
443 case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'}
|
rmeddis@28
|
444 % allow subject time to recover from 'go' press
|
rmeddis@28
|
445 pause(experiment.clickToStimulusPause)
|
rmeddis@28
|
446 end
|
rmeddis@28
|
447
|
rmeddis@28
|
448 errormsg=nextStimulus(handles); % get the show on the road
|
rmeddis@28
|
449
|
rmeddis@28
|
450 % switch experiment.paradigm
|
rmeddis@28
|
451 % case 'SRT'
|
rmeddis@28
|
452 % set(handles.editdigitInput,'visible','on')
|
rmeddis@28
|
453 % uicontrol(handles.editdigitInput)
|
rmeddis@28
|
454 % end
|
rmeddis@28
|
455
|
rmeddis@28
|
456 % terminate if there is any kind of problem
|
rmeddis@28
|
457 if ~isempty(errormsg)
|
rmeddis@28
|
458 % e.g. limits exceeded, clipping
|
rmeddis@28
|
459 disp(errormsg)
|
rmeddis@28
|
460 runCompleted(handles)
|
rmeddis@28
|
461 return
|
rmeddis@28
|
462 end
|
rmeddis@28
|
463
|
rmeddis@28
|
464 % return route is variable (see intro to this function)
|
rmeddis@28
|
465
|
rmeddis@28
|
466 % -----------------------------------------------------buttonBox_callback
|
rmeddis@28
|
467 function buttonBox_callback(obj, info)
|
rmeddis@28
|
468 global experiment
|
rmeddis@28
|
469 global serobj
|
rmeddis@28
|
470 global subjectGUIHandles
|
rmeddis@28
|
471
|
rmeddis@28
|
472 % do not accept callback if one is already in process
|
rmeddis@28
|
473 if strcmp(experiment.buttonBoxStatus,'busy')
|
rmeddis@28
|
474 disp(' ignored button press')
|
rmeddis@28
|
475 return
|
rmeddis@28
|
476 end
|
rmeddis@28
|
477 experiment.buttonBoxStatus='busy';
|
rmeddis@28
|
478 % fclose(serobj)
|
rmeddis@28
|
479
|
rmeddis@28
|
480 % identify the code of the button pressed
|
rmeddis@28
|
481 buttonPressedNo = fscanf(serobj,'%c',1);
|
rmeddis@28
|
482
|
rmeddis@28
|
483 % This is the map from the button to the Cedrus codes
|
rmeddis@28
|
484 switch experiment.buttonBoxType
|
rmeddis@28
|
485 case 'horizontal'
|
rmeddis@28
|
486 pbGo='7'; pb0='1';
|
rmeddis@28
|
487 pb1='2'; pb2='3';
|
rmeddis@28
|
488 pbRepeat='4'; pbWrong='6'; pbBlank='5';
|
rmeddis@28
|
489 case 'square'
|
rmeddis@28
|
490 pbGo='7'; pb0='1';
|
rmeddis@28
|
491 pb1='3'; pb2='4';
|
rmeddis@28
|
492 pbRepeat='8'; pbWrong='6'; pbBlank='5';
|
rmeddis@28
|
493 end
|
rmeddis@28
|
494
|
rmeddis@28
|
495 % decide what to do
|
rmeddis@28
|
496 switch experiment.status
|
rmeddis@28
|
497 case {'presentingStimulus', 'waitingForStart', 'trialcompleted', ...
|
rmeddis@28
|
498 'endOfExperiment'}
|
rmeddis@28
|
499 disp(' ignored button press')
|
rmeddis@28
|
500
|
rmeddis@28
|
501 case 'waitingForGO'
|
rmeddis@28
|
502 % i.e. waiting for new run
|
rmeddis@28
|
503 if strcmp(buttonPressedNo,pbGo) % only GO button accepted
|
rmeddis@28
|
504 startNewRun(subjectGUIHandles)
|
rmeddis@28
|
505 else
|
rmeddis@28
|
506 disp(' ignored button press')
|
rmeddis@28
|
507 end
|
rmeddis@28
|
508
|
rmeddis@28
|
509 case 'waitingForResponse'
|
rmeddis@28
|
510 % response to stimuli
|
rmeddis@28
|
511 switch buttonPressedNo
|
rmeddis@28
|
512 case pb0 % button 0 (top left)
|
rmeddis@28
|
513 switch experiment.threshEstMethod
|
rmeddis@28
|
514 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@28
|
515 disp(' ignored button press')
|
rmeddis@28
|
516 otherwise
|
rmeddis@28
|
517 set(subjectGUIHandles.pushbutton0,...
|
rmeddis@28
|
518 'backgroundcolor','r')
|
rmeddis@28
|
519 pause(.1)
|
rmeddis@28
|
520 set(subjectGUIHandles.pushbutton0,...
|
rmeddis@28
|
521 'backgroundcolor',get(0,...
|
rmeddis@28
|
522 'defaultUicontrolBackgroundColor'))
|
rmeddis@28
|
523 userSelects0or1(subjectGUIHandles)
|
rmeddis@28
|
524 end
|
rmeddis@28
|
525
|
rmeddis@28
|
526 case pb1 % button 1 (bottom left)
|
rmeddis@28
|
527 switch experiment.threshEstMethod
|
rmeddis@28
|
528 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@28
|
529 userSelects0or1(subjectGUIHandles)
|
rmeddis@28
|
530 otherwise
|
rmeddis@28
|
531 set(subjectGUIHandles.pushbutton1,...
|
rmeddis@28
|
532 'backgroundcolor','r')
|
rmeddis@28
|
533 pause(.1)
|
rmeddis@28
|
534 set(subjectGUIHandles.pushbutton1,...
|
rmeddis@28
|
535 'backgroundcolor',get(0,...
|
rmeddis@28
|
536 'defaultUicontrolBackgroundColor'))
|
rmeddis@28
|
537 userSelects0or1(subjectGUIHandles)
|
rmeddis@28
|
538 end
|
rmeddis@28
|
539
|
rmeddis@28
|
540 case pb2 % button 2 (bottom right)
|
rmeddis@28
|
541 switch experiment.threshEstMethod
|
rmeddis@28
|
542 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@28
|
543 userSelects2 (subjectGUIHandles)
|
rmeddis@28
|
544 otherwise
|
rmeddis@28
|
545 set(subjectGUIHandles.pushbutton2,...
|
rmeddis@28
|
546 'backgroundcolor','r')
|
rmeddis@28
|
547 pause(.1)
|
rmeddis@28
|
548 set(subjectGUIHandles.pushbutton2,...
|
rmeddis@28
|
549 'backgroundcolor',get(0,...
|
rmeddis@28
|
550 'defaultUicontrolBackgroundColor'))
|
rmeddis@28
|
551 userSelects2 (subjectGUIHandles)
|
rmeddis@28
|
552 end
|
rmeddis@28
|
553
|
rmeddis@28
|
554 case pbRepeat % extreme right button
|
rmeddis@28
|
555 switch experiment.threshEstMethod
|
rmeddis@28
|
556 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@28
|
557 disp(' ignored button press')
|
rmeddis@28
|
558 otherwise
|
rmeddis@28
|
559
|
rmeddis@28
|
560 set(subjectGUIHandles.pushbuttoNotSure,...
|
rmeddis@28
|
561 'backgroundcolor','r')
|
rmeddis@28
|
562 pause(.1)
|
rmeddis@28
|
563 set(subjectGUIHandles.pushbuttoNotSure,...
|
rmeddis@28
|
564 'backgroundcolor',get(0,...
|
rmeddis@28
|
565 'defaultUicontrolBackgroundColor'))
|
rmeddis@28
|
566 userSelectsPleaseRepeat (subjectGUIHandles)
|
rmeddis@28
|
567 end
|
rmeddis@28
|
568
|
rmeddis@28
|
569 case {pbWrong, pbBlank}
|
rmeddis@28
|
570 disp(' ignored button press')
|
rmeddis@28
|
571
|
rmeddis@28
|
572 otherwise % unrecognised button
|
rmeddis@28
|
573 disp('ignored button press')
|
rmeddis@28
|
574 end % end (button press number)
|
rmeddis@28
|
575 otherwise
|
rmeddis@28
|
576 disp('ignored button press')
|
rmeddis@28
|
577 end % experiment status
|
rmeddis@28
|
578
|
rmeddis@28
|
579 % All processing returns through here.
|
rmeddis@28
|
580 % fopen(serobj); % flushes the input buffer
|
rmeddis@28
|
581
|
rmeddis@28
|
582 % buttonPressedNo = fscanf(serobj,'%c',1);
|
rmeddis@28
|
583
|
rmeddis@28
|
584 % button box remains 'busy' until after the stimulus has been presented
|
rmeddis@28
|
585 experiment.buttonBoxStatus='not busy';
|
rmeddis@28
|
586
|
rmeddis@28
|
587 % -------------------------------------------------- pushbuttonGO_Callback
|
rmeddis@28
|
588 function pushbuttonGO_Callback(hObject, eventdata, handles)
|
rmeddis@28
|
589 % This is a mouse click path
|
rmeddis@28
|
590 % GO function is also called directly from button box
|
rmeddis@28
|
591 % and from MAP model and stats model
|
rmeddis@28
|
592
|
rmeddis@28
|
593 set(handles.pushbuttonGO,'visible','off')
|
rmeddis@28
|
594 startNewRun(handles)
|
rmeddis@28
|
595
|
rmeddis@28
|
596 % ---------------------------------------------------pushbutton0_Callback
|
rmeddis@28
|
597 function pushbutton0_Callback(hObject, eventdata, handles)
|
rmeddis@28
|
598 global experiment
|
rmeddis@28
|
599 % This is a mouse click path
|
rmeddis@28
|
600
|
rmeddis@28
|
601 % ignore 0 button if 2I2AFC used
|
rmeddis@28
|
602 if findstr(experiment.threshEstMethod,'2I2AFC'), return, end
|
rmeddis@28
|
603
|
rmeddis@28
|
604 % userDoesNotHearTarget(handles) % only possible interpretation
|
rmeddis@28
|
605 userDecides(handles, false)
|
rmeddis@28
|
606
|
rmeddis@28
|
607 % -------------------------------------------------- pushbutton1_Callback
|
rmeddis@28
|
608 function pushbutton1_Callback(hObject, eventdata, handles)
|
rmeddis@28
|
609 userSelects0or1(handles) % also called from buttonBox
|
rmeddis@28
|
610
|
rmeddis@28
|
611 % ---------------------------------------------------pushbutton2_Callback
|
rmeddis@28
|
612 function pushbutton2_Callback(hObject, eventdata, handles)
|
rmeddis@28
|
613 userSelects2(handles) % also called from buttonBox
|
rmeddis@28
|
614
|
rmeddis@28
|
615 % --------------------------------------------- pushbuttoNotSure_Callback
|
rmeddis@28
|
616 function pushbuttoNotSure_Callback(hObject, eventdata, handles)
|
rmeddis@28
|
617 userSelectsPleaseRepeat(handles) % also called from buttonBox
|
rmeddis@28
|
618
|
rmeddis@28
|
619 % -------------------------------------------------- pushbutton3_Callback
|
rmeddis@28
|
620 function pushbutton3_Callback(hObject, eventdata, handles)
|
rmeddis@28
|
621
|
rmeddis@28
|
622 % ------------------------------------------------- pushbutton19_Callback
|
rmeddis@28
|
623 function pushbutton19_Callback(hObject, eventdata, handles)
|
rmeddis@28
|
624 % should be invisible (ignore)
|
rmeddis@28
|
625
|
rmeddis@28
|
626 % --------------------------------------- pushbuttonWrongButton_Callback
|
rmeddis@28
|
627 function pushbuttonWrongButton_Callback(hObject, eventdata, handles)
|
rmeddis@28
|
628 userSelectsWrongButton(handles)
|
rmeddis@28
|
629
|
rmeddis@28
|
630 % --------------------------------------- editdigitInput_Callback
|
rmeddis@28
|
631 function editdigitInput_Callback(hObject, eventdata, handles)
|
rmeddis@28
|
632 userSelects0or1(handles) % after digit string input
|
rmeddis@28
|
633
|
rmeddis@28
|
634
|
rmeddis@28
|
635
|
rmeddis@28
|
636 % ----------------------------------------------------- userSelects0or1
|
rmeddis@28
|
637 function userSelects0or1(handles)
|
rmeddis@28
|
638 global experiment withinRuns
|
rmeddis@28
|
639
|
rmeddis@28
|
640 switch experiment.threshEstMethod
|
rmeddis@28
|
641 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@28
|
642 switch withinRuns.stimulusOrder
|
rmeddis@28
|
643 case 'targetFirst';
|
rmeddis@28
|
644 % userHearsTarget(handles)
|
rmeddis@28
|
645 userDecides(handles, true)
|
rmeddis@28
|
646 otherwise
|
rmeddis@28
|
647 % userDoesNotHearTarget(handles)
|
rmeddis@28
|
648 userDecides(handles, false)
|
rmeddis@28
|
649 end
|
rmeddis@28
|
650 otherwise
|
rmeddis@28
|
651 % single interval
|
rmeddis@28
|
652 % 0 or 1 are treated as equivalent (i.e. target is not heard)
|
rmeddis@28
|
653 userDecides(handles, false)
|
rmeddis@28
|
654 end
|
rmeddis@28
|
655 % return to pushButton1 callback
|
rmeddis@28
|
656
|
rmeddis@28
|
657 % ----------------------------------------------------- userSelects2
|
rmeddis@28
|
658 function userSelects2(handles)
|
rmeddis@28
|
659 global experiment withinRuns
|
rmeddis@28
|
660 switch experiment.threshEstMethod
|
rmeddis@28
|
661 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@28
|
662 switch withinRuns.stimulusOrder
|
rmeddis@28
|
663 case 'targetSecond';
|
rmeddis@28
|
664 % userDoesNotHearTarget(handles)
|
rmeddis@28
|
665 userDecides(handles, true)
|
rmeddis@28
|
666 otherwise
|
rmeddis@28
|
667 % userHearsTarget(handles)
|
rmeddis@28
|
668 userDecides(handles, false)
|
rmeddis@28
|
669 end
|
rmeddis@28
|
670 otherwise
|
rmeddis@28
|
671 % single interval (2 targets heard)
|
rmeddis@28
|
672 userDecides(handles, true)
|
rmeddis@28
|
673 end
|
rmeddis@28
|
674 % return to pushButton2 callback
|
rmeddis@28
|
675
|
rmeddis@28
|
676 % ----------------------------------------------------- ---- userDecides
|
rmeddis@28
|
677 function userDecides(handles, saidYes)
|
rmeddis@28
|
678 global experiment stimulusParameters betweenRuns withinRuns
|
rmeddis@28
|
679 global rareEvent logistic psy levelsBinVector
|
rmeddis@28
|
680
|
rmeddis@28
|
681 if experiment.singleShot
|
rmeddis@28
|
682 return
|
rmeddis@28
|
683 end
|
rmeddis@28
|
684
|
rmeddis@28
|
685 % ignore click if not 'waitingForResponse'
|
rmeddis@28
|
686 if ~strcmp(experiment.status,'waitingForResponse')
|
rmeddis@28
|
687 disp('ignored click')
|
rmeddis@28
|
688 return
|
rmeddis@28
|
689 end
|
rmeddis@28
|
690
|
rmeddis@28
|
691 % speech reception threshold
|
rmeddis@28
|
692 if strcmp(stimulusParameters.targetType,'digitStrings')
|
rmeddis@28
|
693 digitsInput=get(handles.editdigitInput,'string');
|
rmeddis@28
|
694 % must be three digits
|
rmeddis@28
|
695 if ~(length(digitsInput)==3)
|
rmeddis@28
|
696 addToMsg(['error message: Wrong no of digits'], 0, 1)
|
rmeddis@28
|
697 set(handles.textMSG,'string', 'Wrong no of digits', ...
|
rmeddis@28
|
698 'BackgroundColor','r', 'ForegroundColor', 'w')
|
rmeddis@28
|
699 set(handles.editdigitInput,'string','')
|
rmeddis@28
|
700
|
rmeddis@28
|
701 return
|
rmeddis@28
|
702 end
|
rmeddis@28
|
703 % obtain correct answer from file name
|
rmeddis@28
|
704 x=stimulusParameters.digitString;
|
rmeddis@28
|
705 idx=find(x=='O'); x(idx)='0'; % replace 'oh' with zero
|
rmeddis@28
|
706
|
rmeddis@28
|
707 disp([x ' ' digitsInput])
|
rmeddis@28
|
708
|
rmeddis@28
|
709 if x==digitsInput
|
rmeddis@28
|
710 saidYes=1;
|
rmeddis@28
|
711 else
|
rmeddis@28
|
712 saidYes=0;
|
rmeddis@28
|
713 end
|
rmeddis@28
|
714 set(handles.editdigitInput,'string','')
|
rmeddis@28
|
715 set(handles.editdigitInput,'visible','off')
|
rmeddis@28
|
716 pause(0.1)
|
rmeddis@28
|
717 end
|
rmeddis@28
|
718
|
rmeddis@28
|
719
|
rmeddis@28
|
720
|
rmeddis@28
|
721 % no button presses accepted while processing
|
rmeddis@28
|
722 experiment.status='processingResponse';
|
rmeddis@28
|
723
|
rmeddis@28
|
724 % catch trials. Restart trial if caught
|
rmeddis@28
|
725 if withinRuns.catchTrial
|
rmeddis@28
|
726 if saidYes
|
rmeddis@28
|
727 disp('catch trial - caught out')
|
rmeddis@28
|
728 withinRuns.caughtOut=withinRuns.caughtOut+1;
|
rmeddis@28
|
729
|
rmeddis@28
|
730 % special: estimate caught out rate by allowing the trial
|
rmeddis@28
|
731 % to continue after catch
|
rmeddis@28
|
732 if stimulusParameters.catchTrialBaseRate==0.5
|
rmeddis@28
|
733 % To use this facility, set the catchTrialRate and the
|
rmeddis@28
|
734 % catchTrialBaseRate both to 0.5
|
rmeddis@28
|
735 % update false positive rate
|
rmeddis@28
|
736 betweenRuns.caughtOut(betweenRuns.runNumber)=...
|
rmeddis@28
|
737 withinRuns.caughtOut;
|
rmeddis@28
|
738 plotProgressThisTrial(handles)
|
rmeddis@28
|
739 nextStimulus(handles);
|
rmeddis@28
|
740 return
|
rmeddis@28
|
741 end
|
rmeddis@28
|
742
|
rmeddis@28
|
743 % Punishment: restart the trial
|
rmeddis@28
|
744 set(handles.frame1,'backgroundColor','r')
|
rmeddis@28
|
745 set(handles.pushbuttonGO, ...
|
rmeddis@28
|
746 'visible','on', 'backgroundcolor','y') % and go again
|
rmeddis@28
|
747 msg=[{'Start again: catch trial error'}, {' '},...
|
rmeddis@28
|
748 {'Please,click on the GO button'}];
|
rmeddis@28
|
749 set(handles.textMSG,'string',msg)
|
rmeddis@28
|
750 [y,fs]=wavread('ding.wav');
|
rmeddis@28
|
751 wavplay(y/100,fs)
|
rmeddis@28
|
752
|
rmeddis@28
|
753 % raise catch trial rate temporarily.
|
rmeddis@28
|
754 % this is normally reduced on each new trial (see GO)
|
rmeddis@28
|
755 stimulusParameters.catchTrialRate=...
|
rmeddis@28
|
756 stimulusParameters.catchTrialRate+0.1;
|
rmeddis@28
|
757 if stimulusParameters.catchTrialRate>0.5
|
rmeddis@28
|
758 stimulusParameters.catchTrialRate=0.5;
|
rmeddis@28
|
759 end
|
rmeddis@28
|
760 fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
|
rmeddis@28
|
761 stimulusParameters.catchTrialRate)
|
rmeddis@28
|
762
|
rmeddis@28
|
763 betweenRuns.caughtOut(betweenRuns.runNumber)=...
|
rmeddis@28
|
764 1+betweenRuns.caughtOut(betweenRuns.runNumber);
|
rmeddis@28
|
765 betweenRuns.runNumber=betweenRuns.runNumber-1;
|
rmeddis@28
|
766 experiment.status='waitingForGO';
|
rmeddis@28
|
767 return % unwind and wait for button press
|
rmeddis@28
|
768 else % (said No)
|
rmeddis@28
|
769 % user claims not to have heard target. fortunate as it was not
|
rmeddis@28
|
770 % present. So, repeat the stimulus (possibly with target)
|
rmeddis@28
|
771 % and behave as if the last trial did not occur
|
rmeddis@28
|
772 errormsg=nextStimulus(handles);
|
rmeddis@28
|
773
|
rmeddis@28
|
774 % terminate if there is any kind of problem
|
rmeddis@28
|
775 if ~isempty(errormsg)
|
rmeddis@28
|
776 % e.g. limits exceeded, clipping
|
rmeddis@28
|
777 disp(['Error nextStimulus: ' errormsg])
|
rmeddis@28
|
778 runCompleted(handles)
|
rmeddis@28
|
779 return
|
rmeddis@28
|
780 end
|
rmeddis@28
|
781 return % no further action - next trial
|
rmeddis@28
|
782 end
|
rmeddis@28
|
783 end
|
rmeddis@28
|
784
|
rmeddis@28
|
785 % This section analyses the responses, makes tracks and defines next stim.
|
rmeddis@28
|
786
|
rmeddis@28
|
787 % Define response and update response list
|
rmeddis@28
|
788 if saidYes
|
rmeddis@28
|
789 % target was heard, so response=1;
|
rmeddis@28
|
790 withinRuns.responseList=[withinRuns.responseList 1]; % 'heard it!'
|
rmeddis@28
|
791 else
|
rmeddis@28
|
792 % target was not hear heard, so response=0;
|
rmeddis@28
|
793 withinRuns.responseList=[withinRuns.responseList 0];
|
rmeddis@28
|
794 end
|
rmeddis@28
|
795 withinRuns.levelList=[withinRuns.levelList withinRuns.variableValue];
|
rmeddis@28
|
796 trialNumber=length(withinRuns.responseList);
|
rmeddis@28
|
797
|
rmeddis@28
|
798 % keep track of peaks and troughs;
|
rmeddis@28
|
799 % identify direction of change during initial period
|
rmeddis@28
|
800 if saidYes
|
rmeddis@28
|
801 % default step size before first reversal
|
rmeddis@28
|
802 WRVinitialStep=-stimulusParameters.WRVinitialStep;
|
rmeddis@28
|
803 WRVsmallStep=-stimulusParameters.WRVsmallStep;
|
rmeddis@28
|
804 % if the previous direction was 'less difficult', this must be a peak
|
rmeddis@28
|
805 if strcmp(withinRuns.direction,'less difficult') ...
|
rmeddis@28
|
806 && length(withinRuns.levelList)>1
|
rmeddis@28
|
807 withinRuns.peaks=[withinRuns.peaks withinRuns.variableValue];
|
rmeddis@28
|
808 end
|
rmeddis@28
|
809 withinRuns.direction='more difficult';
|
rmeddis@28
|
810
|
rmeddis@28
|
811 else
|
rmeddis@28
|
812 % said 'no'
|
rmeddis@28
|
813 % default step size before first reversal
|
rmeddis@28
|
814 WRVinitialStep=stimulusParameters.WRVinitialStep;
|
rmeddis@28
|
815 WRVsmallStep=stimulusParameters.WRVsmallStep;
|
rmeddis@28
|
816
|
rmeddis@28
|
817 % if the previous direction was 'up', this must be a peak
|
rmeddis@28
|
818 if strcmp(withinRuns.direction,'more difficult') ...
|
rmeddis@28
|
819 && length(withinRuns.levelList)>1
|
rmeddis@28
|
820 withinRuns.troughs=[withinRuns.troughs withinRuns.variableValue];
|
rmeddis@28
|
821 end
|
rmeddis@28
|
822 withinRuns.direction='less difficult';
|
rmeddis@28
|
823 end
|
rmeddis@28
|
824
|
rmeddis@28
|
825 % phase 2 is all the levels after and incuding the first reversal
|
rmeddis@28
|
826 % plus the level before that
|
rmeddis@28
|
827 if ~withinRuns.nowInPhase2 && length(withinRuns.peaks)+ ...
|
rmeddis@28
|
828 length(withinRuns.troughs)>0
|
rmeddis@28
|
829 % if ~withinRuns.nowInPhase2 && (~isempty(withinRuns.peaks) ...
|
rmeddis@28
|
830 % || ~isempty(withinRuns.troughs))
|
rmeddis@28
|
831 % define phase 2
|
rmeddis@28
|
832 withinRuns.beginningOfPhase2=trialNumber-1;
|
rmeddis@28
|
833 withinRuns.nowInPhase2=1;
|
rmeddis@28
|
834 WRVsmallStep=WRVinitialStep/2;
|
rmeddis@28
|
835 end
|
rmeddis@28
|
836
|
rmeddis@28
|
837 if withinRuns.nowInPhase2
|
rmeddis@28
|
838 % keep a record of all levels and responses in phase 2 only
|
rmeddis@28
|
839 withinRuns.levelsPhaseTwo=...
|
rmeddis@28
|
840 withinRuns.levelList(withinRuns.beginningOfPhase2:end);
|
rmeddis@28
|
841 withinRuns.responsesPhaseTwo=...
|
rmeddis@28
|
842 withinRuns.responseList(withinRuns.beginningOfPhase2:end);
|
rmeddis@28
|
843 else
|
rmeddis@28
|
844 withinRuns.levelsPhaseTwo=[];
|
rmeddis@28
|
845 end
|
rmeddis@28
|
846
|
rmeddis@28
|
847
|
rmeddis@28
|
848 % get (or substitute) threshold estimate
|
rmeddis@28
|
849 switch experiment.threshEstMethod
|
rmeddis@28
|
850 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@28
|
851 % for plotting psychometric function only
|
rmeddis@28
|
852 if withinRuns.beginningOfPhase2>0
|
rmeddis@28
|
853 [psy, levelsBinVector, logistic, rareEvent]= ...
|
rmeddis@28
|
854 bestFitPsychometicFunctions...
|
rmeddis@28
|
855 (withinRuns.levelsPhaseTwo, withinRuns.responsesPhaseTwo);
|
rmeddis@28
|
856 end
|
rmeddis@28
|
857
|
rmeddis@28
|
858 if ~isempty(withinRuns.peaks) && ~isempty(withinRuns.troughs)
|
rmeddis@28
|
859 thresholdEstimate= ...
|
rmeddis@28
|
860 mean([mean(withinRuns.peaks) mean(withinRuns.troughs)]);
|
rmeddis@28
|
861 else
|
rmeddis@28
|
862 thresholdEstimate=NaN;
|
rmeddis@28
|
863 end
|
rmeddis@28
|
864 otherwise
|
rmeddis@28
|
865 % single interval methods
|
rmeddis@28
|
866 try
|
rmeddis@28
|
867 % using the s trial after the first reversal
|
rmeddis@28
|
868 [psy, levelsBinVector, logistic, rareEvent]= ...
|
rmeddis@28
|
869 bestFitPsychometicFunctions(withinRuns.levelsPhaseTwo,...
|
rmeddis@28
|
870 withinRuns.responsesPhaseTwo);
|
rmeddis@28
|
871 catch
|
rmeddis@28
|
872 logistic.bestThreshold=NaN;
|
rmeddis@28
|
873 end
|
rmeddis@28
|
874 end
|
rmeddis@28
|
875
|
rmeddis@28
|
876 if withinRuns.nowInPhase2
|
rmeddis@28
|
877 % save tracks of threshold estimates for plotting andprinting
|
rmeddis@28
|
878 switch experiment.functionEstMethod
|
rmeddis@28
|
879 case {'logisticLS', 'logisticML'}
|
rmeddis@28
|
880 if withinRuns.nowInPhase2
|
rmeddis@28
|
881 withinRuns.meanEstTrack=...
|
rmeddis@28
|
882 [withinRuns.meanEstTrack ...
|
rmeddis@28
|
883 mean(withinRuns.levelsPhaseTwo)];
|
rmeddis@28
|
884 withinRuns.thresholdEstimateTrack=...
|
rmeddis@28
|
885 [withinRuns.thresholdEstimateTrack ...
|
rmeddis@28
|
886 logistic.bestThreshold];
|
rmeddis@28
|
887 end
|
rmeddis@28
|
888 case 'rareEvent'
|
rmeddis@28
|
889 withinRuns.meanEstTrack=...
|
rmeddis@28
|
890 [withinRuns.meanEstTrack rareEvent.thresholddB];
|
rmeddis@28
|
891 withinRuns.thresholdEstimateTrack=...
|
rmeddis@28
|
892 [withinRuns.thresholdEstimateTrack logistic.bestThreshold];
|
rmeddis@28
|
893 case 'peaksAndTroughs'
|
rmeddis@28
|
894 withinRuns.meanEstTrack=...
|
rmeddis@28
|
895 [withinRuns.meanEstTrack thresholdEstimate];
|
rmeddis@28
|
896 withinRuns.thresholdEstimateTrack=...
|
rmeddis@28
|
897 [withinRuns.thresholdEstimateTrack thresholdEstimate];
|
rmeddis@28
|
898 end
|
rmeddis@28
|
899 end
|
rmeddis@28
|
900
|
rmeddis@28
|
901 % special discomfort condition
|
rmeddis@28
|
902 % run is completed when subject hits '2' button
|
rmeddis@28
|
903 switch experiment.paradigm
|
rmeddis@28
|
904 case 'discomfort'
|
rmeddis@28
|
905 if saidYes
|
rmeddis@28
|
906 runCompleted(handles)
|
rmeddis@28
|
907 return
|
rmeddis@28
|
908 end
|
rmeddis@28
|
909 end
|
rmeddis@28
|
910
|
rmeddis@28
|
911 % choose the next level for the stimulus
|
rmeddis@28
|
912 switch experiment.threshEstMethod
|
rmeddis@28
|
913 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@28
|
914 if saidYes
|
rmeddis@28
|
915 [WRVinitialStep, msg]=Levitt2('hit', withinRuns.variableValue);
|
rmeddis@28
|
916 else
|
rmeddis@28
|
917 [WRVinitialStep, msg]=Levitt2('miss',withinRuns.variableValue);
|
rmeddis@28
|
918 end
|
rmeddis@28
|
919
|
rmeddis@28
|
920 % empty message means continue as normal
|
rmeddis@28
|
921 if ~isempty(msg)
|
rmeddis@28
|
922 runCompleted(handles)
|
rmeddis@28
|
923 return
|
rmeddis@28
|
924 end
|
rmeddis@28
|
925 newWRVvalue=withinRuns.variableValue-WRVinitialStep;
|
rmeddis@28
|
926
|
rmeddis@28
|
927 case {'MaxLikelihood', 'oneIntervalUpDown'}
|
rmeddis@28
|
928 % run completed by virtue of number of trials
|
rmeddis@28
|
929 % or restart because listener is in trouble
|
rmeddis@28
|
930 if length(withinRuns.levelsPhaseTwo)== experiment.maxTrials
|
rmeddis@28
|
931 % Use bonomial test to decide if there is an imbalance in the
|
rmeddis@28
|
932 % number of 'yes'es and 'no's
|
rmeddis@28
|
933 yesCount=sum(withinRuns.responseList);
|
rmeddis@28
|
934 noCount=length(withinRuns.responseList)-yesCount;
|
rmeddis@28
|
935 z=abs(yesCount-noCount)/(yesCount+noCount)^0.5;
|
rmeddis@28
|
936 if z>1.96
|
rmeddis@28
|
937 betweenRuns.resets=betweenRuns.resets+1;
|
rmeddis@28
|
938 disp([ 'reset / z= ' num2str( z) ...
|
rmeddis@28
|
939 ' Nresets= ' num2str( betweenRuns.resets) ] )
|
rmeddis@28
|
940 withinRuns.peaks=[];
|
rmeddis@28
|
941 withinRuns.troughs=[];
|
rmeddis@28
|
942 withinRuns.levelList=withinRuns.levelList(end);
|
rmeddis@28
|
943 withinRuns.meanEstTrack=withinRuns.meanEstTrack(end);
|
rmeddis@28
|
944 withinRuns.forceThreshold=NaN;
|
rmeddis@28
|
945 withinRuns.responseList=withinRuns.responseList(end);
|
rmeddis@28
|
946 withinRuns.beginningOfPhase2=0;
|
rmeddis@28
|
947 withinRuns.nowInPhase2=0;
|
rmeddis@28
|
948 withinRuns.thresholdEstimateTrack=...
|
rmeddis@28
|
949 withinRuns.thresholdEstimateTrack(end);
|
rmeddis@28
|
950 else
|
rmeddis@28
|
951 runCompleted(handles)
|
rmeddis@28
|
952 return
|
rmeddis@28
|
953 end
|
rmeddis@28
|
954 end
|
rmeddis@28
|
955
|
rmeddis@28
|
956 % set new value for WRV
|
rmeddis@28
|
957 if withinRuns.nowInPhase2
|
rmeddis@28
|
958 % phase 2
|
rmeddis@28
|
959 currentMeanEst=withinRuns.thresholdEstimateTrack(end);
|
rmeddis@28
|
960 switch experiment.threshEstMethod
|
rmeddis@28
|
961 case 'MaxLikelihood'
|
rmeddis@28
|
962 newWRVvalue=currentMeanEst;
|
rmeddis@28
|
963 case {'oneIntervalUpDown'}
|
rmeddis@28
|
964 newWRVvalue=withinRuns.variableValue+WRVsmallStep;
|
rmeddis@28
|
965 end
|
rmeddis@28
|
966 else
|
rmeddis@28
|
967 % phase 1
|
rmeddis@28
|
968 if withinRuns.variableValue+2*WRVinitialStep>...
|
rmeddis@28
|
969 stimulusParameters.WRVlimits(2)
|
rmeddis@28
|
970 % use smaller steps when close to maximum
|
rmeddis@28
|
971 WRVinitialStep=WRVinitialStep/2;
|
rmeddis@28
|
972 end
|
rmeddis@28
|
973 newWRVvalue=withinRuns.variableValue+WRVinitialStep;
|
rmeddis@28
|
974 end
|
rmeddis@28
|
975 otherwise
|
rmeddis@28
|
976 error( 'assessment method not recognised')
|
rmeddis@28
|
977 end
|
rmeddis@28
|
978
|
rmeddis@28
|
979 switch experiment.paradigm
|
rmeddis@28
|
980 % prevent unrealistic gap durations 'gapDetection' tasks.
|
rmeddis@28
|
981 % Note that the gap begins when the ramp ends not when stimulus ends
|
rmeddis@28
|
982 case 'gapDetection'
|
rmeddis@28
|
983 if newWRVvalue<-2*stimulusParameters.rampDuration
|
rmeddis@28
|
984 newWRVvalue=-2*stimulusParameters.rampDuration;
|
rmeddis@28
|
985 addToMsg('gap duration fixed at - 2 * ramp!',1, 1)
|
rmeddis@28
|
986 end
|
rmeddis@28
|
987 end
|
rmeddis@28
|
988
|
rmeddis@28
|
989 withinRuns.variableValue=newWRVvalue;
|
rmeddis@28
|
990 withinRuns.trialNumber=withinRuns.trialNumber+1;
|
rmeddis@28
|
991
|
rmeddis@28
|
992 % Trial continues
|
rmeddis@28
|
993 plotProgressThisTrial(handles)
|
rmeddis@28
|
994
|
rmeddis@28
|
995 % next stimulus and so the cycle continues
|
rmeddis@28
|
996 errormsg=nextStimulus(handles);
|
rmeddis@28
|
997 % after the stimulus is presented, control returns here and the system
|
rmeddis@28
|
998 % waits for user action.
|
rmeddis@28
|
999
|
rmeddis@28
|
1000 % terminate if there is any kind of problem
|
rmeddis@28
|
1001 if ~isempty(errormsg)
|
rmeddis@28
|
1002 % e.g. limits exceeded, clipping
|
rmeddis@28
|
1003 disp(['Error nextStimulus: ' errormsg])
|
rmeddis@28
|
1004 runCompleted(handles)
|
rmeddis@28
|
1005 return
|
rmeddis@28
|
1006 end
|
rmeddis@28
|
1007
|
rmeddis@28
|
1008 % ------------------------------------------------ userSelectsPleaseRepeat
|
rmeddis@28
|
1009 function userSelectsPleaseRepeat(handles)
|
rmeddis@28
|
1010 global experiment withinRuns
|
rmeddis@28
|
1011 % ignore click if not 'waitingForResponse'
|
rmeddis@28
|
1012 if ~strcmp(experiment.status,'waitingForResponse')
|
rmeddis@28
|
1013 disp('ignored click')
|
rmeddis@28
|
1014 return
|
rmeddis@28
|
1015 end
|
rmeddis@28
|
1016 % Take no action other than to make a
|
rmeddis@28
|
1017 % tally of repeat requests
|
rmeddis@28
|
1018 experiment.pleaseRepeat=experiment.pleaseRepeat+1;
|
rmeddis@28
|
1019 withinRuns.thisIsRepeatTrial=1;
|
rmeddis@28
|
1020 nextStimulus(handles);
|
rmeddis@28
|
1021
|
rmeddis@28
|
1022 % ------------------------------------------------ userSelectsWrongButton
|
rmeddis@28
|
1023 function userSelectsWrongButton(handles)
|
rmeddis@28
|
1024 global withinRuns experiment
|
rmeddis@28
|
1025 % restart is the simplest solution for a 'wrong button' request
|
rmeddis@28
|
1026 withinRuns.wrongButton=withinRuns.wrongButton+1;
|
rmeddis@28
|
1027 set(handles.pushbuttonGO, 'visible','on', 'backgroundcolor','y')
|
rmeddis@28
|
1028 msg=[{'Start again: wrong button pressed'}, {' '},...
|
rmeddis@28
|
1029 {'Please,click on the GO button'}];
|
rmeddis@28
|
1030 set(handles.textMSG,'string',msg)
|
rmeddis@28
|
1031 experiment.status='waitingForGO';
|
rmeddis@28
|
1032
|
rmeddis@28
|
1033 % ------------------------------------------------- plotProgressThisTrial
|
rmeddis@28
|
1034 function plotProgressThisTrial(handles)
|
rmeddis@28
|
1035
|
rmeddis@28
|
1036 % used for all responses
|
rmeddis@28
|
1037 global experiment stimulusParameters betweenRuns withinRuns expGUIhandles
|
rmeddis@28
|
1038 global psy levelsBinVector binFrequencies rareEvent logistic statsModel
|
rmeddis@28
|
1039
|
rmeddis@28
|
1040
|
rmeddis@28
|
1041 % plot the levelTrack and the threshold track
|
rmeddis@28
|
1042
|
rmeddis@28
|
1043 % Panel 2
|
rmeddis@28
|
1044 % plot the levelList
|
rmeddis@28
|
1045 axes(expGUIhandles.axes2); cla
|
rmeddis@28
|
1046 plot( withinRuns.levelList,'o','markerFaceColor','k'), hold on
|
rmeddis@28
|
1047 % plot the best threshold estimate tracks
|
rmeddis@28
|
1048 if length(withinRuns.meanEstTrack)>=1
|
rmeddis@28
|
1049 % The length of the levelList is 2 greater than number of thresholds
|
rmeddis@28
|
1050 ptr=withinRuns.beginningOfPhase2+1;
|
rmeddis@28
|
1051 plot(ptr: ptr+length(withinRuns.meanEstTrack)-1, ...
|
rmeddis@28
|
1052 withinRuns.meanEstTrack, 'r')
|
rmeddis@28
|
1053 plot( ptr: ptr+length(withinRuns.thresholdEstimateTrack)-1, ...
|
rmeddis@28
|
1054 withinRuns.thresholdEstimateTrack, 'g')
|
rmeddis@28
|
1055 hold off
|
rmeddis@28
|
1056 estThresh=withinRuns.thresholdEstimateTrack(end);
|
rmeddis@28
|
1057 switch experiment.threshEstMethod
|
rmeddis@28
|
1058 % add appropriate labels to subject GUI buttons
|
rmeddis@28
|
1059 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@28
|
1060 title([stimulusParameters.WRVname ' = ' ...
|
rmeddis@28
|
1061 num2str(withinRuns.variableValue, '%5.1f')])
|
rmeddis@28
|
1062 otherwise
|
rmeddis@28
|
1063 title([stimulusParameters.WRVname ' = ' ...
|
rmeddis@28
|
1064 num2str(withinRuns.variableValue, '%5.1f') ...
|
rmeddis@28
|
1065 '; TH= ' num2str(estThresh, '%5.1f')])
|
rmeddis@28
|
1066 end
|
rmeddis@28
|
1067 end
|
rmeddis@28
|
1068 xlim([0 experiment.maxTrials+withinRuns.beginningOfPhase2]);
|
rmeddis@28
|
1069 ylim(stimulusParameters.WRVlimits)
|
rmeddis@28
|
1070 grid on
|
rmeddis@28
|
1071
|
rmeddis@28
|
1072 % Panel 4: Summary of threshold estimates (not used here)
|
rmeddis@28
|
1073 % Earlier estimates are set in 'runCompleted'
|
rmeddis@28
|
1074 % However, title shows runs/trials remaining
|
rmeddis@28
|
1075
|
rmeddis@28
|
1076 axes(expGUIhandles.axes4)
|
rmeddis@28
|
1077 runsToGo=length(betweenRuns.var1Sequence)-betweenRuns.runNumber;
|
rmeddis@28
|
1078 if withinRuns.beginningOfPhase2>0
|
rmeddis@28
|
1079 trialsToGo= experiment.singleIntervalMaxTrials(1) ...
|
rmeddis@28
|
1080 + withinRuns.beginningOfPhase2- withinRuns.trialNumber;
|
rmeddis@28
|
1081 title(['trials remaining = ' num2str(trialsToGo) ...
|
rmeddis@28
|
1082 ': runs to go= ' num2str(runsToGo)])
|
rmeddis@28
|
1083 end
|
rmeddis@28
|
1084
|
rmeddis@28
|
1085 % plot psychometric function - panel 5
|
rmeddis@28
|
1086 axes(expGUIhandles.axes5), cla
|
rmeddis@28
|
1087 plot(withinRuns.levelList, withinRuns.responseList,'b.'), hold on
|
rmeddis@28
|
1088 ylim([0 1])
|
rmeddis@28
|
1089 title('')
|
rmeddis@28
|
1090
|
rmeddis@28
|
1091 switch experiment.threshEstMethod
|
rmeddis@28
|
1092 case {'MaxLikelihood', 'oneIntervalUpDown'}
|
rmeddis@28
|
1093 if withinRuns.beginningOfPhase2>0
|
rmeddis@28
|
1094 % display only when in phase 2.
|
rmeddis@28
|
1095 withinRuns.levelsPhaseTwo=...
|
rmeddis@28
|
1096 withinRuns.levelList(withinRuns.beginningOfPhase2:end);
|
rmeddis@28
|
1097 withinRuns.responsesPhaseTwo=...
|
rmeddis@28
|
1098 withinRuns.responseList(withinRuns.beginningOfPhase2:end);
|
rmeddis@28
|
1099
|
rmeddis@28
|
1100 % organise data as psychometric function
|
rmeddis@28
|
1101 [psy, levelsBinVector, binFrequencies]= ...
|
rmeddis@28
|
1102 psychometricFunction(withinRuns.levelsPhaseTwo,...
|
rmeddis@28
|
1103 withinRuns.responsesPhaseTwo, experiment.psyBinWidth);
|
rmeddis@28
|
1104
|
rmeddis@28
|
1105 % Plot the function
|
rmeddis@28
|
1106 % point by point with circles of appropiate weighted size
|
rmeddis@28
|
1107 hold on,
|
rmeddis@28
|
1108 for i=1:length(psy)
|
rmeddis@28
|
1109 plot(levelsBinVector(i), psy(i), 'ro', ...
|
rmeddis@28
|
1110 'markersize', 50*binFrequencies(i)/sum(binFrequencies))
|
rmeddis@28
|
1111 end
|
rmeddis@28
|
1112 % save info for later
|
rmeddis@28
|
1113 betweenRuns.psychometicFunction{betweenRuns.runNumber}=...
|
rmeddis@28
|
1114 [levelsBinVector; psy];
|
rmeddis@28
|
1115
|
rmeddis@28
|
1116 % fitPsychometric functions is computed in 'userDecides'
|
rmeddis@28
|
1117 % plot(rareEvent.predictionLevels, rareEvent.predictionsRE,'k')
|
rmeddis@28
|
1118 plot(logistic.predictionLevels, logistic.predictionsLOG, 'r')
|
rmeddis@28
|
1119 plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k')
|
rmeddis@28
|
1120 if ~isnan(logistic.bestThreshold )
|
rmeddis@28
|
1121 % xlim([ (logistic.bestThreshold -20) ...
|
rmeddis@28
|
1122 % (logistic.bestThreshold +20) ])
|
rmeddis@28
|
1123 xlim([ 0 100 ])
|
rmeddis@28
|
1124 % if logistic.bestK< max(experiment.possLogSlopes)
|
rmeddis@28
|
1125 title(['k= ' num2str(logistic.bestK, '%6.2f') ' g= '...
|
rmeddis@28
|
1126 num2str(rareEvent.bestGain,'%6.3f') ' A=' ...
|
rmeddis@28
|
1127 num2str(rareEvent.bestVMin,'%8.1f')])
|
rmeddis@28
|
1128 % title('')
|
rmeddis@28
|
1129 % end
|
rmeddis@28
|
1130 else
|
rmeddis@28
|
1131 title(' ')
|
rmeddis@28
|
1132 end
|
rmeddis@28
|
1133
|
rmeddis@28
|
1134 switch experiment.ear
|
rmeddis@28
|
1135 %plot green line for statsModel a priori model
|
rmeddis@28
|
1136 case 'statsModelLogistic'
|
rmeddis@28
|
1137 % plot proTem logistic (green) used by stats model
|
rmeddis@28
|
1138 p= 1./(1+exp(-statsModel.logisticSlope...
|
rmeddis@28
|
1139 *(levelsBinVector-logistic.bestThreshold)));
|
rmeddis@28
|
1140 if experiment.psyFunSlope<0, p=1-p;end
|
rmeddis@28
|
1141 titleText=[ ', statsModel: logistic'];
|
rmeddis@28
|
1142 hold on, plot(levelsBinVector, p,'g')
|
rmeddis@28
|
1143 case 'statsModelRareEvent'
|
rmeddis@28
|
1144 pressure=28*10.^(levelsBinVector/20);
|
rmeddis@28
|
1145 p=1-exp(-stimulusParameters.targetDuration...
|
rmeddis@28
|
1146 *(statsModel.rareEvenGain...
|
rmeddis@28
|
1147 * pressure-statsModel.rareEventVmin));
|
rmeddis@28
|
1148 p(p<0)=0;
|
rmeddis@28
|
1149 if experiment.psyFunSlope<0, p=1-p;end
|
rmeddis@28
|
1150 hold on, plot(levelsBinVector, p,'g')
|
rmeddis@28
|
1151 end %(estMethod)
|
rmeddis@28
|
1152 end
|
rmeddis@28
|
1153 otherwise % 2A2IFC
|
rmeddis@28
|
1154
|
rmeddis@28
|
1155 message3= ...
|
rmeddis@28
|
1156 ([ 'peaks=' num2str(withinRuns.peaks) ...
|
rmeddis@28
|
1157 'troughs=' num2str(withinRuns.troughs)]);
|
rmeddis@28
|
1158 ylimRM([-0.1 1.1]) % 0=no / 1=yes
|
rmeddis@28
|
1159 set(gca,'ytick',[0 1], 'yTickLabel', {'no';'yes'})
|
rmeddis@28
|
1160 ylabel('psychometric function'), xlabel('target level')
|
rmeddis@28
|
1161 if length(levelsBinVector)>1
|
rmeddis@28
|
1162 xlim([ min(levelsBinVector) max(levelsBinVector)])
|
rmeddis@28
|
1163 xlim([ 0 100])
|
rmeddis@28
|
1164 end
|
rmeddis@28
|
1165 end
|
rmeddis@28
|
1166
|
rmeddis@28
|
1167 % command window summary
|
rmeddis@28
|
1168 % Accumulate things to say in the message window
|
rmeddis@28
|
1169 message1= (['responses: ' num2str(withinRuns.responseList,'%9.0f')]);
|
rmeddis@28
|
1170 switch experiment.paradigm
|
rmeddis@28
|
1171 % more decimal places needed on GUI
|
rmeddis@28
|
1172 case { 'gapDetection', 'frequencyDiscrimination', 'forwardMaskingD'}
|
rmeddis@28
|
1173 message2= ([stimulusParameters.WRVname ...
|
rmeddis@28
|
1174 ': ' num2str(withinRuns.levelList,'%7.3f')]);
|
rmeddis@28
|
1175 message3= (['Thresh (logistic mean): ' ...
|
rmeddis@28
|
1176 num2str(withinRuns.thresholdEstimateTrack,'%7.3f')]);
|
rmeddis@28
|
1177 otherwise
|
rmeddis@28
|
1178 message2= ([stimulusParameters.WRVname ': ' ...
|
rmeddis@28
|
1179 num2str(withinRuns.levelList,'%7.1f')]);
|
rmeddis@28
|
1180 message3= (['Thresh (logistic mean): ' ...
|
rmeddis@28
|
1181 num2str(withinRuns.thresholdEstimateTrack,'%7.1f')]);
|
rmeddis@28
|
1182 end
|
rmeddis@28
|
1183
|
rmeddis@28
|
1184 addToMsg(str2mat(message1, message2, message3), 0)
|
rmeddis@28
|
1185
|
rmeddis@28
|
1186 % -----------------------------------------------------runCompleted
|
rmeddis@28
|
1187 function runCompleted(handles)
|
rmeddis@28
|
1188 % Used at the end of each run
|
rmeddis@28
|
1189 global experiment stimulusParameters betweenRuns withinRuns
|
rmeddis@28
|
1190 global rareEvent expGUIhandles
|
rmeddis@28
|
1191 % disp('run completed')
|
rmeddis@28
|
1192
|
rmeddis@28
|
1193 experiment.status='runCompleted';
|
rmeddis@28
|
1194
|
rmeddis@28
|
1195 plotProgressThisTrial(handles)
|
rmeddis@28
|
1196
|
rmeddis@28
|
1197 switch experiment.ear
|
rmeddis@28
|
1198 case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ...
|
rmeddis@28
|
1199 'MAPmodelMultiCh','MAPmodelSingleCh', 'MAPmodelListen'}
|
rmeddis@28
|
1200 % no changes required if model used
|
rmeddis@28
|
1201 otherwise
|
rmeddis@28
|
1202 set(handles.frame1,'visible','off')
|
rmeddis@28
|
1203 set(handles.pushbuttoNotSure,'visible','off')
|
rmeddis@28
|
1204 set(handles.pushbuttonWrongButton,'visible','off')
|
rmeddis@28
|
1205 set(handles.pushbutton3,'visible','off')
|
rmeddis@28
|
1206 set(handles.pushbutton2,'visible','off')
|
rmeddis@28
|
1207 set(handles.pushbutton1,'visible','off')
|
rmeddis@28
|
1208 set(handles.pushbutton0,'visible','off')
|
rmeddis@28
|
1209 set(handles.pushbuttonGO,'visible','off')
|
rmeddis@28
|
1210 end
|
rmeddis@28
|
1211
|
rmeddis@28
|
1212 if isnan(withinRuns.forceThreshold)
|
rmeddis@28
|
1213 % the experiment has been aborted for some reason
|
rmeddis@28
|
1214 threshold=withinRuns.forceThreshold;
|
rmeddis@28
|
1215 stdev=NaN;
|
rmeddis@28
|
1216 logistic.bestK=NaN;
|
rmeddis@28
|
1217 logistic.bestThreshold=NaN;
|
rmeddis@28
|
1218 medianThreshold=NaN;
|
rmeddis@28
|
1219 meanThreshold=NaN;
|
rmeddis@28
|
1220 else
|
rmeddis@28
|
1221 % use only phase 2 levels and responses for calculating thresholds
|
rmeddis@28
|
1222 withinRuns.levelsPhaseTwo=...
|
rmeddis@28
|
1223 withinRuns.levelList(withinRuns.beginningOfPhase2:end);
|
rmeddis@28
|
1224 withinRuns.responsesPhaseTwo=...
|
rmeddis@28
|
1225 withinRuns.responseList(withinRuns.beginningOfPhase2:end);
|
rmeddis@28
|
1226 [psy, levelsPhaseTwoBinVector, logistic, rareEvent]= ...
|
rmeddis@28
|
1227 bestFitPsychometicFunctions...
|
rmeddis@28
|
1228 (withinRuns.levelsPhaseTwo, withinRuns.responsesPhaseTwo);
|
rmeddis@28
|
1229
|
rmeddis@28
|
1230 % plot final psychometric function
|
rmeddis@28
|
1231 axes(expGUIhandles.axes5),cla
|
rmeddis@28
|
1232 hold on, plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k')
|
rmeddis@28
|
1233 hold on, plot(logistic.predictionLevels, logistic.predictionsLOG, 'r')
|
rmeddis@28
|
1234 % organise data as psychometric function
|
rmeddis@28
|
1235 [psy, levelsBinVector, binFrequencies]= ...
|
rmeddis@28
|
1236 psychometricFunction(withinRuns.levelsPhaseTwo,...
|
rmeddis@28
|
1237 withinRuns.responsesPhaseTwo, experiment.psyBinWidth);
|
rmeddis@28
|
1238 % point by point with circles of appropiate weighted size
|
rmeddis@28
|
1239 hold on,
|
rmeddis@28
|
1240 for i=1:length(psy)
|
rmeddis@28
|
1241 plot(levelsBinVector(i), psy(i), 'ro', ...
|
rmeddis@28
|
1242 'markersize', 50*binFrequencies(i)/sum(binFrequencies))
|
rmeddis@28
|
1243 end
|
rmeddis@28
|
1244
|
rmeddis@28
|
1245
|
rmeddis@28
|
1246 % experimental
|
rmeddis@28
|
1247 medianThreshold=median(withinRuns.levelsPhaseTwo);
|
rmeddis@28
|
1248 warning off
|
rmeddis@28
|
1249 meanThreshold=mean(withinRuns.levelsPhaseTwo);
|
rmeddis@28
|
1250
|
rmeddis@28
|
1251 % identify the current threshold estimate
|
rmeddis@28
|
1252 switch experiment.paradigm
|
rmeddis@28
|
1253 case 'discomfort'
|
rmeddis@28
|
1254 % most recent value (not truely a mean value)
|
rmeddis@28
|
1255 threshold=withinRuns.levelList(end);
|
rmeddis@28
|
1256 stdev=NaN;
|
rmeddis@28
|
1257 otherwise
|
rmeddis@28
|
1258 switch experiment.threshEstMethod
|
rmeddis@28
|
1259 case {'MaxLikelihood', 'oneIntervalUpDown'}
|
rmeddis@28
|
1260 % last value in the list
|
rmeddis@28
|
1261 % threshold=withinRuns.meanEstTrack(end);
|
rmeddis@28
|
1262 threshold=withinRuns.thresholdEstimateTrack(end);
|
rmeddis@28
|
1263 stdev=NaN;
|
rmeddis@28
|
1264
|
rmeddis@28
|
1265 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@28
|
1266 % use peaks and troughs
|
rmeddis@28
|
1267 try % there may not be enough values to use
|
rmeddis@28
|
1268 peaksUsed=experiment.peaksUsed;
|
rmeddis@28
|
1269 threshold=...
|
rmeddis@28
|
1270 mean(...
|
rmeddis@28
|
1271 [withinRuns.peaks(end-peaksUsed+1:end) ...
|
rmeddis@28
|
1272 withinRuns.troughs(end-peaksUsed+1:end)]);
|
rmeddis@28
|
1273 stdev=...
|
rmeddis@28
|
1274 std([withinRuns.peaks(end-peaksUsed +1:end) ...
|
rmeddis@28
|
1275 withinRuns.troughs(end-peaksUsed:end)]);
|
rmeddis@28
|
1276 catch
|
rmeddis@28
|
1277 threshold=NaN;
|
rmeddis@28
|
1278 stdev=NaN;
|
rmeddis@28
|
1279 end
|
rmeddis@28
|
1280 end
|
rmeddis@28
|
1281 end
|
rmeddis@28
|
1282 end
|
rmeddis@28
|
1283
|
rmeddis@28
|
1284 % Store thresholds
|
rmeddis@28
|
1285 betweenRuns.thresholds=[betweenRuns.thresholds threshold];
|
rmeddis@28
|
1286 betweenRuns.thresholds_mean=[betweenRuns.thresholds_mean meanThreshold];
|
rmeddis@28
|
1287 betweenRuns.thresholds_median=...
|
rmeddis@28
|
1288 [betweenRuns.thresholds_median medianThreshold];
|
rmeddis@28
|
1289 betweenRuns.forceThresholds=...
|
rmeddis@28
|
1290 [betweenRuns.forceThresholds withinRuns.forceThreshold];
|
rmeddis@28
|
1291
|
rmeddis@28
|
1292 % count observations after the startup phase for record keeping
|
rmeddis@28
|
1293 betweenRuns.observationCount=...
|
rmeddis@28
|
1294 [betweenRuns.observationCount length(withinRuns.levelList)];
|
rmeddis@28
|
1295 betweenRuns.timesOfFirstReversals=...
|
rmeddis@28
|
1296 [betweenRuns.timesOfFirstReversals withinRuns.beginningOfPhase2];
|
rmeddis@28
|
1297 betweenRuns.catchTrials=...
|
rmeddis@28
|
1298 [betweenRuns.catchTrials withinRuns.catchTrialCount];
|
rmeddis@28
|
1299
|
rmeddis@28
|
1300 % add variable length tracks to cell arrays
|
rmeddis@28
|
1301 if withinRuns.beginningOfPhase2>0
|
rmeddis@28
|
1302 betweenRuns.bestThresholdTracks{length(betweenRuns.thresholds)}=...
|
rmeddis@28
|
1303 withinRuns.thresholdEstimateTrack;
|
rmeddis@28
|
1304 betweenRuns.levelTracks{length(betweenRuns.thresholds)}=...
|
rmeddis@28
|
1305 withinRuns.levelList(withinRuns.beginningOfPhase2:end);
|
rmeddis@28
|
1306 betweenRuns.responseTracks{length(betweenRuns.thresholds)}=...
|
rmeddis@28
|
1307 withinRuns.responseList(withinRuns.beginningOfPhase2:end);
|
rmeddis@28
|
1308 else
|
rmeddis@28
|
1309 betweenRuns.bestThresholdTracks{length(betweenRuns.thresholds)}=[];
|
rmeddis@28
|
1310 betweenRuns.levelTracks{length(betweenRuns.thresholds)}=[];
|
rmeddis@28
|
1311 betweenRuns.responseTracks{length(betweenRuns.thresholds)}=[];
|
rmeddis@28
|
1312 end
|
rmeddis@28
|
1313
|
rmeddis@28
|
1314 betweenRuns.bestGain=[betweenRuns.bestGain rareEvent.bestGain];
|
rmeddis@28
|
1315 betweenRuns.bestVMin=[betweenRuns.bestVMin rareEvent.bestVMin];
|
rmeddis@28
|
1316 betweenRuns.bestPaMin=[betweenRuns.bestPaMin rareEvent.bestPaMindB];
|
rmeddis@28
|
1317 betweenRuns.bestLogisticM=...
|
rmeddis@28
|
1318 [betweenRuns.bestLogisticM logistic.bestThreshold];
|
rmeddis@28
|
1319 betweenRuns.bestLogisticK=[betweenRuns.bestLogisticK logistic.bestK];
|
rmeddis@28
|
1320
|
rmeddis@28
|
1321 resultsSoFar=[betweenRuns.var1Sequence(betweenRuns.runNumber)'...
|
rmeddis@28
|
1322 betweenRuns.var2Sequence(betweenRuns.runNumber)'...
|
rmeddis@28
|
1323 betweenRuns.thresholds(betweenRuns.runNumber)'
|
rmeddis@28
|
1324 ];
|
rmeddis@28
|
1325
|
rmeddis@28
|
1326 fprintf('%10.3f \t%10.3f \t%10.1f \n', resultsSoFar')
|
rmeddis@28
|
1327
|
rmeddis@28
|
1328 switch experiment.ear
|
rmeddis@28
|
1329 case {'left', 'right', 'diotic', 'dichoticLeft','dichoticRight'}
|
rmeddis@28
|
1330 disp(['caught out= ' num2str(betweenRuns.caughtOut)])
|
rmeddis@28
|
1331 end
|
rmeddis@28
|
1332
|
rmeddis@28
|
1333 % plot history of thresholds in panel 4
|
rmeddis@28
|
1334 axes(expGUIhandles.axes4), cla
|
rmeddis@28
|
1335 plotColors='rgbmckywrgbmckyw';
|
rmeddis@28
|
1336 for i=1:length(betweenRuns.thresholds)
|
rmeddis@28
|
1337 faceColor=plotColors(floor(i/length(betweenRuns.variableList1)-.01)+1);
|
rmeddis@28
|
1338 switch betweenRuns.variableName1
|
rmeddis@28
|
1339 case {'targetFrequency', 'maskerRelativeFrequency'}
|
rmeddis@28
|
1340 if min(betweenRuns.var1Sequence)>0
|
rmeddis@28
|
1341 % semilogx(betweenRuns.var1Sequence(1:betweenRuns.runNumber), ...
|
rmeddis@28
|
1342 % betweenRuns.thresholds, 'o', ...
|
rmeddis@28
|
1343 % 'markerSize', 5,'markerFaceColor',faceColor)
|
rmeddis@28
|
1344 semilogx(betweenRuns.var1Sequence(i), ...
|
rmeddis@28
|
1345 betweenRuns.thresholds(i), 'o', ...
|
rmeddis@28
|
1346 'markerSize', 5,'markerFaceColor',faceColor)
|
rmeddis@28
|
1347 else
|
rmeddis@28
|
1348 plot(betweenRuns.var1Sequence(1:betweenRuns.runNumber), ...
|
rmeddis@28
|
1349 betweenRuns.thresholds, 'o', ...
|
rmeddis@28
|
1350 'markerSize', 5,'markerFaceColor',faceColor)
|
rmeddis@28
|
1351 plot(betweenRuns.var1Sequence(i), ...
|
rmeddis@28
|
1352 betweenRuns.thresholds(i), 'o', ...
|
rmeddis@28
|
1353 'markerSize', 5,'markerFaceColor',faceColor)
|
rmeddis@28
|
1354 end
|
rmeddis@28
|
1355 otherwise
|
rmeddis@28
|
1356 % plot(betweenRuns.var1Sequence(1:betweenRuns.runNumber), ...
|
rmeddis@28
|
1357 % betweenRuns.thresholds, 'o', 'markerSize', 5,...
|
rmeddis@28
|
1358 % 'markerFaceColor',faceColor)
|
rmeddis@28
|
1359 plot(betweenRuns.var1Sequence(i), ...
|
rmeddis@28
|
1360 betweenRuns.thresholds(i), 'o', 'markerSize', 5,...
|
rmeddis@28
|
1361 'markerFaceColor',faceColor)
|
rmeddis@28
|
1362 end
|
rmeddis@28
|
1363 hold on
|
rmeddis@28
|
1364 end
|
rmeddis@28
|
1365 xlimRM([ min(betweenRuns.variableList1) max(betweenRuns.variableList1) ])
|
rmeddis@28
|
1366 ylim(stimulusParameters.WRVlimits)
|
rmeddis@28
|
1367 ylabel('thresholds')
|
rmeddis@28
|
1368 xlabel(betweenRuns.variableName1)
|
rmeddis@28
|
1369 set(gca,'ytick', [0 20 40 60 80 100])
|
rmeddis@28
|
1370 try
|
rmeddis@28
|
1371 % problems if only one x value
|
rmeddis@28
|
1372 set(gca,'XTick', sort(betweenRuns.variableList1))
|
rmeddis@28
|
1373 catch
|
rmeddis@28
|
1374 end
|
rmeddis@28
|
1375 grid on, set(gca,'XMinorGrid', 'off')
|
rmeddis@28
|
1376
|
rmeddis@28
|
1377 % If comparison data is available in pearmeter file, plot it now
|
rmeddis@28
|
1378 if ~isempty (experiment.comparisonData)
|
rmeddis@28
|
1379 comparisonData=experiment.comparisonData(:,1:end-1); % ignore final BF
|
rmeddis@28
|
1380 [x, ncols]=size(comparisonData);
|
rmeddis@28
|
1381 if length(betweenRuns.variableList1)==ncols
|
rmeddis@28
|
1382 hold on
|
rmeddis@28
|
1383 plot (sort(betweenRuns.variableList1), comparisonData, 'r')
|
rmeddis@28
|
1384 hold off
|
rmeddis@28
|
1385 end
|
rmeddis@28
|
1386 end
|
rmeddis@28
|
1387
|
rmeddis@28
|
1388 % End of the Experiment also?
|
rmeddis@28
|
1389 if betweenRuns.runNumber==length(betweenRuns.var1Sequence)
|
rmeddis@28
|
1390 % yes, end of experiment
|
rmeddis@28
|
1391 fileName=['savedData/' experiment.name experiment.date ...
|
rmeddis@28
|
1392 experiment.paradigm];
|
rmeddis@28
|
1393 % save (fileName, 'experiment', 'stimulusParameters', 'betweenRuns', 'withinRuns', 'variableNames', 'paradigmNames', 'LevittControl')
|
rmeddis@28
|
1394 disp('Experiment completed')
|
rmeddis@28
|
1395
|
rmeddis@28
|
1396 % update subject GUI to acknowledge end of run
|
rmeddis@28
|
1397 subjGUImsg=[{'Experiment completed'}, {' '}, {'Thank you!'}];
|
rmeddis@28
|
1398 set(handles.textMSG,'string', subjGUImsg )
|
rmeddis@28
|
1399 % play 'Tada'
|
rmeddis@28
|
1400 [y,fs,nbits]=wavread('TADA.wav');
|
rmeddis@28
|
1401 musicGain=10^(stimulusParameters.musicLeveldB/20);
|
rmeddis@28
|
1402 y=y*musicGain;
|
rmeddis@28
|
1403 wavplay(y/100,fs, 'async')
|
rmeddis@28
|
1404
|
rmeddis@28
|
1405 % update experimenter GUI
|
rmeddis@28
|
1406 addToMsg('Experiment completed.',1)
|
rmeddis@28
|
1407
|
rmeddis@28
|
1408 printReport
|
rmeddis@28
|
1409 experiment.status='endOfExperiment';
|
rmeddis@28
|
1410 return
|
rmeddis@28
|
1411 else
|
rmeddis@28
|
1412 % No, hang on.
|
rmeddis@28
|
1413 switch experiment.ear
|
rmeddis@28
|
1414 case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ...
|
rmeddis@28
|
1415 'MAPmodelMultiCh','MAPmodelSingleCh', 'MAPmodelListen'}
|
rmeddis@28
|
1416 % no changes required if model used
|
rmeddis@28
|
1417 otherwise
|
rmeddis@28
|
1418 % decrement catchTrialRate towards baseRate
|
rmeddis@28
|
1419 stimulusParameters.catchTrialRate=...
|
rmeddis@28
|
1420 stimulusParameters.catchTrialBaseRate + ...
|
rmeddis@28
|
1421 (stimulusParameters.catchTrialRate...
|
rmeddis@28
|
1422 -stimulusParameters.catchTrialBaseRate)...
|
rmeddis@28
|
1423 *(1-exp(-stimulusParameters.catchTrialTimeConstant));
|
rmeddis@28
|
1424 fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
|
rmeddis@28
|
1425 stimulusParameters.catchTrialRate)
|
rmeddis@28
|
1426
|
rmeddis@28
|
1427 % and go again
|
rmeddis@28
|
1428 set(handles.pushbuttonGO,'backgroundcolor','y')
|
rmeddis@28
|
1429 set(handles.frame1,'visible','off')
|
rmeddis@28
|
1430 set(handles.pushbuttonGO,'visible','on')
|
rmeddis@28
|
1431 msg=[{'Ready to start new trial'}, {' '},...
|
rmeddis@28
|
1432 {'Please,click on the GO button'}];
|
rmeddis@28
|
1433 set(handles.textMSG,'string',msg)
|
rmeddis@28
|
1434 end
|
rmeddis@28
|
1435 experiment.status='waitingForGO';
|
rmeddis@28
|
1436 % fprintf('\n')
|
rmeddis@28
|
1437
|
rmeddis@28
|
1438 [y,fs,nbits]=wavread('CHIMES.wav');
|
rmeddis@28
|
1439 musicGain=10^(stimulusParameters.musicLeveldB/20);
|
rmeddis@28
|
1440 y=y*musicGain;
|
rmeddis@28
|
1441 wavplay(y/100,fs,'async')
|
rmeddis@28
|
1442 end
|
rmeddis@28
|
1443
|
rmeddis@28
|
1444 % -----------------------------------------------------MAPmodelRunsGUI
|
rmeddis@28
|
1445 % The computer presses the buttons
|
rmeddis@28
|
1446 function MAPmodelRunsGUI(handles)
|
rmeddis@28
|
1447 global experiment stimulusParameters method expGUIhandles
|
rmeddis@28
|
1448 global AN_IHCsynapseParams
|
rmeddis@28
|
1449 method=[];
|
rmeddis@28
|
1450
|
rmeddis@28
|
1451 while strcmp(experiment.status,'waitingForGO')
|
rmeddis@28
|
1452 % no catch trials for MAP model
|
rmeddis@28
|
1453 experiment.allowCatchTrials=0;
|
rmeddis@28
|
1454
|
rmeddis@28
|
1455 % initiates run and plays first stimulus and it returns
|
rmeddis@28
|
1456 % without waiting for button press
|
rmeddis@28
|
1457 startNewRun(handles)
|
rmeddis@28
|
1458
|
rmeddis@28
|
1459 if sum(strcmp(experiment.ear,...
|
rmeddis@28
|
1460 {'MAPmodelMultiCh', 'MAPmodelListen'}))
|
rmeddis@28
|
1461 % use BFlist specified in MAPparams file
|
rmeddis@28
|
1462 BFlist= -1;
|
rmeddis@28
|
1463 else
|
rmeddis@28
|
1464 BFlist=stimulusParameters.targetFrequency;
|
rmeddis@28
|
1465 end
|
rmeddis@28
|
1466 showParams=0;
|
rmeddis@28
|
1467 % find model parameters using the 'name' box (e.g. CTa ->MAPparamsCTa)
|
rmeddis@28
|
1468 paramFunctionName=['method=MAPparams' experiment.name ...
|
rmeddis@28
|
1469 '(BFlist, stimulusParameters.sampleRate, showParams);'];
|
rmeddis@28
|
1470 eval(paramFunctionName) % go and fetch the parameters
|
rmeddis@28
|
1471
|
rmeddis@28
|
1472
|
rmeddis@28
|
1473 % show sample Rate on GUI; it must be set in MAPparams
|
rmeddis@28
|
1474 set(expGUIhandles.textsampleRate,'string',...
|
rmeddis@28
|
1475 num2str(stimulusParameters.sampleRate))
|
rmeddis@28
|
1476
|
rmeddis@28
|
1477 if experiment.singleShot
|
rmeddis@28
|
1478 % AN_IHCsynapseParams.showSummaryStatistics=1;
|
rmeddis@28
|
1479 method.showSummaryStatistics=1;
|
rmeddis@28
|
1480 AN_IHCsynapseParams.plotSynapseContents=1;
|
rmeddis@28
|
1481 else
|
rmeddis@28
|
1482 method.showSummaryStatistics=0;
|
rmeddis@28
|
1483 AN_IHCsynapseParams.plotSynapseContents=0;
|
rmeddis@28
|
1484 end
|
rmeddis@28
|
1485
|
rmeddis@28
|
1486 if strcmp(experiment.ear, 'MAPmodelSingleCh')
|
rmeddis@28
|
1487 method.MGmembranePotentialSave=1;
|
rmeddis@28
|
1488 end
|
rmeddis@28
|
1489
|
rmeddis@28
|
1490 % continuous loop until the program stops itself
|
rmeddis@28
|
1491 while strcmp(experiment.status,'waitingForResponse')
|
rmeddis@28
|
1492 % NB at this point the stimulus has been played
|
rmeddis@28
|
1493 pause(0.1) % to allow interrupt with CTRL/C
|
rmeddis@28
|
1494
|
rmeddis@28
|
1495 switch experiment.ear
|
rmeddis@28
|
1496 case { 'MAPmodelListen'}
|
rmeddis@28
|
1497 set(handles.pushbutton1,'backgroundcolor','y','visible','on')
|
rmeddis@28
|
1498 set(handles.pushbutton2,'backgroundcolor','y','visible','on')
|
rmeddis@28
|
1499 end
|
rmeddis@28
|
1500
|
rmeddis@28
|
1501 AN_IHCsynapseParams.mode= 'spikes';
|
rmeddis@28
|
1502
|
rmeddis@28
|
1503 % Analayse the current stimulus using MAP
|
rmeddis@28
|
1504 [modelResponse earObject]= MAPmodel( experiment.MAPplot, method);
|
rmeddis@28
|
1505
|
rmeddis@28
|
1506 if experiment.stop || experiment.singleShot
|
rmeddis@28
|
1507 % trap for single trial or user interrupt using 'stop' button.
|
rmeddis@28
|
1508 experiment.status= 'waitingForStart';
|
rmeddis@28
|
1509 experiment.stop=0;
|
rmeddis@28
|
1510 addToMsg('manually stopped',1);
|
rmeddis@28
|
1511 return
|
rmeddis@28
|
1512 end
|
rmeddis@28
|
1513
|
rmeddis@28
|
1514 switch modelResponse
|
rmeddis@28
|
1515 case 1
|
rmeddis@28
|
1516 % userDoesNotHearTarget(handles)
|
rmeddis@28
|
1517 switch experiment.ear
|
rmeddis@28
|
1518 case {'MAPmodelListen'}
|
rmeddis@28
|
1519 % illuminate appropriate button
|
rmeddis@28
|
1520 set(handles.pushbutton1,...
|
rmeddis@28
|
1521 'backgroundcolor','r','visible','on')
|
rmeddis@28
|
1522 set(handles.pushbutton2,'backgroundcolor','y')
|
rmeddis@28
|
1523 end
|
rmeddis@28
|
1524 userDecides(handles, false)
|
rmeddis@28
|
1525 if experiment.singleShot, return, end
|
rmeddis@28
|
1526
|
rmeddis@28
|
1527 case 2
|
rmeddis@28
|
1528 % userHearsTarget(handles)
|
rmeddis@28
|
1529 switch experiment.ear
|
rmeddis@28
|
1530 case {'MAPmodelListen'}
|
rmeddis@28
|
1531 % illuminate appropriate button (DEMO only)
|
rmeddis@28
|
1532 set(handles.pushbutton2,'backgroundcolor',...
|
rmeddis@28
|
1533 'r','visible','on')
|
rmeddis@28
|
1534 set(handles.pushbutton1,'backgroundcolor','y')
|
rmeddis@28
|
1535 end
|
rmeddis@28
|
1536
|
rmeddis@28
|
1537 switch experiment.paradigm
|
rmeddis@28
|
1538 case 'discomfort'
|
rmeddis@28
|
1539 % always treat discomfort as 'not heard'
|
rmeddis@28
|
1540 userDecides(handles, false)
|
rmeddis@28
|
1541 otherwise
|
rmeddis@28
|
1542 userDecides(handles, true)
|
rmeddis@28
|
1543 end
|
rmeddis@28
|
1544 otherwise
|
rmeddis@28
|
1545 % probably an abort
|
rmeddis@28
|
1546 return
|
rmeddis@28
|
1547 end
|
rmeddis@28
|
1548 end
|
rmeddis@28
|
1549 end
|
rmeddis@28
|
1550
|
rmeddis@28
|
1551 function [modelResponse, MacGregorResponse]=MAPmodel( MAPplot, method)
|
rmeddis@28
|
1552
|
rmeddis@28
|
1553 global experiment stimulusParameters audio withinRuns
|
rmeddis@28
|
1554 global outerMiddleEarParams DRNLParams AN_IHCsynapseParams
|
rmeddis@28
|
1555
|
rmeddis@28
|
1556 savePath=path;
|
rmeddis@28
|
1557 addpath(['..' filesep 'MAP'], ['..' filesep 'utilities'])
|
rmeddis@28
|
1558 modelResponse=[];
|
rmeddis@28
|
1559 MacGregorResponse=[];
|
rmeddis@28
|
1560
|
rmeddis@28
|
1561 % mono only (column vector)
|
rmeddis@28
|
1562 audio=audio(:,1)';
|
rmeddis@28
|
1563
|
rmeddis@28
|
1564 % if stop button pressed earlier
|
rmeddis@28
|
1565 if experiment.stop, return, end
|
rmeddis@28
|
1566
|
rmeddis@28
|
1567 % -------------------------------------------------------------- run Model
|
rmeddis@28
|
1568 MAPparamsName=experiment.name;
|
rmeddis@28
|
1569 showPlotsAndDetails=experiment.MAPplot;
|
rmeddis@28
|
1570 AN_spikesOrProbability='spikes';
|
rmeddis@28
|
1571
|
rmeddis@28
|
1572 % [response, method]=MAPsequenceSeg(audio, method, 1:8);
|
rmeddis@28
|
1573 global ICoutput ANdt
|
rmeddis@28
|
1574 MAP1_14(audio, 1/method.dt, method.nonlinCF,...
|
rmeddis@28
|
1575 MAPparamsName, AN_spikesOrProbability);
|
rmeddis@28
|
1576
|
rmeddis@28
|
1577 if showPlotsAndDetails
|
rmeddis@28
|
1578 options.printModelParameters=0;
|
rmeddis@28
|
1579 options.showModelOutput=1;
|
rmeddis@28
|
1580 options.printFiringRates=1;
|
rmeddis@28
|
1581 options.showACF=0;
|
rmeddis@28
|
1582 options.showEfferent=1;
|
rmeddis@28
|
1583 options.surfProbability=0;
|
rmeddis@28
|
1584 showMapOptions.surfSpikes=0;
|
rmeddis@28
|
1585 UTIL_showMAP(options)
|
rmeddis@28
|
1586 end
|
rmeddis@28
|
1587
|
rmeddis@28
|
1588 % No response, probably caused by hitting 'stop' button
|
rmeddis@28
|
1589 if isempty(ICoutput), return, end
|
rmeddis@28
|
1590
|
rmeddis@28
|
1591 % MacGregor response is the sum total of all final stage spiking
|
rmeddis@28
|
1592 MacGregorResponse= sum(ICoutput,1); % use IC
|
rmeddis@28
|
1593
|
rmeddis@28
|
1594 % ---------------------------------------------------------- end model run
|
rmeddis@28
|
1595
|
rmeddis@28
|
1596 dt=ANdt;
|
rmeddis@28
|
1597 time=dt:dt:dt*length(MacGregorResponse);
|
rmeddis@28
|
1598
|
rmeddis@28
|
1599 % group delay on unit response
|
rmeddis@28
|
1600 MacGonsetDelay= 0.004;
|
rmeddis@28
|
1601 MacGoffsetDelay= 0.022;
|
rmeddis@28
|
1602
|
rmeddis@28
|
1603 % now find the response of the MacGregor model during the target presentation + group delay
|
rmeddis@28
|
1604 switch experiment.threshEstMethod
|
rmeddis@28
|
1605 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@28
|
1606 idx= time>stimulusParameters.testTargetBegins+MacGonsetDelay ...
|
rmeddis@28
|
1607 & time<stimulusParameters.testTargetEnds+MacGoffsetDelay;
|
rmeddis@28
|
1608 nSpikesTrueWindow=sum(MacGregorResponse(:,idx));
|
rmeddis@28
|
1609 idx=find(time>stimulusParameters.testNonTargetBegins+MacGonsetDelay ...
|
rmeddis@28
|
1610 & time<stimulusParameters.testNonTargetEnds+MacGoffsetDelay);
|
rmeddis@28
|
1611 nSpikesFalseWindow=sum(MacGregorResponse(:,idx));
|
rmeddis@28
|
1612 % nSpikesDuringTarget is +ve when more spikes are found
|
rmeddis@28
|
1613 % in the target window
|
rmeddis@28
|
1614 difference= nSpikesTrueWindow-nSpikesFalseWindow;
|
rmeddis@28
|
1615
|
rmeddis@28
|
1616 if difference>0
|
rmeddis@28
|
1617 % hit
|
rmeddis@28
|
1618 nSpikesDuringTarget=experiment.MacGThreshold+1;
|
rmeddis@28
|
1619 elseif difference<0
|
rmeddis@28
|
1620 % miss (wrong choice)
|
rmeddis@28
|
1621 nSpikesDuringTarget=experiment.MacGThreshold-1;
|
rmeddis@28
|
1622 else
|
rmeddis@28
|
1623 if rand>0.5
|
rmeddis@28
|
1624 % hit (random choice)
|
rmeddis@28
|
1625 nSpikesDuringTarget=experiment.MacGThreshold+1;
|
rmeddis@28
|
1626 else
|
rmeddis@28
|
1627 % miss (random choice)
|
rmeddis@28
|
1628 nSpikesDuringTarget=experiment.MacGThreshold-1;
|
rmeddis@28
|
1629 end
|
rmeddis@28
|
1630 end
|
rmeddis@28
|
1631 disp(['level target dummy decision: ' ...
|
rmeddis@28
|
1632 num2str([withinRuns.variableValue nSpikesTrueWindow ...
|
rmeddis@28
|
1633 nSpikesFalseWindow nSpikesDuringTarget], '%4.0f') ] )
|
rmeddis@28
|
1634
|
rmeddis@28
|
1635 otherwise
|
rmeddis@28
|
1636 % idx=find(time>stimulusParameters.testTargetBegins+MacGonsetDelay ...
|
rmeddis@28
|
1637 % & time<stimulusParameters.testTargetEnds+MacGoffsetDelay);
|
rmeddis@28
|
1638 % no delay at onset
|
rmeddis@28
|
1639 idx=find(time>stimulusParameters.testTargetBegins +MacGonsetDelay...
|
rmeddis@28
|
1640 & time<stimulusParameters.testTargetEnds+MacGoffsetDelay);
|
rmeddis@28
|
1641 nSpikesDuringTarget=sum(MacGregorResponse(:,idx));
|
rmeddis@28
|
1642
|
rmeddis@28
|
1643 % find(MacGregorResponse)*dt-stimulusParameters.stimulusDelay
|
rmeddis@28
|
1644 timeX=time(idx);
|
rmeddis@28
|
1645 end
|
rmeddis@28
|
1646
|
rmeddis@28
|
1647 % now find the response of the MacGregor model at the end of the masker
|
rmeddis@28
|
1648 idx2=find(time>stimulusParameters.testTargetBegins-0.02 ...
|
rmeddis@28
|
1649 & time<stimulusParameters.testTargetBegins);
|
rmeddis@28
|
1650 if ~isempty(idx2)
|
rmeddis@28
|
1651 maskerRate=mean(mean(MacGregorResponse(idx2)));
|
rmeddis@28
|
1652 else
|
rmeddis@28
|
1653 %e.g. no masker
|
rmeddis@28
|
1654 maskerRate=0;
|
rmeddis@28
|
1655 end
|
rmeddis@28
|
1656
|
rmeddis@28
|
1657 if experiment.MAPplot
|
rmeddis@28
|
1658 % add vertical lines to indicate target region
|
rmeddis@28
|
1659 figure(99), subplot(6,1,6)
|
rmeddis@28
|
1660 hold on
|
rmeddis@28
|
1661 yL=get(gca,'YLim');
|
rmeddis@28
|
1662 plot([stimulusParameters.testTargetBegins + MacGonsetDelay ...
|
rmeddis@28
|
1663 stimulusParameters.testTargetBegins + MacGonsetDelay],yL,'r')
|
rmeddis@28
|
1664 plot([stimulusParameters.testTargetEnds + MacGoffsetDelay ...
|
rmeddis@28
|
1665 stimulusParameters.testTargetEnds + MacGoffsetDelay],yL,'r')
|
rmeddis@28
|
1666 end
|
rmeddis@28
|
1667
|
rmeddis@28
|
1668 % specify unambiguous response
|
rmeddis@28
|
1669 switch experiment.paradigm
|
rmeddis@28
|
1670 case 'gapDetection'
|
rmeddis@28
|
1671 gapResponse=(maskerRate-nSpikesDuringTarget)/maskerRate;
|
rmeddis@28
|
1672 if gapResponse>0.2
|
rmeddis@28
|
1673 modelResponse=2; % gap detected
|
rmeddis@28
|
1674 else
|
rmeddis@28
|
1675 modelResponse=1; % gap not detected
|
rmeddis@28
|
1676 end
|
rmeddis@28
|
1677 [nSpikesDuringTarget maskerRate gapResponse modelResponse]
|
rmeddis@28
|
1678 figure(22), plot(timeX,earObject(idx))
|
rmeddis@28
|
1679 otherwise
|
rmeddis@28
|
1680 if nSpikesDuringTarget>experiment.MacGThreshold
|
rmeddis@28
|
1681 modelResponse=2; % stimulus detected
|
rmeddis@28
|
1682 else
|
rmeddis@28
|
1683 modelResponse=1; % nothing heard (default)
|
rmeddis@28
|
1684 end
|
rmeddis@28
|
1685 end
|
rmeddis@28
|
1686
|
rmeddis@28
|
1687
|
rmeddis@28
|
1688 path(savePath)
|
rmeddis@28
|
1689
|
rmeddis@28
|
1690 % -----------------------------------------------------statsModelRunsGUI
|
rmeddis@28
|
1691 % The computer presses the buttons
|
rmeddis@28
|
1692 function statsModelRunsGUI(handles)
|
rmeddis@28
|
1693 % Decision are made at random using a prescribe statistical function
|
rmeddis@28
|
1694 % to set probabilities as a function of signal level.
|
rmeddis@28
|
1695 global experiment
|
rmeddis@28
|
1696
|
rmeddis@28
|
1697 experiment.allowCatchTrials=0;
|
rmeddis@28
|
1698
|
rmeddis@28
|
1699 while strcmp(experiment.status,'waitingForGO')
|
rmeddis@28
|
1700 % i.e. waiting for new run
|
rmeddis@28
|
1701 if experiment.stop
|
rmeddis@28
|
1702 % user has requested an abort
|
rmeddis@28
|
1703 experiment.status= 'waitingForStart';
|
rmeddis@28
|
1704 addToMsg('manually stopped',1)
|
rmeddis@28
|
1705 return
|
rmeddis@28
|
1706 end
|
rmeddis@28
|
1707
|
rmeddis@28
|
1708 % initiates run and plays first stimulus and it returns
|
rmeddis@28
|
1709 % without waiting for button press
|
rmeddis@28
|
1710 % NB stimulus is not actually generated (for speed)
|
rmeddis@28
|
1711 startNewRun(handles)
|
rmeddis@28
|
1712
|
rmeddis@28
|
1713 while strcmp(experiment.status,'waitingForResponse')
|
rmeddis@28
|
1714 % create artificial response here
|
rmeddis@28
|
1715 modelResponse=statsModelGetResponse;
|
rmeddis@28
|
1716 switch modelResponse
|
rmeddis@28
|
1717 case 1
|
rmeddis@28
|
1718 % userDoesNotHearTarget(handles)
|
rmeddis@28
|
1719 userDecides(handles, false)
|
rmeddis@28
|
1720 case 2
|
rmeddis@28
|
1721 % userHearsTarget(handles)
|
rmeddis@28
|
1722 userDecides(handles, true)
|
rmeddis@28
|
1723 end
|
rmeddis@28
|
1724 end
|
rmeddis@28
|
1725 end
|
rmeddis@28
|
1726
|
rmeddis@28
|
1727 % -----------------------------------------------------statsModelGetResponse
|
rmeddis@28
|
1728 function modelResponse=statsModelGetResponse(handles)
|
rmeddis@28
|
1729 global experiment withinRuns statsModel stimulusParameters
|
rmeddis@28
|
1730 % use the generating function to decide if a detection occurs or not
|
rmeddis@28
|
1731
|
rmeddis@28
|
1732 % pause(0.1) % to allow stopping with CTRL/C but slows things down
|
rmeddis@28
|
1733
|
rmeddis@28
|
1734 % first compute the probability that a detection occurs
|
rmeddis@28
|
1735 switch experiment.ear
|
rmeddis@28
|
1736 case {'statsModelLogistic'}
|
rmeddis@28
|
1737 prob= 1./(1+exp(-statsModel.logisticSlope.*(withinRuns.variableValue-statsModel.logisticMean)));
|
rmeddis@28
|
1738 % if experiment.psyFunSlope<0,
|
rmeddis@28
|
1739 % prob=1-prob;
|
rmeddis@28
|
1740 % end
|
rmeddis@28
|
1741
|
rmeddis@28
|
1742 case 'statsModelRareEvent'
|
rmeddis@28
|
1743 if experiment.psyFunSlope<0
|
rmeddis@28
|
1744 addToMsg('statsModelRareEvent cannot be used with negative slope',0)
|
rmeddis@28
|
1745 error('statsModelRareEvent cannot be used with negative slope')
|
rmeddis@28
|
1746 end
|
rmeddis@28
|
1747
|
rmeddis@28
|
1748 % standard formula is prob = 1 – exp(-d (g P – A))
|
rmeddis@28
|
1749 % here A->A; To find Pmin use A/gain
|
rmeddis@28
|
1750 pressure=28*10^(withinRuns.variableValue/20);
|
rmeddis@28
|
1751 gain=statsModel.rareEvenGain;
|
rmeddis@28
|
1752 A=statsModel.rareEventVmin;
|
rmeddis@28
|
1753 d=stimulusParameters.targetDuration;
|
rmeddis@28
|
1754 gP_Vmin=gain*pressure-A;
|
rmeddis@28
|
1755 if gP_Vmin>0
|
rmeddis@28
|
1756 prob=1-exp(-d*(gP_Vmin));
|
rmeddis@28
|
1757 else
|
rmeddis@28
|
1758 prob=0;
|
rmeddis@28
|
1759 end
|
rmeddis@28
|
1760 end
|
rmeddis@28
|
1761
|
rmeddis@28
|
1762 % Use the probability to choose whether or not a detection has occurred
|
rmeddis@28
|
1763 switch experiment.threshEstMethod
|
rmeddis@28
|
1764 case {'MaxLikelihood', 'oneIntervalUpDown'}
|
rmeddis@28
|
1765 if rand<prob
|
rmeddis@28
|
1766 modelResponse=2; %bingo
|
rmeddis@28
|
1767 else
|
rmeddis@28
|
1768 modelResponse=1; %nothing heard
|
rmeddis@28
|
1769 end
|
rmeddis@28
|
1770
|
rmeddis@28
|
1771 case {'2I2AFC++', '2I2AFC+++'}
|
rmeddis@28
|
1772 if rand<prob
|
rmeddis@28
|
1773 modelResponse=2; %bingo
|
rmeddis@28
|
1774 else %if the stimulus is not audible, take a 50:50 chance of getting it right
|
rmeddis@28
|
1775 if rand<0.5
|
rmeddis@28
|
1776 modelResponse=2; %bingo
|
rmeddis@28
|
1777 else
|
rmeddis@28
|
1778 modelResponse=1; %nothing heard
|
rmeddis@28
|
1779 end
|
rmeddis@28
|
1780 end
|
rmeddis@28
|
1781 end
|
rmeddis@28
|
1782
|
rmeddis@28
|
1783
|
rmeddis@28
|
1784 % ------------------------------------------------------- printTabTable
|
rmeddis@28
|
1785 function printTabTable(M, headers)
|
rmeddis@28
|
1786 % printTabTable prints a matrix as a table with tabs
|
rmeddis@28
|
1787 %headers are optional
|
rmeddis@28
|
1788 %headers=strvcat('firstname', 'secondname')
|
rmeddis@28
|
1789 % printTabTable([1 2; 3 4],strvcat('a1','a2'));
|
rmeddis@28
|
1790
|
rmeddis@28
|
1791 if nargin>1
|
rmeddis@28
|
1792 [r c]=size(headers);
|
rmeddis@28
|
1793 for no=1:r
|
rmeddis@28
|
1794 fprintf('%s\t',headers(no,:))
|
rmeddis@28
|
1795 end
|
rmeddis@28
|
1796 fprintf('\n')
|
rmeddis@28
|
1797 end
|
rmeddis@28
|
1798
|
rmeddis@28
|
1799 [r c]=size(M);
|
rmeddis@28
|
1800
|
rmeddis@28
|
1801 for row=1:r
|
rmeddis@28
|
1802 for col=1:c
|
rmeddis@28
|
1803 if row==1 && col==1 && M(1,1)==-1000
|
rmeddis@28
|
1804 % Print nothing (tab follows below)
|
rmeddis@28
|
1805 else
|
rmeddis@28
|
1806 fprintf('%s',num2str(M(row,col)))
|
rmeddis@28
|
1807 end
|
rmeddis@28
|
1808 if col<c
|
rmeddis@28
|
1809 fprintf('\t')
|
rmeddis@28
|
1810 end
|
rmeddis@28
|
1811 end
|
rmeddis@28
|
1812 fprintf('\n')
|
rmeddis@28
|
1813 end
|
rmeddis@28
|
1814
|
rmeddis@28
|
1815 % ------------------------------------------------------- xlimRM
|
rmeddis@28
|
1816 function xlimRM(x)
|
rmeddis@28
|
1817 try
|
rmeddis@28
|
1818 xlim([x(1) x(2)])
|
rmeddis@28
|
1819 catch
|
rmeddis@28
|
1820 end
|
rmeddis@28
|
1821
|
rmeddis@28
|
1822 % ------------------------------------------------------- ylimRM
|
rmeddis@28
|
1823 function ylimRM(x)
|
rmeddis@28
|
1824 try
|
rmeddis@28
|
1825 ylim([x(1) x(2)])
|
rmeddis@28
|
1826 catch
|
rmeddis@28
|
1827 end
|
rmeddis@28
|
1828
|
rmeddis@28
|
1829
|
rmeddis@28
|
1830 function editdigitInput_CreateFcn(hObject, eventdata, handles)
|
rmeddis@28
|
1831
|
rmeddis@28
|
1832 % Hint: edit controls usually have a white background on Windows.
|
rmeddis@28
|
1833 % See ISPC and COMPUTER.
|
rmeddis@28
|
1834 if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
|
rmeddis@28
|
1835 set(hObject,'BackgroundColor','white');
|
rmeddis@28
|
1836 end
|
rmeddis@28
|
1837
|
rmeddis@28
|
1838
|
rmeddis@28
|
1839 % -----------------------------------------------------buttonBoxIntitialize
|
rmeddis@28
|
1840 function buttonBoxIntitialize
|
rmeddis@28
|
1841 % initialize button box
|
rmeddis@28
|
1842 global serobj
|
rmeddis@28
|
1843 try
|
rmeddis@28
|
1844 fclose(serobj);
|
rmeddis@28
|
1845 catch
|
rmeddis@28
|
1846 end
|
rmeddis@28
|
1847
|
rmeddis@28
|
1848 try
|
rmeddis@28
|
1849 serobj = serial('COM4') ; % Creating serial port object now its connected to COM4 !!! button boxes in booths are connected to COM2
|
rmeddis@28
|
1850 serobj.Baudrate = 9600; % Set the baud rate at the specific value
|
rmeddis@28
|
1851 set(serobj, 'Parity', 'none') ; % Set parity as none
|
rmeddis@28
|
1852 set(serobj, 'Databits', 8) ; % set the number of data bits
|
rmeddis@28
|
1853 set(serobj, 'StopBits', 1) ; % set number of stop bits as 1
|
rmeddis@28
|
1854 set(serobj, 'Terminator', 'CR') ; % set the terminator value to carriage return
|
rmeddis@28
|
1855 set(serobj, 'InputBufferSize', 512) ; % Buffer for read operation, default it is 512
|
rmeddis@28
|
1856 set(serobj,'timeout',10); % 10 sec timeout on button press
|
rmeddis@28
|
1857 set(serobj, 'ReadAsyncMode', 'continuous')
|
rmeddis@28
|
1858 set(serobj, 'BytesAvailableFcn', @buttonBox_callback)
|
rmeddis@28
|
1859 set(serobj, 'BytesAvailableFcnCount', 1)
|
rmeddis@28
|
1860 set(serobj, 'BytesAvailableFcnMode', 'byte')
|
rmeddis@28
|
1861 % set(serobj, 'BreakInterruptFcn', '@buttonBox_Calback')
|
rmeddis@28
|
1862
|
rmeddis@28
|
1863 fopen(serobj);
|
rmeddis@28
|
1864 buttonBoxStatus=get(serobj,'status');
|
rmeddis@28
|
1865 catch
|
rmeddis@28
|
1866 disp('** no button box found - use mouse **')
|
rmeddis@28
|
1867 end
|