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 @ 28:02aa9826efe0

History | View | Annotate | Download (63.4 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
    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
axes(expGUIhandles.axes4), cla
72
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
        experiment.allowCatchTrials=0;
118
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
date=datestr(now);idx=findstr(':',date);date(idx)='_';
145
experiment.date=date;
146
timeNow=clock; betweenRuns.timeNow= timeNow;
147
experiment.timeAtStart=[num2str(timeNow(4)) ':' num2str(timeNow(5))];
148
experiment.minElapsed=0;
149

    
150
% unpack catch trial rates. The rate declines from the start rate
151
%  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
% Create two sequence vectors to represent the sequence of var1 and var2
201
% values. 'var1' changes most rapidly.
202
switch betweenRuns.randomizeSequence
203
    case 'fixed sequence'
204
        var1Sequence=repmat(betweenRuns.variableList1, 1,nVar2);
205
        var2Sequence=reshape(repmat(betweenRuns.variableList2, ...
206
            nVar1,1),1,nVar1*nVar2);
207
    case 'randomize within blocks'
208
        % the blocks are not randomized
209
        var1Sequence=betweenRuns.variableList1;
210
        ranNums=rand(1, length(var1Sequence)); [x idx]=sort(ranNums);
211
        var1Sequence=var1Sequence(idx);
212
        betweenRuns.variableList1=variableList1(idx);
213
        var1Sequence=repmat(var1Sequence, 1,nVar2);
214
        var2Sequence=reshape(repmat(betweenRuns.variableList2, nVar1,1)...
215
            ,1,nVar1*nVar2);
216
    case 'randomize across blocks'
217
        var1Sequence=repmat(betweenRuns.variableList1, 1,nVar2);
218
        var2Sequence=reshape(repmat(betweenRuns.variableList2, nVar1,1),...
219
            1,nVar1*nVar2);
220
        ranNums=rand(1, nVar1*nVar2);
221
        [x idx]=sort(ranNums);
222
        var1Sequence=var1Sequence(idx);
223
        var2Sequence=var2Sequence(idx);
224
        % there should be one start value for every combination
225
        %  of var1/ var2. In principle this allows these values to be
226
        % programmed. Not currently in use.
227
        stimulusParameters.WRVstartValues=...
228
            stimulusParameters.WRVstartValues(idx);
229
end
230
betweenRuns.var1Sequence=var1Sequence;
231
betweenRuns.var2Sequence=var2Sequence;
232

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

    
236
disp('planned sequence:')
237
if min(var1Sequence)>1
238
    % use decidaml places only if necessary
239
    disp([betweenRuns.variableName1 ': ' num2str(var1Sequence,'%6.0f')  ])
240
else
241
    disp([betweenRuns.variableName1 ': ' num2str(var1Sequence,'%8.3f')  ])
242
end
243
if min(var1Sequence)>1
244
    disp([betweenRuns.variableName2 ': ' num2str(var2Sequence,'%6.0f') ])
245
else
246
    disp([betweenRuns.variableName2 ': ' num2str(var2Sequence,'%8.3f') ])
247
end
248

    
249
fprintf('\nvariable1 \t  variable2\t  \n')
250
fprintf('%s \t  %s\t  Threshold  \n',betweenRuns.variableName1,...
251
    betweenRuns.variableName2)
252

    
253
% Light up 'GO' on subjGUI and advise.
254
set(handles.editdigitInput,'visible','off')
255
switch experiment.ear
256
    case {'statsModelLogistic', 'statsModelRareEvent',...
257
            'MAPmodel',  'MAPmodelMultiCh','MAPmodelSingleCh'}
258
        % no changes required if model used
259
    otherwise
260
        set(handles.pushbuttonGO,'backgroundcolor','y')
261
        set(handles.pushbuttonGO,'visible','on')
262
        set(handles.frame1,'visible','off')
263
        set(handles.textMSG,'backgroundcolor', 'w')
264
        msg=[{'Ready to start new Experiment'}, {' '}, {'Please, click on the GO button'}];
265
        set(handles.textMSG,'string', msg)
266

    
267
        set(handles.pushbuttoNotSure,'visible','off')
268
        set(handles.pushbuttonWrongButton,'visible','off')
269
        set(handles.pushbutton3,'visible','off')
270
        set(handles.pushbutton2,'visible','off')
271
        set(handles.pushbutton1,'visible','off')
272
        set(handles.pushbutton0,'visible','off')
273
        pause(.1) % to allow display to be drawn
274
end
275

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

    
279
% control is now either manual, model (MAP) or randomization
280
switch experiment.ear
281
    case {'MAPmodel','MAPmodelMultiCh','MAPmodelSingleCh','MAPmodelListen'}                                     % MAP model is now the subject
282
        stimulusParameters.calibrationdB=0;             % Pascals required!
283
        MAPmodelRunsGUI(handles)
284
        % model is now the subject
285
    case  {'statsModelLogistic', 'statsModelRareEvent'}
286
        % no catch trials for the statistical model
287
        stimulusParameters.catchTrialBaseRate=0;
288
        stimulusParameters.catchTrialRate=0;
289
        statsModelRunsGUI(handles)
290
    otherwise
291
        %manual operation; wait for user to click on 'GO'
292
end
293

    
294
% Experiment complete (after MAP or randomization)
295
% return to  'initializeGUI' and then back to expGUI
296
% Manual control finds its own way home. Program control assumed when
297
% the user hits the GO button
298

    
299
% -----------------------------------------------------------------   startNewRun
300
function startNewRun(handles)
301
% There are many ways to arrive here.
302
%  Under manual control this is achieved by hitting the GO button
303
%   either via the button box or a mouse click
304
%  MAP and randomization methods call this too
305

    
306
global experiment stimulusParameters betweenRuns withinRuns expGUIhandles
307
global LevittControl rareEvent errormsg
308

    
309
figure(handles.figure1) % guarantee subject GUI visibility
310

    
311
% ignore call if program is not ready
312
if ~strcmp(experiment.status,'waitingForGO'), return, end
313

    
314
set(handles.pushbuttonGO,'visible','off')
315

    
316
% append message to expGUI message box to alert experimenter that the user
317
% is active
318
addToMsg('Starting new trial',0)
319

    
320
cla(expGUIhandles.axes1),  title(''); % stimulus
321
cla(expGUIhandles.axes2),  title(''); % WRV track
322
drawnow
323

    
324
betweenRuns.runNumber=betweenRuns.runNumber + 1;
325

    
326
withinRuns.trialNumber=1;
327
withinRuns.variableValue=...
328
    stimulusParameters.WRVstartValues(betweenRuns.runNumber);
329
% add random jitter to start level
330
if ~experiment.singleShot
331
    % SS or single shot allows the user to precisely set the WRV
332
    withinRuns.variableValue=withinRuns.variableValue +...
333
        (rand-0.5)*stimulusParameters.jitterStartdB;
334
end
335

    
336
withinRuns.peaks=[];
337
withinRuns.troughs=[];
338
withinRuns.levelList=[];
339
withinRuns.meanEstTrack=[];
340
withinRuns.bestSlopeK=[];
341
withinRuns.bestGain=[];
342
withinRuns.bestVMin=[];
343
withinRuns.forceThreshold=NaN;
344
withinRuns.responseList=[];
345
withinRuns.caughtOut=0;
346
withinRuns.wrongButton=0;
347
withinRuns.catchTrialCount=0;
348
withinRuns.thresholdEstimateTrack=[];
349

    
350
withinRuns.beginningOfPhase2=0;
351
withinRuns.nowInPhase2=0;
352
withinRuns.thisIsRepeatTrial=0;
353

    
354
rareEvent.Euclid=NaN;
355
rareEvent.bestGain=NaN;
356
rareEvent.bestVMin=NaN;
357
rareEvent.thresholddB=0;
358
rareEvent.bestPaMindB=NaN;
359
rareEvent.predictionLevels=[];
360
rareEvent.predictionsRE=[];
361

    
362
LevittControl.sequence=[];
363

    
364
% on-screen count of number of runs still to complete
365
trialsToGo=length(betweenRuns.var1Sequence)-betweenRuns.runNumber;
366
set(handles.toGoCounter,'string', trialsToGo);
367

    
368
switch experiment.threshEstMethod
369
    case {'2I2AFC++', '2I2AFC+++'}
370
        % For 2I2AFC the buttons need to be on the screen ab initio
371
        Levitt2      % inititalize Levitt2 procedure
372
end
373

    
374
switch experiment.ear
375
    case{'left', 'right','diotic', 'dichoticLeft','dichoticRight'}
376
        % allow subject time to recover from 'go' press
377
        pause(experiment.clickToStimulusPause)
378
end
379

    
380
errormsg=nextStimulus(handles);				% get the show on the road
381

    
382
% terminate if there is any kind of problem
383
if ~isempty(errormsg)
384
    % e.g. limits exceeded, clipping
385
    disp(errormsg)
386
    runCompleted(handles)
387
    return
388
end
389
% return route is variable (see intro to this function)
390

    
391
% -----------------------------------------------------buttonBox_callback
392
function buttonBox_callback(obj, info)
393
% deals with a button press on the button box.
394

    
395
global experiment
396
global serobj
397
global subjectGUIHandles
398

    
399
% do not accept callback if one is already in process
400
if strcmp(experiment.buttonBoxStatus,'busy')
401
    disp(' ignored button press')
402
    return % to quiescent state
403
end
404
experiment.buttonBoxStatus='busy';
405

    
406
% identify the code of the button pressed
407
buttonPressedNo = fscanf(serobj,'%c',1);
408

    
409
% This is the map from the button to the Cedrus codes
410
switch experiment.buttonBoxType
411
    case 'horizontal'
412
        pbGo='7'; 		pb0='1';
413
        pb1='2';		pb2='3';
414
        pbRepeat='4';	pbWrong='6';	pbBlank='5';
415
    case 'square'
416
        pbGo='7';		pb0='1';
417
        pb1='3';		pb2='4';
418
        pbRepeat='8';	pbWrong='6';	pbBlank='5';
419
end
420

    
421
% decide what to do
422
switch experiment.status
423
    case {'presentingStimulus', 'waitingForStart', 'trialcompleted', ...
424
            'endOfExperiment'}
425
        disp(' ignored button press')
426

    
427
    case 'waitingForGO'
428
        % i.e. waiting for new run
429
        if strcmp(buttonPressedNo,pbGo)			% only GO button  accepted
430
            startNewRun(subjectGUIHandles)
431
        else
432
            disp(' ignored button press')
433
        end
434

    
435
    case 'waitingForResponse'
436
        % response to stimuli
437
        switch buttonPressedNo
438
            case pb0						% button 0 (top left)
439
                switch experiment.threshEstMethod
440
                    case {'2I2AFC++', '2I2AFC+++'}
441
                        disp(' ignored button press')
442
                    otherwise
443
                        set(subjectGUIHandles.pushbutton0,...
444
                            'backgroundcolor','r')
445
                        pause(.1)
446
                        set(subjectGUIHandles.pushbutton0,...
447
                            'backgroundcolor',get(0,...
448
                            'defaultUicontrolBackgroundColor'))
449
                        userSelects0or1(subjectGUIHandles)
450
                end
451

    
452
            case pb1						% button 1 (bottom left)
453
                switch experiment.threshEstMethod
454
                    case {'2I2AFC++', '2I2AFC+++'}
455
                        userSelects0or1(subjectGUIHandles)
456
                    otherwise
457
                        set(subjectGUIHandles.pushbutton1,...
458
                            'backgroundcolor','r')
459
                        pause(.1)
460
                        set(subjectGUIHandles.pushbutton1,...
461
                            'backgroundcolor',get(0,...
462
                            'defaultUicontrolBackgroundColor'))
463
                        userSelects0or1(subjectGUIHandles)
464
                end
465

    
466
            case pb2						% button 2 (bottom right)
467
                switch experiment.threshEstMethod
468
                    case {'2I2AFC++', '2I2AFC+++'}
469
                        userSelects2 (subjectGUIHandles)
470
                    otherwise
471
                        set(subjectGUIHandles.pushbutton2,...
472
                            'backgroundcolor','r')
473
                        pause(.1)
474
                        set(subjectGUIHandles.pushbutton2,...
475
                            'backgroundcolor',get(0,...
476
                            'defaultUicontrolBackgroundColor'))
477
                        userSelects2 (subjectGUIHandles)
478
                end
479

    
480
            case pbRepeat                   % extreme right button
481
                switch experiment.threshEstMethod
482
                    case {'2I2AFC++', '2I2AFC+++'}
483
                        disp(' ignored button press')
484
                    otherwise
485

    
486
                        set(subjectGUIHandles.pushbuttoNotSure,...
487
                            'backgroundcolor','r')
488
                        pause(.1)
489
                        set(subjectGUIHandles.pushbuttoNotSure,...
490
                            'backgroundcolor',get(0,...
491
                            'defaultUicontrolBackgroundColor'))
492
                        userSelectsPleaseRepeat (subjectGUIHandles)
493
                end
494

    
495
            case {pbWrong, pbBlank}
496
                disp(' ignored button press')
497

    
498
            otherwise						% unrecognised button
499
                disp('ignored button press')
500
        end									% end (button press number)
501
    otherwise
502
        disp('ignored button press')
503
end											% experiment status
504

    
505
% button box remains 'busy' until after the stimulus has been presented
506
experiment.buttonBoxStatus='not busy';
507

    
508
% -------------------------------------------------- pushbuttonGO_Callback
509
function pushbuttonGO_Callback(hObject, eventdata, handles)
510
% This is a mouse click path
511
% GO function is also called directly from button box
512
%  and from MAP model and stats model
513

    
514
set(handles.pushbuttonGO,'visible','off')
515
startNewRun(handles)
516

    
517
% ---------------------------------------------------pushbutton0_Callback
518
function pushbutton0_Callback(hObject, eventdata, handles)
519
global experiment
520
% This is a mouse click path
521

    
522
% ignore 0 button if 2I2AFC used
523
if findstr(experiment.threshEstMethod,'2I2AFC')
524
    return  % to quiescent state
525
end
526

    
527
% userDoesNotHearTarget(handles)		% only possible interpretation
528
userDecides(handles, false)
529

    
530
% -------------------------------------------------- pushbutton1_Callback
531
function pushbutton1_Callback(hObject, eventdata, handles)
532
userSelects0or1(handles)				% also called from buttonBox
533

    
534
% ---------------------------------------------------pushbutton2_Callback
535
function pushbutton2_Callback(hObject, eventdata, handles)
536
userSelects2(handles)					% also called from buttonBox
537

    
538
% --------------------------------------------- pushbuttoNotSure_Callback
539
function pushbuttoNotSure_Callback(hObject, eventdata, handles)
540
userSelectsPleaseRepeat(handles)		% also called from buttonBox
541

    
542
% -------------------------------------------------- pushbutton3_Callback
543
function pushbutton3_Callback(hObject, eventdata, handles)
544

    
545
% ------------------------------------------------- pushbutton19_Callback
546
function pushbutton19_Callback(hObject, eventdata, handles)
547
% should be invisible (ignore)
548

    
549
% --------------------------------------- pushbuttonWrongButton_Callback
550
function pushbuttonWrongButton_Callback(hObject, eventdata, handles)
551
userSelectsWrongButton(handles)
552

    
553
% --------------------------------------- editdigitInput_Callback
554
function editdigitInput_Callback(hObject, eventdata, handles)
555
userSelects0or1(handles)				% after digit string input
556

    
557

    
558

    
559
% ----------------------------------------------------- userSelects0or1
560
function userSelects0or1(handles)
561
global experiment withinRuns
562

    
563
switch experiment.threshEstMethod
564
    case {'2I2AFC++', '2I2AFC+++'}
565
        switch withinRuns.stimulusOrder
566
            case 'targetFirst';
567
                %                 userHearsTarget(handles)
568
                userDecides(handles, true)
569
            otherwise
570
                %                 userDoesNotHearTarget(handles)
571
                userDecides(handles, false)
572
        end
573
    otherwise
574
        % single interval
575
        % 0 or 1 are treated as equivalent (i.e. target is not heard)
576
        userDecides(handles, false)
577
end
578
% return to pushButton1 callback
579

    
580
% ----------------------------------------------------- userSelects2
581
function userSelects2(handles)
582
global experiment withinRuns
583
switch experiment.threshEstMethod
584
    case {'2I2AFC++', '2I2AFC+++'}
585
        switch withinRuns.stimulusOrder
586
            case 'targetSecond';
587
                %                 userDoesNotHearTarget(handles)
588
                userDecides(handles, true)
589
            otherwise
590
                %                 userHearsTarget(handles)
591
                userDecides(handles, false)
592
        end
593
    otherwise
594
        % single interval (2 targets heard)
595
        userDecides(handles, true)
596
end
597
% return to pushButton2 callback
598

    
599
% ----------------------------------------------------- ---- userDecides
600
function userDecides(handles, saidYes)
601
global experiment stimulusParameters betweenRuns withinRuns
602
global rareEvent logistic psy levelsBinVector errormsg
603

    
604
if experiment.singleShot
605
    return  % not clear why this should be here
606
end
607

    
608
% ignore click if not 'waitingForResponse'
609
if ~strcmp(experiment.status,'waitingForResponse')
610
    disp('ignored click')
611
    return % to userSelects
612
end
613

    
614
% speech reception threshold
615
if strcmp(stimulusParameters.targetType,'digitStrings')
616
    % read triple digits from userGUI
617
    digitsInput=get(handles.editdigitInput,'string');
618
    % must be three digits
619
    if ~(length(digitsInput)==3)
620
        addToMsg(['error message: Wrong no of digits'], 0, 1)
621
        set(handles.textMSG,'string', 'Wrong no of digits', ...
622
            'BackgroundColor','r', 'ForegroundColor', 'w')
623
        set(handles.editdigitInput,'string','')
624
        return
625
    end
626
    % obtain correct answer from file name
627
    x=stimulusParameters.digitString;
628
    idx=find(x=='O'); x(idx)='0'; % replace 'oh' with zero
629
    disp([x '   ' digitsInput])
630
    if x==digitsInput
631
        saidYes=1;  % i.e. correct response
632
    else
633
        saidYes=0;  % i.e  wrong response
634
    end
635
    set(handles.editdigitInput,'string','')
636
    set(handles.editdigitInput,'visible','off')
637
    pause(0.1)
638
end
639

    
640
% no button presses accepted while processing
641
experiment.status='processingResponse';
642

    
643
% catch trials. Restart trial if caught
644
if withinRuns.catchTrial
645
    if saidYes
646
        disp('catch trial - caught out')
647
        withinRuns.caughtOut=withinRuns.caughtOut+1;
648

    
649
        % special: estimate caught out rate by allowing the trial
650
        %  to continue after catch
651
        if stimulusParameters.catchTrialBaseRate==0.5
652
            %  To use this facility, set the catchTrialRate and the
653
            %   catchTrialBaseRate both to 0.5
654
            %    update false positive rate
655
            betweenRuns.caughtOut(betweenRuns.runNumber)=...
656
                withinRuns.caughtOut;
657
            plotProgressThisTrial(handles)
658
            nextStimulus(handles);
659
            return
660
        end
661

    
662
        % Punishment: caught out restarts the trial
663
        set(handles.frame1,'backgroundColor','r')
664
        set(handles.pushbuttonGO, ...
665
            'visible','on', 'backgroundcolor','y') % and go again
666
        msg=[{'Start again: catch trial error'}, {' '},...
667
            {'Please,click on the GO button'}];
668
        set(handles.textMSG,'string',msg)
669
        [y,fs]=wavread('ding.wav');
670
        wavplay(y/100,fs)
671

    
672
        % raise catch trial rate temporarily.
673
        %  this is normally reduced on each new trial (see GO)
674
        stimulusParameters.catchTrialRate=...
675
            stimulusParameters.catchTrialRate+0.1;
676
        if stimulusParameters.catchTrialRate>0.5
677
            stimulusParameters.catchTrialRate=0.5;
678
        end
679
        fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
680
            stimulusParameters.catchTrialRate)
681

    
682
        betweenRuns.caughtOut(betweenRuns.runNumber)=...
683
            1+betweenRuns.caughtOut(betweenRuns.runNumber);
684
        betweenRuns.runNumber=betweenRuns.runNumber-1;
685
        experiment.status='waitingForGO';
686
        return % unwind and wait for button press
687
    else % (said No)
688
        % user claims not to have heard target.
689
        % This is good as it was not present.
690
        % So, repeat the stimulus (possibly with target)
691
        %  and behave as if the last trial did not occur
692
        errormsg=nextStimulus(handles);
693

    
694
        % terminate if there is any kind of problem
695
        if ~isempty(errormsg)
696
            % e.g. limits exceeded, clipping
697
            disp(['Error nextStimulus: ' errormsg])
698
            runCompleted(handles)
699
            return
700
        end
701
        return      % no further action - next trial
702
    end
703
end     % of catch trial
704

    
705
% Real target: analyse the response, make tracks and define next stim.
706

    
707
% Define response and update response list
708
if saidYes
709
    % target was heard, so response=1;
710
    withinRuns.responseList=[withinRuns.responseList 1];	% 'heard it!'
711
else
712
    % target was not hear heard, so response=0;
713
    withinRuns.responseList=[withinRuns.responseList 0];
714
end
715
withinRuns.levelList=[withinRuns.levelList withinRuns.variableValue];
716
trialNumber=length(withinRuns.responseList);
717

    
718
% keep track of peaks and troughs;
719
% identify direction of change during initial period
720
if saidYes
721
    % default step size before first reversal
722
    WRVinitialStep=-stimulusParameters.WRVinitialStep;
723
    WRVsmallStep=-stimulusParameters.WRVsmallStep;
724
    % if the previous direction was 'less difficult', this must be a peak
725
    if strcmp(withinRuns.direction,'less difficult') ...
726
            && length(withinRuns.levelList)>1
727
        withinRuns.peaks=[withinRuns.peaks withinRuns.variableValue];
728
    end
729
    withinRuns.direction='more difficult';
730
else
731
    % said 'no'
732
    % default step size before first reversal
733
    WRVinitialStep=stimulusParameters.WRVinitialStep;
734
    WRVsmallStep=stimulusParameters.WRVsmallStep;
735

    
736
    % if the previous direction was 'up', this must be a peak
737
    if strcmp(withinRuns.direction,'more difficult') ...
738
            && length(withinRuns.levelList)>1
739
        withinRuns.troughs=[withinRuns.troughs withinRuns.variableValue];
740
    end
741
    withinRuns.direction='less difficult';
742
end
743

    
744
% phase 2 is all the levels after and incuding the first reversal
745
%  plus the level before that
746
% Look for the end of phase 1
747
if ~withinRuns.nowInPhase2 && length(withinRuns.peaks)+ ...
748
        length(withinRuns.troughs)>0
749
    % define phase 2
750
    withinRuns.beginningOfPhase2=trialNumber-1;
751
    withinRuns.nowInPhase2=1;
752
    WRVsmallStep=WRVinitialStep/2;
753
end
754

    
755
if withinRuns.nowInPhase2
756
    % keep a record of all levels and responses in phase 2 only
757
    withinRuns.levelsPhaseTwo=...
758
        withinRuns.levelList(withinRuns.beginningOfPhase2:end);
759
    withinRuns.responsesPhaseTwo=...
760
        withinRuns.responseList(withinRuns.beginningOfPhase2:end);
761
else
762
    withinRuns.levelsPhaseTwo=[];
763
end
764

    
765
% get (or substitute) threshold estimate
766
switch experiment.threshEstMethod
767
    case {'2I2AFC++', '2I2AFC+++'}
768
        % for plotting psychometric function only
769
        if withinRuns.beginningOfPhase2>0
770
            [psy, levelsBinVector, logistic, rareEvent]= ...
771
                bestFitPsychometicFunctions...
772
                (withinRuns.levelsPhaseTwo,  withinRuns.responsesPhaseTwo);
773
        end
774

    
775
        if ~isempty(withinRuns.peaks) && ~isempty(withinRuns.troughs)
776
            thresholdEstimate= ...
777
                mean([mean(withinRuns.peaks) mean(withinRuns.troughs)]);
778
        else
779
            thresholdEstimate=NaN;
780
        end
781

    
782
    otherwise
783
        % single interval methods
784
        try
785
            % using the s trial after the first reversal
786
            [psy, levelsBinVector, logistic, rareEvent]= ...
787
                bestFitPsychometicFunctions(withinRuns.levelsPhaseTwo,...
788
                withinRuns.responsesPhaseTwo);
789
        catch
790
            logistic.bestThreshold=NaN;
791
        end
792
end
793

    
794
if withinRuns.nowInPhase2
795
    % save tracks of threshold estimates for plotting andprinting
796
    switch experiment.functionEstMethod
797
        case {'logisticLS', 'logisticML'}
798
            if withinRuns.nowInPhase2
799
                withinRuns.meanEstTrack=...
800
                    [withinRuns.meanEstTrack ...
801
                    mean(withinRuns.levelsPhaseTwo)];
802
                withinRuns.thresholdEstimateTrack=...
803
                    [withinRuns.thresholdEstimateTrack ...
804
                    logistic.bestThreshold];
805
            end
806
        case 'rareEvent'
807
            withinRuns.meanEstTrack=...
808
                [withinRuns.meanEstTrack rareEvent.thresholddB];
809
            withinRuns.thresholdEstimateTrack=...
810
                [withinRuns.thresholdEstimateTrack logistic.bestThreshold];
811
        case 'peaksAndTroughs'
812
            withinRuns.meanEstTrack=...
813
                [withinRuns.meanEstTrack thresholdEstimate];
814
            withinRuns.thresholdEstimateTrack=...
815
                [withinRuns.thresholdEstimateTrack thresholdEstimate];
816
    end
817
end
818

    
819
% special discomfort condition
820
% run is completed when subject hits '2' button
821
switch experiment.paradigm
822
    case 'discomfort'
823
        if saidYes
824
            runCompleted(handles)
825
            return
826
        end
827
end
828

    
829
% choose the next level for the stimulus
830
switch experiment.threshEstMethod
831
    case {'2I2AFC++', '2I2AFC+++'}
832
        if saidYes
833
            [WRVinitialStep, msg]=Levitt2('hit', withinRuns.variableValue);
834
        else
835
            [WRVinitialStep, msg]=Levitt2('miss',withinRuns.variableValue);
836
        end
837

    
838
        % empty message means continue as normal
839
        if ~isempty(msg)
840
            runCompleted(handles)
841
            return
842
        end
843
        newWRVvalue=withinRuns.variableValue-WRVinitialStep;
844

    
845
    case {'MaxLikelihood', 'oneIntervalUpDown'}
846
        % run completed by virtue of number of trials
847
        % or restart because listener is in trouble
848
        if length(withinRuns.levelsPhaseTwo)== experiment.maxTrials
849
            % Use bonomial test to decide if there is an imbalance in the
850
            % number of 'yes'es and 'no's
851
            yesCount=sum(withinRuns.responseList);
852
            noCount=length(withinRuns.responseList)-yesCount;
853
            z=abs(yesCount-noCount)/(yesCount+noCount)^0.5;
854
            if z>1.96
855
                betweenRuns.resets=betweenRuns.resets+1;
856
                disp([ 'reset / z= ' num2str( z)  ...
857
                    '   Nresets= ' num2str( betweenRuns.resets) ] )
858
                withinRuns.peaks=[];
859
                withinRuns.troughs=[];
860
                withinRuns.levelList=withinRuns.levelList(end);
861
                withinRuns.meanEstTrack=withinRuns.meanEstTrack(end);
862
                withinRuns.forceThreshold=NaN;
863
                withinRuns.responseList=withinRuns.responseList(end);
864
                withinRuns.beginningOfPhase2=0;
865
                withinRuns.nowInPhase2=0;
866
                withinRuns.thresholdEstimateTrack=...
867
                    withinRuns.thresholdEstimateTrack(end);
868
            else
869
                runCompleted(handles)
870
                return
871
            end
872
        end
873

    
874
        % set new value for WRV
875
        if withinRuns.nowInPhase2
876
            % phase 2
877
            currentMeanEst=withinRuns.thresholdEstimateTrack(end);
878
            switch experiment.threshEstMethod
879
                case 'MaxLikelihood'
880
                    newWRVvalue=currentMeanEst;
881
                case {'oneIntervalUpDown'}
882
                    newWRVvalue=withinRuns.variableValue+WRVsmallStep;
883
            end
884
        else
885
            % phase 1
886
            if withinRuns.variableValue+2*WRVinitialStep>...
887
                    stimulusParameters.WRVlimits(2)
888
                % use smaller steps when close to maximum
889
                WRVinitialStep=WRVinitialStep/2;
890
            end
891
            newWRVvalue=withinRuns.variableValue+WRVinitialStep;
892
        end
893
    otherwise
894
        error(  'assessment method not recognised')
895
end
896

    
897
switch experiment.paradigm
898
    % prevent unrealistic gap durations 'gapDetection' tasks.
899
    % Note that the gap begins when the ramp ends not when stimulus ends
900
    case 'gapDetection'
901
        if newWRVvalue<-2*stimulusParameters.rampDuration
902
            newWRVvalue=-2*stimulusParameters.rampDuration;
903
            addToMsg('gap duration fixed at - 2 * ramp!',1, 1)
904
        end
905
end
906

    
907
withinRuns.variableValue=newWRVvalue;
908
withinRuns.trialNumber=withinRuns.trialNumber+1;
909

    
910
% Trial continues
911
plotProgressThisTrial(handles)
912

    
913
% next stimulus and so the cycle continues
914
errormsg=nextStimulus(handles);
915
% after the stimulus is presented, control returns here and the system
916
% waits for user action.
917

    
918
% terminate if there is any kind of problem
919
if ~isempty(errormsg)
920
    % e.g. limits exceeded, clipping
921
    disp(['Error nextStimulus: ' errormsg])
922
    runCompleted(handles)
923
    return
924
end
925

    
926
% ------------------------------------------------ userSelectsPleaseRepeat
927
function userSelectsPleaseRepeat(handles)
928
global experiment withinRuns
929
% ignore click if not 'waitingForResponse'
930
if ~strcmp(experiment.status,'waitingForResponse')
931
    disp('ignored click')
932
    return
933
end
934
% Take no action other than to make a
935
%  tally of repeat requests
936
experiment.pleaseRepeat=experiment.pleaseRepeat+1;
937
withinRuns.thisIsRepeatTrial=1;
938
nextStimulus(handles);
939

    
940
% ------------------------------------------------ userSelectsWrongButton
941
function userSelectsWrongButton(handles)
942
global withinRuns experiment
943
% restart is the simplest solution for a 'wrong button' request
944
withinRuns.wrongButton=withinRuns.wrongButton+1;
945
set(handles.pushbuttonGO, 'visible','on', 'backgroundcolor','y')
946
msg=[{'Start again: wrong button pressed'}, {' '},...
947
    {'Please,click on the GO button'}];
948
set(handles.textMSG,'string',msg)
949
experiment.status='waitingForGO';
950

    
951
% ------------------------------------------------- plotProgressThisTrial
952
function plotProgressThisTrial(handles)
953
% updates GUI: used for all responses
954

    
955
global experiment stimulusParameters betweenRuns withinRuns expGUIhandles
956
global  psy levelsBinVector binFrequencies rareEvent logistic statsModel
957

    
958
% plot the levelTrack and the threshold track
959

    
960
% Panel 2
961
% plot the levelList
962
axes(expGUIhandles.axes2); cla
963
plot( withinRuns.levelList,'o','markerFaceColor','k'), hold on
964
% plot the best threshold estimate tracks
965
if length(withinRuns.meanEstTrack)>=1
966
    % The length of the levelList is 2 greater than number of thresholds
967
    ptr=withinRuns.beginningOfPhase2+1;
968
    plot(ptr: ptr+length(withinRuns.meanEstTrack)-1, ...
969
        withinRuns.meanEstTrack, 'r')
970
    plot( ptr: ptr+length(withinRuns.thresholdEstimateTrack)-1, ...
971
        withinRuns.thresholdEstimateTrack, 'g')
972
    hold off
973
    estThresh=withinRuns.thresholdEstimateTrack(end);
974
    switch experiment.threshEstMethod
975
        % add appropriate labels to subject GUI buttons
976
        case {'2I2AFC++', '2I2AFC+++'}
977
            title([stimulusParameters.WRVname ' = ' ...
978
                num2str(withinRuns.variableValue, '%5.1f')])
979
        otherwise
980
            title([stimulusParameters.WRVname ' = ' ...
981
                num2str(withinRuns.variableValue, '%5.1f') ...
982
                ';    TH= ' num2str(estThresh, '%5.1f')])
983
    end
984
end
985
xlim([0 experiment.maxTrials+withinRuns.beginningOfPhase2]);
986
ylim(stimulusParameters.WRVlimits)
987
grid on
988

    
989
% Panel 4: Summary of threshold estimates (not used here)
990
% Estimates from previous runs are set in 'runCompleted'
991
% It is only necessary to change title showing runs/trials remaining
992
axes(expGUIhandles.axes4)
993
runsToGo=length(betweenRuns.var1Sequence)-betweenRuns.runNumber;
994
if withinRuns.beginningOfPhase2>0
995
    trialsToGo= experiment.singleIntervalMaxTrials(1) ...
996
        + withinRuns.beginningOfPhase2- withinRuns.trialNumber;
997
    title(['trials remaining = ' num2str(trialsToGo) ...
998
        ':    runs to go= ' num2str(runsToGo)])
999
end
1000

    
1001
% plot psychometric function   - panel 5
1002
axes(expGUIhandles.axes5), cla
1003
plot(withinRuns.levelList, withinRuns.responseList,'b.'), hold on
1004
ylim([0 1])
1005
title('')
1006

    
1007
switch experiment.threshEstMethod
1008
    case {'MaxLikelihood', 'oneIntervalUpDown'}
1009
        if withinRuns.beginningOfPhase2>0
1010
            % display only when in phase 2.
1011
            withinRuns.levelsPhaseTwo=...
1012
                withinRuns.levelList(withinRuns.beginningOfPhase2:end);
1013
            withinRuns.responsesPhaseTwo=...
1014
                withinRuns.responseList(withinRuns.beginningOfPhase2:end);
1015

    
1016
            % organise data as psychometric function
1017
            [psy, levelsBinVector, binFrequencies]= ...
1018
                psychometricFunction(withinRuns.levelsPhaseTwo,...
1019
                withinRuns.responsesPhaseTwo, experiment.psyBinWidth);
1020

    
1021
            % Plot the function
1022
            %   point by point with circles of appropiate weighted size
1023
            hold on,
1024
            for i=1:length(psy)
1025
                plot(levelsBinVector(i), psy(i), 'ro', ...
1026
                    'markersize', 50*binFrequencies(i)/sum(binFrequencies))
1027
            end
1028
            % save info for later
1029
            betweenRuns.psychometicFunction{betweenRuns.runNumber}=...
1030
                [levelsBinVector; psy];
1031

    
1032
            % fitPsychometric functions is  computed in 'userDecides'
1033
            % plot(rareEvent.predictionLevels, rareEvent.predictionsRE,'k')
1034
            plot(logistic.predictionLevels, logistic.predictionsLOG, 'r')
1035
            plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k')
1036
            if ~isnan(logistic.bestThreshold )
1037
                xlim([ 0 100 ])
1038
                title(['k= ' num2str(logistic.bestK, '%6.2f') ' g= '...
1039
                    num2str(rareEvent.bestGain,'%6.3f') '  A=' ...
1040
                    num2str(rareEvent.bestVMin,'%8.1f')])
1041
            else
1042
                title(' ')
1043
            end
1044

    
1045
            switch experiment.ear
1046
                %plot green line for statsModel a priori model
1047
                case 'statsModelLogistic'
1048
                    % plot proTem logistic (green) used by stats model
1049
                    p= 1./(1+exp(-statsModel.logisticSlope...
1050
                        *(levelsBinVector-logistic.bestThreshold)));
1051
                    if experiment.psyFunSlope<0, p=1-p;end
1052
                    titleText=[ ',  statsModel: logistic'];
1053
                    hold on,    plot(levelsBinVector, p,'g')
1054
                case  'statsModelRareEvent'
1055
                    pressure=28*10.^(levelsBinVector/20);
1056
                    p=1-exp(-stimulusParameters.targetDuration...
1057
                        *(statsModel.rareEvenGain...
1058
                        * pressure-statsModel.rareEventVmin));
1059
                    p(p<0)=0;
1060
                    if experiment.psyFunSlope<0, p=1-p;end
1061
                    hold on,    plot(levelsBinVector, p,'g')
1062
            end %(estMethod)
1063
        end
1064

    
1065
    otherwise           % 2A2IFC
1066
        message3= ...
1067
            ([ 'peaks='  num2str(withinRuns.peaks) ...
1068
            'troughs='  num2str(withinRuns.troughs)]);
1069
        ylimRM([-0.1 1.1])	% 0=no / 1=yes
1070
        set(gca,'ytick',[0 1], 'yTickLabel', {'no';'yes'})
1071
        ylabel('psychometric function'), xlabel('target level')
1072
        if length(levelsBinVector)>1
1073
            xlim([ min(levelsBinVector) max(levelsBinVector)])
1074
            xlim([ 0 100])
1075
        end
1076
end
1077

    
1078
% command window summary
1079
% Accumulate things to say in the message window
1080
message1= (['responses:      ' num2str(withinRuns.responseList,'%9.0f')]);
1081
switch experiment.paradigm
1082
    % more decimal places needed on GUI
1083
    case { 'gapDetection', 'frequencyDiscrimination', 'forwardMaskingD'}
1084
        message2= ([stimulusParameters.WRVname  ...
1085
            ':       ' num2str(withinRuns.levelList,'%7.3f')]);
1086
        message3= (['Thresh (logistic mean):   ' ...
1087
            num2str(withinRuns.thresholdEstimateTrack,'%7.3f')]);
1088
    otherwise
1089
        message2= ([stimulusParameters.WRVname ':      ' ...
1090
            num2str(withinRuns.levelList,'%7.1f')]);
1091
        message3= (['Thresh (logistic mean):   ' ...
1092
            num2str(withinRuns.thresholdEstimateTrack,'%7.1f')]);
1093
end
1094

    
1095
addToMsg(str2mat(message1, message2, message3), 0)
1096

    
1097
% -----------------------------------------------------runCompleted
1098
function runCompleted(handles)
1099
% Used at the end of each run
1100
global experiment stimulusParameters betweenRuns withinRuns
1101
global rareEvent expGUIhandles
1102
% disp('run completed')
1103

    
1104
experiment.status='runCompleted';
1105
% quick update after final trial just to make sure
1106
plotProgressThisTrial(handles)
1107

    
1108
switch experiment.ear
1109
    case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ...
1110
            'MAPmodelMultiCh','MAPmodelSingleCh', 'MAPmodelListen'}
1111
        % no changes required if model used
1112
    otherwise
1113
        set(handles.frame1,'visible','off')
1114
        set(handles.pushbuttoNotSure,'visible','off')
1115
        set(handles.pushbuttonWrongButton,'visible','off')
1116
        set(handles.pushbutton3,'visible','off')
1117
        set(handles.pushbutton2,'visible','off')
1118
        set(handles.pushbutton1,'visible','off')
1119
        set(handles.pushbutton0,'visible','off')
1120
        set(handles.pushbuttonGO,'visible','off')
1121
end
1122

    
1123
if isnan(withinRuns.forceThreshold)
1124
    % the experiment has been aborted for some reason
1125
    threshold=withinRuns.forceThreshold;
1126
    stdev=NaN;
1127
    logistic.bestK=NaN;
1128
    logistic.bestThreshold=NaN;
1129
    medianThreshold=NaN;
1130
    meanThreshold=NaN;
1131
else
1132
    % use only phase 2 levels and responses for calculating thresholds
1133
    withinRuns.levelsPhaseTwo=...
1134
        withinRuns.levelList(withinRuns.beginningOfPhase2:end);
1135
    withinRuns.responsesPhaseTwo=...
1136
        withinRuns.responseList(withinRuns.beginningOfPhase2:end);
1137
    [psy, levelsPhaseTwoBinVector, logistic, rareEvent]= ...
1138
        bestFitPsychometicFunctions...
1139
        (withinRuns.levelsPhaseTwo, withinRuns.responsesPhaseTwo);
1140

    
1141
    % plot final psychometric function
1142
    axes(expGUIhandles.axes5),cla
1143
    hold on, plot(rareEvent.predictionLevels, rareEvent.predictionsRE, 'k')
1144
    hold on, plot(logistic.predictionLevels, logistic.predictionsLOG, 'r')
1145
    % organise data as psychometric function
1146
    [psy, levelsBinVector, binFrequencies]= ...
1147
        psychometricFunction(withinRuns.levelsPhaseTwo,...
1148
        withinRuns.responsesPhaseTwo, experiment.psyBinWidth);
1149
    %   point by point with circles of appropiate weighted size
1150
    hold on,
1151
    for i=1:length(psy)
1152
        plot(levelsBinVector(i), psy(i), 'ro', ...
1153
            'markersize', 50*binFrequencies(i)/sum(binFrequencies))
1154
    end
1155

    
1156
    % experimental
1157
    medianThreshold=median(withinRuns.levelsPhaseTwo);
1158
    warning off
1159
    meanThreshold=mean(withinRuns.levelsPhaseTwo);
1160

    
1161
    % identify the current threshold estimate
1162
    switch experiment.paradigm
1163
        case 'discomfort'
1164
            % most recent value (not truely a mean value)
1165
            threshold=withinRuns.levelList(end);
1166
            stdev=NaN;
1167
        otherwise
1168
            switch experiment.threshEstMethod
1169
                case {'MaxLikelihood', 'oneIntervalUpDown'}
1170
                    % last value in the list
1171
                    %                     threshold=withinRuns.meanEstTrack(end);
1172
                    threshold=withinRuns.thresholdEstimateTrack(end);
1173
                    stdev=NaN;
1174

    
1175
                case {'2I2AFC++', '2I2AFC+++'}
1176
                    % use peaks and troughs
1177
                    try		% there may not be enough values to use
1178
                        peaksUsed=experiment.peaksUsed;
1179
                        threshold=...
1180
                            mean(...
1181
                            [withinRuns.peaks(end-peaksUsed+1:end) ...
1182
                            withinRuns.troughs(end-peaksUsed+1:end)]);
1183
                        stdev=...
1184
                            std([withinRuns.peaks(end-peaksUsed +1:end) ...
1185
                            withinRuns.troughs(end-peaksUsed:end)]);
1186
                    catch
1187
                        threshold=NaN;
1188
                        stdev=NaN;
1189
                    end
1190
            end
1191
    end
1192
end
1193

    
1194
% Store thresholds
1195
betweenRuns.thresholds=[betweenRuns.thresholds threshold];
1196
betweenRuns.thresholds_mean=[betweenRuns.thresholds_mean meanThreshold];
1197
betweenRuns.thresholds_median=...
1198
    [betweenRuns.thresholds_median medianThreshold];
1199
betweenRuns.forceThresholds=...
1200
    [betweenRuns.forceThresholds withinRuns.forceThreshold];
1201

    
1202
% count observations after the startup phase for record keeping
1203
betweenRuns.observationCount=...
1204
    [betweenRuns.observationCount length(withinRuns.levelList)];
1205
betweenRuns.timesOfFirstReversals=...
1206
    [betweenRuns.timesOfFirstReversals withinRuns.beginningOfPhase2];
1207
betweenRuns.catchTrials=...
1208
    [betweenRuns.catchTrials withinRuns.catchTrialCount];
1209

    
1210
% add variable length tracks to cell arrays
1211
if withinRuns.beginningOfPhase2>0
1212
    betweenRuns.bestThresholdTracks{length(betweenRuns.thresholds)}=...
1213
        withinRuns.thresholdEstimateTrack;
1214
    betweenRuns.levelTracks{length(betweenRuns.thresholds)}=...
1215
        withinRuns.levelList(withinRuns.beginningOfPhase2:end);
1216
    betweenRuns.responseTracks{length(betweenRuns.thresholds)}=...
1217
        withinRuns.responseList(withinRuns.beginningOfPhase2:end);
1218
else
1219
    betweenRuns.bestThresholdTracks{length(betweenRuns.thresholds)}=[];
1220
    betweenRuns.levelTracks{length(betweenRuns.thresholds)}=[];
1221
    betweenRuns.responseTracks{length(betweenRuns.thresholds)}=[];
1222
end
1223

    
1224
betweenRuns.bestGain=[betweenRuns.bestGain rareEvent.bestGain];
1225
betweenRuns.bestVMin=[betweenRuns.bestVMin rareEvent.bestVMin];
1226
betweenRuns.bestPaMin=[betweenRuns.bestPaMin rareEvent.bestPaMindB];
1227
betweenRuns.bestLogisticM=...
1228
    [betweenRuns.bestLogisticM logistic.bestThreshold];
1229
betweenRuns.bestLogisticK=[betweenRuns.bestLogisticK logistic.bestK];
1230

    
1231
resultsSoFar=[betweenRuns.var1Sequence(betweenRuns.runNumber)'...
1232
    betweenRuns.var2Sequence(betweenRuns.runNumber)'...
1233
    betweenRuns.thresholds(betweenRuns.runNumber)'
1234
    ];
1235

    
1236
fprintf('%10.3f \t%10.3f \t%10.1f  \n', resultsSoFar')
1237

    
1238
switch experiment.ear
1239
    case {'left', 'right', 'diotic', 'dichoticLeft','dichoticRight'}
1240
        disp(['caught out= ' num2str(betweenRuns.caughtOut)])
1241
end
1242

    
1243
% plot history of thresholds in panel 4
1244
axes(expGUIhandles.axes4), cla
1245
plotColors='rgbmckywrgbmckyw';
1246
for i=1:length(betweenRuns.thresholds)
1247
    faceColor=plotColors(floor(i/length(betweenRuns.variableList1)-.01)+1);
1248
    switch betweenRuns.variableName1
1249
        case {'targetFrequency', 'maskerRelativeFrequency'}
1250
            if min(betweenRuns.var1Sequence)>0
1251
                semilogx(betweenRuns.var1Sequence(i), ...
1252
                    betweenRuns.thresholds(i),  'o', ...
1253
                    'markerSize', 5,'markerFaceColor',faceColor)
1254
            else
1255
                plot(betweenRuns.var1Sequence(1:betweenRuns.runNumber),  ...
1256
                    betweenRuns.thresholds,  'o', ...
1257
                    'markerSize', 5,'markerFaceColor',faceColor)
1258
                plot(betweenRuns.var1Sequence(i),  ...
1259
                    betweenRuns.thresholds(i),  'o', ...
1260
                    'markerSize', 5,'markerFaceColor',faceColor)
1261
            end
1262
        otherwise
1263
            plot(betweenRuns.var1Sequence(i),  ...
1264
                betweenRuns.thresholds(i),  'o', 'markerSize', 5,...
1265
                'markerFaceColor',faceColor)
1266
    end
1267
    hold on
1268
end
1269
xlimRM([ min(betweenRuns.variableList1) max(betweenRuns.variableList1) ])
1270
ylim(stimulusParameters.WRVlimits)
1271
ylabel('thresholds')
1272
xlabel(betweenRuns.variableName1)
1273
set(gca,'ytick', [0 20 40 60 80 100])
1274
try
1275
    % problems if only one x value
1276
    set(gca,'XTick', sort(betweenRuns.variableList1))
1277
catch
1278
end
1279
grid on, set(gca,'XMinorGrid', 'off')
1280

    
1281
% final run?
1282
if betweenRuns.runNumber==length(betweenRuns.var1Sequence)
1283
    % yes, end of experiment
1284
    fileName=['savedData/' experiment.name experiment.date ...
1285
        experiment.paradigm];
1286
    % 	save (fileName, 'experiment', 'stimulusParameters', 'betweenRuns', 'withinRuns', 'variableNames', 'paradigmNames', 'LevittControl')
1287
    disp('Experiment completed')
1288

    
1289
    % update subject GUI to acknowledge end of run
1290
    subjGUImsg=[{'Experiment completed'}, {' '}, {'Thank you!'}];
1291
    set(handles.textMSG,'string', subjGUImsg   )
1292
    % play 'Tada'
1293
    [y,fs,nbits]=wavread('TADA.wav');
1294
    musicGain=10^(stimulusParameters.musicLeveldB/20);
1295
    y=y*musicGain;
1296
    wavplay(y/100,fs, 'async')
1297

    
1298
    % update experimenter GUI
1299
    addToMsg('Experiment completed.',1)
1300

    
1301
    printReport
1302
    experiment.status='endOfExperiment';
1303
    return
1304
else
1305
    % No, hang on.
1306
    switch experiment.ear
1307
        case {'statsModelLogistic', 'statsModelRareEvent','MAPmodel', ...
1308
                'MAPmodelMultiCh','MAPmodelSingleCh', 'MAPmodelListen'}
1309
            % no changes required if model used
1310
        otherwise
1311
            % decrement catchTrialRate towards baseRate
1312
            stimulusParameters.catchTrialRate=...
1313
                stimulusParameters.catchTrialBaseRate + ...
1314
                (stimulusParameters.catchTrialRate...
1315
                -stimulusParameters.catchTrialBaseRate)...
1316
                *(1-exp(-stimulusParameters.catchTrialTimeConstant));
1317
            fprintf('stimulusParameters.catchTrialRate= %6.3f\n', ...
1318
                stimulusParameters.catchTrialRate)
1319

    
1320
            % and go again
1321
            set(handles.pushbuttonGO,'backgroundcolor','y')
1322
            set(handles.frame1,'visible','off')
1323
            set(handles.pushbuttonGO,'visible','on')
1324
            msg=[{'Ready to start new trial'}, {' '},...
1325
                {'Please,click on the GO button'}];
1326
            set(handles.textMSG,'string',msg)
1327
    end
1328
    experiment.status='waitingForGO';
1329
    %     fprintf('\n')
1330

    
1331
    [y,fs,nbits]=wavread('CHIMES.wav');
1332
    musicGain=10^(stimulusParameters.musicLeveldB/20);
1333
    y=y*musicGain;
1334
    wavplay(y/100,fs,'async')
1335
end
1336

    
1337
% -----------------------------------------------------MAPmodelRunsGUI
1338
% The computer presses the buttons
1339
function 	MAPmodelRunsGUI(handles)
1340
global experiment stimulusParameters method expGUIhandles
1341
global AN_IHCsynapseParams
1342
method=[];
1343

    
1344
while strcmp(experiment.status,'waitingForGO')
1345
    % no catch trials for MAP model
1346
    experiment.allowCatchTrials=0;
1347

    
1348
    % initiates run and plays first stimulus and it returns
1349
    %  without waiting for button press
1350
    startNewRun(handles)
1351

    
1352
    % show sample Rate on GUI; it must be set in MAPparams
1353
    set(expGUIhandles.textsampleRate,'string',...
1354
        num2str(stimulusParameters.sampleRate))
1355

    
1356
    if experiment.singleShot
1357
        AN_IHCsynapseParams.plotSynapseContents=1;
1358
    else
1359
        AN_IHCsynapseParams.plotSynapseContents=0;
1360
    end
1361

    
1362
    % continuous loop until the program stops itself
1363
    while strcmp(experiment.status,'waitingForResponse')
1364
        %  NB at this point the stimulus has been played
1365
        pause(0.1)  % to allow interrupt with CTRL/C
1366

    
1367
        switch experiment.ear
1368
            case { 'MAPmodelListen'}
1369
                % flash the buttons to show model response
1370
                set(handles.pushbutton1,'backgroundcolor','y','visible','on')
1371
                set(handles.pushbutton2,'backgroundcolor','y','visible','on')
1372
        end
1373

    
1374
        % Analayse the current stimulus using MAP
1375
        [modelResponse earObject]= MAPmodel;
1376

    
1377
        if experiment.stop || experiment.singleShot
1378
            % trap for single trial or user interrupt using 'stop' button.
1379
            experiment.status= 'waitingForStart';
1380
            experiment.stop=0;
1381
            errormsg='manually stopped';
1382
            addToMsg(errormsg,1)
1383
            return
1384
        end
1385

    
1386
        switch modelResponse
1387
            case 1
1388
                %     userDoesNotHearTarget(handles)
1389
                switch experiment.ear
1390
                    case {'MAPmodelListen'}
1391
                        % illuminate appropriate button
1392
                        set(handles.pushbutton1,...
1393
                            'backgroundcolor','r','visible','on')
1394
                        set(handles.pushbutton2,'backgroundcolor','y')
1395
                end
1396
                userDecides(handles, false)
1397
                if experiment.singleShot, return, end
1398

    
1399
            case 2
1400
                %   userHearsTarget(handles)
1401
                switch experiment.ear
1402
                    case {'MAPmodelListen'}
1403
                        % illuminate appropriate button (DEMO only)
1404
                        set(handles.pushbutton2,'backgroundcolor',...
1405
                            'r','visible','on')
1406
                        set(handles.pushbutton1,'backgroundcolor','y')
1407
                end
1408

    
1409
                switch experiment.paradigm
1410
                    case 'discomfort'
1411
                        % always treat discomfort as 'not heard'
1412
                        userDecides(handles, false)
1413
                    otherwise
1414
                        userDecides(handles, true)
1415
                end
1416
            otherwise
1417
                % probably an abort
1418
                return
1419
        end
1420
    end
1421
end
1422

    
1423
% -------------------------------------------------------MAPmodel
1424
function [modelResponse, MacGregorResponse]=MAPmodel
1425

    
1426
global experiment stimulusParameters audio withinRuns
1427
global outerMiddleEarParams DRNLParams AN_IHCsynapseParams
1428

    
1429
savePath=path;
1430
addpath(['..' filesep 'MAP'], ['..' filesep 'utilities'])
1431
modelResponse=[];
1432
MacGregorResponse=[];
1433

    
1434
% mono only (column vector)
1435
audio=audio(:,1)';
1436

    
1437
% if stop button pressed earlier
1438
if experiment.stop
1439
    errormsg='manually stopped';
1440
    addToMsg(errormsg,1)
1441
    return
1442
end
1443

    
1444
% ---------------------------------------------- run Model
1445
MAPparamsName=experiment.name;
1446
showPlotsAndDetails=experiment.MAPplot;
1447
AN_spikesOrProbability='spikes';
1448
AN_spikesOrProbability='probability';
1449

    
1450
% [response, method]=MAPsequenceSeg(audio, method, 1:8);
1451
global ICoutput ANdt dt savedBFlist ANprobRateOutput expGUIhandles
1452
global stimulusParameters experiment
1453

    
1454
if sum(strcmp(experiment.ear,{'MAPmodelMultiCh', 'MAPmodelListen'}))
1455
    % use BFlist specified in MAPparams file
1456
    BFlist= -1;
1457
else
1458
    BFlist=stimulusParameters.targetFrequency;
1459
end
1460
paramChanges=get(expGUIhandles.editparamChanges,'string');
1461
eval(paramChanges)
1462

    
1463
MAP1_14(audio, stimulusParameters.sampleRate, BFlist,...
1464
    MAPparamsName, AN_spikesOrProbability, paramChanges);
1465

    
1466
if showPlotsAndDetails
1467
    options.printModelParameters=0;
1468
    options.showModelOutput=1;
1469
    options.printFiringRates=1;
1470
    options.showACF=0;
1471
    options.showEfferent=1;
1472
    options.surfProbability=0;
1473
    showMapOptions.surfSpikes=0;
1474
    UTIL_showMAP(options)
1475
end
1476

    
1477
% No response,  probably caused by hitting 'stop' button
1478
if strcmp(AN_spikesOrProbability,'spikes') && isempty(ICoutput)
1479
    return
1480
end
1481
% ---------------------------------------------------------- end model run
1482

    
1483
if strcmp(AN_spikesOrProbability,'spikes')
1484
    MacGregorResponse= sum(ICoutput,1);                 % use IC
1485
    dt=ANdt;
1486
    time=dt:dt:dt*length(MacGregorResponse);
1487
else
1488
    % for one channel, ANprobResponse=ANprobRateOutput
1489
    % for multi channel take strongest in any epoch
1490
    nChannels=length(savedBFlist);
1491
    % use only HSR fibers
1492
    ANprobRateOutput=ANprobRateOutput(end-nChannels+1:end,:);
1493
    time=dt:dt:dt*length(ANprobRateOutput);
1494
end
1495

    
1496
% group delay on unit response - these values are iffy
1497
windowOnsetDelay= 0.004;
1498
windowOffsetDelay= 0.022; % long ringing time
1499

    
1500
% now find the response of the MacGregor model during the target presentation + group delay
1501
switch experiment.threshEstMethod
1502
    case {'2I2AFC++', '2I2AFC+++'}
1503
        idx= time>stimulusParameters.testTargetBegins+windowOnsetDelay ...
1504
            & time<stimulusParameters.testTargetEnds+windowOffsetDelay;
1505
        nSpikesTrueWindow=sum(MacGregorResponse(:,idx));
1506
        idx=find(time>stimulusParameters.testNonTargetBegins+windowOnsetDelay ...
1507
            & time<stimulusParameters.testNonTargetEnds+windowOffsetDelay);
1508
        if strcmp(AN_spikesOrProbability,'spikes')
1509
            nSpikesFalseWindow=sum(MacGregorResponse(:,idx));
1510
        else
1511
            nSpikesDuringTarget=mean(ANprobRateOutput(end,idx));
1512
            % compare with spontaneous rate
1513
            if nSpikesDuringTarget>ANprobRateOutput(end,1)+10
1514
                nSpikesDuringTarget=1;  % i.e. at leastone MacG spike
1515
            else
1516
                nSpikesDuringTarget=0;
1517
            end
1518
        end
1519
        % nSpikesDuringTarget is +ve when more spikes are found
1520
        %   in the target window
1521
        difference= nSpikesTrueWindow-nSpikesFalseWindow;
1522

    
1523
        if difference>0
1524
            % hit
1525
            nSpikesDuringTarget=experiment.MacGThreshold+1;
1526
        elseif    difference<0
1527
            % miss (wrong choice)
1528
            nSpikesDuringTarget=experiment.MacGThreshold-1;
1529
        else
1530
            if rand>0.5
1531
                % hit (random choice)
1532
                nSpikesDuringTarget=experiment.MacGThreshold+1;
1533
            else
1534
                % miss (random choice)
1535
                nSpikesDuringTarget=experiment.MacGThreshold-1;
1536
            end
1537
        end
1538
        disp(['level target dummy decision: ' ...
1539
            num2str([withinRuns.variableValue nSpikesTrueWindow ...
1540
            nSpikesFalseWindow  nSpikesDuringTarget], '%4.0f') ] )
1541
    otherwise
1542
        % single interval
1543
        idx=find(time>stimulusParameters.testTargetBegins +windowOnsetDelay...
1544
            & time<stimulusParameters.testTargetEnds+windowOffsetDelay);
1545
        if strcmp(AN_spikesOrProbability,'spikes')
1546
            nSpikesDuringTarget=sum(MacGregorResponse(:,idx));
1547
            timeX=time(idx);
1548
        else
1549
            % probability, use channel with the highest average rate
1550
            nSpikesDuringTarget=max(mean(ANprobRateOutput(:,idx),2));
1551
            if nSpikesDuringTarget>ANprobRateOutput(end,1)+10
1552
                nSpikesDuringTarget=1;
1553
            else
1554
                nSpikesDuringTarget=0;
1555
            end
1556

    
1557
        end
1558
end
1559

    
1560
if experiment.MAPplot
1561
    % add vertical lines to indicate target region
1562
    figure(99), subplot(6,1,6)
1563
    hold on
1564
    yL=get(gca,'YLim');
1565
    plot([stimulusParameters.testTargetBegins + windowOnsetDelay ...
1566
        stimulusParameters.testTargetBegins   + windowOnsetDelay],yL,'r')
1567
    plot([stimulusParameters.testTargetEnds   + windowOffsetDelay ...
1568
        stimulusParameters.testTargetEnds     + windowOffsetDelay],yL,'r')
1569
end
1570

    
1571
% specify unambiguous response
1572
if nSpikesDuringTarget>experiment.MacGThreshold
1573
    modelResponse=2;    % stimulus detected
1574
else
1575
    modelResponse=1;    % nothing heard (default)
1576
end
1577

    
1578
path(savePath)
1579

    
1580
% -----------------------------------------------------statsModelRunsGUI
1581
% The computer presses the buttons
1582
function 	statsModelRunsGUI(handles)
1583
% Decision are made at random using a prescribe statistical function
1584
% to set probabilities as a function of signal level.
1585
global experiment
1586

    
1587
experiment.allowCatchTrials=0;
1588

    
1589
while strcmp(experiment.status,'waitingForGO')
1590
    % i.e. waiting for new run
1591
    if experiment.stop
1592
        % user has requested an abort
1593
        experiment.status= 'waitingForStart';
1594
        addToMsg('manually stopped',1)
1595
        return
1596
    end
1597

    
1598
    % initiates run and plays first stimulus and it returns
1599
    %  without waiting for button press
1600
    % NB stimulus is not actually generated (for speed)
1601
    startNewRun(handles)
1602

    
1603
    while strcmp(experiment.status,'waitingForResponse')
1604
        % create artificial response here
1605
        modelResponse=statsModelGetResponse;
1606
        switch modelResponse
1607
            case 1
1608
                %                 userDoesNotHearTarget(handles)
1609
                userDecides(handles, false)
1610
            case 2
1611
                %                 userHearsTarget(handles)
1612
                userDecides(handles, true)
1613
        end
1614
    end
1615
end
1616

    
1617
% -----------------------------------------------------statsModelGetResponse
1618
function modelResponse=statsModelGetResponse(handles)
1619
global experiment  withinRuns  statsModel stimulusParameters
1620
% use the generating function to decide if a detection occurs or not
1621

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

    
1624
% first compute the probability that a detection occurs
1625
switch experiment.ear
1626
    case {'statsModelLogistic'}
1627
        prob= 1./(1+exp(-statsModel.logisticSlope.*(withinRuns.variableValue-statsModel.logisticMean)));
1628
        %         if experiment.psyFunSlope<0,
1629
        %             prob=1-prob;
1630
        %         end
1631

    
1632
    case 'statsModelRareEvent'
1633
        if experiment.psyFunSlope<0
1634
            addToMsg('statsModelRareEvent cannot be used with negative slope',0)
1635
            error('statsModelRareEvent cannot be used with negative slope')
1636
        end
1637

    
1638
        % standard formula is prob = 1 ? exp(-d (g P ? A))
1639
        % here A->A;  To find Pmin use A/gain
1640
        pressure=28*10^(withinRuns.variableValue/20);
1641
        gain=statsModel.rareEvenGain;
1642
        A=statsModel.rareEventVmin;
1643
        d=stimulusParameters.targetDuration;
1644
        gP_Vmin=gain*pressure-A;
1645
        if gP_Vmin>0
1646
            prob=1-exp(-d*(gP_Vmin));
1647
        else
1648
            prob=0;
1649
        end
1650
end
1651

    
1652
% Use the probability to choose whether or not a detection has occurred
1653
switch experiment.threshEstMethod
1654
    case {'MaxLikelihood', 'oneIntervalUpDown'}
1655
        if rand<prob
1656
            modelResponse=2; %bingo
1657
        else
1658
            modelResponse=1; %nothing heard
1659
        end
1660

    
1661
    case {'2I2AFC++', '2I2AFC+++'}
1662
        if rand<prob
1663
            modelResponse=2; %bingo
1664
        else %if the stimulus is not audible, take a 50:50 chance of getting it right
1665
            if rand<0.5
1666
                modelResponse=2; %bingo
1667
            else
1668
                modelResponse=1; %nothing heard
1669
            end
1670
        end
1671
end
1672

    
1673

    
1674
% ------------------------------------------------------- printTabTable
1675
function printTabTable(M, headers)
1676
% printTabTable prints a matrix as a table with tabs
1677
%headers are optional
1678
%headers=strvcat('firstname', 'secondname')
1679
%  printTabTable([1 2; 3 4],strvcat('a1','a2'));
1680

    
1681
if nargin>1
1682
    [r c]=size(headers);
1683
    for no=1:r
1684
        fprintf('%s\t',headers(no,:))
1685
    end
1686
    fprintf('\n')
1687
end
1688

    
1689
[r c]=size(M);
1690

    
1691
for row=1:r
1692
    for col=1:c
1693
        if row==1 && col==1 && M(1,1)==-1000
1694
            %   Print nothing (tab follows below)
1695
        else
1696
            fprintf('%s',num2str(M(row,col)))
1697
        end
1698
        if col<c
1699
            fprintf('\t')
1700
        end
1701
    end
1702
    fprintf('\n')
1703
end
1704

    
1705
% ------------------------------------------------------- xlimRM
1706
function xlimRM(x)
1707
try
1708
    xlim([x(1) x(2)])
1709
catch
1710
end
1711

    
1712
% ------------------------------------------------------- ylimRM
1713
function ylimRM(x)
1714
try
1715
    ylim([x(1) x(2)])
1716
catch
1717
end
1718

    
1719

    
1720
function editdigitInput_CreateFcn(hObject, eventdata, handles)
1721

    
1722
% Hint: edit controls usually have a white background on Windows.
1723
%       See ISPC and COMPUTER.
1724
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
1725
    set(hObject,'BackgroundColor','white');
1726
end
1727

    
1728

    
1729
% -----------------------------------------------------buttonBoxIntitialize
1730
function buttonBoxIntitialize
1731
% initialize button box
1732
global  serobj
1733
try
1734
    fclose(serobj);
1735
catch
1736
end
1737

    
1738
try
1739
    serobj = serial('COM4') ;           	% Creating serial port object now its connected to COM4 !!! button boxes in booths are connected to COM2
1740
    serobj.Baudrate = 9600;           		% Set the baud rate at the specific value
1741
    set(serobj, 'Parity', 'none') ;     	% Set parity as none
1742
    set(serobj, 'Databits', 8) ;          	% set the number of data bits
1743
    set(serobj, 'StopBits', 1) ;         	% set number of stop bits as 1
1744
    set(serobj, 'Terminator', 'CR') ; 		% set the terminator value to carriage return
1745
    set(serobj, 'InputBufferSize', 512) ;  	% Buffer for read operation, default it is 512
1746
    set(serobj,'timeout',10);           	% 10 sec timeout on button press
1747
    set(serobj, 'ReadAsyncMode', 'continuous')
1748
    set(serobj, 'BytesAvailableFcn', @buttonBox_callback)
1749
    set(serobj, 'BytesAvailableFcnCount', 1)
1750
    set(serobj, 'BytesAvailableFcnMode', 'byte')
1751
    % set(serobj, 'BreakInterruptFcn', '@buttonBox_Calback')
1752

    
1753
    fopen(serobj);
1754
    buttonBoxStatus=get(serobj,'status');
1755
catch
1756
    disp('** no button box found - use mouse **')
1757
end