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