rmeddis@0
|
1 function [nextStep, msg]=Levitt2 (decision, currentValue)
|
rmeddis@0
|
2 global LevittControl withinRuns
|
rmeddis@0
|
3 % descision is a string: 'hit' or 'miss'
|
rmeddis@0
|
4 % current value is the value of the variable parameter (e.g. level)
|
rmeddis@0
|
5 % msg:
|
rmeddis@0
|
6 % msg='' indicates trial progressing successfully
|
rmeddis@0
|
7 % msg='done' indicates that a threshold estimate has been found
|
rmeddis@0
|
8 % msg='maximum level exceeded'
|
rmeddis@0
|
9 % msg='maximum no of trials exceeded'
|
rmeddis@0
|
10
|
rmeddis@0
|
11 % Initialize by running Levitt2 without arguments
|
rmeddis@0
|
12 % later LevittControl will be set in aReadAndCheckParameterBoxes in expGUI_MT
|
rmeddis@0
|
13 if nargin==0
|
rmeddis@0
|
14
|
rmeddis@0
|
15 LevittControl.peakTroughValues=[];
|
rmeddis@0
|
16 LevittControl.trialRunning=0;
|
rmeddis@0
|
17 LevittControl.sequence='****';
|
rmeddis@0
|
18 LevittControl.LevittValuesUsed=[NaN NaN NaN NaN];
|
rmeddis@0
|
19 LevittControl.TurnsToSmallSteps=4; % 2 peaks and 2 troughs
|
rmeddis@0
|
20 LevittControl.direction='same';
|
rmeddis@0
|
21 LevittControl.prevDirection='easier';
|
rmeddis@0
|
22 LevittControl.Nreversals=0;
|
rmeddis@0
|
23
|
rmeddis@0
|
24 LevittControl.trialRunning=1;
|
rmeddis@0
|
25 LevittControl.meanPeakTrough=NaN;
|
rmeddis@0
|
26 LevittControl.sd=NaN;
|
rmeddis@0
|
27 msg='';
|
rmeddis@0
|
28 return
|
rmeddis@0
|
29 end
|
rmeddis@0
|
30
|
rmeddis@0
|
31 % apply Levitt rules to find next stimulus value
|
rmeddis@0
|
32 rule=LevittControl.rule;
|
rmeddis@0
|
33 sequence=LevittControl.sequence;
|
rmeddis@0
|
34 meanPT=LevittControl.meanPeakTrough;
|
rmeddis@0
|
35 sdPT=LevittControl.sd;
|
rmeddis@0
|
36
|
rmeddis@0
|
37 % response sequence: '+' is a hit and '-' is a miss.
|
rmeddis@0
|
38 if strcmp(decision,'hit')
|
rmeddis@0
|
39 sequence=[sequence '+'];
|
rmeddis@0
|
40 else
|
rmeddis@0
|
41 sequence=[sequence '-'];
|
rmeddis@0
|
42 end
|
rmeddis@0
|
43 LevittControl.LevittValuesUsed=[LevittControl.LevittValuesUsed withinRuns.levelList(end)];
|
rmeddis@0
|
44
|
rmeddis@0
|
45 switch rule
|
rmeddis@0
|
46 case '++'
|
rmeddis@0
|
47 peakCriterion='-++';
|
rmeddis@0
|
48 troughCriteria={'++ -', '++ +-'};
|
rmeddis@0
|
49 case '+++'
|
rmeddis@0
|
50 peakCriterion='-+++';
|
rmeddis@0
|
51 troughCriteria={'+++ -', '+++ +-', '+++ ++-'};
|
rmeddis@0
|
52 otherwise
|
rmeddis@0
|
53 error('Levitt:')
|
rmeddis@0
|
54 end
|
rmeddis@0
|
55
|
rmeddis@0
|
56 troughs=[]; allTroughPtrs=[];
|
rmeddis@0
|
57 for i=1:length(troughCriteria) % do all trough criteria
|
rmeddis@0
|
58 troughCriterion=char(troughCriteria(i));% one criterion at a time
|
rmeddis@0
|
59 % identify the location of a trough
|
rmeddis@0
|
60 troughPtrs=findstr(sequence, troughCriterion) + length(troughCriterion)-1;
|
rmeddis@0
|
61 % identify the level at which it occurred
|
rmeddis@0
|
62 troughLevels=LevittControl.LevittValuesUsed(troughPtrs);
|
rmeddis@0
|
63 % archive the list
|
rmeddis@0
|
64 withinRuns.troughs=troughLevels;
|
rmeddis@0
|
65 troughs=[troughs troughLevels];
|
rmeddis@0
|
66 allTroughPtrs=[allTroughPtrs troughPtrs];
|
rmeddis@0
|
67 end
|
rmeddis@0
|
68 % only one peak criterion used
|
rmeddis@0
|
69 withinRuns.troughs=troughs;
|
rmeddis@0
|
70 peakPtrs=findstr(sequence,peakCriterion)+length(peakCriterion)-1;
|
rmeddis@0
|
71 peakLevels=LevittControl.LevittValuesUsed(peakPtrs);
|
rmeddis@0
|
72 withinRuns.peaks=peakLevels;
|
rmeddis@0
|
73
|
rmeddis@0
|
74 % almagamate and sort into date order
|
rmeddis@0
|
75 peakTroughList=[peakLevels troughs];
|
rmeddis@0
|
76 peakTroughPtrs=[peakPtrs allTroughPtrs];
|
rmeddis@0
|
77 [peakTroughPtrs idx]=sort(peakTroughPtrs);
|
rmeddis@0
|
78 % it needs to be sequenced so that the algorithm can take the last peaks
|
rmeddis@0
|
79 % and troughs
|
rmeddis@0
|
80 peakTroughList=peakTroughList(idx);
|
rmeddis@0
|
81
|
rmeddis@0
|
82 % adjust step size as the trial progresses
|
rmeddis@0
|
83 % a positive step size indicates the 'harder' direction
|
rmeddis@0
|
84 if length(peakTroughList)>=LevittControl.TurnsToSmallSteps
|
rmeddis@0
|
85 currentStep=LevittControl.steadyLevittStep;
|
rmeddis@0
|
86 else
|
rmeddis@0
|
87 currentStep=LevittControl.startLevelStep;
|
rmeddis@0
|
88 end
|
rmeddis@0
|
89
|
rmeddis@0
|
90 % base next stimulus on the basis of the sequence
|
rmeddis@0
|
91 % any miss requires an 'easier' stimulus next time.
|
rmeddis@0
|
92 if strcmp(sequence(end),'-')
|
rmeddis@0
|
93 nextStep= -currentStep;
|
rmeddis@0
|
94
|
rmeddis@0
|
95 % success requires 2 or more successive hits
|
rmeddis@0
|
96 elseif strcmp(sequence(end-length(rule)+1:end),rule)
|
rmeddis@0
|
97 sequence=[sequence ' ']; % add space to prevent success on successive trials
|
rmeddis@0
|
98 LevittControl.LevittValuesUsed=[LevittControl.LevittValuesUsed NaN];
|
rmeddis@0
|
99 nextStep=currentStep;
|
rmeddis@0
|
100
|
rmeddis@0
|
101 % not enough hits to provoke a change
|
rmeddis@0
|
102 else
|
rmeddis@0
|
103 nextStep=0;
|
rmeddis@0
|
104 end
|
rmeddis@0
|
105
|
rmeddis@0
|
106 LevittControl.sequence=sequence;
|
rmeddis@0
|
107
|
rmeddis@0
|
108 LevittControl.Nreversals=length(peakTroughList);
|
rmeddis@0
|
109 % compute threshold estimate
|
rmeddis@0
|
110 % only if minReversals exceeded and even number of peaks and troughs
|
rmeddis@0
|
111 if LevittControl.Nreversals>=LevittControl.minReversals && rem(length(peakTroughList),2)==0
|
rmeddis@0
|
112 % use only the peaks and troughs at the end of the sequence
|
rmeddis@0
|
113 peaksAndTroughs=peakTroughList(end-LevittControl.useLastNturns+1:end);
|
rmeddis@0
|
114 disp(['peak/trough sequence= ' num2str(peaksAndTroughs, '%6.0f') ] )
|
rmeddis@0
|
115
|
rmeddis@0
|
116 meanPT=mean(peaksAndTroughs);
|
rmeddis@0
|
117 sdPT=std(peaksAndTroughs);
|
rmeddis@0
|
118 LevittControl.meanPeakTrough=meanPT;
|
rmeddis@0
|
119 LevittControl.sd=sdPT;
|
rmeddis@0
|
120 fprintf('Levitt, mean, sd= %6.1f,%6.1f\n', meanPT, sdPT)
|
rmeddis@0
|
121 % final check that the sd is low enough
|
rmeddis@0
|
122 if sdPT<LevittControl.targetsdPT
|
rmeddis@0
|
123 nextValue=currentValue;
|
rmeddis@0
|
124 msg='done';
|
rmeddis@0
|
125 return
|
rmeddis@0
|
126 end
|
rmeddis@0
|
127 end
|
rmeddis@0
|
128
|
rmeddis@0
|
129 nextValue=currentValue + nextStep;
|
rmeddis@0
|
130 if nextValue>LevittControl.maxLevittValue
|
rmeddis@0
|
131 msg='maximum level exceeded'
|
rmeddis@0
|
132 return
|
rmeddis@0
|
133 end
|
rmeddis@0
|
134
|
rmeddis@0
|
135 % required for later use
|
rmeddis@0
|
136 LevittControl.trialRunning=LevittControl.trialRunning+1;
|
rmeddis@0
|
137 LevittControl.peakTroughValues=peakTroughList;
|
rmeddis@0
|
138
|
rmeddis@0
|
139 if LevittControl.trialRunning>LevittControl.maxTrials
|
rmeddis@0
|
140 msg='maximum no of trials exceeded'
|
rmeddis@0
|
141 return
|
rmeddis@0
|
142 end
|
rmeddis@0
|
143
|
rmeddis@0
|
144 % Trial continues
|
rmeddis@0
|
145 msg='';
|