comparison Copy_of_multithreshold 1.46/subjGUI_MT.m @ 28:02aa9826efe0

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