function results = interleaved_adaptive_track_example(starting_levels,n_rev_back)
%INTERLEAVED_ADAPTIVE_TRACK_EXAMPLE runs n adaptive staircases (demo)
% results = interleaved_adaptive_track_example(starting_levels);
%
% given a set of starting levels, e.g., [60 63 66], this function will
% run a set of interleaved adaptive tracks to estimate the listener's
% threshold. It will run as many interleaved tracks as the number of
% starting levels provided.
%
% **This is meant to simply be an example of how to use the function
% adaptive_track_engine.m in a full interleaved experiment!!**
%
% It includes by default a "simulated listener" with a particular dB
% threshold (the pseudocode GetAnswer). This must be replaced with
% your code that creates a vector of actual listener responses
% (0 = incorrect, 1 = correct).
%
% Also, this code does not actually present signals, it includes a
% commented-out pseudo-code function called 'PlaySignal' which should be
% replaced with whatever presentation code you intend to use
%
% Example usage for two tracks with TH computed over last 5 reversals:
% >> results = interleaved_adaptive_track_example([60 66],5);
%
% After completion, the average threshold for all tracks may be found as
% follows:
% >> threshold = mean([results(:).threshold]);
%
% Author: W. Owen Brimijoin
% Date: 27/05/13
%deal out empty vectors to the results structure:
n_tracks = length(starting_levels);%sort out how many tracks the user wants
[results(n_tracks,1).answers,results(n_tracks,1).reversals] = deal([]);
for n = 1:length(starting_levels), results(n).levels = starting_levels(n);end
%start interleaved adaptive track:
while any(cellfun(@isempty,{results.reversals})),%continue until all tracks are finished
open_tracks = find(cellfun(@isempty,{results.reversals}));
track = open_tracks(randi(length(open_tracks),1)); %pick a random unfinished track
%%%%% Replace below with YOUR code to play out the signal%%%%%
% play signal at the level found in "data(track).levels(end)"
% Example:
% >> PlaySignal(data(track).levels(end));
%%%%% Replace above with YOUR code to play out the signal%%%%%
%%%%% Replace below with YOUR code to check subject's answer %%%%%
% play signal at the level found in "data(track).levels(end)"
% Example:
% >> data(track).answers(end+1) = GetAnswer();
results(track).answers(end+1) = simulate_listener(results(track).levels(end)); %get answers here
%%%%% Replace above with YOUR code to check subject's answer %%%%%
% here is where you use 'adaptive track_engine.m to determine the level
% to be used on next trial for this track. In this example, it uses
% steps of 6,3, and 1 dB for 3,4, then 5 reversals, and its rules are
% based on a 3-down, 1-up track:
[level,results(track).reversals] = ...
adaptive_track_engine(results(track).answers,[6 3 1],[3 4 5],[3 1]);
% add the new level value to the 'level' vector:
results(track).levels(end+1) = results(track).levels(end)+level;
% compute reversals and update plots:
results = update_data(length(starting_levels),results,n_rev_back);
end
%all done!
%plotting stuff:
function data = update_data(n_tracks,data,n_rev_back)
% togglefig('Adaptive Track') % I highly recommend this versatile function,
% written by Brett Shoelson and found on the file exchange:
% http://www.mathworks.co.uk/matlabcentral/fileexchange/18220-togglefig
colors = 'grwymc';
for track = 1:n_tracks,
color = colors(mod(track-1,length(colors))+1); %pick a color
%plot the data up to this point:
%asterisks for 'correct' answers
plot(find(data(track).answers==1),data(track).levels(find(data(track).answers==1)),['*',color]);hold on
%circles for 'incorrect' answers
plot(find(data(track).answers==0),data(track).levels(find(data(track).answers==0)),['o',color]);
%if *any* track has finished, compute threshold:
if ~isempty(data(track).reversals)
%count back 'n_rev_back' trials:
n_reversals_back = max(find(cumsum(fliplr(data(track).reversals))<=n_rev_back));
%take mean of the levels found in these trials:
data(track).threshold = mean(data(track).levels(end-n_reversals_back+1:end));
%plot a line at threshold for that track:
plot([0,length(data(track).levels)],[data(track).threshold,data(track).threshold],['-',color],'LineWidth',2);
%plot a vertical line showing the points used in mean threshold:
first_mean_point = length(data(track).levels) - n_reversals_back;
plot([first_mean_point,first_mean_point],[0,max(cellfun(@max,{data.levels}))],[':',color],'LineWidth',1);
text(first_mean_point,max(cellfun(@max,{data.levels}))-(track*2),...
[num2str(data(track).threshold,3),' dB'],'Color',color)
end
% set axis limits (YOU WILL WANT TO EDIT THIS):
axis([0 90 1 1+max(cellfun(@max,{data.levels}))])
set(gca,'Color',[.2 .2 .2]) %make the background dark so it can be read
end
xlabel('Trial Number'); ylabel('Signal Level (dB)') %label axes
%if all tracks have finished, compute mean threshold and plot on figure:
if ~any(cellfun(@isempty,{data.reversals})),
title(['Mean threshold: ',num2str(mean([data(:).threshold])),' dB'])
end
hold off;drawnow
%%%%% REMOVE below when using in actual experiment%%%%%
function answer = simulate_listener(level)
%self-testing stuff:
threshold = 20;
noise = .8;
accurate_response = .97;
error_estimate = ((level-threshold)/threshold)+(noise*(rand(1)-.5));
if error_estimate<=0,answer=0; else answer = 1;end
if rand(1)>accurate_response,answer = abs(answer - 1);end
%%%%% REMOVE above when using in actual experiment%%%%%