To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

The primary repository for this project is hosted at git://github.com/rmeddis/MAP.git .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Revision:

root / multithreshold 1.46 / subjGUI_MT.m @ 38:c2204b18f4a2

History | View | Annotate | Download (63.8 KB)

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