comparison 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 d2c4c07df02c
children b51bf546ca3f
comparison
equal deleted inserted replaced
27:d4a7675b0413 28:02aa9826efe0
33 33
34 % -----------------------------------------------------initializeGUI 34 % -----------------------------------------------------initializeGUI
35 function initializeGUI(handles) 35 function initializeGUI(handles)
36 global experiment 36 global experiment
37 global subjectGUIHandles expGUIhandles 37 global subjectGUIHandles expGUIhandles
38 addpath (['..' filesep 'MAP'], ['..' filesep 'utilities'], ... 38 addpath (['..' filesep 'MAP'], ['..' filesep 'utilities'], ...
39 ['..' filesep 'parameterStore'], ['..' filesep 'wavFileStore'],... 39 ['..' filesep 'parameterStore'], ['..' filesep 'wavFileStore'],...
40 ['..' filesep 'testPrograms']) 40 ['..' filesep 'testPrograms'])
41 41
42 dbstop if error 42 dbstop if error
43 43
50 'statsModelLogistic','statsModelRareEvent'} 50 'statsModelLogistic','statsModelRareEvent'}
51 % subjectGUI not needed for modelling so minimize subject GUI 51 % subjectGUI not needed for modelling so minimize subject GUI
52 set(gcf, 'units','pixels') 52 set(gcf, 'units','pixels')
53 y=[0*scrnsize(3) 0.8*scrnsize(4) 0.1*scrnsize(3) 0.2*scrnsize(4)]; 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]) 54 set(gcf,'position',y, 'color',[.871 .961 .996])
55 55
56
57
58 case 'MAPmodelListen', 56 case 'MAPmodelListen',
59 % subjectGUI is needed for display purposes. Make it large 57 % subjectGUI is needed for display purposes. Make it large
60 set(gcf, 'units','pixels') 58 set(gcf, 'units','pixels')
61 y=[.665*scrnsize(3) 0.02*scrnsize(4) ... 59 y=[.665*scrnsize(3) 0.02*scrnsize(4) ...
62 0.33*scrnsize(3) 0.5*scrnsize(4)]; % alongside 60 0.33*scrnsize(3) 0.5*scrnsize(4)]; % alongside
67 case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'} 65 case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'}
68 % Look to see if the button box exists and, if so, initialise it 66 % Look to see if the button box exists and, if so, initialise it
69 buttonBoxIntitialize % harmless if no button box attached 67 buttonBoxIntitialize % harmless if no button box attached
70 end 68 end
71 69
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 70 % clear display of previous mean values. This is a new measurement series
139 axes(expGUIhandles.axes4), cla 71 axes(expGUIhandles.axes4), cla
140 reset (expGUIhandles.axes4) 72 reset (expGUIhandles.axes4)
141 73
142 % handles needed in non-callback routines below 74 % handles needed in non-callback routines below
143 subjectGUIHandles=handles; 75 subjectGUIHandles=handles;
144 76
180 case 'discomfort' 112 case 'discomfort'
181 set(handles.pushbutton3,'string','') 113 set(handles.pushbutton3,'string','')
182 set(handles.pushbutton2,'string','uncomfortable') 114 set(handles.pushbutton2,'string','uncomfortable')
183 set(handles.pushbutton1,'string','loud') 115 set(handles.pushbutton1,'string','loud')
184 set(handles.pushbutton0,'string','comfortable') 116 set(handles.pushbutton0,'string','comfortable')
185 experiment.allowCatchTrials=0; 117 experiment.allowCatchTrials=0;
186 end 118 end
187 119
188 % experiment.subjGUIfontSize is set on expGUI 120 % experiment.subjGUIfontSize is set on expGUI
189 set(handles.pushbutton3,'FontSize',experiment.subjGUIfontSize) 121 set(handles.pushbutton3,'FontSize',experiment.subjGUIfontSize)
190 set(handles.pushbutton2,'FontSize',experiment.subjGUIfontSize) 122 set(handles.pushbutton2,'FontSize',experiment.subjGUIfontSize)
207 experiment.stop=0; % status of 'stop' button 139 experiment.stop=0; % status of 'stop' button
208 experiment.pleaseRepeat=0; % status of 'repeat' button 140 experiment.pleaseRepeat=0; % status of 'repeat' button
209 experiment.buttonBoxStatus='not busy'; 141 experiment.buttonBoxStatus='not busy';
210 142
211 % date and time and replace ':' with '_' 143 % date and time and replace ':' with '_'
212 date=datestr(now);idx=findstr(':',date);date(idx)='_'; 144 date=datestr(now);idx=findstr(':',date);date(idx)='_';
213 experiment.date=date; 145 experiment.date=date;
214 timeNow=clock; betweenRuns.timeNow= timeNow; 146 timeNow=clock; betweenRuns.timeNow= timeNow;
215 experiment.timeAtStart=[num2str(timeNow(4)) ':' num2str(timeNow(5))]; 147 experiment.timeAtStart=[num2str(timeNow(4)) ':' num2str(timeNow(5))];
216 experiment.minElapsed=0; 148 experiment.minElapsed=0;
217 149
218 % unpack catch trial rates. The rate declines from the start rate 150 % unpack catch trial rates. The rate declines from the start rate
219 % to the base rate using a time constant. 151 % to the base rate using a time constant.
220 stimulusParameters.catchTrialRate=stimulusParameters.catchTrialRates(1); 152 stimulusParameters.catchTrialRate=stimulusParameters.catchTrialRates(1);
221 stimulusParameters.catchTrialBaseRate=... 153 stimulusParameters.catchTrialBaseRate=...
222 stimulusParameters.catchTrialRates(2); 154 stimulusParameters.catchTrialRates(2);
223 stimulusParameters.catchTrialTimeConstant=... 155 stimulusParameters.catchTrialTimeConstant=...
263 eval(['variableList1=stimulusParameters.' betweenRuns.variableName1 ';']); 195 eval(['variableList1=stimulusParameters.' betweenRuns.variableName1 ';']);
264 eval(['variableList2=stimulusParameters.' betweenRuns.variableName2 ';']); 196 eval(['variableList2=stimulusParameters.' betweenRuns.variableName2 ';']);
265 nVar1=length(variableList1); 197 nVar1=length(variableList1);
266 nVar2=length(variableList2); 198 nVar2=length(variableList2);
267 199
268 % Create two sequence vectors to represent the sequence of var1 and var2 200 % Create two sequence vectors to represent the sequence of var1 and var2
269 % values. 'var1' changes most rapidly. 201 % values. 'var1' changes most rapidly.
270 switch betweenRuns.randomizeSequence 202 switch betweenRuns.randomizeSequence
271 case 'fixed sequence' 203 case 'fixed sequence'
272 var1Sequence=repmat(betweenRuns.variableList1, 1,nVar2); 204 var1Sequence=repmat(betweenRuns.variableList1, 1,nVar2);
273 var2Sequence=reshape(repmat(betweenRuns.variableList2, ... 205 var2Sequence=reshape(repmat(betweenRuns.variableList2, ...
287 1,nVar1*nVar2); 219 1,nVar1*nVar2);
288 ranNums=rand(1, nVar1*nVar2); 220 ranNums=rand(1, nVar1*nVar2);
289 [x idx]=sort(ranNums); 221 [x idx]=sort(ranNums);
290 var1Sequence=var1Sequence(idx); 222 var1Sequence=var1Sequence(idx);
291 var2Sequence=var2Sequence(idx); 223 var2Sequence=var2Sequence(idx);
292 % there should be one start value for every combination 224 % there should be one start value for every combination
293 % of var1/ var2. In principle this allows these values to be 225 % of var1/ var2. In principle this allows these values to be
294 % programmed. Not currently in use. 226 % programmed. Not currently in use.
295 stimulusParameters.WRVstartValues=... 227 stimulusParameters.WRVstartValues=...
296 stimulusParameters.WRVstartValues(idx); 228 stimulusParameters.WRVstartValues(idx);
297 end 229 end
298 betweenRuns.var1Sequence=var1Sequence; 230 betweenRuns.var1Sequence=var1Sequence;
302 betweenRuns.caughtOut=zeros(1,length(var1Sequence)); 234 betweenRuns.caughtOut=zeros(1,length(var1Sequence));
303 235
304 disp('planned sequence:') 236 disp('planned sequence:')
305 if min(var1Sequence)>1 237 if min(var1Sequence)>1
306 % use decidaml places only if necessary 238 % use decidaml places only if necessary
307 disp([betweenRuns.variableName1 ': ' num2str(var1Sequence,'%6.0f') ]) 239 disp([betweenRuns.variableName1 ': ' num2str(var1Sequence,'%6.0f') ])
308 else 240 else
309 disp([betweenRuns.variableName1 ': ' num2str(var1Sequence,'%8.3f') ]) 241 disp([betweenRuns.variableName1 ': ' num2str(var1Sequence,'%8.3f') ])
310 end 242 end
311 if min(var1Sequence)>1 243 if min(var1Sequence)>1
312 disp([betweenRuns.variableName2 ': ' num2str(var2Sequence,'%6.0f') ]) 244 disp([betweenRuns.variableName2 ': ' num2str(var2Sequence,'%6.0f') ])
313 else 245 else
314 disp([betweenRuns.variableName2 ': ' num2str(var2Sequence,'%8.3f') ]) 246 disp([betweenRuns.variableName2 ': ' num2str(var2Sequence,'%8.3f') ])
315 end 247 end
316 248
317 fprintf('\nvariable1 \t variable2\t \n') 249 fprintf('\nvariable1 \t variable2\t \n')
318 fprintf('%s \t %s\t Threshold \n',betweenRuns.variableName1,... 250 fprintf('%s \t %s\t Threshold \n',betweenRuns.variableName1,...
319 betweenRuns.variableName2) 251 betweenRuns.variableName2)
329 set(handles.pushbuttonGO,'visible','on') 261 set(handles.pushbuttonGO,'visible','on')
330 set(handles.frame1,'visible','off') 262 set(handles.frame1,'visible','off')
331 set(handles.textMSG,'backgroundcolor', 'w') 263 set(handles.textMSG,'backgroundcolor', 'w')
332 msg=[{'Ready to start new Experiment'}, {' '}, {'Please, click on the GO button'}]; 264 msg=[{'Ready to start new Experiment'}, {' '}, {'Please, click on the GO button'}];
333 set(handles.textMSG,'string', msg) 265 set(handles.textMSG,'string', msg)
334 266
335 set(handles.pushbuttoNotSure,'visible','off') 267 set(handles.pushbuttoNotSure,'visible','off')
336 set(handles.pushbuttonWrongButton,'visible','off') 268 set(handles.pushbuttonWrongButton,'visible','off')
337 set(handles.pushbutton3,'visible','off') 269 set(handles.pushbutton3,'visible','off')
338 set(handles.pushbutton2,'visible','off') 270 set(handles.pushbutton2,'visible','off')
339 set(handles.pushbutton1,'visible','off') 271 set(handles.pushbutton1,'visible','off')
348 switch experiment.ear 280 switch experiment.ear
349 case {'MAPmodel','MAPmodelMultiCh','MAPmodelSingleCh','MAPmodelListen'} % MAP model is now the subject 281 case {'MAPmodel','MAPmodelMultiCh','MAPmodelSingleCh','MAPmodelListen'} % MAP model is now the subject
350 stimulusParameters.calibrationdB=0; % Pascals required! 282 stimulusParameters.calibrationdB=0; % Pascals required!
351 MAPmodelRunsGUI(handles) 283 MAPmodelRunsGUI(handles)
352 % model is now the subject 284 % model is now the subject
353 case {'statsModelLogistic', 'statsModelRareEvent'} 285 case {'statsModelLogistic', 'statsModelRareEvent'}
354 % no catch trials for the statistical model 286 % no catch trials for the statistical model
355 stimulusParameters.catchTrialBaseRate=0; 287 stimulusParameters.catchTrialBaseRate=0;
356 stimulusParameters.catchTrialRate=0; 288 stimulusParameters.catchTrialRate=0;
357 statsModelRunsGUI(handles) 289 statsModelRunsGUI(handles)
358 otherwise 290 otherwise
359 %manual operation; wait for user to click on 'GO' 291 %manual operation; wait for user to click on 'GO'
360 end 292 end
370 % Under manual control this is achieved by hitting the GO button 302 % Under manual control this is achieved by hitting the GO button
371 % either via the button box or a mouse click 303 % either via the button box or a mouse click
372 % MAP and randomization methods call this too 304 % MAP and randomization methods call this too
373 305
374 global experiment stimulusParameters betweenRuns withinRuns expGUIhandles 306 global experiment stimulusParameters betweenRuns withinRuns expGUIhandles
375 global LevittControl rareEvent 307 global LevittControl rareEvent errormsg
376 308
377 figure(handles.figure1) % guarantee subject GUI visibility 309 figure(handles.figure1) % guarantee subject GUI visibility
378 310
379 % ignore call if program is not ready 311 % ignore call if program is not ready
380 if ~strcmp(experiment.status,'waitingForGO'), return, end 312 if ~strcmp(experiment.status,'waitingForGO'), return, end
445 pause(experiment.clickToStimulusPause) 377 pause(experiment.clickToStimulusPause)
446 end 378 end
447 379
448 errormsg=nextStimulus(handles); % get the show on the road 380 errormsg=nextStimulus(handles); % get the show on the road
449 381
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 382 % terminate if there is any kind of problem
457 if ~isempty(errormsg) 383 if ~isempty(errormsg)
458 % e.g. limits exceeded, clipping 384 % e.g. limits exceeded, clipping
459 disp(errormsg) 385 disp(errormsg)
460 runCompleted(handles) 386 runCompleted(handles)
461 return 387 return
462 end 388 end
463
464 % return route is variable (see intro to this function) 389 % return route is variable (see intro to this function)
465 390
466 % -----------------------------------------------------buttonBox_callback 391 % -----------------------------------------------------buttonBox_callback
467 function buttonBox_callback(obj, info) 392 function buttonBox_callback(obj, info)
393 % deals with a button press on the button box.
394
468 global experiment 395 global experiment
469 global serobj 396 global serobj
470 global subjectGUIHandles 397 global subjectGUIHandles
471 398
472 % do not accept callback if one is already in process 399 % do not accept callback if one is already in process
473 if strcmp(experiment.buttonBoxStatus,'busy') 400 if strcmp(experiment.buttonBoxStatus,'busy')
474 disp(' ignored button press') 401 disp(' ignored button press')
475 return 402 return % to quiescent state
476 end 403 end
477 experiment.buttonBoxStatus='busy'; 404 experiment.buttonBoxStatus='busy';
478 % fclose(serobj)
479 405
480 % identify the code of the button pressed 406 % identify the code of the button pressed
481 buttonPressedNo = fscanf(serobj,'%c',1); 407 buttonPressedNo = fscanf(serobj,'%c',1);
482 408
483 % This is the map from the button to the Cedrus codes 409 % This is the map from the button to the Cedrus codes
484 switch experiment.buttonBoxType 410 switch experiment.buttonBoxType
485 case 'horizontal' 411 case 'horizontal'
486 pbGo='7'; pb0='1'; 412 pbGo='7'; pb0='1';
487 pb1='2'; pb2='3'; 413 pb1='2'; pb2='3';
488 pbRepeat='4'; pbWrong='6'; pbBlank='5'; 414 pbRepeat='4'; pbWrong='6'; pbBlank='5';
489 case 'square' 415 case 'square'
490 pbGo='7'; pb0='1'; 416 pbGo='7'; pb0='1';
491 pb1='3'; pb2='4'; 417 pb1='3'; pb2='4';
492 pbRepeat='8'; pbWrong='6'; pbBlank='5'; 418 pbRepeat='8'; pbWrong='6'; pbBlank='5';
493 end 419 end
494 420
495 % decide what to do 421 % decide what to do
496 switch experiment.status 422 switch experiment.status
497 case {'presentingStimulus', 'waitingForStart', 'trialcompleted', ... 423 case {'presentingStimulus', 'waitingForStart', 'trialcompleted', ...
498 'endOfExperiment'} 424 'endOfExperiment'}
499 disp(' ignored button press') 425 disp(' ignored button press')
500 426
501 case 'waitingForGO' 427 case 'waitingForGO'
502 % i.e. waiting for new run 428 % i.e. waiting for new run
503 if strcmp(buttonPressedNo,pbGo) % only GO button accepted 429 if strcmp(buttonPressedNo,pbGo) % only GO button accepted
504 startNewRun(subjectGUIHandles) 430 startNewRun(subjectGUIHandles)
505 else 431 else
506 disp(' ignored button press') 432 disp(' ignored button press')
507 end 433 end
508 434
509 case 'waitingForResponse' 435 case 'waitingForResponse'
510 % response to stimuli 436 % response to stimuli
511 switch buttonPressedNo 437 switch buttonPressedNo
512 case pb0 % button 0 (top left) 438 case pb0 % button 0 (top left)
513 switch experiment.threshEstMethod 439 switch experiment.threshEstMethod
520 set(subjectGUIHandles.pushbutton0,... 446 set(subjectGUIHandles.pushbutton0,...
521 'backgroundcolor',get(0,... 447 'backgroundcolor',get(0,...
522 'defaultUicontrolBackgroundColor')) 448 'defaultUicontrolBackgroundColor'))
523 userSelects0or1(subjectGUIHandles) 449 userSelects0or1(subjectGUIHandles)
524 end 450 end
525 451
526 case pb1 % button 1 (bottom left) 452 case pb1 % button 1 (bottom left)
527 switch experiment.threshEstMethod 453 switch experiment.threshEstMethod
528 case {'2I2AFC++', '2I2AFC+++'} 454 case {'2I2AFC++', '2I2AFC+++'}
529 userSelects0or1(subjectGUIHandles) 455 userSelects0or1(subjectGUIHandles)
530 otherwise 456 otherwise
531 set(subjectGUIHandles.pushbutton1,... 457 set(subjectGUIHandles.pushbutton1,...
532 'backgroundcolor','r') 458 'backgroundcolor','r')
533 pause(.1) 459 pause(.1)
534 set(subjectGUIHandles.pushbutton1,... 460 set(subjectGUIHandles.pushbutton1,...
535 'backgroundcolor',get(0,... 461 'backgroundcolor',get(0,...
536 'defaultUicontrolBackgroundColor')) 462 'defaultUicontrolBackgroundColor'))
537 userSelects0or1(subjectGUIHandles) 463 userSelects0or1(subjectGUIHandles)
538 end 464 end
539 465
540 case pb2 % button 2 (bottom right) 466 case pb2 % button 2 (bottom right)
541 switch experiment.threshEstMethod 467 switch experiment.threshEstMethod
542 case {'2I2AFC++', '2I2AFC+++'} 468 case {'2I2AFC++', '2I2AFC+++'}
543 userSelects2 (subjectGUIHandles) 469 userSelects2 (subjectGUIHandles)
544 otherwise 470 otherwise
548 set(subjectGUIHandles.pushbutton2,... 474 set(subjectGUIHandles.pushbutton2,...
549 'backgroundcolor',get(0,... 475 'backgroundcolor',get(0,...
550 'defaultUicontrolBackgroundColor')) 476 'defaultUicontrolBackgroundColor'))
551 userSelects2 (subjectGUIHandles) 477 userSelects2 (subjectGUIHandles)
552 end 478 end
553 479
554 case pbRepeat % extreme right button 480 case pbRepeat % extreme right button
555 switch experiment.threshEstMethod 481 switch experiment.threshEstMethod
556 case {'2I2AFC++', '2I2AFC+++'} 482 case {'2I2AFC++', '2I2AFC+++'}
557 disp(' ignored button press') 483 disp(' ignored button press')
558 otherwise 484 otherwise
559 485
560 set(subjectGUIHandles.pushbuttoNotSure,... 486 set(subjectGUIHandles.pushbuttoNotSure,...
561 'backgroundcolor','r') 487 'backgroundcolor','r')
562 pause(.1) 488 pause(.1)
563 set(subjectGUIHandles.pushbuttoNotSure,... 489 set(subjectGUIHandles.pushbuttoNotSure,...
564 'backgroundcolor',get(0,... 490 'backgroundcolor',get(0,...
565 'defaultUicontrolBackgroundColor')) 491 'defaultUicontrolBackgroundColor'))
566 userSelectsPleaseRepeat (subjectGUIHandles) 492 userSelectsPleaseRepeat (subjectGUIHandles)
567 end 493 end
568 494
569 case {pbWrong, pbBlank} 495 case {pbWrong, pbBlank}
570 disp(' ignored button press') 496 disp(' ignored button press')
571 497
572 otherwise % unrecognised button 498 otherwise % unrecognised button
573 disp('ignored button press') 499 disp('ignored button press')
574 end % end (button press number) 500 end % end (button press number)
575 otherwise 501 otherwise
576 disp('ignored button press') 502 disp('ignored button press')
577 end % experiment status 503 end % experiment status
578 504
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 505 % button box remains 'busy' until after the stimulus has been presented
585 experiment.buttonBoxStatus='not busy'; 506 experiment.buttonBoxStatus='not busy';
586 507
587 % -------------------------------------------------- pushbuttonGO_Callback 508 % -------------------------------------------------- pushbuttonGO_Callback
588 function pushbuttonGO_Callback(hObject, eventdata, handles) 509 function pushbuttonGO_Callback(hObject, eventdata, handles)
597 function pushbutton0_Callback(hObject, eventdata, handles) 518 function pushbutton0_Callback(hObject, eventdata, handles)
598 global experiment 519 global experiment
599 % This is a mouse click path 520 % This is a mouse click path
600 521
601 % ignore 0 button if 2I2AFC used 522 % ignore 0 button if 2I2AFC used
602 if findstr(experiment.threshEstMethod,'2I2AFC'), return, end 523 if findstr(experiment.threshEstMethod,'2I2AFC')
524 return % to quiescent state
525 end
603 526
604 % userDoesNotHearTarget(handles) % only possible interpretation 527 % userDoesNotHearTarget(handles) % only possible interpretation
605 userDecides(handles, false) 528 userDecides(handles, false)
606 529
607 % -------------------------------------------------- pushbutton1_Callback 530 % -------------------------------------------------- pushbutton1_Callback
635 558
636 % ----------------------------------------------------- userSelects0or1 559 % ----------------------------------------------------- userSelects0or1
637 function userSelects0or1(handles) 560 function userSelects0or1(handles)
638 global experiment withinRuns 561 global experiment withinRuns
639 562
640 switch experiment.threshEstMethod 563 switch experiment.threshEstMethod
641 case {'2I2AFC++', '2I2AFC+++'} 564 case {'2I2AFC++', '2I2AFC+++'}
642 switch withinRuns.stimulusOrder 565 switch withinRuns.stimulusOrder
643 case 'targetFirst'; 566 case 'targetFirst';
644 % userHearsTarget(handles) 567 % userHearsTarget(handles)
645 userDecides(handles, true) 568 userDecides(handles, true)
655 % return to pushButton1 callback 578 % return to pushButton1 callback
656 579
657 % ----------------------------------------------------- userSelects2 580 % ----------------------------------------------------- userSelects2
658 function userSelects2(handles) 581 function userSelects2(handles)
659 global experiment withinRuns 582 global experiment withinRuns
660 switch experiment.threshEstMethod 583 switch experiment.threshEstMethod
661 case {'2I2AFC++', '2I2AFC+++'} 584 case {'2I2AFC++', '2I2AFC+++'}
662 switch withinRuns.stimulusOrder 585 switch withinRuns.stimulusOrder
663 case 'targetSecond'; 586 case 'targetSecond';
664 % userDoesNotHearTarget(handles) 587 % userDoesNotHearTarget(handles)
665 userDecides(handles, true) 588 userDecides(handles, true)
674 % return to pushButton2 callback 597 % return to pushButton2 callback
675 598
676 % ----------------------------------------------------- ---- userDecides 599 % ----------------------------------------------------- ---- userDecides
677 function userDecides(handles, saidYes) 600 function userDecides(handles, saidYes)
678 global experiment stimulusParameters betweenRuns withinRuns 601 global experiment stimulusParameters betweenRuns withinRuns
679 global rareEvent logistic psy levelsBinVector 602 global rareEvent logistic psy levelsBinVector errormsg
680 603
681 if experiment.singleShot 604 if experiment.singleShot
682 return 605 return % not clear why this should be here
683 end 606 end
684 607
685 % ignore click if not 'waitingForResponse' 608 % ignore click if not 'waitingForResponse'
686 if ~strcmp(experiment.status,'waitingForResponse') 609 if ~strcmp(experiment.status,'waitingForResponse')
687 disp('ignored click') 610 disp('ignored click')
688 return 611 return % to userSelects
689 end 612 end
690 613
691 % speech reception threshold 614 % speech reception threshold
692 if strcmp(stimulusParameters.targetType,'digitStrings') 615 if strcmp(stimulusParameters.targetType,'digitStrings')
616 % read triple digits from userGUI
693 digitsInput=get(handles.editdigitInput,'string'); 617 digitsInput=get(handles.editdigitInput,'string');
694 % must be three digits 618 % must be three digits
695 if ~(length(digitsInput)==3) 619 if ~(length(digitsInput)==3)
696 addToMsg(['error message: Wrong no of digits'], 0, 1) 620 addToMsg(['error message: Wrong no of digits'], 0, 1)
697 set(handles.textMSG,'string', 'Wrong no of digits', ... 621 set(handles.textMSG,'string', 'Wrong no of digits', ...
698 'BackgroundColor','r', 'ForegroundColor', 'w') 622 'BackgroundColor','r', 'ForegroundColor', 'w')
699 set(handles.editdigitInput,'string','') 623 set(handles.editdigitInput,'string','')
700
701 return 624 return
702 end 625 end
703 % obtain correct answer from file name 626 % obtain correct answer from file name
704 x=stimulusParameters.digitString; 627 x=stimulusParameters.digitString;
705 idx=find(x=='O'); x(idx)='0'; % replace 'oh' with zero 628 idx=find(x=='O'); x(idx)='0'; % replace 'oh' with zero
706
707 disp([x ' ' digitsInput]) 629 disp([x ' ' digitsInput])
708
709 if x==digitsInput 630 if x==digitsInput
710 saidYes=1; 631 saidYes=1; % i.e. correct response
711 else 632 else
712 saidYes=0; 633 saidYes=0; % i.e wrong response
713 end 634 end
714 set(handles.editdigitInput,'string','') 635 set(handles.editdigitInput,'string','')
715 set(handles.editdigitInput,'visible','off') 636 set(handles.editdigitInput,'visible','off')
716 pause(0.1) 637 pause(0.1)
717 end 638 end
718
719
720 639
721 % no button presses accepted while processing 640 % no button presses accepted while processing
722 experiment.status='processingResponse'; 641 experiment.status='processingResponse';
723 642
724 % catch trials. Restart trial if caught 643 % catch trials. Restart trial if caught
725 if withinRuns.catchTrial 644 if withinRuns.catchTrial
726 if saidYes 645 if saidYes
727 disp('catch trial - caught out') 646 disp('catch trial - caught out')
728 withinRuns.caughtOut=withinRuns.caughtOut+1; 647 withinRuns.caughtOut=withinRuns.caughtOut+1;
729 648
730 % special: estimate caught out rate by allowing the trial 649 % special: estimate caught out rate by allowing the trial
731 % to continue after catch 650 % to continue after catch
732 if stimulusParameters.catchTrialBaseRate==0.5 651 if stimulusParameters.catchTrialBaseRate==0.5
733 % To use this facility, set the catchTrialRate and the 652 % To use this facility, set the catchTrialRate and the
734 % catchTrialBaseRate both to 0.5 653 % catchTrialBaseRate both to 0.5
735 % update false positive rate 654 % update false positive rate
736 betweenRuns.caughtOut(betweenRuns.runNumber)=... 655 betweenRuns.caughtOut(betweenRuns.runNumber)=...
737 withinRuns.caughtOut; 656 withinRuns.caughtOut;
738 plotProgressThisTrial(handles) 657 plotProgressThisTrial(handles)
739 nextStimulus(handles); 658 nextStimulus(handles);
740 return 659 return
741 end 660 end
742 661
743 % Punishment: restart the trial 662 % Punishment: caught out restarts the trial
744 set(handles.frame1,'backgroundColor','r') 663 set(handles.frame1,'backgroundColor','r')
745 set(handles.pushbuttonGO, ... 664 set(handles.pushbuttonGO, ...
746 'visible','on', 'backgroundcolor','y') % and go again 665 'visible','on', 'backgroundcolor','y') % and go again
747 msg=[{'Start again: catch trial error'}, {' '},... 666 msg=[{'Start again: catch trial error'}, {' '},...
748 {'Please,click on the GO button'}]; 667 {'Please,click on the GO button'}];
749 set(handles.textMSG,'string',msg) 668 set(handles.textMSG,'string',msg)
750 [y,fs]=wavread('ding.wav'); 669 [y,fs]=wavread('ding.wav');
751 wavplay(y/100,fs) 670 wavplay(y/100,fs)
752 671
753 % raise catch trial rate temporarily. 672 % raise catch trial rate temporarily.
754 % this is normally reduced on each new trial (see GO) 673 % this is normally reduced on each new trial (see GO)
755 stimulusParameters.catchTrialRate=... 674 stimulusParameters.catchTrialRate=...
756 stimulusParameters.catchTrialRate+0.1; 675 stimulusParameters.catchTrialRate+0.1;
757 if stimulusParameters.catchTrialRate>0.5 676 if stimulusParameters.catchTrialRate>0.5
758 stimulusParameters.catchTrialRate=0.5; 677 stimulusParameters.catchTrialRate=0.5;
759 end 678 end
760 fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ... 679 fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
761 stimulusParameters.catchTrialRate) 680 stimulusParameters.catchTrialRate)
762 681
763 betweenRuns.caughtOut(betweenRuns.runNumber)=... 682 betweenRuns.caughtOut(betweenRuns.runNumber)=...
764 1+betweenRuns.caughtOut(betweenRuns.runNumber); 683 1+betweenRuns.caughtOut(betweenRuns.runNumber);
765 betweenRuns.runNumber=betweenRuns.runNumber-1; 684 betweenRuns.runNumber=betweenRuns.runNumber-1;
766 experiment.status='waitingForGO'; 685 experiment.status='waitingForGO';
767 return % unwind and wait for button press 686 return % unwind and wait for button press
768 else % (said No) 687 else % (said No)
769 % user claims not to have heard target. fortunate as it was not 688 % user claims not to have heard target.
770 % present. So, repeat the stimulus (possibly with target) 689 % This is good as it was not present.
690 % So, repeat the stimulus (possibly with target)
771 % and behave as if the last trial did not occur 691 % and behave as if the last trial did not occur
772 errormsg=nextStimulus(handles); 692 errormsg=nextStimulus(handles);
773 693
774 % terminate if there is any kind of problem 694 % terminate if there is any kind of problem
775 if ~isempty(errormsg) 695 if ~isempty(errormsg)
776 % e.g. limits exceeded, clipping 696 % e.g. limits exceeded, clipping
777 disp(['Error nextStimulus: ' errormsg]) 697 disp(['Error nextStimulus: ' errormsg])
778 runCompleted(handles) 698 runCompleted(handles)
779 return 699 return
780 end 700 end
781 return % no further action - next trial 701 return % no further action - next trial
782 end 702 end
783 end 703 end % of catch trial
784 704
785 % This section analyses the responses, makes tracks and defines next stim. 705 % Real target: analyse the response, make tracks and define next stim.
786 706
787 % Define response and update response list 707 % Define response and update response list
788 if saidYes 708 if saidYes
789 % target was heard, so response=1; 709 % target was heard, so response=1;
790 withinRuns.responseList=[withinRuns.responseList 1]; % 'heard it!' 710 withinRuns.responseList=[withinRuns.responseList 1]; % 'heard it!'
797 717
798 % keep track of peaks and troughs; 718 % keep track of peaks and troughs;
799 % identify direction of change during initial period 719 % identify direction of change during initial period
800 if saidYes 720 if saidYes
801 % default step size before first reversal 721 % default step size before first reversal
802 WRVinitialStep=-stimulusParameters.WRVinitialStep; 722 WRVinitialStep=-stimulusParameters.WRVinitialStep;
803 WRVsmallStep=-stimulusParameters.WRVsmallStep; 723 WRVsmallStep=-stimulusParameters.WRVsmallStep;
804 % if the previous direction was 'less difficult', this must be a peak 724 % if the previous direction was 'less difficult', this must be a peak
805 if strcmp(withinRuns.direction,'less difficult') ... 725 if strcmp(withinRuns.direction,'less difficult') ...
806 && length(withinRuns.levelList)>1 726 && length(withinRuns.levelList)>1
807 withinRuns.peaks=[withinRuns.peaks withinRuns.variableValue]; 727 withinRuns.peaks=[withinRuns.peaks withinRuns.variableValue];
808 end 728 end
809 withinRuns.direction='more difficult'; 729 withinRuns.direction='more difficult';
810
811 else 730 else
812 % said 'no' 731 % said 'no'
813 % default step size before first reversal 732 % default step size before first reversal
814 WRVinitialStep=stimulusParameters.WRVinitialStep; 733 WRVinitialStep=stimulusParameters.WRVinitialStep;
815 WRVsmallStep=stimulusParameters.WRVsmallStep; 734 WRVsmallStep=stimulusParameters.WRVsmallStep;
816 735
817 % if the previous direction was 'up', this must be a peak 736 % if the previous direction was 'up', this must be a peak
818 if strcmp(withinRuns.direction,'more difficult') ... 737 if strcmp(withinRuns.direction,'more difficult') ...
819 && length(withinRuns.levelList)>1 738 && length(withinRuns.levelList)>1
820 withinRuns.troughs=[withinRuns.troughs withinRuns.variableValue]; 739 withinRuns.troughs=[withinRuns.troughs withinRuns.variableValue];
821 end 740 end
822 withinRuns.direction='less difficult'; 741 withinRuns.direction='less difficult';
823 end 742 end
824 743
825 % phase 2 is all the levels after and incuding the first reversal 744 % phase 2 is all the levels after and incuding the first reversal
826 % plus the level before that 745 % plus the level before that
746 % Look for the end of phase 1
827 if ~withinRuns.nowInPhase2 && length(withinRuns.peaks)+ ... 747 if ~withinRuns.nowInPhase2 && length(withinRuns.peaks)+ ...
828 length(withinRuns.troughs)>0 748 length(withinRuns.troughs)>0
829 % if ~withinRuns.nowInPhase2 && (~isempty(withinRuns.peaks) ...
830 % || ~isempty(withinRuns.troughs))
831 % define phase 2 749 % define phase 2
832 withinRuns.beginningOfPhase2=trialNumber-1; 750 withinRuns.beginningOfPhase2=trialNumber-1;
833 withinRuns.nowInPhase2=1; 751 withinRuns.nowInPhase2=1;
834 WRVsmallStep=WRVinitialStep/2; 752 WRVsmallStep=WRVinitialStep/2;
835 end 753 end
842 withinRuns.responseList(withinRuns.beginningOfPhase2:end); 760 withinRuns.responseList(withinRuns.beginningOfPhase2:end);
843 else 761 else
844 withinRuns.levelsPhaseTwo=[]; 762 withinRuns.levelsPhaseTwo=[];
845 end 763 end
846 764
847
848 % get (or substitute) threshold estimate 765 % get (or substitute) threshold estimate
849 switch experiment.threshEstMethod 766 switch experiment.threshEstMethod
850 case {'2I2AFC++', '2I2AFC+++'} 767 case {'2I2AFC++', '2I2AFC+++'}
851 % for plotting psychometric function only 768 % for plotting psychometric function only
852 if withinRuns.beginningOfPhase2>0 769 if withinRuns.beginningOfPhase2>0
853 [psy, levelsBinVector, logistic, rareEvent]= ... 770 [psy, levelsBinVector, logistic, rareEvent]= ...
854 bestFitPsychometicFunctions... 771 bestFitPsychometicFunctions...
855 (withinRuns.levelsPhaseTwo, withinRuns.responsesPhaseTwo); 772 (withinRuns.levelsPhaseTwo, withinRuns.responsesPhaseTwo);
856 end 773 end
857 774
858 if ~isempty(withinRuns.peaks) && ~isempty(withinRuns.troughs) 775 if ~isempty(withinRuns.peaks) && ~isempty(withinRuns.troughs)
859 thresholdEstimate= ... 776 thresholdEstimate= ...
860 mean([mean(withinRuns.peaks) mean(withinRuns.troughs)]); 777 mean([mean(withinRuns.peaks) mean(withinRuns.troughs)]);
861 else 778 else
862 thresholdEstimate=NaN; 779 thresholdEstimate=NaN;
863 end 780 end
781
864 otherwise 782 otherwise
865 % single interval methods 783 % single interval methods
866 try 784 try
867 % using the s trial after the first reversal 785 % using the s trial after the first reversal
868 [psy, levelsBinVector, logistic, rareEvent]= ... 786 [psy, levelsBinVector, logistic, rareEvent]= ...
914 if saidYes 832 if saidYes
915 [WRVinitialStep, msg]=Levitt2('hit', withinRuns.variableValue); 833 [WRVinitialStep, msg]=Levitt2('hit', withinRuns.variableValue);
916 else 834 else
917 [WRVinitialStep, msg]=Levitt2('miss',withinRuns.variableValue); 835 [WRVinitialStep, msg]=Levitt2('miss',withinRuns.variableValue);
918 end 836 end
919 837
920 % empty message means continue as normal 838 % empty message means continue as normal
921 if ~isempty(msg) 839 if ~isempty(msg)
922 runCompleted(handles) 840 runCompleted(handles)
923 return 841 return
924 end 842 end
925 newWRVvalue=withinRuns.variableValue-WRVinitialStep; 843 newWRVvalue=withinRuns.variableValue-WRVinitialStep;
926 844
927 case {'MaxLikelihood', 'oneIntervalUpDown'} 845 case {'MaxLikelihood', 'oneIntervalUpDown'}
928 % run completed by virtue of number of trials 846 % run completed by virtue of number of trials
929 % or restart because listener is in trouble 847 % or restart because listener is in trouble
930 if length(withinRuns.levelsPhaseTwo)== experiment.maxTrials 848 if length(withinRuns.levelsPhaseTwo)== experiment.maxTrials
931 % Use bonomial test to decide if there is an imbalance in the 849 % Use bonomial test to decide if there is an imbalance in the
932 % number of 'yes'es and 'no's 850 % number of 'yes'es and 'no's
933 yesCount=sum(withinRuns.responseList); 851 yesCount=sum(withinRuns.responseList);
950 else 868 else
951 runCompleted(handles) 869 runCompleted(handles)
952 return 870 return
953 end 871 end
954 end 872 end
955 873
956 % set new value for WRV 874 % set new value for WRV
957 if withinRuns.nowInPhase2 875 if withinRuns.nowInPhase2
958 % phase 2 876 % phase 2
959 currentMeanEst=withinRuns.thresholdEstimateTrack(end); 877 currentMeanEst=withinRuns.thresholdEstimateTrack(end);
960 switch experiment.threshEstMethod 878 switch experiment.threshEstMethod
961 case 'MaxLikelihood' 879 case 'MaxLikelihood'
962 newWRVvalue=currentMeanEst; 880 newWRVvalue=currentMeanEst;
963 case {'oneIntervalUpDown'} 881 case {'oneIntervalUpDown'}
964 newWRVvalue=withinRuns.variableValue+WRVsmallStep; 882 newWRVvalue=withinRuns.variableValue+WRVsmallStep;
965 end 883 end
966 else 884 else
967 % phase 1 885 % phase 1
1011 % ignore click if not 'waitingForResponse' 929 % ignore click if not 'waitingForResponse'
1012 if ~strcmp(experiment.status,'waitingForResponse') 930 if ~strcmp(experiment.status,'waitingForResponse')
1013 disp('ignored click') 931 disp('ignored click')
1014 return 932 return
1015 end 933 end
1016 % Take no action other than to make a 934 % Take no action other than to make a
1017 % tally of repeat requests 935 % tally of repeat requests
1018 experiment.pleaseRepeat=experiment.pleaseRepeat+1; 936 experiment.pleaseRepeat=experiment.pleaseRepeat+1;
1019 withinRuns.thisIsRepeatTrial=1; 937 withinRuns.thisIsRepeatTrial=1;
1020 nextStimulus(handles); 938 nextStimulus(handles);
1021 939
1022 % ------------------------------------------------ userSelectsWrongButton 940 % ------------------------------------------------ userSelectsWrongButton
1023 function userSelectsWrongButton(handles) 941 function userSelectsWrongButton(handles)
1024 global withinRuns experiment 942 global withinRuns experiment
1025 % restart is the simplest solution for a 'wrong button' request 943 % restart is the simplest solution for a 'wrong button' request
1026 withinRuns.wrongButton=withinRuns.wrongButton+1; 944 withinRuns.wrongButton=withinRuns.wrongButton+1;
1027 set(handles.pushbuttonGO, 'visible','on', 'backgroundcolor','y') 945 set(handles.pushbuttonGO, 'visible','on', 'backgroundcolor','y')
1028 msg=[{'Start again: wrong button pressed'}, {' '},... 946 msg=[{'Start again: wrong button pressed'}, {' '},...
1029 {'Please,click on the GO button'}]; 947 {'Please,click on the GO button'}];
1030 set(handles.textMSG,'string',msg) 948 set(handles.textMSG,'string',msg)
1031 experiment.status='waitingForGO'; 949 experiment.status='waitingForGO';
1032 950
1033 % ------------------------------------------------- plotProgressThisTrial 951 % ------------------------------------------------- plotProgressThisTrial
1034 function plotProgressThisTrial(handles) 952 function plotProgressThisTrial(handles)
1035 953 % updates GUI: used for all responses
1036 % used for all responses 954
1037 global experiment stimulusParameters betweenRuns withinRuns expGUIhandles 955 global experiment stimulusParameters betweenRuns withinRuns expGUIhandles
1038 global psy levelsBinVector binFrequencies rareEvent logistic statsModel 956 global psy levelsBinVector binFrequencies rareEvent logistic statsModel
1039
1040 957
1041 % plot the levelTrack and the threshold track 958 % plot the levelTrack and the threshold track
1042 959
1043 % Panel 2 960 % Panel 2
1044 % plot the levelList 961 % plot the levelList
1068 xlim([0 experiment.maxTrials+withinRuns.beginningOfPhase2]); 985 xlim([0 experiment.maxTrials+withinRuns.beginningOfPhase2]);
1069 ylim(stimulusParameters.WRVlimits) 986 ylim(stimulusParameters.WRVlimits)
1070 grid on 987 grid on
1071 988
1072 % Panel 4: Summary of threshold estimates (not used here) 989 % Panel 4: Summary of threshold estimates (not used here)
1073 % Earlier estimates are set in 'runCompleted' 990 % Estimates from previous runs are set in 'runCompleted'
1074 % However, title shows runs/trials remaining 991 % It is only necessary to change title showing runs/trials remaining
1075
1076 axes(expGUIhandles.axes4) 992 axes(expGUIhandles.axes4)
1077 runsToGo=length(betweenRuns.var1Sequence)-betweenRuns.runNumber; 993 runsToGo=length(betweenRuns.var1Sequence)-betweenRuns.runNumber;
1078 if withinRuns.beginningOfPhase2>0 994 if withinRuns.beginningOfPhase2>0
1079 trialsToGo= experiment.singleIntervalMaxTrials(1) ... 995 trialsToGo= experiment.singleIntervalMaxTrials(1) ...
1080 + withinRuns.beginningOfPhase2- withinRuns.trialNumber; 996 + withinRuns.beginningOfPhase2- withinRuns.trialNumber;
1094 % display only when in phase 2. 1010 % display only when in phase 2.
1095 withinRuns.levelsPhaseTwo=... 1011 withinRuns.levelsPhaseTwo=...
1096 withinRuns.levelList(withinRuns.beginningOfPhase2:end); 1012 withinRuns.levelList(withinRuns.beginningOfPhase2:end);
1097 withinRuns.responsesPhaseTwo=... 1013 withinRuns.responsesPhaseTwo=...
1098 withinRuns.responseList(withinRuns.beginningOfPhase2:end); 1014 withinRuns.responseList(withinRuns.beginningOfPhase2:end);
1099 1015
1100 % organise data as psychometric function 1016 % organise data as psychometric function
1101 [psy, levelsBinVector, binFrequencies]= ... 1017 [psy, levelsBinVector, binFrequencies]= ...
1102 psychometricFunction(withinRuns.levelsPhaseTwo,... 1018 psychometricFunction(withinRuns.levelsPhaseTwo,...
1103 withinRuns.responsesPhaseTwo, experiment.psyBinWidth); 1019 withinRuns.responsesPhaseTwo, experiment.psyBinWidth);
1104 1020
1105 % Plot the function 1021 % Plot the function
1106 % point by point with circles of appropiate weighted size 1022 % point by point with circles of appropiate weighted size
1107 hold on, 1023 hold on,
1108 for i=1:length(psy) 1024 for i=1:length(psy)
1109 plot(levelsBinVector(i), psy(i), 'ro', ... 1025 plot(levelsBinVector(i), psy(i), 'ro', ...
1110 'markersize', 50*binFrequencies(i)/sum(binFrequencies)) 1026 'markersize', 50*binFrequencies(i)/sum(binFrequencies))
1111 end 1027 end
1112 % save info for later 1028 % save info for later
1113 betweenRuns.psychometicFunction{betweenRuns.runNumber}=... 1029 betweenRuns.psychometicFunction{betweenRuns.runNumber}=...
1114 [levelsBinVector; psy]; 1030 [levelsBinVector; psy];
1115 1031
1116 % fitPsychometric functions is computed in 'userDecides' 1032 % fitPsychometric functions is computed in 'userDecides'
1117 % plot(rareEvent.predictionLevels, rareEvent.predictionsRE,'k') 1033 % plot(rareEvent.predictionLevels, rareEvent.predictionsRE,'k')
1118 plot(logistic.predictionLevels, logistic.predictionsLOG, 'r') 1034 plot(logistic.predictionLevels, logistic.predictionsLOG, 'r')
1119 plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k') 1035 plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k')
1120 if ~isnan(logistic.bestThreshold ) 1036 if ~isnan(logistic.bestThreshold )
1121 % xlim([ (logistic.bestThreshold -20) ...
1122 % (logistic.bestThreshold +20) ])
1123 xlim([ 0 100 ]) 1037 xlim([ 0 100 ])
1124 % if logistic.bestK< max(experiment.possLogSlopes) 1038 title(['k= ' num2str(logistic.bestK, '%6.2f') ' g= '...
1125 title(['k= ' num2str(logistic.bestK, '%6.2f') ' g= '... 1039 num2str(rareEvent.bestGain,'%6.3f') ' A=' ...
1126 num2str(rareEvent.bestGain,'%6.3f') ' A=' ... 1040 num2str(rareEvent.bestVMin,'%8.1f')])
1127 num2str(rareEvent.bestVMin,'%8.1f')])
1128 % title('')
1129 % end
1130 else 1041 else
1131 title(' ') 1042 title(' ')
1132 end 1043 end
1133 1044
1134 switch experiment.ear 1045 switch experiment.ear
1135 %plot green line for statsModel a priori model 1046 %plot green line for statsModel a priori model
1136 case 'statsModelLogistic' 1047 case 'statsModelLogistic'
1137 % plot proTem logistic (green) used by stats model 1048 % plot proTem logistic (green) used by stats model
1138 p= 1./(1+exp(-statsModel.logisticSlope... 1049 p= 1./(1+exp(-statsModel.logisticSlope...
1148 p(p<0)=0; 1059 p(p<0)=0;
1149 if experiment.psyFunSlope<0, p=1-p;end 1060 if experiment.psyFunSlope<0, p=1-p;end
1150 hold on, plot(levelsBinVector, p,'g') 1061 hold on, plot(levelsBinVector, p,'g')
1151 end %(estMethod) 1062 end %(estMethod)
1152 end 1063 end
1064
1153 otherwise % 2A2IFC 1065 otherwise % 2A2IFC
1154
1155 message3= ... 1066 message3= ...
1156 ([ 'peaks=' num2str(withinRuns.peaks) ... 1067 ([ 'peaks=' num2str(withinRuns.peaks) ...
1157 'troughs=' num2str(withinRuns.troughs)]); 1068 'troughs=' num2str(withinRuns.troughs)]);
1158 ylimRM([-0.1 1.1]) % 0=no / 1=yes 1069 ylimRM([-0.1 1.1]) % 0=no / 1=yes
1159 set(gca,'ytick',[0 1], 'yTickLabel', {'no';'yes'}) 1070 set(gca,'ytick',[0 1], 'yTickLabel', {'no';'yes'})
1189 global experiment stimulusParameters betweenRuns withinRuns 1100 global experiment stimulusParameters betweenRuns withinRuns
1190 global rareEvent expGUIhandles 1101 global rareEvent expGUIhandles
1191 % disp('run completed') 1102 % disp('run completed')
1192 1103
1193 experiment.status='runCompleted'; 1104 experiment.status='runCompleted';
1194 1105 % quick update after final trial just to make sure
1195 plotProgressThisTrial(handles) 1106 plotProgressThisTrial(handles)
1196 1107
1197 switch experiment.ear 1108 switch experiment.ear
1198 case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ... 1109 case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ...
1199 'MAPmodelMultiCh','MAPmodelSingleCh', 'MAPmodelListen'} 1110 'MAPmodelMultiCh','MAPmodelSingleCh', 'MAPmodelListen'}
1224 withinRuns.responsesPhaseTwo=... 1135 withinRuns.responsesPhaseTwo=...
1225 withinRuns.responseList(withinRuns.beginningOfPhase2:end); 1136 withinRuns.responseList(withinRuns.beginningOfPhase2:end);
1226 [psy, levelsPhaseTwoBinVector, logistic, rareEvent]= ... 1137 [psy, levelsPhaseTwoBinVector, logistic, rareEvent]= ...
1227 bestFitPsychometicFunctions... 1138 bestFitPsychometicFunctions...
1228 (withinRuns.levelsPhaseTwo, withinRuns.responsesPhaseTwo); 1139 (withinRuns.levelsPhaseTwo, withinRuns.responsesPhaseTwo);
1229 1140
1230 % plot final psychometric function 1141 % plot final psychometric function
1231 axes(expGUIhandles.axes5),cla 1142 axes(expGUIhandles.axes5),cla
1232 hold on, plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k') 1143 hold on, plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k')
1233 hold on, plot(logistic.predictionLevels, logistic.predictionsLOG, 'r') 1144 hold on, plot(logistic.predictionLevels, logistic.predictionsLOG, 'r')
1234 % organise data as psychometric function 1145 % organise data as psychometric function
1240 for i=1:length(psy) 1151 for i=1:length(psy)
1241 plot(levelsBinVector(i), psy(i), 'ro', ... 1152 plot(levelsBinVector(i), psy(i), 'ro', ...
1242 'markersize', 50*binFrequencies(i)/sum(binFrequencies)) 1153 'markersize', 50*binFrequencies(i)/sum(binFrequencies))
1243 end 1154 end
1244 1155
1245
1246 % experimental 1156 % experimental
1247 medianThreshold=median(withinRuns.levelsPhaseTwo); 1157 medianThreshold=median(withinRuns.levelsPhaseTwo);
1248 warning off 1158 warning off
1249 meanThreshold=mean(withinRuns.levelsPhaseTwo); 1159 meanThreshold=mean(withinRuns.levelsPhaseTwo);
1250 1160
1251 % identify the current threshold estimate 1161 % identify the current threshold estimate
1252 switch experiment.paradigm 1162 switch experiment.paradigm
1253 case 'discomfort' 1163 case 'discomfort'
1254 % most recent value (not truely a mean value) 1164 % most recent value (not truely a mean value)
1255 threshold=withinRuns.levelList(end); 1165 threshold=withinRuns.levelList(end);
1256 stdev=NaN; 1166 stdev=NaN;
1257 otherwise 1167 otherwise
1258 switch experiment.threshEstMethod 1168 switch experiment.threshEstMethod
1259 case {'MaxLikelihood', 'oneIntervalUpDown'} 1169 case {'MaxLikelihood', 'oneIntervalUpDown'}
1260 % last value in the list 1170 % last value in the list
1261 % threshold=withinRuns.meanEstTrack(end); 1171 % threshold=withinRuns.meanEstTrack(end);
1262 threshold=withinRuns.thresholdEstimateTrack(end); 1172 threshold=withinRuns.thresholdEstimateTrack(end);
1263 stdev=NaN; 1173 stdev=NaN;
1264 1174
1265 case {'2I2AFC++', '2I2AFC+++'} 1175 case {'2I2AFC++', '2I2AFC+++'}
1266 % use peaks and troughs 1176 % use peaks and troughs
1267 try % there may not be enough values to use 1177 try % there may not be enough values to use
1268 peaksUsed=experiment.peaksUsed; 1178 peaksUsed=experiment.peaksUsed;
1269 threshold=... 1179 threshold=...
1298 [betweenRuns.catchTrials withinRuns.catchTrialCount]; 1208 [betweenRuns.catchTrials withinRuns.catchTrialCount];
1299 1209
1300 % add variable length tracks to cell arrays 1210 % add variable length tracks to cell arrays
1301 if withinRuns.beginningOfPhase2>0 1211 if withinRuns.beginningOfPhase2>0
1302 betweenRuns.bestThresholdTracks{length(betweenRuns.thresholds)}=... 1212 betweenRuns.bestThresholdTracks{length(betweenRuns.thresholds)}=...
1303 withinRuns.thresholdEstimateTrack; 1213 withinRuns.thresholdEstimateTrack;
1304 betweenRuns.levelTracks{length(betweenRuns.thresholds)}=... 1214 betweenRuns.levelTracks{length(betweenRuns.thresholds)}=...
1305 withinRuns.levelList(withinRuns.beginningOfPhase2:end); 1215 withinRuns.levelList(withinRuns.beginningOfPhase2:end);
1306 betweenRuns.responseTracks{length(betweenRuns.thresholds)}=... 1216 betweenRuns.responseTracks{length(betweenRuns.thresholds)}=...
1307 withinRuns.responseList(withinRuns.beginningOfPhase2:end); 1217 withinRuns.responseList(withinRuns.beginningOfPhase2:end);
1308 else 1218 else
1336 for i=1:length(betweenRuns.thresholds) 1246 for i=1:length(betweenRuns.thresholds)
1337 faceColor=plotColors(floor(i/length(betweenRuns.variableList1)-.01)+1); 1247 faceColor=plotColors(floor(i/length(betweenRuns.variableList1)-.01)+1);
1338 switch betweenRuns.variableName1 1248 switch betweenRuns.variableName1
1339 case {'targetFrequency', 'maskerRelativeFrequency'} 1249 case {'targetFrequency', 'maskerRelativeFrequency'}
1340 if min(betweenRuns.var1Sequence)>0 1250 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), ... 1251 semilogx(betweenRuns.var1Sequence(i), ...
1345 betweenRuns.thresholds(i), 'o', ... 1252 betweenRuns.thresholds(i), 'o', ...
1346 'markerSize', 5,'markerFaceColor',faceColor) 1253 'markerSize', 5,'markerFaceColor',faceColor)
1347 else 1254 else
1348 plot(betweenRuns.var1Sequence(1:betweenRuns.runNumber), ... 1255 plot(betweenRuns.var1Sequence(1:betweenRuns.runNumber), ...
1351 plot(betweenRuns.var1Sequence(i), ... 1258 plot(betweenRuns.var1Sequence(i), ...
1352 betweenRuns.thresholds(i), 'o', ... 1259 betweenRuns.thresholds(i), 'o', ...
1353 'markerSize', 5,'markerFaceColor',faceColor) 1260 'markerSize', 5,'markerFaceColor',faceColor)
1354 end 1261 end
1355 otherwise 1262 otherwise
1356 % plot(betweenRuns.var1Sequence(1:betweenRuns.runNumber), ...
1357 % betweenRuns.thresholds, 'o', 'markerSize', 5,...
1358 % 'markerFaceColor',faceColor)
1359 plot(betweenRuns.var1Sequence(i), ... 1263 plot(betweenRuns.var1Sequence(i), ...
1360 betweenRuns.thresholds(i), 'o', 'markerSize', 5,... 1264 betweenRuns.thresholds(i), 'o', 'markerSize', 5,...
1361 'markerFaceColor',faceColor) 1265 'markerFaceColor',faceColor)
1362 end 1266 end
1363 hold on 1267 hold on
1372 set(gca,'XTick', sort(betweenRuns.variableList1)) 1276 set(gca,'XTick', sort(betweenRuns.variableList1))
1373 catch 1277 catch
1374 end 1278 end
1375 grid on, set(gca,'XMinorGrid', 'off') 1279 grid on, set(gca,'XMinorGrid', 'off')
1376 1280
1377 % If comparison data is available in pearmeter file, plot it now 1281 % final run?
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) 1282 if betweenRuns.runNumber==length(betweenRuns.var1Sequence)
1390 % yes, end of experiment 1283 % yes, end of experiment
1391 fileName=['savedData/' experiment.name experiment.date ... 1284 fileName=['savedData/' experiment.name experiment.date ...
1392 experiment.paradigm]; 1285 experiment.paradigm];
1393 % save (fileName, 'experiment', 'stimulusParameters', 'betweenRuns', 'withinRuns', 'variableNames', 'paradigmNames', 'LevittControl') 1286 % save (fileName, 'experiment', 'stimulusParameters', 'betweenRuns', 'withinRuns', 'variableNames', 'paradigmNames', 'LevittControl')
1394 disp('Experiment completed') 1287 disp('Experiment completed')
1395 1288
1396 % update subject GUI to acknowledge end of run 1289 % update subject GUI to acknowledge end of run
1397 subjGUImsg=[{'Experiment completed'}, {' '}, {'Thank you!'}]; 1290 subjGUImsg=[{'Experiment completed'}, {' '}, {'Thank you!'}];
1398 set(handles.textMSG,'string', subjGUImsg ) 1291 set(handles.textMSG,'string', subjGUImsg )
1399 % play 'Tada' 1292 % play 'Tada'
1400 [y,fs,nbits]=wavread('TADA.wav'); 1293 [y,fs,nbits]=wavread('TADA.wav');
1401 musicGain=10^(stimulusParameters.musicLeveldB/20); 1294 musicGain=10^(stimulusParameters.musicLeveldB/20);
1402 y=y*musicGain; 1295 y=y*musicGain;
1403 wavplay(y/100,fs, 'async') 1296 wavplay(y/100,fs, 'async')
1404 1297
1405 % update experimenter GUI 1298 % update experimenter GUI
1406 addToMsg('Experiment completed.',1) 1299 addToMsg('Experiment completed.',1)
1407 1300
1408 printReport 1301 printReport
1409 experiment.status='endOfExperiment'; 1302 experiment.status='endOfExperiment';
1410 return 1303 return
1411 else 1304 else
1412 % No, hang on. 1305 % No, hang on.
1413 switch experiment.ear 1306 switch experiment.ear
1414 case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ... 1307 case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ...
1421 (stimulusParameters.catchTrialRate... 1314 (stimulusParameters.catchTrialRate...
1422 -stimulusParameters.catchTrialBaseRate)... 1315 -stimulusParameters.catchTrialBaseRate)...
1423 *(1-exp(-stimulusParameters.catchTrialTimeConstant)); 1316 *(1-exp(-stimulusParameters.catchTrialTimeConstant));
1424 fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ... 1317 fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
1425 stimulusParameters.catchTrialRate) 1318 stimulusParameters.catchTrialRate)
1426 1319
1427 % and go again 1320 % and go again
1428 set(handles.pushbuttonGO,'backgroundcolor','y') 1321 set(handles.pushbuttonGO,'backgroundcolor','y')
1429 set(handles.frame1,'visible','off') 1322 set(handles.frame1,'visible','off')
1430 set(handles.pushbuttonGO,'visible','on') 1323 set(handles.pushbuttonGO,'visible','on')
1431 msg=[{'Ready to start new trial'}, {' '},... 1324 msg=[{'Ready to start new trial'}, {' '},...
1432 {'Please,click on the GO button'}]; 1325 {'Please,click on the GO button'}];
1433 set(handles.textMSG,'string',msg) 1326 set(handles.textMSG,'string',msg)
1434 end 1327 end
1435 experiment.status='waitingForGO'; 1328 experiment.status='waitingForGO';
1436 % fprintf('\n') 1329 % fprintf('\n')
1437 1330
1438 [y,fs,nbits]=wavread('CHIMES.wav'); 1331 [y,fs,nbits]=wavread('CHIMES.wav');
1439 musicGain=10^(stimulusParameters.musicLeveldB/20); 1332 musicGain=10^(stimulusParameters.musicLeveldB/20);
1440 y=y*musicGain; 1333 y=y*musicGain;
1441 wavplay(y/100,fs,'async') 1334 wavplay(y/100,fs,'async')
1442 end 1335 end
1446 function MAPmodelRunsGUI(handles) 1339 function MAPmodelRunsGUI(handles)
1447 global experiment stimulusParameters method expGUIhandles 1340 global experiment stimulusParameters method expGUIhandles
1448 global AN_IHCsynapseParams 1341 global AN_IHCsynapseParams
1449 method=[]; 1342 method=[];
1450 1343
1451 while strcmp(experiment.status,'waitingForGO') 1344 while strcmp(experiment.status,'waitingForGO')
1452 % no catch trials for MAP model 1345 % no catch trials for MAP model
1453 experiment.allowCatchTrials=0; 1346 experiment.allowCatchTrials=0;
1454 1347
1455 % initiates run and plays first stimulus and it returns 1348 % initiates run and plays first stimulus and it returns
1456 % without waiting for button press 1349 % without waiting for button press
1457 startNewRun(handles) 1350 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 1351
1473 % show sample Rate on GUI; it must be set in MAPparams 1352 % show sample Rate on GUI; it must be set in MAPparams
1474 set(expGUIhandles.textsampleRate,'string',... 1353 set(expGUIhandles.textsampleRate,'string',...
1475 num2str(stimulusParameters.sampleRate)) 1354 num2str(stimulusParameters.sampleRate))
1476 1355
1477 if experiment.singleShot 1356 if experiment.singleShot
1478 % AN_IHCsynapseParams.showSummaryStatistics=1;
1479 method.showSummaryStatistics=1;
1480 AN_IHCsynapseParams.plotSynapseContents=1; 1357 AN_IHCsynapseParams.plotSynapseContents=1;
1481 else 1358 else
1482 method.showSummaryStatistics=0;
1483 AN_IHCsynapseParams.plotSynapseContents=0; 1359 AN_IHCsynapseParams.plotSynapseContents=0;
1484 end 1360 end
1485 1361
1486 if strcmp(experiment.ear, 'MAPmodelSingleCh')
1487 method.MGmembranePotentialSave=1;
1488 end
1489
1490 % continuous loop until the program stops itself 1362 % continuous loop until the program stops itself
1491 while strcmp(experiment.status,'waitingForResponse') 1363 while strcmp(experiment.status,'waitingForResponse')
1492 % NB at this point the stimulus has been played 1364 % NB at this point the stimulus has been played
1493 pause(0.1) % to allow interrupt with CTRL/C 1365 pause(0.1) % to allow interrupt with CTRL/C
1494 1366
1495 switch experiment.ear 1367 switch experiment.ear
1496 case { 'MAPmodelListen'} 1368 case { 'MAPmodelListen'}
1497 set(handles.pushbutton1,'backgroundcolor','y','visible','on') 1369 % flash the buttons to show model response
1498 set(handles.pushbutton2,'backgroundcolor','y','visible','on') 1370 set(handles.pushbutton1,'backgroundcolor','y','visible','on')
1499 end 1371 set(handles.pushbutton2,'backgroundcolor','y','visible','on')
1500 1372 end
1501 AN_IHCsynapseParams.mode= 'spikes'; 1373
1502 1374 % Analayse the current stimulus using MAP
1503 % Analayse the current stimulus using MAP 1375 [modelResponse earObject]= MAPmodel;
1504 [modelResponse earObject]= MAPmodel( experiment.MAPplot, method); 1376
1505
1506 if experiment.stop || experiment.singleShot 1377 if experiment.stop || experiment.singleShot
1507 % trap for single trial or user interrupt using 'stop' button. 1378 % trap for single trial or user interrupt using 'stop' button.
1508 experiment.status= 'waitingForStart'; 1379 experiment.status= 'waitingForStart';
1509 experiment.stop=0; 1380 experiment.stop=0;
1510 addToMsg('manually stopped',1); 1381 errormsg='manually stopped';
1382 addToMsg(errormsg,1)
1511 return 1383 return
1512 end 1384 end
1513 1385
1514 switch modelResponse 1386 switch modelResponse
1515 case 1 1387 case 1
1516 % userDoesNotHearTarget(handles) 1388 % userDoesNotHearTarget(handles)
1517 switch experiment.ear 1389 switch experiment.ear
1518 case {'MAPmodelListen'} 1390 case {'MAPmodelListen'}
1531 % illuminate appropriate button (DEMO only) 1403 % illuminate appropriate button (DEMO only)
1532 set(handles.pushbutton2,'backgroundcolor',... 1404 set(handles.pushbutton2,'backgroundcolor',...
1533 'r','visible','on') 1405 'r','visible','on')
1534 set(handles.pushbutton1,'backgroundcolor','y') 1406 set(handles.pushbutton1,'backgroundcolor','y')
1535 end 1407 end
1536 1408
1537 switch experiment.paradigm 1409 switch experiment.paradigm
1538 case 'discomfort' 1410 case 'discomfort'
1539 % always treat discomfort as 'not heard' 1411 % always treat discomfort as 'not heard'
1540 userDecides(handles, false) 1412 userDecides(handles, false)
1541 otherwise 1413 otherwise
1546 return 1418 return
1547 end 1419 end
1548 end 1420 end
1549 end 1421 end
1550 1422
1551 function [modelResponse, MacGregorResponse]=MAPmodel( MAPplot, method) 1423 % -------------------------------------------------------MAPmodel
1424 function [modelResponse, MacGregorResponse]=MAPmodel
1552 1425
1553 global experiment stimulusParameters audio withinRuns 1426 global experiment stimulusParameters audio withinRuns
1554 global outerMiddleEarParams DRNLParams AN_IHCsynapseParams 1427 global outerMiddleEarParams DRNLParams AN_IHCsynapseParams
1555 1428
1556 savePath=path; 1429 savePath=path;
1560 1433
1561 % mono only (column vector) 1434 % mono only (column vector)
1562 audio=audio(:,1)'; 1435 audio=audio(:,1)';
1563 1436
1564 % if stop button pressed earlier 1437 % if stop button pressed earlier
1565 if experiment.stop, return, end 1438 if experiment.stop
1566 1439 errormsg='manually stopped';
1567 % -------------------------------------------------------------- run Model 1440 addToMsg(errormsg,1)
1441 return
1442 end
1443
1444 % ---------------------------------------------- run Model
1568 MAPparamsName=experiment.name; 1445 MAPparamsName=experiment.name;
1569 showPlotsAndDetails=experiment.MAPplot; 1446 showPlotsAndDetails=experiment.MAPplot;
1570 AN_spikesOrProbability='spikes'; 1447 AN_spikesOrProbability='spikes';
1448 AN_spikesOrProbability='probability';
1571 1449
1572 % [response, method]=MAPsequenceSeg(audio, method, 1:8); 1450 % [response, method]=MAPsequenceSeg(audio, method, 1:8);
1573 global ICoutput ANdt 1451 global ICoutput ANdt dt savedBFlist ANprobRateOutput expGUIhandles
1574 MAP1_14(audio, 1/method.dt, method.nonlinCF,... 1452 global stimulusParameters experiment
1575 MAPparamsName, AN_spikesOrProbability); 1453
1576 1454 if sum(strcmp(experiment.ear,{'MAPmodelMultiCh', 'MAPmodelListen'}))
1455 % use BFlist specified in MAPparams file
1456 BFlist= -1;
1457 else
1458 BFlist=stimulusParameters.targetFrequency;
1459 end
1460 paramChanges=get(expGUIhandles.editparamChanges,'string');
1461 eval(paramChanges)
1462
1463 MAP1_14(audio, stimulusParameters.sampleRate, BFlist,...
1464 MAPparamsName, AN_spikesOrProbability, paramChanges);
1465
1577 if showPlotsAndDetails 1466 if showPlotsAndDetails
1578 options.printModelParameters=0; 1467 options.printModelParameters=0;
1579 options.showModelOutput=1; 1468 options.showModelOutput=1;
1580 options.printFiringRates=1; 1469 options.printFiringRates=1;
1581 options.showACF=0; 1470 options.showACF=0;
1584 showMapOptions.surfSpikes=0; 1473 showMapOptions.surfSpikes=0;
1585 UTIL_showMAP(options) 1474 UTIL_showMAP(options)
1586 end 1475 end
1587 1476
1588 % No response, probably caused by hitting 'stop' button 1477 % No response, probably caused by hitting 'stop' button
1589 if isempty(ICoutput), return, end 1478 if strcmp(AN_spikesOrProbability,'spikes') && isempty(ICoutput)
1590 1479 return
1591 % MacGregor response is the sum total of all final stage spiking 1480 end
1592 MacGregorResponse= sum(ICoutput,1); % use IC
1593
1594 % ---------------------------------------------------------- end model run 1481 % ---------------------------------------------------------- end model run
1595 1482
1596 dt=ANdt; 1483 if strcmp(AN_spikesOrProbability,'spikes')
1597 time=dt:dt:dt*length(MacGregorResponse); 1484 MacGregorResponse= sum(ICoutput,1); % use IC
1598 1485 dt=ANdt;
1599 % group delay on unit response 1486 time=dt:dt:dt*length(MacGregorResponse);
1600 MacGonsetDelay= 0.004; 1487 else
1601 MacGoffsetDelay= 0.022; 1488 % for one channel, ANprobResponse=ANprobRateOutput
1489 % for multi channel take strongest in any epoch
1490 nChannels=length(savedBFlist);
1491 % use only HSR fibers
1492 ANprobRateOutput=ANprobRateOutput(end-nChannels+1:end,:);
1493 time=dt:dt:dt*length(ANprobRateOutput);
1494 end
1495
1496 % group delay on unit response - these values are iffy
1497 windowOnsetDelay= 0.004;
1498 windowOffsetDelay= 0.022; % long ringing time
1602 1499
1603 % now find the response of the MacGregor model during the target presentation + group delay 1500 % now find the response of the MacGregor model during the target presentation + group delay
1604 switch experiment.threshEstMethod 1501 switch experiment.threshEstMethod
1605 case {'2I2AFC++', '2I2AFC+++'} 1502 case {'2I2AFC++', '2I2AFC+++'}
1606 idx= time>stimulusParameters.testTargetBegins+MacGonsetDelay ... 1503 idx= time>stimulusParameters.testTargetBegins+windowOnsetDelay ...
1607 & time<stimulusParameters.testTargetEnds+MacGoffsetDelay; 1504 & time<stimulusParameters.testTargetEnds+windowOffsetDelay;
1608 nSpikesTrueWindow=sum(MacGregorResponse(:,idx)); 1505 nSpikesTrueWindow=sum(MacGregorResponse(:,idx));
1609 idx=find(time>stimulusParameters.testNonTargetBegins+MacGonsetDelay ... 1506 idx=find(time>stimulusParameters.testNonTargetBegins+windowOnsetDelay ...
1610 & time<stimulusParameters.testNonTargetEnds+MacGoffsetDelay); 1507 & time<stimulusParameters.testNonTargetEnds+windowOffsetDelay);
1611 nSpikesFalseWindow=sum(MacGregorResponse(:,idx)); 1508 if strcmp(AN_spikesOrProbability,'spikes')
1509 nSpikesFalseWindow=sum(MacGregorResponse(:,idx));
1510 else
1511 nSpikesDuringTarget=mean(ANprobRateOutput(end,idx));
1512 % compare with spontaneous rate
1513 if nSpikesDuringTarget>ANprobRateOutput(end,1)+10
1514 nSpikesDuringTarget=1; % i.e. at leastone MacG spike
1515 else
1516 nSpikesDuringTarget=0;
1517 end
1518 end
1612 % nSpikesDuringTarget is +ve when more spikes are found 1519 % nSpikesDuringTarget is +ve when more spikes are found
1613 % in the target window 1520 % in the target window
1614 difference= nSpikesTrueWindow-nSpikesFalseWindow; 1521 difference= nSpikesTrueWindow-nSpikesFalseWindow;
1615 1522
1616 if difference>0 1523 if difference>0
1629 end 1536 end
1630 end 1537 end
1631 disp(['level target dummy decision: ' ... 1538 disp(['level target dummy decision: ' ...
1632 num2str([withinRuns.variableValue nSpikesTrueWindow ... 1539 num2str([withinRuns.variableValue nSpikesTrueWindow ...
1633 nSpikesFalseWindow nSpikesDuringTarget], '%4.0f') ] ) 1540 nSpikesFalseWindow nSpikesDuringTarget], '%4.0f') ] )
1634
1635 otherwise 1541 otherwise
1636 % idx=find(time>stimulusParameters.testTargetBegins+MacGonsetDelay ... 1542 % single interval
1637 % & time<stimulusParameters.testTargetEnds+MacGoffsetDelay); 1543 idx=find(time>stimulusParameters.testTargetBegins +windowOnsetDelay...
1638 % no delay at onset 1544 & time<stimulusParameters.testTargetEnds+windowOffsetDelay);
1639 idx=find(time>stimulusParameters.testTargetBegins +MacGonsetDelay... 1545 if strcmp(AN_spikesOrProbability,'spikes')
1640 & time<stimulusParameters.testTargetEnds+MacGoffsetDelay); 1546 nSpikesDuringTarget=sum(MacGregorResponse(:,idx));
1641 nSpikesDuringTarget=sum(MacGregorResponse(:,idx)); 1547 timeX=time(idx);
1642 1548 else
1643 % find(MacGregorResponse)*dt-stimulusParameters.stimulusDelay 1549 % probability, use channel with the highest average rate
1644 timeX=time(idx); 1550 nSpikesDuringTarget=max(mean(ANprobRateOutput(:,idx),2));
1645 end 1551 if nSpikesDuringTarget>ANprobRateOutput(end,1)+10
1646 1552 nSpikesDuringTarget=1;
1647 % now find the response of the MacGregor model at the end of the masker 1553 else
1648 idx2=find(time>stimulusParameters.testTargetBegins-0.02 ... 1554 nSpikesDuringTarget=0;
1649 & time<stimulusParameters.testTargetBegins); 1555 end
1650 if ~isempty(idx2) 1556
1651 maskerRate=mean(mean(MacGregorResponse(idx2))); 1557 end
1652 else
1653 %e.g. no masker
1654 maskerRate=0;
1655 end 1558 end
1656 1559
1657 if experiment.MAPplot 1560 if experiment.MAPplot
1658 % add vertical lines to indicate target region 1561 % add vertical lines to indicate target region
1659 figure(99), subplot(6,1,6) 1562 figure(99), subplot(6,1,6)
1660 hold on 1563 hold on
1661 yL=get(gca,'YLim'); 1564 yL=get(gca,'YLim');
1662 plot([stimulusParameters.testTargetBegins + MacGonsetDelay ... 1565 plot([stimulusParameters.testTargetBegins + windowOnsetDelay ...
1663 stimulusParameters.testTargetBegins + MacGonsetDelay],yL,'r') 1566 stimulusParameters.testTargetBegins + windowOnsetDelay],yL,'r')
1664 plot([stimulusParameters.testTargetEnds + MacGoffsetDelay ... 1567 plot([stimulusParameters.testTargetEnds + windowOffsetDelay ...
1665 stimulusParameters.testTargetEnds + MacGoffsetDelay],yL,'r') 1568 stimulusParameters.testTargetEnds + windowOffsetDelay],yL,'r')
1666 end 1569 end
1667 1570
1668 % specify unambiguous response 1571 % specify unambiguous response
1669 switch experiment.paradigm 1572 if nSpikesDuringTarget>experiment.MacGThreshold
1670 case 'gapDetection' 1573 modelResponse=2; % stimulus detected
1671 gapResponse=(maskerRate-nSpikesDuringTarget)/maskerRate; 1574 else
1672 if gapResponse>0.2 1575 modelResponse=1; % nothing heard (default)
1673 modelResponse=2; % gap detected 1576 end
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 1577
1688 path(savePath) 1578 path(savePath)
1689 1579
1690 % -----------------------------------------------------statsModelRunsGUI 1580 % -----------------------------------------------------statsModelRunsGUI
1691 % The computer presses the buttons 1581 % The computer presses the buttons
1702 % user has requested an abort 1592 % user has requested an abort
1703 experiment.status= 'waitingForStart'; 1593 experiment.status= 'waitingForStart';
1704 addToMsg('manually stopped',1) 1594 addToMsg('manually stopped',1)
1705 return 1595 return
1706 end 1596 end
1707 1597
1708 % initiates run and plays first stimulus and it returns 1598 % initiates run and plays first stimulus and it returns
1709 % without waiting for button press 1599 % without waiting for button press
1710 % NB stimulus is not actually generated (for speed) 1600 % NB stimulus is not actually generated (for speed)
1711 startNewRun(handles) 1601 startNewRun(handles)
1712 1602
1713 while strcmp(experiment.status,'waitingForResponse') 1603 while strcmp(experiment.status,'waitingForResponse')
1714 % create artificial response here 1604 % create artificial response here
1715 modelResponse=statsModelGetResponse; 1605 modelResponse=statsModelGetResponse;
1716 switch modelResponse 1606 switch modelResponse
1717 case 1 1607 case 1
1736 case {'statsModelLogistic'} 1626 case {'statsModelLogistic'}
1737 prob= 1./(1+exp(-statsModel.logisticSlope.*(withinRuns.variableValue-statsModel.logisticMean))); 1627 prob= 1./(1+exp(-statsModel.logisticSlope.*(withinRuns.variableValue-statsModel.logisticMean)));
1738 % if experiment.psyFunSlope<0, 1628 % if experiment.psyFunSlope<0,
1739 % prob=1-prob; 1629 % prob=1-prob;
1740 % end 1630 % end
1741 1631
1742 case 'statsModelRareEvent' 1632 case 'statsModelRareEvent'
1743 if experiment.psyFunSlope<0 1633 if experiment.psyFunSlope<0
1744 addToMsg('statsModelRareEvent cannot be used with negative slope',0) 1634 addToMsg('statsModelRareEvent cannot be used with negative slope',0)
1745 error('statsModelRareEvent cannot be used with negative slope') 1635 error('statsModelRareEvent cannot be used with negative slope')
1746 end 1636 end
1747 1637
1748 % standard formula is prob = 1 – exp(-d (g P – A)) 1638 % standard formula is prob = 1 – exp(-d (g P – A))
1749 % here A->A; To find Pmin use A/gain 1639 % here A->A; To find Pmin use A/gain
1750 pressure=28*10^(withinRuns.variableValue/20); 1640 pressure=28*10^(withinRuns.variableValue/20);
1751 gain=statsModel.rareEvenGain; 1641 gain=statsModel.rareEvenGain;
1752 A=statsModel.rareEventVmin; 1642 A=statsModel.rareEventVmin;
1765 if rand<prob 1655 if rand<prob
1766 modelResponse=2; %bingo 1656 modelResponse=2; %bingo
1767 else 1657 else
1768 modelResponse=1; %nothing heard 1658 modelResponse=1; %nothing heard
1769 end 1659 end
1770 1660
1771 case {'2I2AFC++', '2I2AFC+++'} 1661 case {'2I2AFC++', '2I2AFC+++'}
1772 if rand<prob 1662 if rand<prob
1773 modelResponse=2; %bingo 1663 modelResponse=2; %bingo
1774 else %if the stimulus is not audible, take a 50:50 chance of getting it right 1664 else %if the stimulus is not audible, take a 50:50 chance of getting it right
1775 if rand<0.5 1665 if rand<0.5
1857 set(serobj, 'ReadAsyncMode', 'continuous') 1747 set(serobj, 'ReadAsyncMode', 'continuous')
1858 set(serobj, 'BytesAvailableFcn', @buttonBox_callback) 1748 set(serobj, 'BytesAvailableFcn', @buttonBox_callback)
1859 set(serobj, 'BytesAvailableFcnCount', 1) 1749 set(serobj, 'BytesAvailableFcnCount', 1)
1860 set(serobj, 'BytesAvailableFcnMode', 'byte') 1750 set(serobj, 'BytesAvailableFcnMode', 'byte')
1861 % set(serobj, 'BreakInterruptFcn', '@buttonBox_Calback') 1751 % set(serobj, 'BreakInterruptFcn', '@buttonBox_Calback')
1862 1752
1863 fopen(serobj); 1753 fopen(serobj);
1864 buttonBoxStatus=get(serobj,'status'); 1754 buttonBoxStatus=get(serobj,'status');
1865 catch 1755 catch
1866 disp('** no button box found - use mouse **') 1756 disp('** no button box found - use mouse **')
1867 end 1757 end