Code covered by the BSD License  

Highlights from
Adaptive Track Engine

image thumbnail
from Adaptive Track Engine by W. Owen Brimijoin
Determines what changes you should make to the signal during a psychoacoustic adaptive track.

interleaved_adaptive_track_example(starting_levels,n_rev_back)
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%%%%%

Contact us