annotate Copy_of_multithreshold 1.46/subjGUI_MT.m @ 30:1a502830d462

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