annotate multithreshold 1.46/subjGUI_MT.m @ 29:b51bf546ca3f

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