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 @ 0:f233164f4c86

History | View | Annotate | Download (63.1 KB)

1
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
        addpath (['..' filesep 'MAP'], ['..' filesep 'utilities'], ...
39
    ['..' 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

    
57
        
58
    case 'MAPmodelListen',
59
        % 	subjectGUI is needed for display purposes. Make it large
60
        set(gcf, 'units','pixels')
61
        y=[.665*scrnsize(3) 0.02*scrnsize(4) ...
62
            0.33*scrnsize(3) 0.5*scrnsize(4)]; % alongside
63
        set(gcf,'position',y, 'color',[.871 .961 .996])
64
end
65

    
66
switch experiment.ear
67
    case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'}
68
        % Look to see if the button box exists and, if so, initialise it
69
        buttonBoxIntitialize		% harmless if no button box attached
70
end
71

    
72
% function varargout = subjGUI_MT(varargin)
73
% 
74
% % Begin initialization code - DO NOT EDIT
75
% gui_Singleton = 1;
76
% gui_State = struct('gui_Name',       mfilename, ...
77
%     'gui_Singleton',  gui_Singleton, ...
78
%     'gui_OpeningFcn', @subjGUI_MT_OpeningFcn, ...
79
%     'gui_OutputFcn',  @subjGUI_MT_OutputFcn, ...
80
%     'gui_LayoutFcn',  [] , ...
81
%     'gui_Callback',   []);
82
% if nargin && isstr(varargin{1})
83
%     gui_State.gui_Callback = str2func(varargin{1});
84
% end
85
% 
86
% if nargout
87
%     [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
88
% else
89
%     gui_mainfcn(gui_State, varargin{:});
90
% end
91
% % End initialization code - DO NOT EDIT
92
% 
93
% % --- Executes just before subjGUI_MT is made visible.
94
% function subjGUI_MT_OpeningFcn(hObject, eventdata, handles, varargin)
95
% 
96
% % Choose default command line output for subjGUI_MT
97
% handles.output = hObject;
98
% initializeGUI(handles)
99
% guidata(hObject, handles);
100
% 
101
% function varargout = subjGUI_MT_OutputFcn(hObject, eventdata, handles)
102
% % Get default command line output from handles structure
103
% varargout{1} = handles.output;
104
% 
105
% % -----------------------------------------------------initializeGUI
106
% function initializeGUI(handles)
107
% global experiment
108
% global subjectGUIHandles expGUIhandles
109
% 
110
% dbstop if error
111
% 
112
% % subjectGUI size and location         % [left bottom width height]
113
% scrnsize=get(0,'screensize');
114
% set(0, 'units','pixels')
115
% switch experiment.ear
116
%     % use default size unless...
117
%     case {'MAPmodel',  'MAPmodelMultiCh','MAPmodelSingleCh',  ...
118
%             'statsModelLogistic','statsModelRareEvent'}
119
%         % 	subjectGUI not needed for modelling so minimize subject GUI
120
%         set(gcf, 'units','pixels')
121
%         y=[0*scrnsize(3) 0.8*scrnsize(4) 0.1*scrnsize(3) 0.2*scrnsize(4)];
122
%         set(gcf,'position',y, 'color',[.871 .961 .996])
123
%         
124
%     case 'MAPmodelListen',
125
%         % 	subjectGUI is needed for display purposes. Make it large
126
%         set(gcf, 'units','pixels')
127
%         y=[.665*scrnsize(3) 0.02*scrnsize(4) ...
128
%             0.33*scrnsize(3) 0.5*scrnsize(4)]; % alongside
129
%         set(gcf,'position',y, 'color',[.871 .961 .996])
130
% end
131
% 
132
% switch experiment.ear
133
%     case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'}
134
%         % Look to see if the button box exists and, if so, initialise it
135
%         buttonBoxIntitialize		% harmless if no button box attached
136
% end
137

    
138
% clear display of previous mean values. This is a new measurement series
139
axes(expGUIhandles.axes4), cla           
140
reset (expGUIhandles.axes4)
141

    
142
% handles needed in non-callback routines below
143
subjectGUIHandles=handles;
144

    
145
% start immediately
146
startNewExperiment(handles, expGUIhandles)
147
% This is the end of the experiment. Exit here and return to ExpGUI.
148

    
149
% ----------------------------------------------------- startNewExperiment
150
function startNewExperiment(handles, expGUIhandles)
151
% An experiment consists of a series of 'runs'.
152
% Resets all relevant variables at the beginning of a new experiment.
153
global experiment stimulusParameters betweenRuns
154

    
155
% 'start new experiment' button is the only valid action now
156
experiment.status='waitingForStart';
157

    
158
switch experiment.threshEstMethod
159
    % add appropriate labels to subject GUI buttons
160
    case {'2I2AFC++', '2I2AFC+++'}
161
        set(handles.pushbutton3,'string','')
162
        set(handles.pushbutton2,'string','2')
163
        set(handles.pushbutton1,'string','1')
164
        set(handles.pushbutton0,'string','0')
165
    case {'MaxLikelihood', 'oneIntervalUpDown'}
166
        if stimulusParameters.includeCue
167
            set(handles.pushbutton3,'string','')
168
            set(handles.pushbutton2,'string','2')
169
            set(handles.pushbutton1,'string','1')
170
            set(handles.pushbutton0,'string','0')
171
        else
172
            set(handles.pushbutton3,'string','')
173
            set(handles.pushbutton2,'string','YES')
174
            set(handles.pushbutton1,'string','NO')
175
            set(handles.pushbutton0,'string','')
176
        end
177
end
178

    
179
switch experiment.paradigm
180
    case 'discomfort'
181
        set(handles.pushbutton3,'string','')
182
        set(handles.pushbutton2,'string','uncomfortable')
183
        set(handles.pushbutton1,'string','loud')
184
        set(handles.pushbutton0,'string','comfortable')
185
            experiment.allowCatchTrials=0;
186
end
187

    
188
% experiment.subjGUIfontSize is set on expGUI
189
set(handles.pushbutton3,'FontSize',experiment.subjGUIfontSize)
190
set(handles.pushbutton2,'FontSize',experiment.subjGUIfontSize)
191
set(handles.pushbutton1,'FontSize',experiment.subjGUIfontSize)
192
set(handles.pushbutton0,'FontSize',experiment.subjGUIfontSize)
193
set(handles.pushbuttoNotSure,'FontSize',experiment.subjGUIfontSize)
194
set(handles.pushbuttonGO,'FontSize',experiment.subjGUIfontSize)
195
set(handles.textMSG,'FontSize',experiment.subjGUIfontSize)
196

    
197
set(handles.pushbutton19,'visible','off') % unused button
198

    
199
% start command window summary of progress
200
fprintf(' \n ----------- NEW MEASUREMENTS\n')
201
disp(['paradigm:   ' experiment.paradigm])
202
cla(expGUIhandles.axes1)
203
cla(expGUIhandles.axes2)
204
cla(expGUIhandles.axes4)
205
cla(expGUIhandles.axes5)
206

    
207
experiment.stop=0;              % status of 'stop' button
208
experiment.pleaseRepeat=0;      % status of 'repeat' button
209
experiment.buttonBoxStatus='not busy';
210

    
211
% date and time and replace ':' with '_'
212
date=datestr(now);idx=findstr(':',date);date(idx)='_'; 
213
experiment.date=date;
214
timeNow=clock; betweenRuns.timeNow= timeNow;
215
experiment.timeAtStart=[num2str(timeNow(4)) ':' num2str(timeNow(5))];
216
experiment.minElapsed=0; 
217

    
218
% unpack catch trial rates. The rate declines from the start rate 
219
%  to the base rate using a time constant.
220
stimulusParameters.catchTrialRate=stimulusParameters.catchTrialRates(1);
221
stimulusParameters.catchTrialBaseRate=...
222
    stimulusParameters.catchTrialRates(2);
223
stimulusParameters.catchTrialTimeConstant=...
224
    stimulusParameters.catchTrialRates(3);
225
if stimulusParameters.catchTrialBaseRate==0
226
    stimulusParameters.catchTrialRate=0;
227
end
228

    
229
% for human measurements only, identify the start catch trial rate
230
switch experiment.ear
231
    case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'}
232
        fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
233
            stimulusParameters.catchTrialRate)
234
end
235

    
236
% Reset betweenRuns parameters. this occurs only at experiment start
237
% withinRuns values are reset in 'startNewRun'
238
% this approach creates a more readable structure summary printout.
239
betweenRuns.thresholds=[];
240
betweenRuns.thresholds_mean=[];
241
betweenRuns.thresholds_median=[];
242
betweenRuns.forceThresholds=[];
243
betweenRuns.observationCount=[];
244
betweenRuns.catchTrials=[];
245
betweenRuns.timesOfFirstReversals=[];
246
betweenRuns.bestThresholdTracks=[];
247
betweenRuns.bestThresholdMeanTracks=[];
248
betweenRuns.bestThresholdMedianTracks=[];
249
betweenRuns.levelTracks=[];
250
betweenRuns.responseTracks=[];
251
betweenRuns.slopeKTracks=[];
252
betweenRuns.gainTracks=[];
253
betweenRuns.VminTracks=[];
254
betweenRuns.bestGain=[];
255
betweenRuns.bestVMin=[];
256
betweenRuns.bestPaMin=[];
257
betweenRuns.bestLogisticM=[];
258
betweenRuns.bestLogisticK=[];
259
betweenRuns.resets=0;
260
betweenRuns.runNumber=0;
261

    
262
% Up to two parameters can be changed between runs
263
% Find the variable parameters and randomize them
264
% e.g. 'variableList1 = stimulusParameters.targetFrequency;'
265
eval(['variableList1=stimulusParameters.' betweenRuns.variableName1 ';']);
266
eval(['variableList2=stimulusParameters.' betweenRuns.variableName2 ';']);
267
nVar1=length(variableList1);
268
nVar2=length(variableList2);
269

    
270
% Create two sequence vectors to represent the sequence of var1 and var2 
271
% values. 'var1' changes most rapidly.
272
switch betweenRuns.randomizeSequence
273
    case 'fixed sequence'
274
        var1Sequence=repmat(betweenRuns.variableList1, 1,nVar2);
275
        var2Sequence=reshape(repmat(betweenRuns.variableList2, ...
276
            nVar1,1),1,nVar1*nVar2);
277
    case 'randomize within blocks'
278
        % the blocks are not randomized
279
        var1Sequence=betweenRuns.variableList1;
280
        ranNums=rand(1, length(var1Sequence)); [x idx]=sort(ranNums);
281
        var1Sequence=var1Sequence(idx);
282
        betweenRuns.variableList1=variableList1(idx);
283
        var1Sequence=repmat(var1Sequence, 1,nVar2);
284
        var2Sequence=reshape(repmat(betweenRuns.variableList2, nVar1,1)...
285
            ,1,nVar1*nVar2);
286
    case 'randomize across blocks'
287
        var1Sequence=repmat(betweenRuns.variableList1, 1,nVar2);
288
        var2Sequence=reshape(repmat(betweenRuns.variableList2, nVar1,1),...
289
            1,nVar1*nVar2);
290
        ranNums=rand(1, nVar1*nVar2);
291
        [x idx]=sort(ranNums);
292
        var1Sequence=var1Sequence(idx);
293
        var2Sequence=var2Sequence(idx);
294
        % there should be one start value for every combination 
295
        %  of var1/ var2. In principle this allows these values to be 
296
        % programmed. Not currently in use.
297
        stimulusParameters.WRVstartValues=...
298
            stimulusParameters.WRVstartValues(idx);
299
end
300
betweenRuns.var1Sequence=var1Sequence;
301
betweenRuns.var2Sequence=var2Sequence;
302

    
303
% caught out vector needs to be linked to the length of the whole sequence
304
betweenRuns.caughtOut=zeros(1,length(var1Sequence));
305

    
306
disp('planned sequence:')
307
if min(var1Sequence)>1
308
    % use decidaml places only if necessary
309
disp([betweenRuns.variableName1 ': ' num2str(var1Sequence,'%6.0f')  ])
310
else
311
disp([betweenRuns.variableName1 ': ' num2str(var1Sequence,'%8.3f')  ])
312
end
313
if min(var1Sequence)>1
314
disp([betweenRuns.variableName2 ': ' num2str(var2Sequence,'%6.0f') ])
315
else
316
disp([betweenRuns.variableName2 ': ' num2str(var2Sequence,'%8.3f') ])
317
end
318

    
319
fprintf('\nvariable1 \t  variable2\t  \n')
320
fprintf('%s \t  %s\t  Threshold  \n',betweenRuns.variableName1,...
321
    betweenRuns.variableName2)
322

    
323
% Light up 'GO' on subjGUI and advise.
324
set(handles.editdigitInput,'visible','off')
325
switch experiment.ear
326
    case {'statsModelLogistic', 'statsModelRareEvent',...
327
            'MAPmodel',  'MAPmodelMultiCh','MAPmodelSingleCh'}
328
        % no changes required if model used
329
    otherwise
330
        set(handles.pushbuttonGO,'backgroundcolor','y')
331
        set(handles.pushbuttonGO,'visible','on')
332
        set(handles.frame1,'visible','off')
333
        set(handles.textMSG,'backgroundcolor', 'w')
334
        msg=[{'Ready to start new Experiment'}, {' '}, {'Please, click on the GO button'}];
335
        set(handles.textMSG,'string', msg)
336
        
337
        set(handles.pushbuttoNotSure,'visible','off')
338
        set(handles.pushbuttonWrongButton,'visible','off')
339
        set(handles.pushbutton3,'visible','off')
340
        set(handles.pushbutton2,'visible','off')
341
        set(handles.pushbutton1,'visible','off')
342
        set(handles.pushbutton0,'visible','off')
343
        pause(.1) % to allow display to be drawn
344
end
345

    
346
% Selecting the 'GO' button is the only valid operation action now
347
experiment.status='waitingForGO'; 	% i.e. waiting for new run
348

    
349
% control is now either manual, model (MAP) or randomization
350
switch experiment.ear
351
    case {'MAPmodel','MAPmodelMultiCh','MAPmodelSingleCh','MAPmodelListen'}                                     % MAP model is now the subject
352
        stimulusParameters.calibrationdB=0;             % Pascals required!
353
        MAPmodelRunsGUI(handles)
354
        % model is now the subject
355
    case  {'statsModelLogistic', 'statsModelRareEvent'}	
356
        % no catch trials for the statistical model
357
        stimulusParameters.catchTrialBaseRate=0;		
358
        stimulusParameters.catchTrialRate=0;
359
        statsModelRunsGUI(handles)
360
    otherwise
361
        %manual operation; wait for user to click on 'GO'
362
end
363

    
364
% Experiment complete (after MAP or randomization)
365
% return to  'initializeGUI' and then back to expGUI
366
% Manual control finds its own way home. Program control assumed when
367
% the user hits the GO button
368

    
369
% -----------------------------------------------------------------   startNewRun
370
function startNewRun(handles)
371
% There are many ways to arrive here.
372
%  Under manual control this is achieved by hitting the GO button
373
%   either via the button box or a mouse click
374
%  MAP and randomization methods call this too
375

    
376
global experiment stimulusParameters betweenRuns withinRuns expGUIhandles
377
global LevittControl rareEvent
378

    
379
figure(handles.figure1) % guarantee subject GUI visibility
380

    
381
% ignore call if program is not ready
382
if ~strcmp(experiment.status,'waitingForGO'), return, end
383

    
384
set(handles.pushbuttonGO,'visible','off')
385

    
386
% append message to expGUI message box to alert experimenter that the user
387
% is active
388
addToMsg('Starting new trial',0)
389

    
390
cla(expGUIhandles.axes1),  title(''); % stimulus
391
cla(expGUIhandles.axes2),  title(''); % WRV track
392
drawnow
393

    
394
betweenRuns.runNumber=betweenRuns.runNumber + 1;
395

    
396
withinRuns.trialNumber=1;
397
withinRuns.variableValue=...
398
    stimulusParameters.WRVstartValues(betweenRuns.runNumber);
399
% add random jitter to start level
400
if ~experiment.singleShot
401
    % SS or single shot allows the user to precisely set the WRV
402
    withinRuns.variableValue=withinRuns.variableValue +...
403
        (rand-0.5)*stimulusParameters.jitterStartdB;
404
end
405

    
406
withinRuns.peaks=[];
407
withinRuns.troughs=[];
408
withinRuns.levelList=[];
409
withinRuns.meanEstTrack=[];
410
withinRuns.bestSlopeK=[];
411
withinRuns.bestGain=[];
412
withinRuns.bestVMin=[];
413
withinRuns.forceThreshold=NaN;
414
withinRuns.responseList=[];
415
withinRuns.caughtOut=0;
416
withinRuns.wrongButton=0;
417
withinRuns.catchTrialCount=0;
418
withinRuns.thresholdEstimateTrack=[];
419

    
420
withinRuns.beginningOfPhase2=0;
421
withinRuns.nowInPhase2=0;
422
withinRuns.thisIsRepeatTrial=0;
423

    
424
rareEvent.Euclid=NaN;
425
rareEvent.bestGain=NaN;
426
rareEvent.bestVMin=NaN;
427
rareEvent.thresholddB=0;
428
rareEvent.bestPaMindB=NaN;
429
rareEvent.predictionLevels=[];
430
rareEvent.predictionsRE=[];
431

    
432
LevittControl.sequence=[];
433

    
434
% on-screen count of number of runs still to complete
435
trialsToGo=length(betweenRuns.var1Sequence)-betweenRuns.runNumber;
436
set(handles.toGoCounter,'string', trialsToGo);
437

    
438
switch experiment.threshEstMethod
439
    case {'2I2AFC++', '2I2AFC+++'}
440
        % For 2I2AFC the buttons need to be on the screen ab initio
441
        Levitt2      % inititalize Levitt2 procedure
442
end
443

    
444
switch experiment.ear
445
    case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'}
446
        % allow subject time to recover from 'go' press
447
        pause(experiment.clickToStimulusPause)
448
end
449

    
450
errormsg=nextStimulus(handles);				% get the show on the road
451

    
452
% switch experiment.paradigm
453
%     case 'SRT'
454
%         set(handles.editdigitInput,'visible','on')
455
%         uicontrol(handles.editdigitInput)
456
% end
457

    
458
% terminate if there is any kind of problem
459
if ~isempty(errormsg)
460
    % e.g. limits exceeded, clipping
461
    disp(errormsg)
462
    runCompleted(handles)
463
    return
464
end
465

    
466
% return route is variable (see intro to this function)
467

    
468
% -----------------------------------------------------buttonBox_callback
469
function buttonBox_callback(obj, info)
470
global experiment
471
global serobj
472
global subjectGUIHandles
473

    
474
% do not accept callback if one is already in process
475
if strcmp(experiment.buttonBoxStatus,'busy')
476
    disp(' ignored button press')
477
    return
478
end
479
experiment.buttonBoxStatus='busy';
480
% fclose(serobj)
481

    
482
% identify the code of the button pressed
483
buttonPressedNo = fscanf(serobj,'%c',1);
484

    
485
% This is the map from the button to the Cedrus codes
486
switch experiment.buttonBoxType
487
    case 'horizontal'
488
        pbGo='7'; 		pb0='1';		
489
        pb1='2';		pb2='3';		
490
        pbRepeat='4';	pbWrong='6';	pbBlank='5';
491
    case 'square'
492
        pbGo='7';		pb0='1';		
493
        pb1='3';		pb2='4';		
494
        pbRepeat='8';	pbWrong='6';	pbBlank='5';
495
end
496

    
497
% decide what to do
498
switch experiment.status
499
    case {'presentingStimulus', 'waitingForStart', 'trialcompleted', ...
500
            'endOfExperiment'}
501
        disp(' ignored button press')
502
        
503
    case 'waitingForGO'
504
        % i.e. waiting for new run
505
        if strcmp(buttonPressedNo,pbGo)			% only GO button  accepted
506
            startNewRun(subjectGUIHandles)
507
        else
508
            disp(' ignored button press')
509
        end
510
        
511
    case 'waitingForResponse'
512
        % response to stimuli
513
        switch buttonPressedNo
514
            case pb0						% button 0 (top left)
515
                switch experiment.threshEstMethod
516
                    case {'2I2AFC++', '2I2AFC+++'}
517
                        disp(' ignored button press')
518
                    otherwise
519
                        set(subjectGUIHandles.pushbutton0,...
520
                            'backgroundcolor','r')
521
                        pause(.1)
522
                        set(subjectGUIHandles.pushbutton0,...
523
                            'backgroundcolor',get(0,...
524
                            'defaultUicontrolBackgroundColor'))
525
                        userSelects0or1(subjectGUIHandles)
526
                end
527
                
528
            case pb1						% button 1 (bottom left)
529
                switch experiment.threshEstMethod
530
                    case {'2I2AFC++', '2I2AFC+++'}
531
                        userSelects0or1(subjectGUIHandles)   
532
                    otherwise
533
                        set(subjectGUIHandles.pushbutton1,...
534
                            'backgroundcolor','r')
535
                        pause(.1)
536
                        set(subjectGUIHandles.pushbutton1,...
537
                            'backgroundcolor',get(0,...
538
                            'defaultUicontrolBackgroundColor'))
539
                        userSelects0or1(subjectGUIHandles)
540
                end
541
                
542
            case pb2						% button 2 (bottom right)
543
                switch experiment.threshEstMethod
544
                    case {'2I2AFC++', '2I2AFC+++'}
545
                        userSelects2 (subjectGUIHandles)
546
                    otherwise
547
                        set(subjectGUIHandles.pushbutton2,...
548
                            'backgroundcolor','r')
549
                        pause(.1)
550
                        set(subjectGUIHandles.pushbutton2,...
551
                            'backgroundcolor',get(0,...
552
                            'defaultUicontrolBackgroundColor'))
553
                        userSelects2 (subjectGUIHandles)
554
                end
555
                
556
            case pbRepeat                   % extreme right button
557
                switch experiment.threshEstMethod
558
                    case {'2I2AFC++', '2I2AFC+++'}
559
                        disp(' ignored button press')
560
                    otherwise
561
                        
562
                        set(subjectGUIHandles.pushbuttoNotSure,...
563
                            'backgroundcolor','r')
564
                        pause(.1)
565
                        set(subjectGUIHandles.pushbuttoNotSure,...
566
                            'backgroundcolor',get(0,...
567
                            'defaultUicontrolBackgroundColor'))
568
                        userSelectsPleaseRepeat (subjectGUIHandles)
569
                end
570
                
571
            case {pbWrong, pbBlank}
572
                disp(' ignored button press')
573
                
574
            otherwise						% unrecognised button
575
                disp('ignored button press')
576
        end									% end (button press number)
577
    otherwise
578
        disp('ignored button press')
579
end											% experiment status
580

    
581
% All processing returns through here. 
582
% 	fopen(serobj);		% flushes the input buffer
583

    
584
% buttonPressedNo = fscanf(serobj,'%c',1);
585

    
586
% button box remains 'busy' until after the stimulus has been presented
587
experiment.buttonBoxStatus='not busy';
588

    
589
% -------------------------------------------------- pushbuttonGO_Callback
590
function pushbuttonGO_Callback(hObject, eventdata, handles)
591
% This is a mouse click path
592
% GO function is also called directly from button box
593
%  and from MAP model and stats model
594

    
595
set(handles.pushbuttonGO,'visible','off')
596
startNewRun(handles)
597

    
598
% ---------------------------------------------------pushbutton0_Callback
599
function pushbutton0_Callback(hObject, eventdata, handles)
600
global experiment
601
% This is a mouse click path
602

    
603
% ignore 0 button if 2I2AFC used
604
if findstr(experiment.threshEstMethod,'2I2AFC'), return, end   	
605

    
606
% userDoesNotHearTarget(handles)		% only possible interpretation
607
userDecides(handles, false)
608

    
609
% -------------------------------------------------- pushbutton1_Callback
610
function pushbutton1_Callback(hObject, eventdata, handles)
611
userSelects0or1(handles)				% also called from buttonBox
612

    
613
% ---------------------------------------------------pushbutton2_Callback
614
function pushbutton2_Callback(hObject, eventdata, handles)
615
userSelects2(handles)					% also called from buttonBox
616

    
617
% --------------------------------------------- pushbuttoNotSure_Callback
618
function pushbuttoNotSure_Callback(hObject, eventdata, handles)
619
userSelectsPleaseRepeat(handles)		% also called from buttonBox
620

    
621
% -------------------------------------------------- pushbutton3_Callback
622
function pushbutton3_Callback(hObject, eventdata, handles)
623

    
624
% ------------------------------------------------- pushbutton19_Callback
625
function pushbutton19_Callback(hObject, eventdata, handles)
626
% should be invisible (ignore)
627

    
628
% --------------------------------------- pushbuttonWrongButton_Callback
629
function pushbuttonWrongButton_Callback(hObject, eventdata, handles)
630
userSelectsWrongButton(handles)
631

    
632
% --------------------------------------- editdigitInput_Callback
633
function editdigitInput_Callback(hObject, eventdata, handles)
634
userSelects0or1(handles)				% after digit string input
635

    
636

    
637

    
638
% ----------------------------------------------------- userSelects0or1
639
function userSelects0or1(handles)
640
global experiment withinRuns
641

    
642
switch experiment.threshEstMethod			
643
    case {'2I2AFC++', '2I2AFC+++'}
644
        switch withinRuns.stimulusOrder
645
            case 'targetFirst';
646
                %                 userHearsTarget(handles)
647
                userDecides(handles, true)
648
            otherwise
649
                %                 userDoesNotHearTarget(handles)
650
                userDecides(handles, false)
651
        end
652
    otherwise
653
        % single interval
654
        % 0 or 1 are treated as equivalent (i.e. target is not heard)
655
        userDecides(handles, false)
656
end
657
% return to pushButton1 callback
658

    
659
% ----------------------------------------------------- userSelects2
660
function userSelects2(handles)
661
global experiment withinRuns
662
switch experiment.threshEstMethod			
663
    case {'2I2AFC++', '2I2AFC+++'}
664
        switch withinRuns.stimulusOrder
665
            case 'targetSecond';
666
                %                 userDoesNotHearTarget(handles)
667
                userDecides(handles, true)
668
            otherwise
669
                %                 userHearsTarget(handles)
670
                userDecides(handles, false)
671
        end
672
    otherwise
673
        % single interval (2 targets heard)
674
        userDecides(handles, true)
675
end
676
% return to pushButton2 callback
677

    
678
% ----------------------------------------------------- ---- userDecides
679
function userDecides(handles, saidYes)
680
global experiment stimulusParameters betweenRuns withinRuns
681
global rareEvent logistic psy levelsBinVector
682

    
683
if experiment.singleShot
684
    return
685
end
686

    
687
% ignore click if not 'waitingForResponse'
688
if ~strcmp(experiment.status,'waitingForResponse')
689
    disp('ignored click')
690
    return
691
end
692

    
693
% speech reception threshold
694
if strcmp(stimulusParameters.targetType,'digitStrings')
695
    digitsInput=get(handles.editdigitInput,'string');
696
    % must be three digits
697
    if ~(length(digitsInput)==3)
698
        addToMsg(['error message: Wrong no of digits'], 0, 1)
699
        set(handles.textMSG,'string', 'Wrong no of digits', ...
700
            'BackgroundColor','r', 'ForegroundColor', 'w')
701
        set(handles.editdigitInput,'string','')
702

    
703
        return
704
    end
705
    % obtain correct answer from file name
706
    x=stimulusParameters.digitString;
707
    idx=find(x=='O'); x(idx)='0'; % replace 'oh' with zero
708

    
709
    disp([x '   ' digitsInput])
710

    
711
    if x==digitsInput
712
        saidYes=1;
713
    else
714
        saidYes=0;
715
    end
716
set(handles.editdigitInput,'string','')
717
set(handles.editdigitInput,'visible','off')
718
pause(0.1)
719
end
720

    
721

    
722

    
723
% no button presses accepted while processing
724
experiment.status='processingResponse';
725

    
726
% catch trials. Restart trial if caught
727
if withinRuns.catchTrial
728
    if saidYes
729
        disp('catch trial - caught out')
730
        withinRuns.caughtOut=withinRuns.caughtOut+1;
731
        
732
        % special: estimate caught out rate by allowing the trial 
733
        %  to continue after catch
734
        if stimulusParameters.catchTrialBaseRate==0.5
735
            %  To use this facility, set the catchTrialRate and the 
736
            %   catchTrialBaseRate both to 0.5
737
            %    update false positive rate
738
            betweenRuns.caughtOut(betweenRuns.runNumber)=...
739
                withinRuns.caughtOut;         
740
            plotProgressThisTrial(handles)
741
            nextStimulus(handles);
742
            return
743
        end
744
        
745
        % Punishment: restart the trial
746
        set(handles.frame1,'backgroundColor','r')
747
        set(handles.pushbuttonGO, ...
748
            'visible','on', 'backgroundcolor','y') % and go again
749
        msg=[{'Start again: catch trial error'}, {' '},...
750
            {'Please,click on the GO button'}];
751
        set(handles.textMSG,'string',msg)
752
        [y,fs]=wavread('ding.wav');
753
        wavplay(y/100,fs)
754
        
755
        % raise catch trial rate temporarily. 
756
        %  this is normally reduced on each new trial (see GO)
757
        stimulusParameters.catchTrialRate=...
758
            stimulusParameters.catchTrialRate+0.1;
759
        if stimulusParameters.catchTrialRate>0.5 
760
            stimulusParameters.catchTrialRate=0.5; 
761
        end
762
        fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
763
            stimulusParameters.catchTrialRate)
764
        
765
        betweenRuns.caughtOut(betweenRuns.runNumber)=...
766
            1+betweenRuns.caughtOut(betweenRuns.runNumber);
767
        betweenRuns.runNumber=betweenRuns.runNumber-1;
768
        experiment.status='waitingForGO';
769
        return % unwind and wait for button press
770
    else % (said No)
771
        % user claims not to have heard target. fortunate as it was not
772
        %  present. So, repeat the stimulus (possibly with target)
773
        %  and behave as if the last trial did not occur
774
        errormsg=nextStimulus(handles);
775
        
776
        % terminate if there is any kind of problem
777
        if ~isempty(errormsg)
778
            % e.g. limits exceeded, clipping
779
            disp(['Error nextStimulus: ' errormsg])
780
            runCompleted(handles)
781
            return
782
        end
783
        return      % no further action - next trial
784
    end
785
end
786

    
787
% This section analyses the responses, makes tracks and defines next stim.
788

    
789
% Define response and update response list
790
if saidYes
791
    % target was heard, so response=1;
792
    withinRuns.responseList=[withinRuns.responseList 1];	% 'heard it!'
793
else
794
    % target was not hear heard, so response=0;
795
    withinRuns.responseList=[withinRuns.responseList 0];
796
end
797
withinRuns.levelList=[withinRuns.levelList withinRuns.variableValue];
798
trialNumber=length(withinRuns.responseList);
799

    
800
% keep track of peaks and troughs;
801
% identify direction of change during initial period
802
if saidYes
803
    % default step size before first reversal
804
    WRVinitialStep=-stimulusParameters.WRVinitialStep; 
805
    WRVsmallStep=-stimulusParameters.WRVsmallStep;
806
    % if the previous direction was 'less difficult', this must be a peak
807
    if strcmp(withinRuns.direction,'less difficult') ...
808
            && length(withinRuns.levelList)>1
809
        withinRuns.peaks=[withinRuns.peaks withinRuns.variableValue];
810
    end
811
    withinRuns.direction='more difficult';
812
    
813
else
814
    % said 'no'
815
    % default step size before first reversal
816
    WRVinitialStep=stimulusParameters.WRVinitialStep; 
817
    WRVsmallStep=stimulusParameters.WRVsmallStep;
818
    
819
    % if the previous direction was 'up', this must be a peak
820
    if strcmp(withinRuns.direction,'more difficult') ...
821
            && length(withinRuns.levelList)>1
822
        withinRuns.troughs=[withinRuns.troughs withinRuns.variableValue];
823
    end
824
    withinRuns.direction='less difficult';
825
end
826

    
827
% phase 2 is all the levels after and incuding the first reversal 
828
%  plus the level before that
829
if ~withinRuns.nowInPhase2 && length(withinRuns.peaks)+ ...
830
        length(withinRuns.troughs)>0
831
% if ~withinRuns.nowInPhase2 && (~isempty(withinRuns.peaks) ...
832
%         || ~isempty(withinRuns.troughs))
833
    % define phase 2
834
    withinRuns.beginningOfPhase2=trialNumber-1;
835
    withinRuns.nowInPhase2=1;
836
    WRVsmallStep=WRVinitialStep/2;
837
end
838

    
839
if withinRuns.nowInPhase2
840
    % keep a record of all levels and responses in phase 2 only
841
    withinRuns.levelsPhaseTwo=...
842
        withinRuns.levelList(withinRuns.beginningOfPhase2:end);
843
    withinRuns.responsesPhaseTwo=...
844
        withinRuns.responseList(withinRuns.beginningOfPhase2:end);
845
else
846
    withinRuns.levelsPhaseTwo=[];
847
end
848

    
849

    
850
% get (or substitute) threshold estimate
851
switch experiment.threshEstMethod
852
    case {'2I2AFC++', '2I2AFC+++'}
853
        % for plotting psychometric function only
854
        if withinRuns.beginningOfPhase2>0
855
            [psy, levelsBinVector, logistic, rareEvent]= ...
856
                bestFitPsychometicFunctions...
857
                (withinRuns.levelsPhaseTwo,  withinRuns.responsesPhaseTwo);
858
        end
859
        
860
        if ~isempty(withinRuns.peaks) && ~isempty(withinRuns.troughs)
861
            thresholdEstimate= ...
862
                mean([mean(withinRuns.peaks) mean(withinRuns.troughs)]);
863
        else
864
            thresholdEstimate=NaN;
865
        end
866
    otherwise
867
        % single interval methods
868
        try
869
            % using the s trial after the first reversal
870
            [psy, levelsBinVector, logistic, rareEvent]= ...
871
                bestFitPsychometicFunctions(withinRuns.levelsPhaseTwo,...
872
                withinRuns.responsesPhaseTwo);
873
        catch
874
            logistic.bestThreshold=NaN;
875
        end
876
end
877

    
878
if withinRuns.nowInPhase2
879
    % save tracks of threshold estimates for plotting andprinting
880
    switch experiment.functionEstMethod
881
        case {'logisticLS', 'logisticML'}
882
            if withinRuns.nowInPhase2
883
                withinRuns.meanEstTrack=...
884
                    [withinRuns.meanEstTrack ...
885
                    mean(withinRuns.levelsPhaseTwo)];
886
                withinRuns.thresholdEstimateTrack=...
887
                    [withinRuns.thresholdEstimateTrack ...
888
                    logistic.bestThreshold];
889
            end
890
        case 'rareEvent'
891
            withinRuns.meanEstTrack=...
892
                [withinRuns.meanEstTrack rareEvent.thresholddB];
893
            withinRuns.thresholdEstimateTrack=...
894
                [withinRuns.thresholdEstimateTrack logistic.bestThreshold];
895
        case 'peaksAndTroughs'
896
            withinRuns.meanEstTrack=...
897
                [withinRuns.meanEstTrack thresholdEstimate];
898
            withinRuns.thresholdEstimateTrack=...
899
                [withinRuns.thresholdEstimateTrack thresholdEstimate];
900
    end
901
end
902

    
903
% special discomfort condition
904
% run is completed when subject hits '2' button
905
switch experiment.paradigm
906
    case 'discomfort'
907
        if saidYes
908
            runCompleted(handles)
909
            return
910
        end
911
end
912

    
913
% choose the next level for the stimulus
914
switch experiment.threshEstMethod
915
    case {'2I2AFC++', '2I2AFC+++'}
916
        if saidYes
917
            [WRVinitialStep, msg]=Levitt2('hit', withinRuns.variableValue);
918
        else
919
            [WRVinitialStep, msg]=Levitt2('miss',withinRuns.variableValue);
920
        end
921
        
922
        % empty message means continue as normal
923
        if ~isempty(msg)				
924
            runCompleted(handles)
925
            return
926
        end
927
        newWRVvalue=withinRuns.variableValue-WRVinitialStep;
928
        
929
    case {'MaxLikelihood', 'oneIntervalUpDown'}
930
        % run completed by virtue of number of trials               
931
        % or restart because listener is in trouble
932
        if length(withinRuns.levelsPhaseTwo)== experiment.maxTrials
933
            % Use bonomial test to decide if there is an imbalance in the
934
            % number of 'yes'es and 'no's
935
            yesCount=sum(withinRuns.responseList);
936
            noCount=length(withinRuns.responseList)-yesCount;
937
            z=abs(yesCount-noCount)/(yesCount+noCount)^0.5;
938
            if z>1.96
939
                betweenRuns.resets=betweenRuns.resets+1;
940
                disp([ 'reset / z= ' num2str( z)  ...
941
                    '   Nresets= ' num2str( betweenRuns.resets) ] )
942
                withinRuns.peaks=[];
943
                withinRuns.troughs=[];
944
                withinRuns.levelList=withinRuns.levelList(end);
945
                withinRuns.meanEstTrack=withinRuns.meanEstTrack(end);
946
                withinRuns.forceThreshold=NaN;
947
                withinRuns.responseList=withinRuns.responseList(end);
948
                withinRuns.beginningOfPhase2=0;
949
                withinRuns.nowInPhase2=0;
950
                withinRuns.thresholdEstimateTrack=...
951
                    withinRuns.thresholdEstimateTrack(end);
952
            else
953
                runCompleted(handles)
954
                return
955
            end
956
        end
957
        
958
        % set new value for WRV
959
        if withinRuns.nowInPhase2
960
            % phase 2
961
            currentMeanEst=withinRuns.thresholdEstimateTrack(end);
962
            switch experiment.threshEstMethod
963
                case 'MaxLikelihood'
964
                    newWRVvalue=currentMeanEst;                    
965
                case {'oneIntervalUpDown'}
966
                    newWRVvalue=withinRuns.variableValue+WRVsmallStep;
967
            end
968
        else
969
            % phase 1
970
            if withinRuns.variableValue+2*WRVinitialStep>...
971
                    stimulusParameters.WRVlimits(2)
972
                % use smaller steps when close to maximum
973
                WRVinitialStep=WRVinitialStep/2;
974
            end
975
            newWRVvalue=withinRuns.variableValue+WRVinitialStep;
976
        end
977
    otherwise
978
        error(  'assessment method not recognised')
979
end
980

    
981
switch experiment.paradigm
982
    % prevent unrealistic gap durations 'gapDetection' tasks.
983
    % Note that the gap begins when the ramp ends not when stimulus ends
984
    case 'gapDetection'
985
        if newWRVvalue<-2*stimulusParameters.rampDuration
986
            newWRVvalue=-2*stimulusParameters.rampDuration;
987
            addToMsg('gap duration fixed at - 2 * ramp!',1, 1)
988
        end
989
end
990

    
991
withinRuns.variableValue=newWRVvalue;
992
withinRuns.trialNumber=withinRuns.trialNumber+1;
993

    
994
% Trial continues
995
plotProgressThisTrial(handles)
996

    
997
% next stimulus and so the cycle continues
998
errormsg=nextStimulus(handles);
999
% after the stimulus is presented, control returns here and the system
1000
% waits for user action.
1001

    
1002
% terminate if there is any kind of problem
1003
if ~isempty(errormsg)
1004
    % e.g. limits exceeded, clipping
1005
    disp(['Error nextStimulus: ' errormsg])
1006
    runCompleted(handles)
1007
    return
1008
end
1009

    
1010
% ------------------------------------------------ userSelectsPleaseRepeat
1011
function userSelectsPleaseRepeat(handles)
1012
global experiment withinRuns
1013
% ignore click if not 'waitingForResponse'
1014
if ~strcmp(experiment.status,'waitingForResponse')
1015
    disp('ignored click')
1016
    return
1017
end
1018
% Take no action other than to make a 
1019
%  tally of repeat requests
1020
experiment.pleaseRepeat=experiment.pleaseRepeat+1;
1021
withinRuns.thisIsRepeatTrial=1;
1022
nextStimulus(handles);
1023

    
1024
% ------------------------------------------------ userSelectsWrongButton
1025
function userSelectsWrongButton(handles)
1026
global withinRuns experiment
1027
% restart is the simplest solution for a 'wrong button' request
1028
withinRuns.wrongButton=withinRuns.wrongButton+1;
1029
set(handles.pushbuttonGO, 'visible','on', 'backgroundcolor','y') 
1030
msg=[{'Start again: wrong button pressed'}, {' '},...
1031
    {'Please,click on the GO button'}];
1032
set(handles.textMSG,'string',msg)
1033
experiment.status='waitingForGO';
1034

    
1035
% ------------------------------------------------- plotProgressThisTrial
1036
function plotProgressThisTrial(handles)
1037

    
1038
% used for all responses
1039
global experiment stimulusParameters betweenRuns withinRuns expGUIhandles
1040
global  psy levelsBinVector binFrequencies rareEvent logistic statsModel
1041

    
1042

    
1043
% plot the levelTrack and the threshold track
1044

    
1045
% Panel 2
1046
% plot the levelList
1047
axes(expGUIhandles.axes2); cla
1048
plot( withinRuns.levelList,'o','markerFaceColor','k'), hold on
1049
% plot the best threshold estimate tracks
1050
if length(withinRuns.meanEstTrack)>=1
1051
    % The length of the levelList is 2 greater than number of thresholds
1052
    ptr=withinRuns.beginningOfPhase2+1;
1053
    plot(ptr: ptr+length(withinRuns.meanEstTrack)-1, ...
1054
        withinRuns.meanEstTrack, 'r')
1055
    plot( ptr: ptr+length(withinRuns.thresholdEstimateTrack)-1, ...
1056
        withinRuns.thresholdEstimateTrack, 'g')
1057
    hold off
1058
    estThresh=withinRuns.thresholdEstimateTrack(end);
1059
    switch experiment.threshEstMethod
1060
        % add appropriate labels to subject GUI buttons
1061
        case {'2I2AFC++', '2I2AFC+++'}
1062
            title([stimulusParameters.WRVname ' = ' ...
1063
                num2str(withinRuns.variableValue, '%5.1f')])
1064
        otherwise
1065
            title([stimulusParameters.WRVname ' = ' ...
1066
                num2str(withinRuns.variableValue, '%5.1f') ...
1067
                ';    TH= ' num2str(estThresh, '%5.1f')])
1068
    end
1069
end
1070
xlim([0 experiment.maxTrials+withinRuns.beginningOfPhase2]);
1071
ylim(stimulusParameters.WRVlimits)
1072
grid on
1073

    
1074
% Panel 4: Summary of threshold estimates (not used here)
1075
% Earlier estimates are set in 'runCompleted'
1076
% However, title shows runs/trials remaining
1077

    
1078
axes(expGUIhandles.axes4)
1079
runsToGo=length(betweenRuns.var1Sequence)-betweenRuns.runNumber;
1080
if withinRuns.beginningOfPhase2>0
1081
    trialsToGo= experiment.singleIntervalMaxTrials(1) ...
1082
        + withinRuns.beginningOfPhase2- withinRuns.trialNumber;
1083
    title(['trials remaining = ' num2str(trialsToGo) ...
1084
        ':    runs to go= ' num2str(runsToGo)])
1085
end
1086

    
1087
% plot psychometric function   - panel 5
1088
axes(expGUIhandles.axes5), cla
1089
plot(withinRuns.levelList, withinRuns.responseList,'b.'), hold on
1090
ylim([0 1])
1091
title('')
1092

    
1093
switch experiment.threshEstMethod
1094
    case {'MaxLikelihood', 'oneIntervalUpDown'}
1095
        if withinRuns.beginningOfPhase2>0
1096
            % display only when in phase 2.
1097
            withinRuns.levelsPhaseTwo=...
1098
                withinRuns.levelList(withinRuns.beginningOfPhase2:end);
1099
            withinRuns.responsesPhaseTwo=...
1100
                withinRuns.responseList(withinRuns.beginningOfPhase2:end);
1101
            
1102
            % organise data as psychometric function
1103
            [psy, levelsBinVector, binFrequencies]= ...
1104
                psychometricFunction(withinRuns.levelsPhaseTwo,...
1105
                withinRuns.responsesPhaseTwo, experiment.psyBinWidth);
1106
            
1107
            % Plot the function
1108
            %   point by point with circles of appropiate weighted size
1109
            hold on,
1110
            for i=1:length(psy)
1111
                plot(levelsBinVector(i), psy(i), 'ro', ...
1112
                    'markersize', 50*binFrequencies(i)/sum(binFrequencies))
1113
            end
1114
            % save info for later
1115
            betweenRuns.psychometicFunction{betweenRuns.runNumber}=...
1116
                [levelsBinVector; psy];
1117
            
1118
            % fitPsychometric functions is  computed in 'userDecides'
1119
            % plot(rareEvent.predictionLevels, rareEvent.predictionsRE,'k')
1120
            plot(logistic.predictionLevels, logistic.predictionsLOG, 'r')
1121
            plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k')
1122
            if ~isnan(logistic.bestThreshold )
1123
%                 xlim([ (logistic.bestThreshold -20) ...
1124
%                     (logistic.bestThreshold +20) ])
1125
                xlim([ 0 100 ])
1126
%                 if logistic.bestK< max(experiment.possLogSlopes)
1127
                    title(['k= ' num2str(logistic.bestK, '%6.2f') ' g= '...
1128
                        num2str(rareEvent.bestGain,'%6.3f') '  A=' ...
1129
                        num2str(rareEvent.bestVMin,'%8.1f')])
1130
%                     title('')
1131
%                 end
1132
            else
1133
                title(' ')
1134
            end
1135
            
1136
            switch experiment.ear
1137
                %plot green line for statsModel a priori model
1138
                case 'statsModelLogistic'
1139
                    % plot proTem logistic (green) used by stats model
1140
                    p= 1./(1+exp(-statsModel.logisticSlope...
1141
                        *(levelsBinVector-logistic.bestThreshold)));
1142
                    if experiment.psyFunSlope<0, p=1-p;end
1143
                    titleText=[ ',  statsModel: logistic'];
1144
                    hold on,    plot(levelsBinVector, p,'g')
1145
                case  'statsModelRareEvent'
1146
                    pressure=28*10.^(levelsBinVector/20);
1147
                    p=1-exp(-stimulusParameters.targetDuration...
1148
                        *(statsModel.rareEvenGain...
1149
                        * pressure-statsModel.rareEventVmin));
1150
                    p(p<0)=0;
1151
                    if experiment.psyFunSlope<0, p=1-p;end
1152
                    hold on,    plot(levelsBinVector, p,'g')
1153
            end %(estMethod)
1154
        end
1155
    otherwise           % 2A2IFC
1156
        
1157
        message3= ...
1158
            ([ 'peaks='  num2str(withinRuns.peaks) ...
1159
            'troughs='  num2str(withinRuns.troughs)]);
1160
        ylimRM([-0.1 1.1])	% 0=no / 1=yes
1161
        set(gca,'ytick',[0 1], 'yTickLabel', {'no';'yes'})
1162
        ylabel('psychometric function'), xlabel('target level')
1163
        if length(levelsBinVector)>1
1164
            xlim([ min(levelsBinVector) max(levelsBinVector)])
1165
            xlim([ 0 100])
1166
        end
1167
end
1168

    
1169
% command window summary
1170
% Accumulate things to say in the message window
1171
message1= (['responses:      ' num2str(withinRuns.responseList,'%9.0f')]);
1172
switch experiment.paradigm
1173
    % more decimal places needed on GUI
1174
    case { 'gapDetection', 'frequencyDiscrimination', 'forwardMaskingD'}
1175
        message2= ([stimulusParameters.WRVname  ...
1176
            ':       ' num2str(withinRuns.levelList,'%7.3f')]);
1177
        message3= (['Thresh (logistic mean):   ' ...
1178
            num2str(withinRuns.thresholdEstimateTrack,'%7.3f')]);
1179
    otherwise
1180
        message2= ([stimulusParameters.WRVname ':      ' ...
1181
            num2str(withinRuns.levelList,'%7.1f')]);
1182
        message3= (['Thresh (logistic mean):   ' ...
1183
            num2str(withinRuns.thresholdEstimateTrack,'%7.1f')]);
1184
end
1185

    
1186
addToMsg(str2mat(message1, message2, message3), 0)
1187

    
1188
% -----------------------------------------------------runCompleted
1189
function runCompleted(handles)
1190
% Used at the end of each run
1191
global experiment stimulusParameters betweenRuns withinRuns
1192
global rareEvent expGUIhandles
1193
% disp('run completed')
1194

    
1195
experiment.status='runCompleted';
1196

    
1197
plotProgressThisTrial(handles)
1198

    
1199
switch experiment.ear
1200
    case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ...
1201
            'MAPmodelMultiCh','MAPmodelSingleCh', 'MAPmodelListen'}
1202
        % no changes required if model used
1203
    otherwise
1204
        set(handles.frame1,'visible','off')
1205
        set(handles.pushbuttoNotSure,'visible','off')
1206
        set(handles.pushbuttonWrongButton,'visible','off')
1207
        set(handles.pushbutton3,'visible','off')
1208
        set(handles.pushbutton2,'visible','off')
1209
        set(handles.pushbutton1,'visible','off')
1210
        set(handles.pushbutton0,'visible','off')
1211
        set(handles.pushbuttonGO,'visible','off')
1212
end
1213

    
1214
if isnan(withinRuns.forceThreshold)
1215
    % the experiment has been aborted for some reason
1216
    threshold=withinRuns.forceThreshold;
1217
    stdev=NaN;
1218
    logistic.bestK=NaN;
1219
    logistic.bestThreshold=NaN;
1220
    medianThreshold=NaN;
1221
    meanThreshold=NaN;
1222
else
1223
    % use only phase 2 levels and responses for calculating thresholds
1224
    withinRuns.levelsPhaseTwo=...
1225
        withinRuns.levelList(withinRuns.beginningOfPhase2:end);
1226
    withinRuns.responsesPhaseTwo=...
1227
        withinRuns.responseList(withinRuns.beginningOfPhase2:end);
1228
    [psy, levelsPhaseTwoBinVector, logistic, rareEvent]= ...
1229
        bestFitPsychometicFunctions...
1230
        (withinRuns.levelsPhaseTwo, withinRuns.responsesPhaseTwo);
1231
    
1232
    % plot final psychometric function
1233
    axes(expGUIhandles.axes5),cla
1234
    hold on, plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k')
1235
    hold on, plot(logistic.predictionLevels, logistic.predictionsLOG, 'r')
1236
    % organise data as psychometric function
1237
    [psy, levelsBinVector, binFrequencies]= ...
1238
        psychometricFunction(withinRuns.levelsPhaseTwo,...
1239
        withinRuns.responsesPhaseTwo, experiment.psyBinWidth);
1240
    %   point by point with circles of appropiate weighted size
1241
    hold on,
1242
    for i=1:length(psy)
1243
        plot(levelsBinVector(i), psy(i), 'ro', ...
1244
            'markersize', 50*binFrequencies(i)/sum(binFrequencies))
1245
    end
1246

    
1247
    
1248
    % experimental
1249
    medianThreshold=median(withinRuns.levelsPhaseTwo);
1250
    warning off
1251
    meanThreshold=mean(withinRuns.levelsPhaseTwo);
1252
    
1253
    % identify the current threshold estimate
1254
    switch experiment.paradigm
1255
        case 'discomfort'
1256
            % most recent value (not truely a mean value)
1257
            threshold=withinRuns.levelList(end);
1258
            stdev=NaN;            
1259
        otherwise
1260
            switch experiment.threshEstMethod
1261
                case {'MaxLikelihood', 'oneIntervalUpDown'}
1262
                    % last value in the list
1263
                    threshold=withinRuns.meanEstTrack(end);
1264
                    threshold=withinRuns.thresholdEstimateTrack(end);
1265
                    stdev=NaN;
1266
                    
1267
                case {'2I2AFC++', '2I2AFC+++'}
1268
                    % use peaks and troughs
1269
                    try		% there may not be enough values to use
1270
                        peaksUsed=experiment.peaksUsed;
1271
                        threshold=...
1272
                            mean(...
1273
                            [withinRuns.peaks(end-peaksUsed+1:end) ...
1274
                            withinRuns.troughs(end-peaksUsed+1:end)]);
1275
                        stdev=...
1276
                            std([withinRuns.peaks(end-peaksUsed +1:end) ...
1277
                            withinRuns.troughs(end-peaksUsed:end)]);
1278
                    catch
1279
                        threshold=NaN;
1280
                        stdev=NaN;
1281
                    end
1282
            end
1283
    end
1284
end
1285

    
1286
% Store thresholds
1287
betweenRuns.thresholds=[betweenRuns.thresholds threshold];
1288
betweenRuns.thresholds_mean=[betweenRuns.thresholds_mean meanThreshold];
1289
betweenRuns.thresholds_median=...
1290
    [betweenRuns.thresholds_median medianThreshold];
1291
betweenRuns.forceThresholds=...
1292
    [betweenRuns.forceThresholds withinRuns.forceThreshold];
1293

    
1294
% count observations after the startup phase for record keeping
1295
betweenRuns.observationCount=...
1296
    [betweenRuns.observationCount length(withinRuns.levelList)];
1297
betweenRuns.timesOfFirstReversals=...
1298
    [betweenRuns.timesOfFirstReversals withinRuns.beginningOfPhase2];
1299
betweenRuns.catchTrials=...
1300
    [betweenRuns.catchTrials withinRuns.catchTrialCount];
1301

    
1302
% add variable length tracks to cell arrays
1303
if withinRuns.beginningOfPhase2>0
1304
    betweenRuns.bestThresholdTracks{length(betweenRuns.thresholds)}=...
1305
        withinRuns.thresholdEstimateTrack;
1306
    betweenRuns.bestThresholdMeanTracks...
1307
        {length(betweenRuns.thresholds_mean)}=...
1308
        withinRuns.thresholdEstimateTrack;
1309
    betweenRuns.bestThresholdMedianTracks...
1310
        {length(betweenRuns.thresholds_median)}=...
1311
        withinRuns.thresholdEstimateTrack;
1312
    
1313
    betweenRuns.levelTracks{length(betweenRuns.thresholds)}=...
1314
        withinRuns.levelList(withinRuns.beginningOfPhase2:end);
1315
    betweenRuns.responseTracks{length(betweenRuns.thresholds)}=...
1316
        withinRuns.responseList(withinRuns.beginningOfPhase2:end);
1317
else
1318
    betweenRuns.bestThresholdTracks{length(betweenRuns.thresholds)}=[];
1319
    betweenRuns.bestThresholdMeanTracks{length(betweenRuns.thresholds)}=[];
1320
    betweenRuns.bestThresholdMedianTracks{length(betweenRuns.thresholds)}=...
1321
        [];
1322
    betweenRuns.levelTracks{length(betweenRuns.thresholds)}=[];
1323
    betweenRuns.responseTracks{length(betweenRuns.thresholds)}=[];
1324
end
1325

    
1326
betweenRuns.bestGain=[betweenRuns.bestGain rareEvent.bestGain];
1327
betweenRuns.bestVMin=[betweenRuns.bestVMin rareEvent.bestVMin];
1328
betweenRuns.bestPaMin=[betweenRuns.bestPaMin rareEvent.bestPaMindB];
1329
betweenRuns.bestLogisticM=...
1330
    [betweenRuns.bestLogisticM logistic.bestThreshold];
1331
betweenRuns.bestLogisticK=[betweenRuns.bestLogisticK logistic.bestK];
1332

    
1333
resultsSoFar=[betweenRuns.var1Sequence(betweenRuns.runNumber)'...
1334
    betweenRuns.var2Sequence(betweenRuns.runNumber)'...
1335
    betweenRuns.thresholds(betweenRuns.runNumber)'
1336
    ];
1337

    
1338
fprintf('%10.3f \t%10.3f \t%10.1f  \n', resultsSoFar')
1339

    
1340
switch experiment.ear
1341
    case {'left', 'right', 'diotic', 'dichoticLeft','dichoticRight'}
1342
        disp(['caught out= ' num2str(betweenRuns.caughtOut)])
1343
end
1344

    
1345
% plot history of thresholds in panel 4
1346
axes(expGUIhandles.axes4), cla
1347
plotColors='rgbmckywrgbmckyw';
1348
for i=1:length(betweenRuns.thresholds)
1349
    faceColor=plotColors(floor(i/length(betweenRuns.variableList1)-.01)+1);
1350
    switch betweenRuns.variableName1
1351
        case {'targetFrequency', 'maskerRelativeFrequency'}
1352
            if min(betweenRuns.var1Sequence)>0
1353
                %             semilogx(betweenRuns.var1Sequence(1:betweenRuns.runNumber), ...
1354
                %                 betweenRuns.thresholds,  'o', ...
1355
                %                 'markerSize', 5,'markerFaceColor',faceColor)
1356
                semilogx(betweenRuns.var1Sequence(i), ...
1357
                    betweenRuns.thresholds(i),  'o', ...
1358
                    'markerSize', 5,'markerFaceColor',faceColor)
1359
            else
1360
                plot(betweenRuns.var1Sequence(1:betweenRuns.runNumber),  ...
1361
                    betweenRuns.thresholds,  'o', ...
1362
                    'markerSize', 5,'markerFaceColor',faceColor)
1363
                plot(betweenRuns.var1Sequence(i),  ...
1364
                    betweenRuns.thresholds(i),  'o', ...
1365
                    'markerSize', 5,'markerFaceColor',faceColor)
1366
            end
1367
        otherwise
1368
            %         plot(betweenRuns.var1Sequence(1:betweenRuns.runNumber),  ...
1369
            %             betweenRuns.thresholds,  'o', 'markerSize', 5,...
1370
            %             'markerFaceColor',faceColor)
1371
            plot(betweenRuns.var1Sequence(i),  ...
1372
                betweenRuns.thresholds(i),  'o', 'markerSize', 5,...
1373
                'markerFaceColor',faceColor)
1374
    end
1375
    hold on
1376
end
1377
xlimRM([ min(betweenRuns.variableList1) max(betweenRuns.variableList1) ])
1378
ylim(stimulusParameters.WRVlimits)
1379
ylabel('thresholds')
1380
xlabel(betweenRuns.variableName1)
1381
set(gca,'ytick', [0 20 40 60 80 100])
1382
try
1383
    % problems if only one x value
1384
    set(gca,'XTick', sort(betweenRuns.variableList1))
1385
catch
1386
end
1387
grid on, set(gca,'XMinorGrid', 'off')
1388

    
1389
% If comparison data is available in pearmeter file, plot it now
1390
if ~isempty (experiment.comparisonData)
1391
    comparisonData=experiment.comparisonData(:,1:end-1); % ignore final BF
1392
    [x, ncols]=size(comparisonData);
1393
    if  length(betweenRuns.variableList1)==ncols
1394
        hold on
1395
        plot (sort(betweenRuns.variableList1), comparisonData, 'r')
1396
        hold off
1397
    end
1398
end
1399

    
1400
% End of the Experiment also?
1401
if betweenRuns.runNumber==length(betweenRuns.var1Sequence)
1402
    % yes, end of experiment
1403
    fileName=['savedData/' experiment.name experiment.date ...
1404
        experiment.paradigm];
1405
    % 	save (fileName, 'experiment', 'stimulusParameters', 'betweenRuns', 'withinRuns', 'variableNames', 'paradigmNames', 'LevittControl')
1406
    disp('Experiment completed')
1407
    
1408
    % update subject GUI to acknowledge end of run
1409
    subjGUImsg=[{'Experiment completed'}, {' '}, {'Thank you!'}];
1410
    set(handles.textMSG,'string', subjGUImsg   )
1411
    % play 'Tada'
1412
    [y,fs,nbits]=wavread('TADA.wav');
1413
    musicGain=10^(stimulusParameters.musicLeveldB/20);
1414
    y=y*musicGain;
1415
    wavplay(y/100,fs, 'async')
1416
    
1417
    % update experimenter GUI
1418
    addToMsg('Experiment completed.',1)
1419
    
1420
    printReport
1421
    experiment.status='endOfExperiment';  
1422
    return
1423
else
1424
    % No, hang on.
1425
    switch experiment.ear
1426
        case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ...
1427
                'MAPmodelMultiCh','MAPmodelSingleCh', 'MAPmodelListen'}
1428
            % no changes required if model used
1429
        otherwise
1430
            % decrement catchTrialRate towards baseRate
1431
            stimulusParameters.catchTrialRate=...
1432
                stimulusParameters.catchTrialBaseRate + ...
1433
                (stimulusParameters.catchTrialRate...
1434
                -stimulusParameters.catchTrialBaseRate)...
1435
                *(1-exp(-stimulusParameters.catchTrialTimeConstant));
1436
            fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
1437
                stimulusParameters.catchTrialRate)
1438
            
1439
            % and go again
1440
            set(handles.pushbuttonGO,'backgroundcolor','y') 
1441
            set(handles.frame1,'visible','off')
1442
            set(handles.pushbuttonGO,'visible','on')
1443
            msg=[{'Ready to start new trial'}, {' '},...
1444
                {'Please,click on the GO button'}];
1445
            set(handles.textMSG,'string',msg)
1446
    end
1447
    experiment.status='waitingForGO';
1448
    %     fprintf('\n')
1449
    
1450
    [y,fs,nbits]=wavread('CHIMES.wav');
1451
    musicGain=10^(stimulusParameters.musicLeveldB/20);
1452
    y=y*musicGain;
1453
    wavplay(y/100,fs,'async')
1454
end
1455

    
1456
% -----------------------------------------------------MAPmodelRunsGUI
1457
% The computer presses the buttons
1458
function 	MAPmodelRunsGUI(handles)
1459
global experiment stimulusParameters method expGUIhandles
1460
global AN_IHCsynapseParams
1461
method=[];
1462

    
1463
while strcmp(experiment.status,'waitingForGO') 
1464
    % no catch trials for MAP model
1465
    experiment.allowCatchTrials=0;
1466
    
1467
    % initiates run and plays first stimulus and it returns 
1468
    %  without waiting for button press
1469
    startNewRun(handles)	
1470

    
1471
    if sum(strcmp(experiment.ear,...
1472
            {'MAPmodelMultiCh', 'MAPmodelListen'}))
1473
        % use BFlist specified in MAPparams file
1474
        BFlist= -1;
1475
    else
1476
        BFlist=stimulusParameters.targetFrequency;
1477
    end
1478
    showParams=0;
1479
    %  find model parameters using the 'name' box (e.g. CTa ->MAPparamsCTa)
1480
    paramFunctionName=['method=MAPparams' experiment.name ...
1481
        '(BFlist, stimulusParameters.sampleRate, showParams);'];
1482
    eval(paramFunctionName) % go and fetch the parameters
1483
    
1484

    
1485
    % show sample Rate on GUI; it must be set in MAPparams
1486
    set(expGUIhandles.textsampleRate,'string',...
1487
        num2str(stimulusParameters.sampleRate))
1488
    
1489
    if experiment.singleShot
1490
%         AN_IHCsynapseParams.showSummaryStatistics=1;
1491
        method.showSummaryStatistics=1;
1492
        AN_IHCsynapseParams.plotSynapseContents=1;
1493
    else
1494
        method.showSummaryStatistics=0;
1495
        AN_IHCsynapseParams.plotSynapseContents=0;
1496
    end
1497
    
1498
    if strcmp(experiment.ear, 'MAPmodelSingleCh')
1499
    method.MGmembranePotentialSave=1;
1500
    end
1501
    
1502
    % continuous loop until the program stops itself
1503
    while strcmp(experiment.status,'waitingForResponse')
1504
        %  NB at this point the stimulus has been played
1505
        pause(0.1)  % to allow interrupt with CTRL/C
1506
        
1507
        switch experiment.ear
1508
            case { 'MAPmodelListen'}
1509
            set(handles.pushbutton1,'backgroundcolor','y','visible','on')
1510
            set(handles.pushbutton2,'backgroundcolor','y','visible','on')
1511
        end
1512

    
1513
AN_IHCsynapseParams.mode=	'spikes';
1514

    
1515
% Analayse the current stimulus using MAP
1516
        [modelResponse earObject]= MAPmodel( experiment.MAPplot, method);
1517
        
1518
        if experiment.stop || experiment.singleShot
1519
            % trap for single trial or user interrupt using 'stop' button.
1520
            experiment.status= 'waitingForStart';
1521
            experiment.stop=0;
1522
            addToMsg('manually stopped',1);
1523
            return
1524
        end
1525
        
1526
        switch modelResponse
1527
            case 1
1528
                %     userDoesNotHearTarget(handles)
1529
                switch experiment.ear
1530
                    case {'MAPmodelListen'}
1531
                        % illuminate appropriate button
1532
                        set(handles.pushbutton1,...
1533
                            'backgroundcolor','r','visible','on')
1534
                        set(handles.pushbutton2,'backgroundcolor','y')
1535
                end
1536
                userDecides(handles, false)
1537
                if experiment.singleShot, return, end
1538

    
1539
            case 2
1540
                %   userHearsTarget(handles)
1541
                switch experiment.ear
1542
                    case {'MAPmodelListen'}
1543
                        % illuminate appropriate button (DEMO only)
1544
                        set(handles.pushbutton2,'backgroundcolor',...
1545
                            'r','visible','on')
1546
                        set(handles.pushbutton1,'backgroundcolor','y')
1547
                end
1548
                
1549
                switch experiment.paradigm
1550
                    case 'discomfort'
1551
                        % always treat discomfort as 'not heard'
1552
                        userDecides(handles, false)
1553
                    otherwise
1554
                        userDecides(handles, true)
1555
                end
1556
            otherwise
1557
                % probably an abort
1558
                return
1559
        end
1560
    end
1561
end
1562

    
1563

    
1564
% -----------------------------------------------------statsModelRunsGUI
1565
% The computer presses the buttons
1566
function 	statsModelRunsGUI(handles)
1567
% Decision are made at random using a prescribe statistical function
1568
% to set probabilities as a function of signal level.
1569
global experiment
1570

    
1571
experiment.allowCatchTrials=0;
1572

    
1573
while strcmp(experiment.status,'waitingForGO')
1574
    % i.e. waiting for new run
1575
    if experiment.stop
1576
        % user has requested an abort
1577
        experiment.status= 'waitingForStart';
1578
        addToMsg('manually stopped',1)
1579
        return
1580
    end
1581
    
1582
    % initiates run and plays first stimulus and it returns
1583
    %  without waiting for button press
1584
    % NB stimulus is not actually generated (for speed)
1585
    startNewRun(handles)
1586
    
1587
    while strcmp(experiment.status,'waitingForResponse')
1588
        % create artificial response here
1589
        modelResponse=statsModelGetResponse;
1590
        switch modelResponse
1591
            case 1
1592
                %                 userDoesNotHearTarget(handles)
1593
                userDecides(handles, false)
1594
            case 2
1595
                %                 userHearsTarget(handles)
1596
                userDecides(handles, true)
1597
        end
1598
    end
1599
end
1600

    
1601
% -----------------------------------------------------statsModelGetResponse
1602
function modelResponse=statsModelGetResponse(handles)
1603
global experiment  withinRuns  statsModel stimulusParameters
1604
% use the generating function to decide if a detection occurs or not
1605

    
1606
% pause(0.1)  % to allow stopping with CTRL/C but slows things down
1607

    
1608
% first compute the probability that a detection occurs
1609
switch experiment.ear
1610
    case {'statsModelLogistic'}
1611
        prob= 1./(1+exp(-statsModel.logisticSlope.*(withinRuns.variableValue-statsModel.logisticMean)));
1612
        %         if experiment.psyFunSlope<0,
1613
        %             prob=1-prob;
1614
        %         end
1615
        
1616
    case 'statsModelRareEvent'
1617
        if experiment.psyFunSlope<0
1618
            addToMsg('statsModelRareEvent cannot be used with negative slope',0)
1619
            error('statsModelRareEvent cannot be used with negative slope')
1620
        end
1621
        
1622
        % standard formula is prob = 1 ? exp(-d (g P ? A))
1623
        % here A->A;  To find Pmin use A/gain
1624
        pressure=28*10^(withinRuns.variableValue/20);
1625
        gain=statsModel.rareEvenGain;
1626
        A=statsModel.rareEventVmin;
1627
        d=stimulusParameters.targetDuration;
1628
        gP_Vmin=gain*pressure-A;
1629
        if gP_Vmin>0
1630
            prob=1-exp(-d*(gP_Vmin));
1631
        else
1632
            prob=0;
1633
        end
1634
end
1635

    
1636
% Use the probability to choose whether or not a detection has occurred
1637
switch experiment.threshEstMethod
1638
    case {'MaxLikelihood', 'oneIntervalUpDown'}
1639
        if rand<prob
1640
            modelResponse=2; %bingo
1641
        else
1642
            modelResponse=1; %nothing heard
1643
        end
1644
        
1645
    case {'2I2AFC++', '2I2AFC+++'}
1646
        if rand<prob
1647
            modelResponse=2; %bingo
1648
        else %if the stimulus is not audible, take a 50:50 chance of getting it right
1649
            if rand<0.5
1650
                modelResponse=2; %bingo
1651
            else
1652
                modelResponse=1; %nothing heard
1653
            end
1654
        end
1655
end
1656

    
1657

    
1658
% ------------------------------------------------------- printTabTable
1659
function printTabTable(M, headers)
1660
% printTabTable prints a matrix as a table with tabs
1661
%headers are optional
1662
%headers=strvcat('firstname', 'secondname')
1663
%  printTabTable([1 2; 3 4],strvcat('a1','a2'));
1664

    
1665
if nargin>1
1666
    [r c]=size(headers);
1667
    for no=1:r
1668
        fprintf('%s\t',headers(no,:))
1669
    end
1670
    fprintf('\n')
1671
end
1672

    
1673
[r c]=size(M);
1674

    
1675
for row=1:r
1676
    for col=1:c
1677
        if row==1 && col==1 && M(1,1)==-1000
1678
            %   Print nothing (tab follows below)
1679
        else
1680
            fprintf('%s',num2str(M(row,col)))
1681
        end
1682
        if col<c
1683
            fprintf('\t')
1684
        end
1685
    end
1686
    fprintf('\n')
1687
end
1688

    
1689
% ------------------------------------------------------- xlimRM
1690
function xlimRM(x)
1691
try
1692
    xlim([x(1) x(2)])
1693
catch
1694
end
1695

    
1696
% ------------------------------------------------------- ylimRM
1697
function ylimRM(x)
1698
try
1699
    ylim([x(1) x(2)])
1700
catch
1701
end
1702

    
1703

    
1704
function editdigitInput_CreateFcn(hObject, eventdata, handles)
1705

    
1706
% Hint: edit controls usually have a white background on Windows.
1707
%       See ISPC and COMPUTER.
1708
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
1709
    set(hObject,'BackgroundColor','white');
1710
end
1711

    
1712

    
1713
% -----------------------------------------------------buttonBoxIntitialize
1714
function buttonBoxIntitialize
1715
% initialize button box
1716
global  serobj
1717
try
1718
    fclose(serobj);
1719
catch
1720
end
1721

    
1722
try
1723
    serobj = serial('COM4') ;           	% Creating serial port object now its connected to COM4 !!! button boxes in booths are connected to COM2
1724
    serobj.Baudrate = 9600;           		% Set the baud rate at the specific value
1725
    set(serobj, 'Parity', 'none') ;     	% Set parity as none
1726
    set(serobj, 'Databits', 8) ;          	% set the number of data bits
1727
    set(serobj, 'StopBits', 1) ;         	% set number of stop bits as 1
1728
    set(serobj, 'Terminator', 'CR') ; 		% set the terminator value to carriage return
1729
    set(serobj, 'InputBufferSize', 512) ;  	% Buffer for read operation, default it is 512
1730
    set(serobj,'timeout',10);           	% 10 sec timeout on button press
1731
    set(serobj, 'ReadAsyncMode', 'continuous')
1732
    set(serobj, 'BytesAvailableFcn', @buttonBox_callback)
1733
    set(serobj, 'BytesAvailableFcnCount', 1)
1734
    set(serobj, 'BytesAvailableFcnMode', 'byte')
1735
    % set(serobj, 'BreakInterruptFcn', '@buttonBox_Calback')
1736
    
1737
    fopen(serobj);
1738
    buttonBoxStatus=get(serobj,'status');
1739
catch
1740
    disp('** no button box found - use mouse **')
1741
end