annotate multithreshold 1.46/subjGUI_MT.m @ 38:c2204b18f4a2 tip

End nov big change
author Ray Meddis <rmeddis@essex.ac.uk>
date Mon, 28 Nov 2011 13:34:28 +0000
parents 25d53244d5c8
children
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@35 672 if ispc
rmeddis@35 673 wavplay(y/100,fs)
rmeddis@35 674 else
rmeddis@35 675 sound(y/100,fs)
rmeddis@35 676 end
rmeddis@35 677
rmeddis@28 678
rmeddis@28 679 % raise catch trial rate temporarily.
rmeddis@0 680 % this is normally reduced on each new trial (see GO)
rmeddis@0 681 stimulusParameters.catchTrialRate=...
rmeddis@0 682 stimulusParameters.catchTrialRate+0.1;
rmeddis@28 683 if stimulusParameters.catchTrialRate>0.5
rmeddis@28 684 stimulusParameters.catchTrialRate=0.5;
rmeddis@0 685 end
rmeddis@0 686 fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
rmeddis@0 687 stimulusParameters.catchTrialRate)
rmeddis@28 688
rmeddis@0 689 betweenRuns.caughtOut(betweenRuns.runNumber)=...
rmeddis@0 690 1+betweenRuns.caughtOut(betweenRuns.runNumber);
rmeddis@0 691 betweenRuns.runNumber=betweenRuns.runNumber-1;
rmeddis@0 692 experiment.status='waitingForGO';
rmeddis@0 693 return % unwind and wait for button press
rmeddis@0 694 else % (said No)
rmeddis@28 695 % user claims not to have heard target.
rmeddis@28 696 % This is good as it was not present.
rmeddis@28 697 % So, repeat the stimulus (possibly with target)
rmeddis@0 698 % and behave as if the last trial did not occur
rmeddis@0 699 errormsg=nextStimulus(handles);
rmeddis@28 700
rmeddis@0 701 % terminate if there is any kind of problem
rmeddis@0 702 if ~isempty(errormsg)
rmeddis@0 703 % e.g. limits exceeded, clipping
rmeddis@0 704 disp(['Error nextStimulus: ' errormsg])
rmeddis@0 705 runCompleted(handles)
rmeddis@0 706 return
rmeddis@0 707 end
rmeddis@0 708 return % no further action - next trial
rmeddis@0 709 end
rmeddis@28 710 end % of catch trial
rmeddis@0 711
rmeddis@28 712 % Real target: analyse the response, make tracks and define next stim.
rmeddis@0 713
rmeddis@0 714 % Define response and update response list
rmeddis@0 715 if saidYes
rmeddis@0 716 % target was heard, so response=1;
rmeddis@0 717 withinRuns.responseList=[withinRuns.responseList 1]; % 'heard it!'
rmeddis@0 718 else
rmeddis@0 719 % target was not hear heard, so response=0;
rmeddis@0 720 withinRuns.responseList=[withinRuns.responseList 0];
rmeddis@0 721 end
rmeddis@0 722 withinRuns.levelList=[withinRuns.levelList withinRuns.variableValue];
rmeddis@0 723 trialNumber=length(withinRuns.responseList);
rmeddis@0 724
rmeddis@0 725 % keep track of peaks and troughs;
rmeddis@0 726 % identify direction of change during initial period
rmeddis@0 727 if saidYes
rmeddis@0 728 % default step size before first reversal
rmeddis@28 729 WRVinitialStep=-stimulusParameters.WRVinitialStep;
rmeddis@0 730 WRVsmallStep=-stimulusParameters.WRVsmallStep;
rmeddis@0 731 % if the previous direction was 'less difficult', this must be a peak
rmeddis@0 732 if strcmp(withinRuns.direction,'less difficult') ...
rmeddis@0 733 && length(withinRuns.levelList)>1
rmeddis@0 734 withinRuns.peaks=[withinRuns.peaks withinRuns.variableValue];
rmeddis@0 735 end
rmeddis@0 736 withinRuns.direction='more difficult';
rmeddis@0 737 else
rmeddis@0 738 % said 'no'
rmeddis@0 739 % default step size before first reversal
rmeddis@28 740 WRVinitialStep=stimulusParameters.WRVinitialStep;
rmeddis@0 741 WRVsmallStep=stimulusParameters.WRVsmallStep;
rmeddis@28 742
rmeddis@0 743 % if the previous direction was 'up', this must be a peak
rmeddis@0 744 if strcmp(withinRuns.direction,'more difficult') ...
rmeddis@0 745 && length(withinRuns.levelList)>1
rmeddis@0 746 withinRuns.troughs=[withinRuns.troughs withinRuns.variableValue];
rmeddis@0 747 end
rmeddis@0 748 withinRuns.direction='less difficult';
rmeddis@0 749 end
rmeddis@0 750
rmeddis@28 751 % phase 2 is all the levels after and incuding the first reversal
rmeddis@0 752 % plus the level before that
rmeddis@28 753 % Look for the end of phase 1
rmeddis@0 754 if ~withinRuns.nowInPhase2 && length(withinRuns.peaks)+ ...
rmeddis@0 755 length(withinRuns.troughs)>0
rmeddis@0 756 % define phase 2
rmeddis@0 757 withinRuns.beginningOfPhase2=trialNumber-1;
rmeddis@0 758 withinRuns.nowInPhase2=1;
rmeddis@0 759 WRVsmallStep=WRVinitialStep/2;
rmeddis@0 760 end
rmeddis@0 761
rmeddis@0 762 if withinRuns.nowInPhase2
rmeddis@0 763 % keep a record of all levels and responses in phase 2 only
rmeddis@0 764 withinRuns.levelsPhaseTwo=...
rmeddis@0 765 withinRuns.levelList(withinRuns.beginningOfPhase2:end);
rmeddis@0 766 withinRuns.responsesPhaseTwo=...
rmeddis@0 767 withinRuns.responseList(withinRuns.beginningOfPhase2:end);
rmeddis@0 768 else
rmeddis@0 769 withinRuns.levelsPhaseTwo=[];
rmeddis@0 770 end
rmeddis@0 771
rmeddis@0 772 % get (or substitute) threshold estimate
rmeddis@0 773 switch experiment.threshEstMethod
rmeddis@0 774 case {'2I2AFC++', '2I2AFC+++'}
rmeddis@0 775 % for plotting psychometric function only
rmeddis@0 776 if withinRuns.beginningOfPhase2>0
rmeddis@0 777 [psy, levelsBinVector, logistic, rareEvent]= ...
rmeddis@0 778 bestFitPsychometicFunctions...
rmeddis@0 779 (withinRuns.levelsPhaseTwo, withinRuns.responsesPhaseTwo);
rmeddis@0 780 end
rmeddis@28 781
rmeddis@0 782 if ~isempty(withinRuns.peaks) && ~isempty(withinRuns.troughs)
rmeddis@0 783 thresholdEstimate= ...
rmeddis@0 784 mean([mean(withinRuns.peaks) mean(withinRuns.troughs)]);
rmeddis@0 785 else
rmeddis@0 786 thresholdEstimate=NaN;
rmeddis@0 787 end
rmeddis@28 788
rmeddis@0 789 otherwise
rmeddis@0 790 % single interval methods
rmeddis@0 791 try
rmeddis@0 792 % using the s trial after the first reversal
rmeddis@0 793 [psy, levelsBinVector, logistic, rareEvent]= ...
rmeddis@0 794 bestFitPsychometicFunctions(withinRuns.levelsPhaseTwo,...
rmeddis@0 795 withinRuns.responsesPhaseTwo);
rmeddis@0 796 catch
rmeddis@0 797 logistic.bestThreshold=NaN;
rmeddis@0 798 end
rmeddis@0 799 end
rmeddis@0 800
rmeddis@0 801 if withinRuns.nowInPhase2
rmeddis@0 802 % save tracks of threshold estimates for plotting andprinting
rmeddis@0 803 switch experiment.functionEstMethod
rmeddis@0 804 case {'logisticLS', 'logisticML'}
rmeddis@0 805 if withinRuns.nowInPhase2
rmeddis@0 806 withinRuns.meanEstTrack=...
rmeddis@0 807 [withinRuns.meanEstTrack ...
rmeddis@0 808 mean(withinRuns.levelsPhaseTwo)];
rmeddis@0 809 withinRuns.thresholdEstimateTrack=...
rmeddis@0 810 [withinRuns.thresholdEstimateTrack ...
rmeddis@0 811 logistic.bestThreshold];
rmeddis@0 812 end
rmeddis@0 813 case 'rareEvent'
rmeddis@0 814 withinRuns.meanEstTrack=...
rmeddis@0 815 [withinRuns.meanEstTrack rareEvent.thresholddB];
rmeddis@0 816 withinRuns.thresholdEstimateTrack=...
rmeddis@0 817 [withinRuns.thresholdEstimateTrack logistic.bestThreshold];
rmeddis@0 818 case 'peaksAndTroughs'
rmeddis@0 819 withinRuns.meanEstTrack=...
rmeddis@0 820 [withinRuns.meanEstTrack thresholdEstimate];
rmeddis@0 821 withinRuns.thresholdEstimateTrack=...
rmeddis@0 822 [withinRuns.thresholdEstimateTrack thresholdEstimate];
rmeddis@0 823 end
rmeddis@0 824 end
rmeddis@0 825
rmeddis@0 826 % special discomfort condition
rmeddis@0 827 % run is completed when subject hits '2' button
rmeddis@0 828 switch experiment.paradigm
rmeddis@0 829 case 'discomfort'
rmeddis@0 830 if saidYes
rmeddis@0 831 runCompleted(handles)
rmeddis@0 832 return
rmeddis@0 833 end
rmeddis@0 834 end
rmeddis@0 835
rmeddis@0 836 % choose the next level for the stimulus
rmeddis@0 837 switch experiment.threshEstMethod
rmeddis@0 838 case {'2I2AFC++', '2I2AFC+++'}
rmeddis@0 839 if saidYes
rmeddis@0 840 [WRVinitialStep, msg]=Levitt2('hit', withinRuns.variableValue);
rmeddis@0 841 else
rmeddis@0 842 [WRVinitialStep, msg]=Levitt2('miss',withinRuns.variableValue);
rmeddis@0 843 end
rmeddis@28 844
rmeddis@0 845 % empty message means continue as normal
rmeddis@28 846 if ~isempty(msg)
rmeddis@0 847 runCompleted(handles)
rmeddis@0 848 return
rmeddis@0 849 end
rmeddis@0 850 newWRVvalue=withinRuns.variableValue-WRVinitialStep;
rmeddis@28 851
rmeddis@0 852 case {'MaxLikelihood', 'oneIntervalUpDown'}
rmeddis@28 853 % run completed by virtue of number of trials
rmeddis@0 854 % or restart because listener is in trouble
rmeddis@0 855 if length(withinRuns.levelsPhaseTwo)== experiment.maxTrials
rmeddis@0 856 % Use bonomial test to decide if there is an imbalance in the
rmeddis@0 857 % number of 'yes'es and 'no's
rmeddis@0 858 yesCount=sum(withinRuns.responseList);
rmeddis@0 859 noCount=length(withinRuns.responseList)-yesCount;
rmeddis@0 860 z=abs(yesCount-noCount)/(yesCount+noCount)^0.5;
rmeddis@0 861 if z>1.96
rmeddis@0 862 betweenRuns.resets=betweenRuns.resets+1;
rmeddis@0 863 disp([ 'reset / z= ' num2str( z) ...
rmeddis@0 864 ' Nresets= ' num2str( betweenRuns.resets) ] )
rmeddis@0 865 withinRuns.peaks=[];
rmeddis@0 866 withinRuns.troughs=[];
rmeddis@0 867 withinRuns.levelList=withinRuns.levelList(end);
rmeddis@0 868 withinRuns.meanEstTrack=withinRuns.meanEstTrack(end);
rmeddis@0 869 withinRuns.forceThreshold=NaN;
rmeddis@0 870 withinRuns.responseList=withinRuns.responseList(end);
rmeddis@0 871 withinRuns.beginningOfPhase2=0;
rmeddis@0 872 withinRuns.nowInPhase2=0;
rmeddis@0 873 withinRuns.thresholdEstimateTrack=...
rmeddis@0 874 withinRuns.thresholdEstimateTrack(end);
rmeddis@0 875 else
rmeddis@0 876 runCompleted(handles)
rmeddis@0 877 return
rmeddis@0 878 end
rmeddis@0 879 end
rmeddis@28 880
rmeddis@0 881 % set new value for WRV
rmeddis@0 882 if withinRuns.nowInPhase2
rmeddis@0 883 % phase 2
rmeddis@0 884 currentMeanEst=withinRuns.thresholdEstimateTrack(end);
rmeddis@0 885 switch experiment.threshEstMethod
rmeddis@0 886 case 'MaxLikelihood'
rmeddis@28 887 newWRVvalue=currentMeanEst;
rmeddis@0 888 case {'oneIntervalUpDown'}
rmeddis@0 889 newWRVvalue=withinRuns.variableValue+WRVsmallStep;
rmeddis@0 890 end
rmeddis@0 891 else
rmeddis@0 892 % phase 1
rmeddis@0 893 if withinRuns.variableValue+2*WRVinitialStep>...
rmeddis@0 894 stimulusParameters.WRVlimits(2)
rmeddis@0 895 % use smaller steps when close to maximum
rmeddis@0 896 WRVinitialStep=WRVinitialStep/2;
rmeddis@0 897 end
rmeddis@0 898 newWRVvalue=withinRuns.variableValue+WRVinitialStep;
rmeddis@0 899 end
rmeddis@0 900 otherwise
rmeddis@0 901 error( 'assessment method not recognised')
rmeddis@0 902 end
rmeddis@0 903
rmeddis@0 904 switch experiment.paradigm
rmeddis@0 905 % prevent unrealistic gap durations 'gapDetection' tasks.
rmeddis@0 906 % Note that the gap begins when the ramp ends not when stimulus ends
rmeddis@0 907 case 'gapDetection'
rmeddis@0 908 if newWRVvalue<-2*stimulusParameters.rampDuration
rmeddis@0 909 newWRVvalue=-2*stimulusParameters.rampDuration;
rmeddis@0 910 addToMsg('gap duration fixed at - 2 * ramp!',1, 1)
rmeddis@0 911 end
rmeddis@0 912 end
rmeddis@0 913
rmeddis@0 914 withinRuns.variableValue=newWRVvalue;
rmeddis@0 915 withinRuns.trialNumber=withinRuns.trialNumber+1;
rmeddis@0 916
rmeddis@0 917 % Trial continues
rmeddis@0 918 plotProgressThisTrial(handles)
rmeddis@0 919
rmeddis@0 920 % next stimulus and so the cycle continues
rmeddis@0 921 errormsg=nextStimulus(handles);
rmeddis@0 922 % after the stimulus is presented, control returns here and the system
rmeddis@0 923 % waits for user action.
rmeddis@0 924
rmeddis@0 925 % terminate if there is any kind of problem
rmeddis@0 926 if ~isempty(errormsg)
rmeddis@0 927 % e.g. limits exceeded, clipping
rmeddis@0 928 disp(['Error nextStimulus: ' errormsg])
rmeddis@0 929 runCompleted(handles)
rmeddis@0 930 return
rmeddis@0 931 end
rmeddis@0 932
rmeddis@0 933 % ------------------------------------------------ userSelectsPleaseRepeat
rmeddis@0 934 function userSelectsPleaseRepeat(handles)
rmeddis@0 935 global experiment withinRuns
rmeddis@0 936 % ignore click if not 'waitingForResponse'
rmeddis@0 937 if ~strcmp(experiment.status,'waitingForResponse')
rmeddis@0 938 disp('ignored click')
rmeddis@0 939 return
rmeddis@0 940 end
rmeddis@28 941 % Take no action other than to make a
rmeddis@0 942 % tally of repeat requests
rmeddis@0 943 experiment.pleaseRepeat=experiment.pleaseRepeat+1;
rmeddis@0 944 withinRuns.thisIsRepeatTrial=1;
rmeddis@0 945 nextStimulus(handles);
rmeddis@0 946
rmeddis@0 947 % ------------------------------------------------ userSelectsWrongButton
rmeddis@0 948 function userSelectsWrongButton(handles)
rmeddis@0 949 global withinRuns experiment
rmeddis@0 950 % restart is the simplest solution for a 'wrong button' request
rmeddis@0 951 withinRuns.wrongButton=withinRuns.wrongButton+1;
rmeddis@28 952 set(handles.pushbuttonGO, 'visible','on', 'backgroundcolor','y')
rmeddis@0 953 msg=[{'Start again: wrong button pressed'}, {' '},...
rmeddis@0 954 {'Please,click on the GO button'}];
rmeddis@0 955 set(handles.textMSG,'string',msg)
rmeddis@0 956 experiment.status='waitingForGO';
rmeddis@0 957
rmeddis@0 958 % ------------------------------------------------- plotProgressThisTrial
rmeddis@0 959 function plotProgressThisTrial(handles)
rmeddis@28 960 % updates GUI: used for all responses
rmeddis@0 961
rmeddis@0 962 global experiment stimulusParameters betweenRuns withinRuns expGUIhandles
rmeddis@0 963 global psy levelsBinVector binFrequencies rareEvent logistic statsModel
rmeddis@0 964
rmeddis@0 965 % plot the levelTrack and the threshold track
rmeddis@0 966
rmeddis@0 967 % Panel 2
rmeddis@0 968 % plot the levelList
rmeddis@0 969 axes(expGUIhandles.axes2); cla
rmeddis@0 970 plot( withinRuns.levelList,'o','markerFaceColor','k'), hold on
rmeddis@0 971 % plot the best threshold estimate tracks
rmeddis@0 972 if length(withinRuns.meanEstTrack)>=1
rmeddis@0 973 % The length of the levelList is 2 greater than number of thresholds
rmeddis@0 974 ptr=withinRuns.beginningOfPhase2+1;
rmeddis@0 975 plot(ptr: ptr+length(withinRuns.meanEstTrack)-1, ...
rmeddis@0 976 withinRuns.meanEstTrack, 'r')
rmeddis@0 977 plot( ptr: ptr+length(withinRuns.thresholdEstimateTrack)-1, ...
rmeddis@0 978 withinRuns.thresholdEstimateTrack, 'g')
rmeddis@0 979 hold off
rmeddis@0 980 estThresh=withinRuns.thresholdEstimateTrack(end);
rmeddis@0 981 switch experiment.threshEstMethod
rmeddis@0 982 % add appropriate labels to subject GUI buttons
rmeddis@0 983 case {'2I2AFC++', '2I2AFC+++'}
rmeddis@0 984 title([stimulusParameters.WRVname ' = ' ...
rmeddis@0 985 num2str(withinRuns.variableValue, '%5.1f')])
rmeddis@0 986 otherwise
rmeddis@0 987 title([stimulusParameters.WRVname ' = ' ...
rmeddis@0 988 num2str(withinRuns.variableValue, '%5.1f') ...
rmeddis@38 989 '; TH= ' num2str(estThresh, '%5.1f') ' dB'])
rmeddis@0 990 end
rmeddis@0 991 end
rmeddis@0 992 xlim([0 experiment.maxTrials+withinRuns.beginningOfPhase2]);
rmeddis@0 993 ylim(stimulusParameters.WRVlimits)
rmeddis@38 994 ylabel ('dB SPL')
rmeddis@0 995 grid on
rmeddis@0 996
rmeddis@0 997 % Panel 4: Summary of threshold estimates (not used here)
rmeddis@28 998 % Estimates from previous runs are set in 'runCompleted'
rmeddis@28 999 % It is only necessary to change title showing runs/trials remaining
rmeddis@0 1000 axes(expGUIhandles.axes4)
rmeddis@0 1001 runsToGo=length(betweenRuns.var1Sequence)-betweenRuns.runNumber;
rmeddis@0 1002 if withinRuns.beginningOfPhase2>0
rmeddis@0 1003 trialsToGo= experiment.singleIntervalMaxTrials(1) ...
rmeddis@0 1004 + withinRuns.beginningOfPhase2- withinRuns.trialNumber;
rmeddis@0 1005 title(['trials remaining = ' num2str(trialsToGo) ...
rmeddis@0 1006 ': runs to go= ' num2str(runsToGo)])
rmeddis@0 1007 end
rmeddis@0 1008
rmeddis@0 1009 % plot psychometric function - panel 5
rmeddis@0 1010 axes(expGUIhandles.axes5), cla
rmeddis@0 1011 plot(withinRuns.levelList, withinRuns.responseList,'b.'), hold on
rmeddis@0 1012 ylim([0 1])
rmeddis@0 1013 title('')
rmeddis@0 1014
rmeddis@0 1015 switch experiment.threshEstMethod
rmeddis@0 1016 case {'MaxLikelihood', 'oneIntervalUpDown'}
rmeddis@0 1017 if withinRuns.beginningOfPhase2>0
rmeddis@0 1018 % display only when in phase 2.
rmeddis@0 1019 withinRuns.levelsPhaseTwo=...
rmeddis@0 1020 withinRuns.levelList(withinRuns.beginningOfPhase2:end);
rmeddis@0 1021 withinRuns.responsesPhaseTwo=...
rmeddis@0 1022 withinRuns.responseList(withinRuns.beginningOfPhase2:end);
rmeddis@28 1023
rmeddis@0 1024 % organise data as psychometric function
rmeddis@0 1025 [psy, levelsBinVector, binFrequencies]= ...
rmeddis@0 1026 psychometricFunction(withinRuns.levelsPhaseTwo,...
rmeddis@0 1027 withinRuns.responsesPhaseTwo, experiment.psyBinWidth);
rmeddis@28 1028
rmeddis@0 1029 % Plot the function
rmeddis@0 1030 % point by point with circles of appropiate weighted size
rmeddis@0 1031 hold on,
rmeddis@0 1032 for i=1:length(psy)
rmeddis@0 1033 plot(levelsBinVector(i), psy(i), 'ro', ...
rmeddis@0 1034 'markersize', 50*binFrequencies(i)/sum(binFrequencies))
rmeddis@0 1035 end
rmeddis@0 1036 % save info for later
rmeddis@0 1037 betweenRuns.psychometicFunction{betweenRuns.runNumber}=...
rmeddis@0 1038 [levelsBinVector; psy];
rmeddis@28 1039
rmeddis@0 1040 % fitPsychometric functions is computed in 'userDecides'
rmeddis@0 1041 % plot(rareEvent.predictionLevels, rareEvent.predictionsRE,'k')
rmeddis@0 1042 plot(logistic.predictionLevels, logistic.predictionsLOG, 'r')
rmeddis@0 1043 plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k')
rmeddis@0 1044 if ~isnan(logistic.bestThreshold )
rmeddis@0 1045 xlim([ 0 100 ])
rmeddis@28 1046 title(['k= ' num2str(logistic.bestK, '%6.2f') ' g= '...
rmeddis@28 1047 num2str(rareEvent.bestGain,'%6.3f') ' A=' ...
rmeddis@28 1048 num2str(rareEvent.bestVMin,'%8.1f')])
rmeddis@0 1049 else
rmeddis@0 1050 title(' ')
rmeddis@0 1051 end
rmeddis@28 1052
rmeddis@0 1053 switch experiment.ear
rmeddis@0 1054 %plot green line for statsModel a priori model
rmeddis@0 1055 case 'statsModelLogistic'
rmeddis@0 1056 % plot proTem logistic (green) used by stats model
rmeddis@0 1057 p= 1./(1+exp(-statsModel.logisticSlope...
rmeddis@0 1058 *(levelsBinVector-logistic.bestThreshold)));
rmeddis@0 1059 if experiment.psyFunSlope<0, p=1-p;end
rmeddis@0 1060 titleText=[ ', statsModel: logistic'];
rmeddis@0 1061 hold on, plot(levelsBinVector, p,'g')
rmeddis@0 1062 case 'statsModelRareEvent'
rmeddis@0 1063 pressure=28*10.^(levelsBinVector/20);
rmeddis@0 1064 p=1-exp(-stimulusParameters.targetDuration...
rmeddis@0 1065 *(statsModel.rareEvenGain...
rmeddis@0 1066 * pressure-statsModel.rareEventVmin));
rmeddis@0 1067 p(p<0)=0;
rmeddis@0 1068 if experiment.psyFunSlope<0, p=1-p;end
rmeddis@0 1069 hold on, plot(levelsBinVector, p,'g')
rmeddis@0 1070 end %(estMethod)
rmeddis@0 1071 end
rmeddis@28 1072
rmeddis@0 1073 otherwise % 2A2IFC
rmeddis@0 1074 message3= ...
rmeddis@0 1075 ([ 'peaks=' num2str(withinRuns.peaks) ...
rmeddis@0 1076 'troughs=' num2str(withinRuns.troughs)]);
rmeddis@0 1077 ylimRM([-0.1 1.1]) % 0=no / 1=yes
rmeddis@0 1078 set(gca,'ytick',[0 1], 'yTickLabel', {'no';'yes'})
rmeddis@0 1079 ylabel('psychometric function'), xlabel('target level')
rmeddis@0 1080 if length(levelsBinVector)>1
rmeddis@0 1081 xlim([ min(levelsBinVector) max(levelsBinVector)])
rmeddis@0 1082 xlim([ 0 100])
rmeddis@0 1083 end
rmeddis@0 1084 end
rmeddis@0 1085
rmeddis@0 1086 % command window summary
rmeddis@0 1087 % Accumulate things to say in the message window
rmeddis@0 1088 message1= (['responses: ' num2str(withinRuns.responseList,'%9.0f')]);
rmeddis@0 1089 switch experiment.paradigm
rmeddis@0 1090 % more decimal places needed on GUI
rmeddis@0 1091 case { 'gapDetection', 'frequencyDiscrimination', 'forwardMaskingD'}
rmeddis@0 1092 message2= ([stimulusParameters.WRVname ...
rmeddis@0 1093 ': ' num2str(withinRuns.levelList,'%7.3f')]);
rmeddis@0 1094 message3= (['Thresh (logistic mean): ' ...
rmeddis@0 1095 num2str(withinRuns.thresholdEstimateTrack,'%7.3f')]);
rmeddis@0 1096 otherwise
rmeddis@0 1097 message2= ([stimulusParameters.WRVname ': ' ...
rmeddis@0 1098 num2str(withinRuns.levelList,'%7.1f')]);
rmeddis@0 1099 message3= (['Thresh (logistic mean): ' ...
rmeddis@0 1100 num2str(withinRuns.thresholdEstimateTrack,'%7.1f')]);
rmeddis@0 1101 end
rmeddis@0 1102
rmeddis@0 1103 addToMsg(str2mat(message1, message2, message3), 0)
rmeddis@0 1104
rmeddis@0 1105 % -----------------------------------------------------runCompleted
rmeddis@0 1106 function runCompleted(handles)
rmeddis@0 1107 % Used at the end of each run
rmeddis@0 1108 global experiment stimulusParameters betweenRuns withinRuns
rmeddis@0 1109 global rareEvent expGUIhandles
rmeddis@0 1110 % disp('run completed')
rmeddis@0 1111
rmeddis@0 1112 experiment.status='runCompleted';
rmeddis@28 1113 % quick update after final trial just to make sure
rmeddis@0 1114 plotProgressThisTrial(handles)
rmeddis@0 1115
rmeddis@0 1116 switch experiment.ear
rmeddis@0 1117 case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ...
rmeddis@0 1118 'MAPmodelMultiCh','MAPmodelSingleCh', 'MAPmodelListen'}
rmeddis@0 1119 % no changes required if model used
rmeddis@0 1120 otherwise
rmeddis@0 1121 set(handles.frame1,'visible','off')
rmeddis@0 1122 set(handles.pushbuttoNotSure,'visible','off')
rmeddis@0 1123 set(handles.pushbuttonWrongButton,'visible','off')
rmeddis@0 1124 set(handles.pushbutton3,'visible','off')
rmeddis@0 1125 set(handles.pushbutton2,'visible','off')
rmeddis@0 1126 set(handles.pushbutton1,'visible','off')
rmeddis@0 1127 set(handles.pushbutton0,'visible','off')
rmeddis@0 1128 set(handles.pushbuttonGO,'visible','off')
rmeddis@0 1129 end
rmeddis@0 1130
rmeddis@0 1131 if isnan(withinRuns.forceThreshold)
rmeddis@0 1132 % the experiment has been aborted for some reason
rmeddis@0 1133 threshold=withinRuns.forceThreshold;
rmeddis@0 1134 stdev=NaN;
rmeddis@0 1135 logistic.bestK=NaN;
rmeddis@0 1136 logistic.bestThreshold=NaN;
rmeddis@0 1137 medianThreshold=NaN;
rmeddis@0 1138 meanThreshold=NaN;
rmeddis@0 1139 else
rmeddis@0 1140 % use only phase 2 levels and responses for calculating thresholds
rmeddis@0 1141 withinRuns.levelsPhaseTwo=...
rmeddis@0 1142 withinRuns.levelList(withinRuns.beginningOfPhase2:end);
rmeddis@0 1143 withinRuns.responsesPhaseTwo=...
rmeddis@0 1144 withinRuns.responseList(withinRuns.beginningOfPhase2:end);
rmeddis@0 1145 [psy, levelsPhaseTwoBinVector, logistic, rareEvent]= ...
rmeddis@0 1146 bestFitPsychometicFunctions...
rmeddis@0 1147 (withinRuns.levelsPhaseTwo, withinRuns.responsesPhaseTwo);
rmeddis@28 1148
rmeddis@0 1149 % plot final psychometric function
rmeddis@0 1150 axes(expGUIhandles.axes5),cla
rmeddis@0 1151 hold on, plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k')
rmeddis@0 1152 hold on, plot(logistic.predictionLevels, logistic.predictionsLOG, 'r')
rmeddis@0 1153 % organise data as psychometric function
rmeddis@0 1154 [psy, levelsBinVector, binFrequencies]= ...
rmeddis@0 1155 psychometricFunction(withinRuns.levelsPhaseTwo,...
rmeddis@0 1156 withinRuns.responsesPhaseTwo, experiment.psyBinWidth);
rmeddis@0 1157 % point by point with circles of appropiate weighted size
rmeddis@0 1158 hold on,
rmeddis@0 1159 for i=1:length(psy)
rmeddis@0 1160 plot(levelsBinVector(i), psy(i), 'ro', ...
rmeddis@0 1161 'markersize', 50*binFrequencies(i)/sum(binFrequencies))
rmeddis@0 1162 end
rmeddis@0 1163
rmeddis@0 1164 % experimental
rmeddis@0 1165 medianThreshold=median(withinRuns.levelsPhaseTwo);
rmeddis@0 1166 warning off
rmeddis@0 1167 meanThreshold=mean(withinRuns.levelsPhaseTwo);
rmeddis@28 1168
rmeddis@0 1169 % identify the current threshold estimate
rmeddis@0 1170 switch experiment.paradigm
rmeddis@0 1171 case 'discomfort'
rmeddis@0 1172 % most recent value (not truely a mean value)
rmeddis@0 1173 threshold=withinRuns.levelList(end);
rmeddis@28 1174 stdev=NaN;
rmeddis@0 1175 otherwise
rmeddis@0 1176 switch experiment.threshEstMethod
rmeddis@0 1177 case {'MaxLikelihood', 'oneIntervalUpDown'}
rmeddis@0 1178 % last value in the list
rmeddis@28 1179 % threshold=withinRuns.meanEstTrack(end);
rmeddis@0 1180 threshold=withinRuns.thresholdEstimateTrack(end);
rmeddis@0 1181 stdev=NaN;
rmeddis@28 1182
rmeddis@0 1183 case {'2I2AFC++', '2I2AFC+++'}
rmeddis@0 1184 % use peaks and troughs
rmeddis@0 1185 try % there may not be enough values to use
rmeddis@0 1186 peaksUsed=experiment.peaksUsed;
rmeddis@0 1187 threshold=...
rmeddis@0 1188 mean(...
rmeddis@0 1189 [withinRuns.peaks(end-peaksUsed+1:end) ...
rmeddis@0 1190 withinRuns.troughs(end-peaksUsed+1:end)]);
rmeddis@0 1191 stdev=...
rmeddis@0 1192 std([withinRuns.peaks(end-peaksUsed +1:end) ...
rmeddis@0 1193 withinRuns.troughs(end-peaksUsed:end)]);
rmeddis@0 1194 catch
rmeddis@0 1195 threshold=NaN;
rmeddis@0 1196 stdev=NaN;
rmeddis@0 1197 end
rmeddis@0 1198 end
rmeddis@0 1199 end
rmeddis@0 1200 end
rmeddis@0 1201
rmeddis@0 1202 % Store thresholds
rmeddis@0 1203 betweenRuns.thresholds=[betweenRuns.thresholds threshold];
rmeddis@0 1204 betweenRuns.thresholds_mean=[betweenRuns.thresholds_mean meanThreshold];
rmeddis@0 1205 betweenRuns.thresholds_median=...
rmeddis@0 1206 [betweenRuns.thresholds_median medianThreshold];
rmeddis@0 1207 betweenRuns.forceThresholds=...
rmeddis@0 1208 [betweenRuns.forceThresholds withinRuns.forceThreshold];
rmeddis@0 1209
rmeddis@0 1210 % count observations after the startup phase for record keeping
rmeddis@0 1211 betweenRuns.observationCount=...
rmeddis@0 1212 [betweenRuns.observationCount length(withinRuns.levelList)];
rmeddis@0 1213 betweenRuns.timesOfFirstReversals=...
rmeddis@0 1214 [betweenRuns.timesOfFirstReversals withinRuns.beginningOfPhase2];
rmeddis@0 1215 betweenRuns.catchTrials=...
rmeddis@0 1216 [betweenRuns.catchTrials withinRuns.catchTrialCount];
rmeddis@0 1217
rmeddis@0 1218 % add variable length tracks to cell arrays
rmeddis@0 1219 if withinRuns.beginningOfPhase2>0
rmeddis@0 1220 betweenRuns.bestThresholdTracks{length(betweenRuns.thresholds)}=...
rmeddis@28 1221 withinRuns.thresholdEstimateTrack;
rmeddis@0 1222 betweenRuns.levelTracks{length(betweenRuns.thresholds)}=...
rmeddis@0 1223 withinRuns.levelList(withinRuns.beginningOfPhase2:end);
rmeddis@0 1224 betweenRuns.responseTracks{length(betweenRuns.thresholds)}=...
rmeddis@0 1225 withinRuns.responseList(withinRuns.beginningOfPhase2:end);
rmeddis@0 1226 else
rmeddis@0 1227 betweenRuns.bestThresholdTracks{length(betweenRuns.thresholds)}=[];
rmeddis@0 1228 betweenRuns.levelTracks{length(betweenRuns.thresholds)}=[];
rmeddis@0 1229 betweenRuns.responseTracks{length(betweenRuns.thresholds)}=[];
rmeddis@0 1230 end
rmeddis@0 1231
rmeddis@0 1232 betweenRuns.bestGain=[betweenRuns.bestGain rareEvent.bestGain];
rmeddis@0 1233 betweenRuns.bestVMin=[betweenRuns.bestVMin rareEvent.bestVMin];
rmeddis@0 1234 betweenRuns.bestPaMin=[betweenRuns.bestPaMin rareEvent.bestPaMindB];
rmeddis@0 1235 betweenRuns.bestLogisticM=...
rmeddis@0 1236 [betweenRuns.bestLogisticM logistic.bestThreshold];
rmeddis@0 1237 betweenRuns.bestLogisticK=[betweenRuns.bestLogisticK logistic.bestK];
rmeddis@0 1238
rmeddis@0 1239 resultsSoFar=[betweenRuns.var1Sequence(betweenRuns.runNumber)'...
rmeddis@0 1240 betweenRuns.var2Sequence(betweenRuns.runNumber)'...
rmeddis@0 1241 betweenRuns.thresholds(betweenRuns.runNumber)'
rmeddis@0 1242 ];
rmeddis@0 1243
rmeddis@0 1244 fprintf('%10.3f \t%10.3f \t%10.1f \n', resultsSoFar')
rmeddis@0 1245
rmeddis@0 1246 switch experiment.ear
rmeddis@0 1247 case {'left', 'right', 'diotic', 'dichoticLeft','dichoticRight'}
rmeddis@0 1248 disp(['caught out= ' num2str(betweenRuns.caughtOut)])
rmeddis@0 1249 end
rmeddis@0 1250
rmeddis@0 1251 % plot history of thresholds in panel 4
rmeddis@0 1252 axes(expGUIhandles.axes4), cla
rmeddis@0 1253 plotColors='rgbmckywrgbmckyw';
rmeddis@0 1254 for i=1:length(betweenRuns.thresholds)
rmeddis@0 1255 faceColor=plotColors(floor(i/length(betweenRuns.variableList1)-.01)+1);
rmeddis@0 1256 switch betweenRuns.variableName1
rmeddis@0 1257 case {'targetFrequency', 'maskerRelativeFrequency'}
rmeddis@0 1258 if min(betweenRuns.var1Sequence)>0
rmeddis@0 1259 semilogx(betweenRuns.var1Sequence(i), ...
rmeddis@0 1260 betweenRuns.thresholds(i), 'o', ...
rmeddis@0 1261 'markerSize', 5,'markerFaceColor',faceColor)
rmeddis@0 1262 else
rmeddis@0 1263 plot(betweenRuns.var1Sequence(1:betweenRuns.runNumber), ...
rmeddis@0 1264 betweenRuns.thresholds, 'o', ...
rmeddis@0 1265 'markerSize', 5,'markerFaceColor',faceColor)
rmeddis@0 1266 plot(betweenRuns.var1Sequence(i), ...
rmeddis@0 1267 betweenRuns.thresholds(i), 'o', ...
rmeddis@0 1268 'markerSize', 5,'markerFaceColor',faceColor)
rmeddis@0 1269 end
rmeddis@0 1270 otherwise
rmeddis@0 1271 plot(betweenRuns.var1Sequence(i), ...
rmeddis@0 1272 betweenRuns.thresholds(i), 'o', 'markerSize', 5,...
rmeddis@0 1273 'markerFaceColor',faceColor)
rmeddis@0 1274 end
rmeddis@0 1275 hold on
rmeddis@0 1276 end
rmeddis@0 1277 xlimRM([ min(betweenRuns.variableList1) max(betweenRuns.variableList1) ])
rmeddis@0 1278 ylim(stimulusParameters.WRVlimits)
rmeddis@38 1279 ylabel('thresholds (dB)')
rmeddis@0 1280 xlabel(betweenRuns.variableName1)
rmeddis@0 1281 set(gca,'ytick', [0 20 40 60 80 100])
rmeddis@0 1282 try
rmeddis@0 1283 % problems if only one x value
rmeddis@0 1284 set(gca,'XTick', sort(betweenRuns.variableList1))
rmeddis@0 1285 catch
rmeddis@0 1286 end
rmeddis@0 1287 grid on, set(gca,'XMinorGrid', 'off')
rmeddis@0 1288
rmeddis@28 1289 % final run?
rmeddis@0 1290 if betweenRuns.runNumber==length(betweenRuns.var1Sequence)
rmeddis@0 1291 % yes, end of experiment
rmeddis@0 1292 fileName=['savedData/' experiment.name experiment.date ...
rmeddis@0 1293 experiment.paradigm];
rmeddis@0 1294 % save (fileName, 'experiment', 'stimulusParameters', 'betweenRuns', 'withinRuns', 'variableNames', 'paradigmNames', 'LevittControl')
rmeddis@0 1295 disp('Experiment completed')
rmeddis@28 1296
rmeddis@0 1297 % update subject GUI to acknowledge end of run
rmeddis@0 1298 subjGUImsg=[{'Experiment completed'}, {' '}, {'Thank you!'}];
rmeddis@0 1299 set(handles.textMSG,'string', subjGUImsg )
rmeddis@0 1300 % play 'Tada'
rmeddis@0 1301 [y,fs,nbits]=wavread('TADA.wav');
rmeddis@0 1302 musicGain=10^(stimulusParameters.musicLeveldB/20);
rmeddis@0 1303 y=y*musicGain;
rmeddis@35 1304 if ispc, wavplay(y/100,fs, 'async'), else sound(y/100,fs, 'async'), end
rmeddis@28 1305
rmeddis@0 1306 % update experimenter GUI
rmeddis@0 1307 addToMsg('Experiment completed.',1)
rmeddis@28 1308
rmeddis@38 1309 set(expGUIhandles.pushbuttonSave,'visible','on')
rmeddis@0 1310 printReport
rmeddis@28 1311 experiment.status='endOfExperiment';
rmeddis@0 1312 return
rmeddis@0 1313 else
rmeddis@0 1314 % No, hang on.
rmeddis@0 1315 switch experiment.ear
rmeddis@0 1316 case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ...
rmeddis@0 1317 'MAPmodelMultiCh','MAPmodelSingleCh', 'MAPmodelListen'}
rmeddis@0 1318 % no changes required if model used
rmeddis@0 1319 otherwise
rmeddis@0 1320 % decrement catchTrialRate towards baseRate
rmeddis@0 1321 stimulusParameters.catchTrialRate=...
rmeddis@0 1322 stimulusParameters.catchTrialBaseRate + ...
rmeddis@0 1323 (stimulusParameters.catchTrialRate...
rmeddis@0 1324 -stimulusParameters.catchTrialBaseRate)...
rmeddis@0 1325 *(1-exp(-stimulusParameters.catchTrialTimeConstant));
rmeddis@0 1326 fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
rmeddis@0 1327 stimulusParameters.catchTrialRate)
rmeddis@28 1328
rmeddis@0 1329 % and go again
rmeddis@28 1330 set(handles.pushbuttonGO,'backgroundcolor','y')
rmeddis@0 1331 set(handles.frame1,'visible','off')
rmeddis@0 1332 set(handles.pushbuttonGO,'visible','on')
rmeddis@0 1333 msg=[{'Ready to start new trial'}, {' '},...
rmeddis@0 1334 {'Please,click on the GO button'}];
rmeddis@0 1335 set(handles.textMSG,'string',msg)
rmeddis@0 1336 end
rmeddis@0 1337 experiment.status='waitingForGO';
rmeddis@0 1338 % fprintf('\n')
rmeddis@28 1339
rmeddis@0 1340 [y,fs,nbits]=wavread('CHIMES.wav');
rmeddis@0 1341 musicGain=10^(stimulusParameters.musicLeveldB/20);
rmeddis@0 1342 y=y*musicGain;
rmeddis@35 1343 if ispc, wavplay(y/100,fs, 'async'), else sound(y/100,fs, 'async'), end
rmeddis@35 1344
rmeddis@0 1345 end
rmeddis@0 1346
rmeddis@0 1347 % -----------------------------------------------------MAPmodelRunsGUI
rmeddis@0 1348 % The computer presses the buttons
rmeddis@0 1349 function MAPmodelRunsGUI(handles)
rmeddis@0 1350 global experiment stimulusParameters method expGUIhandles
rmeddis@0 1351 global AN_IHCsynapseParams
rmeddis@0 1352 method=[];
rmeddis@0 1353
rmeddis@28 1354 while strcmp(experiment.status,'waitingForGO')
rmeddis@0 1355 % no catch trials for MAP model
rmeddis@0 1356 experiment.allowCatchTrials=0;
rmeddis@28 1357
rmeddis@28 1358 % initiates run and plays first stimulus and it returns
rmeddis@0 1359 % without waiting for button press
rmeddis@28 1360 startNewRun(handles)
rmeddis@0 1361
rmeddis@29 1362 % show sample Rate on GUI; it must be set in MAPparams ##??
rmeddis@0 1363 set(expGUIhandles.textsampleRate,'string',...
rmeddis@0 1364 num2str(stimulusParameters.sampleRate))
rmeddis@28 1365
rmeddis@29 1366 if experiment.singleShot % ##??
rmeddis@0 1367 AN_IHCsynapseParams.plotSynapseContents=1;
rmeddis@0 1368 else
rmeddis@0 1369 AN_IHCsynapseParams.plotSynapseContents=0;
rmeddis@0 1370 end
rmeddis@28 1371
rmeddis@0 1372 % continuous loop until the program stops itself
rmeddis@0 1373 while strcmp(experiment.status,'waitingForResponse')
rmeddis@0 1374 % NB at this point the stimulus has been played
rmeddis@0 1375 pause(0.1) % to allow interrupt with CTRL/C
rmeddis@28 1376
rmeddis@0 1377 switch experiment.ear
rmeddis@0 1378 case { 'MAPmodelListen'}
rmeddis@28 1379 % flash the buttons to show model response
rmeddis@28 1380 set(handles.pushbutton1,'backgroundcolor','y','visible','on')
rmeddis@28 1381 set(handles.pushbutton2,'backgroundcolor','y','visible','on')
rmeddis@0 1382 end
rmeddis@0 1383
rmeddis@28 1384 % Analayse the current stimulus using MAP
rmeddis@28 1385 [modelResponse earObject]= MAPmodel;
rmeddis@0 1386
rmeddis@0 1387 if experiment.stop || experiment.singleShot
rmeddis@0 1388 % trap for single trial or user interrupt using 'stop' button.
rmeddis@0 1389 experiment.status= 'waitingForStart';
rmeddis@33 1390 % experiment.stop=0;
rmeddis@28 1391 errormsg='manually stopped';
rmeddis@28 1392 addToMsg(errormsg,1)
rmeddis@0 1393 return
rmeddis@0 1394 end
rmeddis@28 1395
rmeddis@0 1396 switch modelResponse
rmeddis@0 1397 case 1
rmeddis@0 1398 % userDoesNotHearTarget(handles)
rmeddis@0 1399 switch experiment.ear
rmeddis@0 1400 case {'MAPmodelListen'}
rmeddis@0 1401 % illuminate appropriate button
rmeddis@0 1402 set(handles.pushbutton1,...
rmeddis@0 1403 'backgroundcolor','r','visible','on')
rmeddis@0 1404 set(handles.pushbutton2,'backgroundcolor','y')
rmeddis@0 1405 end
rmeddis@0 1406 userDecides(handles, false)
rmeddis@0 1407 if experiment.singleShot, return, end
rmeddis@0 1408
rmeddis@0 1409 case 2
rmeddis@0 1410 % userHearsTarget(handles)
rmeddis@0 1411 switch experiment.ear
rmeddis@0 1412 case {'MAPmodelListen'}
rmeddis@0 1413 % illuminate appropriate button (DEMO only)
rmeddis@0 1414 set(handles.pushbutton2,'backgroundcolor',...
rmeddis@0 1415 'r','visible','on')
rmeddis@0 1416 set(handles.pushbutton1,'backgroundcolor','y')
rmeddis@0 1417 end
rmeddis@28 1418
rmeddis@0 1419 switch experiment.paradigm
rmeddis@0 1420 case 'discomfort'
rmeddis@0 1421 % always treat discomfort as 'not heard'
rmeddis@0 1422 userDecides(handles, false)
rmeddis@0 1423 otherwise
rmeddis@0 1424 userDecides(handles, true)
rmeddis@0 1425 end
rmeddis@0 1426 otherwise
rmeddis@0 1427 % probably an abort
rmeddis@0 1428 return
rmeddis@0 1429 end
rmeddis@0 1430 end
rmeddis@0 1431 end
rmeddis@0 1432
rmeddis@28 1433 % -------------------------------------------------------MAPmodel
rmeddis@28 1434 function [modelResponse, MacGregorResponse]=MAPmodel
rmeddis@9 1435
rmeddis@9 1436 global experiment stimulusParameters audio withinRuns
rmeddis@29 1437 % global outerMiddleEarParams DRNLParams AN_IHCsynapseParams
rmeddis@38 1438 global ICoutput dtSpikes dt savedBFlist ANprobRateOutput expGUIhandles
rmeddis@29 1439 global paramChanges
rmeddis@9 1440
rmeddis@9 1441 savePath=path;
rmeddis@24 1442 addpath(['..' filesep 'MAP'], ['..' filesep 'utilities'])
rmeddis@9 1443 modelResponse=[];
rmeddis@9 1444 MacGregorResponse=[];
rmeddis@9 1445
rmeddis@9 1446 % mono only (column vector)
rmeddis@9 1447 audio=audio(:,1)';
rmeddis@9 1448
rmeddis@9 1449 % if stop button pressed earlier
rmeddis@28 1450 if experiment.stop
rmeddis@28 1451 errormsg='manually stopped';
rmeddis@28 1452 addToMsg(errormsg,1)
rmeddis@28 1453 return
rmeddis@28 1454 end
rmeddis@9 1455
rmeddis@28 1456 % ---------------------------------------------- run Model
rmeddis@9 1457 MAPparamsName=experiment.name;
rmeddis@9 1458 showPlotsAndDetails=experiment.MAPplot;
rmeddis@29 1459
rmeddis@29 1460 % important buried constant ##??
rmeddis@9 1461 AN_spikesOrProbability='spikes';
rmeddis@32 1462 % AN_spikesOrProbability='probability';
rmeddis@9 1463
rmeddis@9 1464 % [response, method]=MAPsequenceSeg(audio, method, 1:8);
rmeddis@28 1465
rmeddis@28 1466 if sum(strcmp(experiment.ear,{'MAPmodelMultiCh', 'MAPmodelListen'}))
rmeddis@28 1467 % use BFlist specified in MAPparams file
rmeddis@28 1468 BFlist= -1;
rmeddis@28 1469 else
rmeddis@28 1470 BFlist=stimulusParameters.targetFrequency;
rmeddis@28 1471 end
rmeddis@28 1472 paramChanges=get(expGUIhandles.editparamChanges,'string');
rmeddis@29 1473 % convert from string to a cell array
rmeddis@29 1474 eval(paramChanges);
rmeddis@28 1475
rmeddis@28 1476 MAP1_14(audio, stimulusParameters.sampleRate, BFlist,...
rmeddis@28 1477 MAPparamsName, AN_spikesOrProbability, paramChanges);
rmeddis@28 1478
rmeddis@9 1479 if showPlotsAndDetails
rmeddis@23 1480 options.printModelParameters=0;
rmeddis@9 1481 options.showModelOutput=1;
rmeddis@9 1482 options.printFiringRates=1;
rmeddis@9 1483 options.showACF=0;
rmeddis@38 1484 options.showEfferent=0;
rmeddis@23 1485 options.surfProbability=0;
rmeddis@25 1486 showMapOptions.surfSpikes=0;
rmeddis@23 1487 UTIL_showMAP(options)
rmeddis@9 1488 end
rmeddis@9 1489
rmeddis@9 1490 % No response, probably caused by hitting 'stop' button
rmeddis@28 1491 if strcmp(AN_spikesOrProbability,'spikes') && isempty(ICoutput)
rmeddis@28 1492 return
rmeddis@28 1493 end
rmeddis@9 1494 % ---------------------------------------------------------- end model run
rmeddis@9 1495
rmeddis@28 1496 if strcmp(AN_spikesOrProbability,'spikes')
rmeddis@28 1497 MacGregorResponse= sum(ICoutput,1); % use IC
rmeddis@38 1498 dt=dtSpikes;
rmeddis@28 1499 time=dt:dt:dt*length(MacGregorResponse);
rmeddis@28 1500 else
rmeddis@28 1501 % for one channel, ANprobResponse=ANprobRateOutput
rmeddis@28 1502 % for multi channel take strongest in any epoch
rmeddis@28 1503 nChannels=length(savedBFlist);
rmeddis@28 1504 % use only HSR fibers
rmeddis@28 1505 ANprobRateOutput=ANprobRateOutput(end-nChannels+1:end,:);
rmeddis@28 1506 time=dt:dt:dt*length(ANprobRateOutput);
rmeddis@28 1507 end
rmeddis@9 1508
rmeddis@28 1509 % group delay on unit response - these values are iffy
rmeddis@28 1510 windowOnsetDelay= 0.004;
rmeddis@28 1511 windowOffsetDelay= 0.022; % long ringing time
rmeddis@9 1512
rmeddis@38 1513 % now find the response of the MacGregor model during
rmeddis@38 1514 % the target presentation + group delay
rmeddis@9 1515 switch experiment.threshEstMethod
rmeddis@9 1516 case {'2I2AFC++', '2I2AFC+++'}
rmeddis@28 1517 idx= time>stimulusParameters.testTargetBegins+windowOnsetDelay ...
rmeddis@28 1518 & time<stimulusParameters.testTargetEnds+windowOffsetDelay;
rmeddis@9 1519 nSpikesTrueWindow=sum(MacGregorResponse(:,idx));
rmeddis@28 1520 idx=find(time>stimulusParameters.testNonTargetBegins+windowOnsetDelay ...
rmeddis@28 1521 & time<stimulusParameters.testNonTargetEnds+windowOffsetDelay);
rmeddis@28 1522 if strcmp(AN_spikesOrProbability,'spikes')
rmeddis@28 1523 nSpikesFalseWindow=sum(MacGregorResponse(:,idx));
rmeddis@28 1524 else
rmeddis@28 1525 nSpikesDuringTarget=mean(ANprobRateOutput(end,idx));
rmeddis@28 1526 % compare with spontaneous rate
rmeddis@28 1527 if nSpikesDuringTarget>ANprobRateOutput(end,1)+10
rmeddis@28 1528 nSpikesDuringTarget=1; % i.e. at leastone MacG spike
rmeddis@28 1529 else
rmeddis@28 1530 nSpikesDuringTarget=0;
rmeddis@28 1531 end
rmeddis@28 1532 end
rmeddis@9 1533 % nSpikesDuringTarget is +ve when more spikes are found
rmeddis@9 1534 % in the target window
rmeddis@9 1535 difference= nSpikesTrueWindow-nSpikesFalseWindow;
rmeddis@9 1536
rmeddis@9 1537 if difference>0
rmeddis@9 1538 % hit
rmeddis@9 1539 nSpikesDuringTarget=experiment.MacGThreshold+1;
rmeddis@9 1540 elseif difference<0
rmeddis@9 1541 % miss (wrong choice)
rmeddis@9 1542 nSpikesDuringTarget=experiment.MacGThreshold-1;
rmeddis@9 1543 else
rmeddis@9 1544 if rand>0.5
rmeddis@9 1545 % hit (random choice)
rmeddis@9 1546 nSpikesDuringTarget=experiment.MacGThreshold+1;
rmeddis@9 1547 else
rmeddis@9 1548 % miss (random choice)
rmeddis@9 1549 nSpikesDuringTarget=experiment.MacGThreshold-1;
rmeddis@9 1550 end
rmeddis@9 1551 end
rmeddis@9 1552 disp(['level target dummy decision: ' ...
rmeddis@9 1553 num2str([withinRuns.variableValue nSpikesTrueWindow ...
rmeddis@9 1554 nSpikesFalseWindow nSpikesDuringTarget], '%4.0f') ] )
rmeddis@28 1555 otherwise
rmeddis@38 1556
rmeddis@38 1557 % single interval up/down
rmeddis@28 1558 idx=find(time>stimulusParameters.testTargetBegins +windowOnsetDelay...
rmeddis@28 1559 & time<stimulusParameters.testTargetEnds+windowOffsetDelay);
rmeddis@28 1560 if strcmp(AN_spikesOrProbability,'spikes')
rmeddis@28 1561 nSpikesDuringTarget=sum(MacGregorResponse(:,idx));
rmeddis@28 1562 timeX=time(idx);
rmeddis@28 1563 else
rmeddis@28 1564 % probability, use channel with the highest average rate
rmeddis@28 1565 nSpikesDuringTarget=max(mean(ANprobRateOutput(:,idx),2));
rmeddis@28 1566 if nSpikesDuringTarget>ANprobRateOutput(end,1)+10
rmeddis@28 1567 nSpikesDuringTarget=1;
rmeddis@28 1568 else
rmeddis@28 1569 nSpikesDuringTarget=0;
rmeddis@28 1570 end
rmeddis@9 1571
rmeddis@28 1572 end
rmeddis@9 1573 end
rmeddis@9 1574
rmeddis@9 1575 if experiment.MAPplot
rmeddis@9 1576 % add vertical lines to indicate target region
rmeddis@9 1577 figure(99), subplot(6,1,6)
rmeddis@9 1578 hold on
rmeddis@9 1579 yL=get(gca,'YLim');
rmeddis@28 1580 plot([stimulusParameters.testTargetBegins + windowOnsetDelay ...
rmeddis@28 1581 stimulusParameters.testTargetBegins + windowOnsetDelay],yL,'r')
rmeddis@28 1582 plot([stimulusParameters.testTargetEnds + windowOffsetDelay ...
rmeddis@28 1583 stimulusParameters.testTargetEnds + windowOffsetDelay],yL,'r')
rmeddis@9 1584 end
rmeddis@9 1585
rmeddis@9 1586 % specify unambiguous response
rmeddis@28 1587 if nSpikesDuringTarget>experiment.MacGThreshold
rmeddis@28 1588 modelResponse=2; % stimulus detected
rmeddis@28 1589 else
rmeddis@28 1590 modelResponse=1; % nothing heard (default)
rmeddis@9 1591 end
rmeddis@9 1592
rmeddis@9 1593 path(savePath)
rmeddis@0 1594
rmeddis@0 1595 % -----------------------------------------------------statsModelRunsGUI
rmeddis@0 1596 % The computer presses the buttons
rmeddis@0 1597 function statsModelRunsGUI(handles)
rmeddis@0 1598 % Decision are made at random using a prescribe statistical function
rmeddis@0 1599 % to set probabilities as a function of signal level.
rmeddis@0 1600 global experiment
rmeddis@0 1601
rmeddis@0 1602 experiment.allowCatchTrials=0;
rmeddis@0 1603
rmeddis@0 1604 while strcmp(experiment.status,'waitingForGO')
rmeddis@0 1605 % i.e. waiting for new run
rmeddis@0 1606 if experiment.stop
rmeddis@0 1607 % user has requested an abort
rmeddis@0 1608 experiment.status= 'waitingForStart';
rmeddis@0 1609 addToMsg('manually stopped',1)
rmeddis@0 1610 return
rmeddis@0 1611 end
rmeddis@28 1612
rmeddis@0 1613 % initiates run and plays first stimulus and it returns
rmeddis@0 1614 % without waiting for button press
rmeddis@0 1615 % NB stimulus is not actually generated (for speed)
rmeddis@0 1616 startNewRun(handles)
rmeddis@28 1617
rmeddis@0 1618 while strcmp(experiment.status,'waitingForResponse')
rmeddis@0 1619 % create artificial response here
rmeddis@0 1620 modelResponse=statsModelGetResponse;
rmeddis@0 1621 switch modelResponse
rmeddis@0 1622 case 1
rmeddis@0 1623 % userDoesNotHearTarget(handles)
rmeddis@0 1624 userDecides(handles, false)
rmeddis@0 1625 case 2
rmeddis@0 1626 % userHearsTarget(handles)
rmeddis@0 1627 userDecides(handles, true)
rmeddis@0 1628 end
rmeddis@0 1629 end
rmeddis@0 1630 end
rmeddis@0 1631
rmeddis@0 1632 % -----------------------------------------------------statsModelGetResponse
rmeddis@0 1633 function modelResponse=statsModelGetResponse(handles)
rmeddis@0 1634 global experiment withinRuns statsModel stimulusParameters
rmeddis@0 1635 % use the generating function to decide if a detection occurs or not
rmeddis@0 1636
rmeddis@0 1637 % pause(0.1) % to allow stopping with CTRL/C but slows things down
rmeddis@0 1638
rmeddis@0 1639 % first compute the probability that a detection occurs
rmeddis@0 1640 switch experiment.ear
rmeddis@0 1641 case {'statsModelLogistic'}
rmeddis@0 1642 prob= 1./(1+exp(-statsModel.logisticSlope.*(withinRuns.variableValue-statsModel.logisticMean)));
rmeddis@0 1643 % if experiment.psyFunSlope<0,
rmeddis@0 1644 % prob=1-prob;
rmeddis@0 1645 % end
rmeddis@28 1646
rmeddis@0 1647 case 'statsModelRareEvent'
rmeddis@0 1648 if experiment.psyFunSlope<0
rmeddis@0 1649 addToMsg('statsModelRareEvent cannot be used with negative slope',0)
rmeddis@0 1650 error('statsModelRareEvent cannot be used with negative slope')
rmeddis@0 1651 end
rmeddis@28 1652
rmeddis@0 1653 % standard formula is prob = 1 – exp(-d (g P – A))
rmeddis@0 1654 % here A->A; To find Pmin use A/gain
rmeddis@0 1655 pressure=28*10^(withinRuns.variableValue/20);
rmeddis@0 1656 gain=statsModel.rareEvenGain;
rmeddis@0 1657 A=statsModel.rareEventVmin;
rmeddis@0 1658 d=stimulusParameters.targetDuration;
rmeddis@0 1659 gP_Vmin=gain*pressure-A;
rmeddis@0 1660 if gP_Vmin>0
rmeddis@0 1661 prob=1-exp(-d*(gP_Vmin));
rmeddis@0 1662 else
rmeddis@0 1663 prob=0;
rmeddis@0 1664 end
rmeddis@0 1665 end
rmeddis@0 1666
rmeddis@0 1667 % Use the probability to choose whether or not a detection has occurred
rmeddis@0 1668 switch experiment.threshEstMethod
rmeddis@0 1669 case {'MaxLikelihood', 'oneIntervalUpDown'}
rmeddis@0 1670 if rand<prob
rmeddis@0 1671 modelResponse=2; %bingo
rmeddis@0 1672 else
rmeddis@0 1673 modelResponse=1; %nothing heard
rmeddis@0 1674 end
rmeddis@28 1675
rmeddis@0 1676 case {'2I2AFC++', '2I2AFC+++'}
rmeddis@0 1677 if rand<prob
rmeddis@0 1678 modelResponse=2; %bingo
rmeddis@0 1679 else %if the stimulus is not audible, take a 50:50 chance of getting it right
rmeddis@0 1680 if rand<0.5
rmeddis@0 1681 modelResponse=2; %bingo
rmeddis@0 1682 else
rmeddis@0 1683 modelResponse=1; %nothing heard
rmeddis@0 1684 end
rmeddis@0 1685 end
rmeddis@0 1686 end
rmeddis@0 1687
rmeddis@0 1688
rmeddis@0 1689 % ------------------------------------------------------- printTabTable
rmeddis@0 1690 function printTabTable(M, headers)
rmeddis@0 1691 % printTabTable prints a matrix as a table with tabs
rmeddis@0 1692 %headers are optional
rmeddis@0 1693 %headers=strvcat('firstname', 'secondname')
rmeddis@0 1694 % printTabTable([1 2; 3 4],strvcat('a1','a2'));
rmeddis@0 1695
rmeddis@0 1696 if nargin>1
rmeddis@0 1697 [r c]=size(headers);
rmeddis@0 1698 for no=1:r
rmeddis@0 1699 fprintf('%s\t',headers(no,:))
rmeddis@0 1700 end
rmeddis@0 1701 fprintf('\n')
rmeddis@0 1702 end
rmeddis@0 1703
rmeddis@0 1704 [r c]=size(M);
rmeddis@0 1705
rmeddis@0 1706 for row=1:r
rmeddis@0 1707 for col=1:c
rmeddis@0 1708 if row==1 && col==1 && M(1,1)==-1000
rmeddis@0 1709 % Print nothing (tab follows below)
rmeddis@0 1710 else
rmeddis@0 1711 fprintf('%s',num2str(M(row,col)))
rmeddis@0 1712 end
rmeddis@0 1713 if col<c
rmeddis@0 1714 fprintf('\t')
rmeddis@0 1715 end
rmeddis@0 1716 end
rmeddis@0 1717 fprintf('\n')
rmeddis@0 1718 end
rmeddis@0 1719
rmeddis@0 1720 % ------------------------------------------------------- xlimRM
rmeddis@0 1721 function xlimRM(x)
rmeddis@0 1722 try
rmeddis@0 1723 xlim([x(1) x(2)])
rmeddis@0 1724 catch
rmeddis@0 1725 end
rmeddis@0 1726
rmeddis@0 1727 % ------------------------------------------------------- ylimRM
rmeddis@0 1728 function ylimRM(x)
rmeddis@0 1729 try
rmeddis@0 1730 ylim([x(1) x(2)])
rmeddis@0 1731 catch
rmeddis@0 1732 end
rmeddis@0 1733
rmeddis@0 1734
rmeddis@0 1735 function editdigitInput_CreateFcn(hObject, eventdata, handles)
rmeddis@0 1736
rmeddis@0 1737 % Hint: edit controls usually have a white background on Windows.
rmeddis@0 1738 % See ISPC and COMPUTER.
rmeddis@0 1739 if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
rmeddis@0 1740 set(hObject,'BackgroundColor','white');
rmeddis@0 1741 end
rmeddis@0 1742
rmeddis@0 1743
rmeddis@0 1744 % -----------------------------------------------------buttonBoxIntitialize
rmeddis@0 1745 function buttonBoxIntitialize
rmeddis@0 1746 % initialize button box
rmeddis@0 1747 global serobj
rmeddis@0 1748 try
rmeddis@0 1749 fclose(serobj);
rmeddis@0 1750 catch
rmeddis@0 1751 end
rmeddis@0 1752
rmeddis@0 1753 try
rmeddis@38 1754 % !!! button boxes in booths are connected to COM2. User beware of
rmeddis@38 1755 % connection port.
rmeddis@38 1756 serobj = serial('COM2') ; % Creating serial port object
rmeddis@0 1757 serobj.Baudrate = 9600; % Set the baud rate at the specific value
rmeddis@0 1758 set(serobj, 'Parity', 'none') ; % Set parity as none
rmeddis@0 1759 set(serobj, 'Databits', 8) ; % set the number of data bits
rmeddis@0 1760 set(serobj, 'StopBits', 1) ; % set number of stop bits as 1
rmeddis@0 1761 set(serobj, 'Terminator', 'CR') ; % set the terminator value to carriage return
rmeddis@0 1762 set(serobj, 'InputBufferSize', 512) ; % Buffer for read operation, default it is 512
rmeddis@0 1763 set(serobj,'timeout',10); % 10 sec timeout on button press
rmeddis@0 1764 set(serobj, 'ReadAsyncMode', 'continuous')
rmeddis@0 1765 set(serobj, 'BytesAvailableFcn', @buttonBox_callback)
rmeddis@0 1766 set(serobj, 'BytesAvailableFcnCount', 1)
rmeddis@0 1767 set(serobj, 'BytesAvailableFcnMode', 'byte')
rmeddis@0 1768 % set(serobj, 'BreakInterruptFcn', '@buttonBox_Calback')
rmeddis@28 1769
rmeddis@0 1770 fopen(serobj);
rmeddis@0 1771 buttonBoxStatus=get(serobj,'status');
rmeddis@0 1772 catch
rmeddis@0 1773 disp('** no button box found - use mouse **')
rmeddis@0 1774 end