Code covered by the BSD License  

Highlights from
Adaptive Track Engine

image thumbnail

Adaptive Track Engine

by

 

20 Mar 2013 (Updated )

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