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