view multithreshold 1.46/Levitt2.m @ 38:c2204b18f4a2 tip

End nov big change
author Ray Meddis <rmeddis@essex.ac.uk>
date Mon, 28 Nov 2011 13:34:28 +0000
parents f233164f4c86
children
line wrap: on
line source
function [nextStep, msg]=Levitt2 (decision, currentValue)
global LevittControl withinRuns
% descision is a string: 'hit' or 'miss'
% current value is the value of the variable parameter (e.g. level)
% msg:
%     msg='' indicates trial progressing successfully
%     msg='done' indicates that a threshold estimate has been found
%     msg='maximum level exceeded'
%     msg='maximum no of trials exceeded'

% Initialize by running Levitt2 without arguments
%  later LevittControl will be set in aReadAndCheckParameterBoxes in  expGUI_MT
if nargin==0
    
    LevittControl.peakTroughValues=[];   
    LevittControl.trialRunning=0;
    LevittControl.sequence='****'; 
    LevittControl.LevittValuesUsed=[NaN NaN NaN NaN];
    LevittControl.TurnsToSmallSteps=4; % 2 peaks and 2 troughs
    LevittControl.direction='same';
    LevittControl.prevDirection='easier';
    LevittControl.Nreversals=0;
    
    LevittControl.trialRunning=1;
    LevittControl.meanPeakTrough=NaN;
    LevittControl.sd=NaN;
    msg='';
    return
end

% apply Levitt rules to find next stimulus value
rule=LevittControl.rule;
sequence=LevittControl.sequence;
meanPT=LevittControl.meanPeakTrough;
sdPT=LevittControl.sd;

% response sequence: '+' is a hit and '-' is a miss.
if strcmp(decision,'hit')
    sequence=[sequence '+'];
else
    sequence=[sequence '-'];
end
LevittControl.LevittValuesUsed=[LevittControl.LevittValuesUsed withinRuns.levelList(end)];

switch rule
    case '++'
        peakCriterion='-++';
        troughCriteria={'++ -', '++ +-'};
    case '+++'
        peakCriterion='-+++';
        troughCriteria={'+++ -', '+++ +-', '+++ ++-'};
    otherwise
        error('Levitt:')
end	

troughs=[]; allTroughPtrs=[];
for i=1:length(troughCriteria)              % do all trough criteria
    troughCriterion=char(troughCriteria(i));% one criterion at a time
    % identify the location of a trough
    troughPtrs=findstr(sequence, troughCriterion) + length(troughCriterion)-1;
    % identify the level at which it occurred
    troughLevels=LevittControl.LevittValuesUsed(troughPtrs);
    % archive the list
    withinRuns.troughs=troughLevels;
    troughs=[troughs troughLevels];
    allTroughPtrs=[allTroughPtrs troughPtrs];
end
% only one peak criterion used
withinRuns.troughs=troughs;
peakPtrs=findstr(sequence,peakCriterion)+length(peakCriterion)-1;
peakLevels=LevittControl.LevittValuesUsed(peakPtrs);
withinRuns.peaks=peakLevels;

% almagamate and sort into date order
peakTroughList=[peakLevels troughs];
peakTroughPtrs=[peakPtrs allTroughPtrs];
[peakTroughPtrs idx]=sort(peakTroughPtrs);
% it needs to be sequenced so that the algorithm can take the last peaks
% and troughs
peakTroughList=peakTroughList(idx);

% adjust step size as the trial progresses
% a positive step size indicates the 'harder' direction 
if length(peakTroughList)>=LevittControl.TurnsToSmallSteps
    currentStep=LevittControl.steadyLevittStep;
else
    currentStep=LevittControl.startLevelStep;
end    

% base next stimulus on the basis of the sequence
%  any miss requires an 'easier' stimulus next time.
if strcmp(sequence(end),'-')
    nextStep= -currentStep;
    
    % success requires 2 or more successive hits
elseif strcmp(sequence(end-length(rule)+1:end),rule)
    sequence=[sequence ' '];  % add space to prevent success on successive trials
    LevittControl.LevittValuesUsed=[LevittControl.LevittValuesUsed NaN];
    nextStep=currentStep;
    
    % not enough hits to provoke a change
else	
    nextStep=0;
end

LevittControl.sequence=sequence;

LevittControl.Nreversals=length(peakTroughList);
% compute threshold estimate 
% only if minReversals exceeded and even number of peaks and troughs
if LevittControl.Nreversals>=LevittControl.minReversals && rem(length(peakTroughList),2)==0   
    % use only the peaks and troughs at the end of the sequence
    peaksAndTroughs=peakTroughList(end-LevittControl.useLastNturns+1:end);
    disp(['peak/trough sequence= ' num2str(peaksAndTroughs, '%6.0f') ] )
    
    meanPT=mean(peaksAndTroughs);
    sdPT=std(peaksAndTroughs);
    LevittControl.meanPeakTrough=meanPT;
    LevittControl.sd=sdPT;
    fprintf('Levitt, mean, sd= %6.1f,%6.1f\n', meanPT, sdPT)
    % final check that the sd is low enough
    if sdPT<LevittControl.targetsdPT        
        nextValue=currentValue;
        msg='done';
        return
    end
end

nextValue=currentValue + nextStep;
if nextValue>LevittControl.maxLevittValue
    msg='maximum level exceeded'
    return
end

% required for later use
LevittControl.trialRunning=LevittControl.trialRunning+1;
LevittControl.peakTroughValues=peakTroughList;

if LevittControl.trialRunning>LevittControl.maxTrials
    msg='maximum no of trials exceeded'
    return
end

% Trial continues
msg='';