THE AUDITORY MODELING TOOLBOX

Applies to version: 1.2.0

View the help

Go to function

EXP_BAUMGARTNER2015 - Results from Baumgartner and Majdak (2015)

Program code:

function varargout = exp_baumgartner2015(varargin)
%EXP_BAUMGARTNER2015 Results from  Baumgartner and Majdak (2015)
%   Usage: data = exp_baumgartner2015(flag) 
%
%   `exp_baumgartner2015(flag)` reproduces figures of the studies from 
%   Baumgartner et al. (2015).
%
%
%   The following flags can be specified
%
%
%     'fig2'                       Reproduce Fig.2 of Baumgartner and Majdak (2015):
%                                  Example showing the spectral discrepancies obtained by VBAP. 
%                                  The targeted spectrum is the HRTF for 20 deg polar angle. 
%                                  The spectrum obtained by VBAP is the superposition of two 
%                                  HRTFs from directions 40 deg polar angle apart of each 
%                                  other with the tar- geted source direction centered in between.
%
%     'fig4'                       Reproduce Fig.4 of Baumgartner and Majdak (2015):
%                                  Response predictions to sounds created by VBAP with two 
%                                  loudspeakers in the median plane positioned at polar 
%                                  angles of -15 and 30 deg, respectively. Predictions for 
%                                  two exemplary listeners and pooled across all listeners. 
%                                  Each column of a panel shows the predicted PMV of 
%                                  polar-angle responses to a certain sound. Note the 
%                                  inter-individual differences and the generally small 
%                                  probabilities at response angles not occupied by the loudspeakers.
%
%     'fig5'                       Reproduce Fig.5 of Baumgartner and Majdak (2015):
%                                  Listener-specific increases in polar error as a function of 
%                                  the panning angle. Increase in polar error defined as 
%                                  the difference between the polar error obtained by the 
%                                  VBAP source and the polar error obtained by the real 
%                                  source at the corresponding panning angle. Same loudspeaker 
%                                  arrangement as for Fig. 4. Note the large inter-individual 
%                                  differences and the increase in polar error being largest 
%                                  at panning angles centered between the loudspeakers, i.e., 
%                                  at panning ratios around R = 0 dB.
%
%     'fig6'                       Reproduce Fig.6 of Baumgartner and Majdak (2015):
%                                  Panning angles for the loudspeaker arrangement of Fig. 4 
%                                  judged best for reference sources at polar angles of 
%                                  0 or 15 deg in the median plane. Comparison between 
%                                  experimental results from [2] and simulated results 
%                                  based on various response strategies: PM, CM, and both 
%                                  mixed. Dotted horizontal line: polar angle of the reference 
%                                  source. Hor- izontal line within box: median; 
%                                  box: inter-quartile range (IQR); 
%                                  whisker: within quartile $\pm 1.5$ IQR; 
%                                  star: outlier. 
%                                  Note that the simulations predicted a bias similar to 
%                                  the results from Pulkki (2001) for the reference source at 0 deg.
%
%     'tab1'                       Reproduce Tab.1 of Baumgartner and Majdak (2015):
%                                  Means and standard deviations of responded panning angles for the 
%                                  two reference sources (Ref.) together with corresponding GOFs 
%                                  evaluated for the actual results from Pulkki (2001) and 
%                                  predicted results based on various response strategies. 
%                                  Note the relatively large GOFs for the simulations based on 
%                                  mixed response strategies indicating a good correspondence 
%                                  between actual and predicted results.
%
%     'fig7'                       Reproduce Fig.7 of Baumgartner and Majdak (2015):
%                                  Increase in polar error (defined as in Fig. 5) as a function 
%                                  of loudspeaker span in the median plane with panning ratio 
%                                  R = 0 dB. Black line with gray area indicates mean 
%                                  $\pm 1$ standard deviation across listeners. Note that the 
%                                  increase in polar error monotonically increases with 
%                                  loudspeaker span.
%
%     'fig8'                       Reproduce Fig.8 of Baumgartner and Majdak (2015):
%                                  Effect of loudspeaker span in the median plane on coefficient 
%                                  of determination, r^2, for virtual source directions 
%                                  created by VBAP. Separate analysis for frontal, rear, 
%                                  and overall (frontal and rear) targets. Data pooled 
%                                  across listeners. Note the correspondence with the 
%                                  results obtained by Bremen et al. (2010).
%
%     'tab3'                       Reproduce Tab.3 of Baumgartner and Majdak (2015):
%                                  Predicted across-listener average of increase in polar 
%                                  errors as referred to a reference system containing 
%                                  loudspeakers at all considered directions. Distinction 
%                                  between mean and maximum degradation across directions. 
%                                  N: Number of loudspeakers. Ele.: Elevation of second layer. 
%                                  Notice that this elevation has a larger effect on mean 
%                                  and maximum degradation than N.
%
%     'fig9'   Reproduce Fig.9 of Baumgartner and Majdak (2015):
%                                  Predicted polar error as a function of the lateral and 
%                                  polar angle of a virtual source created by VBAP in 
%                                  various multichannel systems. Open circles indicate 
%                                  loudspeaker directions. Reference shows polar error 
%                                  predicted for a real source placed at the virtual 
%                                  source directions investigated for systems A, ..., F.
%
%
%   Further, cache flags (see amt_cache) and plot flags can be specified:
%
%     'plot'    Plot the output of the experiment. This is the default.
%
%     'no_plot'  Don't plot, only return data.
%
%   Requirements: 
%   -------------
%
%   1) SOFA API v0.4.3 or higher from http://sourceforge.net/projects/sofacoustics for Matlab (in e.g. thirdparty/SOFA)
% 
%   2) Data in hrtf/baumgartner2014
%
%   3) Statistics Toolbox for Matlab (for some of the figures)
%
%   Examples:
%   ---------
%
%
%   To display Fig.2 of Baumgartner and Majdak (2015) use :::
%
%     exp_baumgartner2015('fig2');
%
%   To display Fig.4 of Baumgartner and Majdak (2015) use :::
%
%     exp_baumgartner2015('fig4');
%
%   To display Fig.5 of Baumgartner and Majdak (2015) use :::
%
%     exp_baumgartner2015('fig5');
%
%   To display Fig.6 of Baumgartner and Majdak (2015) use :::
%
%     exp_baumgartner2015('fig6');
%
%   To display Fig.7 of Baumgartner and Majdak (2015) use :::
%
%     exp_baumgartner2015('fig7');
%
%   To display Fig.8 of Baumgartner and Majdak (2015) use :::
%
%     exp_baumgartner2015('fig8');
%
%   To display Fig.9 of Baumgartner and Majdak (2015) use :::
%
%     exp_baumgartner2015('fig9');
%
%   To display Tab.1 of Baumgartner and Majdak (2015) use :::
%
%     exp_baumgartner2015('tab1');
%
%   To display Tab.3 of Baumgartner and Majdak (2015) use :::
%
%     exp_baumgartner2015('tab3');
%
%   See also: baumgartner2014 data_baumgartner2014
%
%   References: baumgartner2015vbap baumgartner2014modeling bremen2010pinna pulkki2001localization 

%   AUTHOR: Robert Baumgartner


%% ------ Check input options --------------------------------------------

definput.import={'amt_cache'};
definput.keyvals.FontSize = 12;
definput.keyvals.MarkerSize = 6;
% definput.flags.type = {'missingflag',...% 'fig5_baumgartner2015aro',...
%                        'fig2_baumgartner2015jaes','fig4_baumgartner2015jaes',...
%                        'fig5_baumgartner2015jaes','fig6_baumgartner2015jaes',...
%                        'fig7_baumgartner2015jaes','fig8_baumgartner2015jaes',...
%                        'fig9_baumgartner2015jaes','tab1_baumgartner2015jaes',...
%                        'tab3_baumgartner2015jaes',...
%                        };
definput.flags.type = {'missingflag',...
                       'fig2','fig4',...
                       'fig5','fig6',...
                       'fig7','fig8',...
                       'fig9','tab1',...
                       'tab3',...
                       };
definput.flags.plot = {'plot','no_plot'};


[flags,kv]  = ltfatarghelper({'FontSize','MarkerSize'},definput,varargin);


if flags.do_missingflag
  flagnames=[sprintf('%s, ',definput.flags.type{2:end-2}),...
             sprintf('%s or %s',definput.flags.type{end-1},definput.flags.type{end})];
  error('%s: You must specify one of the following flags: %s.',upper(mfilename),flagnames);
end;


%% General Plot Settings
TickLength = [0.02,0.04];



%% ------------------------------------------------------------------------
%  ---- baumgartner2015jaes -----------------------------------------------
%  ------------------------------------------------------------------------
%% ------ FIG 2 of baumgartner2015jaes ------------------------------------
if flags.do_fig2
  pol1 = 0;
  pol2 = 40;

  s = data_baumgartner2014('pool');

  fs = s(1).Obj.Data.SamplingRate;

  [dtfs,pol] = extractsp(0,s(1).Obj);

  polphant = pol1 + (pol2-pol1)/2;

  dtf1 = 10*dtfs(:,pol==pol1,1);
  dtf2 = 10*dtfs(:,pol==pol2,1);
  dtfreal = 10*dtfs(:,pol==polphant,1);
  dtfphant = (dtf1+dtf2)/2;

  %%
  if flags.do_plot
    
    figure

    set(gca,'LineWidth',1)
    plotfft(fft(dtfphant),fs,'posfreq')
    hold on
    plotfft(fft(dtfreal),fs,'posfreq')
    plotfft(fft(dtf1),fs,'posfreq')
    plotfft(fft(dtf2),fs,'posfreq');
    
    % Set line styles
    Color =  {[0.4660    0.6740    0.1880];...
              [0.3010    0.7450    0.9330];...
              [0.8500    0.3250    0.0980];...
              [     0    0.4470    0.7410]};
    LineWidth = [.5,.5,1,1];
    LineStyle = {':',':','--','-'};
    ch = get(gca,'Children');
    for ii = 1:length(ch)
      set(ch(ii),'Color',Color{ii},'LineStyle',LineStyle{ii},'LineWidth',LineWidth(ii));
    end
    
    leg = legend([num2str(polphant) '\circ VBAP'],...
      [num2str(polphant) '\circ source'],...
      ['  ' num2str(pol1) '\circ source'],...
      [num2str(pol2) '\circ source']);
    set(leg,'Location','southeast','FontSize',kv.FontSize)

    set(gca,'XLim',[500,17500],'YLim',[-39.9,9.9],'FontSize',kv.FontSize)

    xticks = get(gca,'XTick');
    set(gca,'XTickLabel',xticks/1000)
    xlabel({'Frequency (kHz)';' '},'FontSize',kv.FontSize)
    
  end
  
end

%% ------ FIG 4 of baumgartner2015jaes ------------------------------------
if flags.do_fig4
  
  [peI,s,pol0,DL,respang] = amt_cache('get','panningangle',flags.cachemode);
  
  if isempty(peI)
  
    MRS = 0;

    pol1 = -15; % polar angle of lower Lsp.
    pol2 = 30; % polar angle of higher Lsp.

    lat = 0; % must be 0 otherwise VBAP wrong!

    s = data_baumgartner2014('pool');

    dPol = pol2-pol1;
    s(1).spdtfs = [];
    [s(1).spdtfs,polang] = extractsp(lat,s(1).Obj); 
    idtest = find(polang >= pol1 & polang <= pol2);
    qeI = zeros(length(s),length(idtest));
    peI = qeI;

    for ii = 1:length(idtest)

      id1 = idtest(1); % ID lower pos.
      id2 = idtest(end); % ID higher pos.
      id0 = idtest(ii);  % ID pos. of phantom source
      pol0(ii) = polang(id0);

      % VBAP
      [p(1,1),p(1,2),p(1,3)] = sph2cart(lat,deg2rad(pol0(ii)),1);
      [L(1,1),L(1,2),L(1,3)] = sph2cart(lat,deg2rad(pol1),1);
      [L(2,1),L(2,2),L(2,3)] = sph2cart(lat,deg2rad(pol2),1);
      g = p/L;
      g = g/norm(g);

      DL(ii) = db(g(1)) - db(g(2));

      for ll = 1:length(s)

          s(ll).spdtfs = extractsp(lat,s(ll).Obj);

          % superposition
          s(ll).dtfs2{ii} = g(1)*s(ll).spdtfs(:,id1,:) + g(2)*s(ll).spdtfs(:,id2,:);

          [s(ll).p1(:,ii),respang] = baumgartner2014(...
            s(ll).spdtfs(:,id0,:),s(ll).spdtfs,s(ll).fs,'S',s(ll).S,...
            'mrsmsp',MRS,'polsamp',polang);
          s(ll).p2(:,ii) = baumgartner2014(...
            s(ll).dtfs2{ii},s(ll).spdtfs,s(ll).fs,'S',s(ll).S,...
            'mrsmsp',MRS,'polsamp',polang);

          [s(ll).qe1(ii),s(ll).pe1(ii)] = baumgartner2014_pmv2ppp(...
            s(ll).p1(:,ii),polang(id0),respang);
          [s(ll).qe2(ii),s(ll).pe2(ii)] = baumgartner2014_pmv2ppp(...
            s(ll).p2(:,ii),polang(id0),respang);

          % Increse of error
          qeI(ll,ii) = s(ll).qe2(ii) - s(ll).qe1(ii);
          peI(ll,ii) = s(ll).pe2(ii) - s(ll).pe1(ii);
      end
      amt_disp([num2str(ii) ' of ' num2str(length(idtest)) ' completed']);
    end

    amt_cache('set','panningangle',peI,s,pol0,DL,respang);
    
  end
  
  id1 = 'NH71'; % positive example
  id2 = 'NH62'; % negative example
  
  if flags.do_plot
    
    cmp= [0.2081    0.1663    0.5292;
          0.2052    0.2467    0.6931;
          0.0843    0.3472    0.8573;
          0.0157    0.4257    0.8789;
          0.0658    0.4776    0.8532;
          0.0777    0.5300    0.8279;
          0.0356    0.5946    0.8203;
          0.0230    0.6443    0.7883;
          0.0485    0.6793    0.7341;
          0.1401    0.7085    0.6680;
          0.2653    0.7327    0.5916;
          0.4176    0.7471    0.5142;
          0.5624    0.7487    0.4529;
          0.6872    0.7433    0.4029;
          0.7996    0.7344    0.3576;
          0.9057    0.7261    0.3105;
          0.9944    0.7464    0.2390;
          0.9847    0.8141    0.1734;
          0.9596    0.8869    0.1190;
          0.9763    0.9831    0.0538]; % parula colormap (defined for compatibility with older Matlab versions)
    
    figure

    p_pool = nan(size(s(1).p2,1),size(s(1).p2,2),length(s));
    for ll = 1:length(s)
      p_pool(:,:,ll) = s(ll).p2;
      if strcmp(s(ll).id,id1)
        subplot(1,4,1)
        plot_baumgartner2014(s(ll).p2,pol0,respang,'cmax',0.08)
        colormap(cmp)
        title(s(ll).id,'FontSize',kv.FontSize)
        xlabel(''); 
        ylabel('Response angle (deg)','FontSize',kv.FontSize);
        colorbar off
      elseif strcmp(s(ll).id,id2)
        subplot(1,4,2)
        plot_baumgartner2014(s(ll).p2,pol0,respang,'cmax',0.08)
        colormap(cmp)
        xlabel('Panning angle (deg)','FontSize',kv.FontSize);      
        ylabel(''); set(gca,'YTickLabel',[]);
        title(s(ll).id,'FontSize',kv.FontSize)
        colorbar off
      end
    end
    p_pool = mean(p_pool,3);
    subplot(1,4,3)
    plot_baumgartner2014(p_pool,pol0,respang,'cmax',0.08)
    colormap(cmp)
    title('Pool','FontSize',kv.FontSize)
    xlabel(''); 
    ylabel(''); set(gca,'YTickLabel',[]);
    colorbar off

    subplot(1,4,4)
    ymax = 8;
    y = -0.15:0.1:ymax+0.15;
    Ny = length(y);
    pcolor(1:2,y,repmat(y(:),1,2))
    shading flat
    axis tight
    colormap(cmp)
    title({' ';' '})
    set(gca,'XTick',[],'YTick',0:1:ymax,... 
      'YDir','normal','YAxisLocation','right','FontSize',kv.FontSize)
    ylabel({'Probability density (% per 5\circ)'},'FontSize',kv.FontSize)
    set(gca,'Position',get(gca,'Position').*[1.05,1,0.3,1])
  
  end
  
end

%% ------ FIG 5 of baumgartner2015jaes ------------------------------------
if flags.do_fig5
  
  [peI,s,pol0,DL,respang] = amt_cache('get','panningangle',flags.cachemode);
  
  if isempty(peI)
    exp_baumgartner2015('fig4','no_plot',flags.cachemode);
    [peI,s,pol0,DL,respang] = amt_cache('get','panningangle',flags.cachemode);
  end
  
  figure

  plot(peI')
  ylabel('Increase in polar error (deg)')

  % Panning angle axis
  set(gca,'XTick',1:10,'XTickLabel',round(pol0),...
      'YMinorTick','on','XLim',[1,10],'YLim',[-9,59])
  xlabel('Panning angle (deg)')
  
end

%% ------ FIG 6 of baumgartner2015jaes ------------------------------------
if flags.do_fig6
  
  results = amt_cache('get','replicatePulkki2001',flags.cachemode);
   
  if isempty(results)
  
    amt_disp('Results may slightly vary from simulation to simulation because noise stimulus is not fixed.');
    
    MRS = 0;

    pol1 = -15; % polar angle of lower Lsp.
    pol2 = 30; % polar angle of higher Lsp.

    polphant = [0,15]; % polar angles of phantom sources
    Pmax = nan(length(polphant),23); % max Probabilities
    panang_Pmax = nan(length(polphant),23); % panning angle selected by max P
    panang_Cen = nan(length(polphant),23); % panning angle selected by centroid
    for pp = 1:length(polphant)

    lat = 0; % must be 0 otherwise VBAP wrong!

    s = data_baumgartner2014('pool');

    s(1).spdtfs = [];
    [s(1).spdtfs,polang] = extractsp(lat,s(1).Obj); 

    % restrict response range
    idrang = find(polang >= pol1 & polang <= pol2); % to range between loudspeakers
    % idrang = find(polang <= 90); % to the front

    idtest = find(polang >= pol1 & polang <= pol2);
    id1 = find(polang >= pol1,1); % ID lower pos.
    id2 = find(polang <= pol2,1,'last'); % ID higher pos.
    tang = polang(id1:id2);

    for ll = 1:length(s)
      s(ll).spdtfs = extractsp(lat,s(ll).Obj);

      for ii = 1:length(idtest)

        id0 = idtest(ii);  % ID pos. of phantom source

        % VBAP
        [p(1,1),p(1,2),p(1,3)] = sph2cart(lat,deg2rad(polang(id0)),1);
        [L(1,1),L(1,2),L(1,3)] = sph2cart(lat,deg2rad(pol1),1);
        [L(2,1),L(2,2),L(2,3)] = sph2cart(lat,deg2rad(pol2),1);
        g = p/L;
        g = g/norm(g);

        DL(ii) = db(g(1)) - db(g(2));

        % superposition
        s(ll).dtfs2{ii} = g(1)*s(ll).spdtfs(:,id1,:) + g(2)*s(ll).spdtfs(:,id2,:);    

        [s(ll).p(:,ii),rang] = baumgartner2014(...
              s(ll).dtfs2{ii},s(ll).spdtfs(:,idrang,:),s(ll).fs,'S',s(ll).S,...
              'mrsmsp',MRS,'polsamp',polang(idrang),'rangsamp',5,...
              'stim',noise(10000,1,'pink')); % phantom source

      end

      id_rang = rang == polphant(pp);

      % interpolation between target angles
      tang_int = tang(1):1:tang(end);
      p_int = interp2(tang(:)',rang(:),s(ll).p,tang_int(:)',rang(:),'spline');
      p_int = p_int./repmat(sum(p_int,1),size(p_int,1),1); % normalize to PMVs

      % Variant 1: max P at source direction
      [Pmax(pp,ll),id_best_pan] = max(p_int(id_rang,:));
      panang_Pmax(pp,ll) = tang_int(id_best_pan);

      % Variant 2: centroid closest to source direction
      M = rang*p_int;
      [tmp,id_best_pan] = min(abs(M-polphant(pp)));
      panang_Cen(pp,ll) = tang_int(id_best_pan);

    end
      fprintf([num2str(pp) ' of ' num2str(length(polphant)) ' completed \n']);
    end

    results = struct('panang_Pmax',panang_Pmax,'Pmax',Pmax,...
      'panang_Cen',panang_Cen,'polphant',polphant,'DL',DL,'rang',rang);
    
    amt_cache('set','replicatePulkki2001',results);
    
  end
  
  [panang_varStrat,nCM_varStrat,p_varStrat,muhat,sigmahat] = amt_cache('get','replicatePulkki2001_varStrat',flags.cachemode);
  if isempty(panang_varStrat)
    
    pulkki01 = data_pulkki2001;
    [muhat(1),sigmahat(1)] = normfit(pulkki01(1,:));
    [muhat(2),sigmahat(2)] = normfit(pulkki01(2,:));
    
    Nsub = size(results.panang_Cen,2);
    panang_all = [];
    p = [];
    nCM = [];
    tmp = [];
    ii = 1;
    for inCM = 1:Nsub+1
      c = nchoosek(1:Nsub,inCM-1); % listeners with CM strategy
      lenC = size(c,1);
      nCM = [nCM;repmat(inCM,lenC,1)];
      panang_all = cat(3,panang_all , nan(2,Nsub,lenC));
      p = [p ; nan(lenC,2)];
      for ic = 1:lenC
        idCM = false(1,Nsub);
        idCM(c(ic,:)) = true;
        panang_all(:,:,ii) = [results.panang_Cen(:,idCM) results.panang_Pmax(:,not(idCM))];
        [tmp.h1,p(ii,1)] = kstest((panang_all(1,:,ii)-muhat(1))/sigmahat(1)); % center data acc. to target distribution and then test similarity to standard normal distribution
        [tmp.h2,p(ii,2)] = kstest((panang_all(2,:,ii)-muhat(2))/sigmahat(2));
        ii = ii+1;
      end
      disp([num2str(inCM) ' of ' num2str(Nsub+1) ' done'])
    end
    [tmp.min,idmax] = max(sum(p,2)); % best fit
    panang_varStrat = panang_all(:,:,idmax);
    nCM_varStrat = nCM(idmax);
    p_varStrat = p(idmax,:);
    
    amt_cache('set','replicatePulkki2001_varStrat',panang_varStrat,nCM_varStrat,p_varStrat,muhat,sigmahat)
    
  end
  
  if flags.do_plot
    
    pulkki01 = data_pulkki2001;
    Nsub = size(results.panang_Cen,2);
    
    figure
    for ii = 1:2

      subplot(1,2,ii)

      X = nan(size(pulkki01,2)*size(pulkki01,3),4);
      X(:,1) = pulkki01(ii,:);
      X(1:Nsub,2) = results.panang_Pmax(ii,:)';
      X(1:Nsub,3) = results.panang_Cen(ii,:)';

      X(1:Nsub,4) = panang_varStrat(ii,:)';

      plot([0,5],(ii-1)*15*[1,1],'k:') 
      hold on

      boxplot(X,'symbol','k*','outliersize',3)

      set(gca,'YLim',[-17,32], 'XTickLabel',{'[2]','PM','CM','Mixed'});
	  if ~verLessThan('matlab','8.4'), set(gca,'XTickLabelRotation',45); end
      if ii==1; 
        ylabel('Panning angle (deg)')
        text(0.7,27.5,'0\circ')
      else
        set(gca,'YTickLabel',[]); 
        text(0.7,27.5,'15\circ')
      end
    end
    
  end
  
end

%% ------ FIG 7 of baumgartner2015jaes ------------------------------------
if flags.do_fig7
  
  [peI,dPol] = amt_cache('get','loudspeakerspan',flags.cachemode);
  
  if isempty(peI)
    
    MRS = 0;

    flags.do_fig20 = false;
    flags.do_fig19 = false;

    s = data_baumgartner2014('pool');

    if flags.do_fig19
      dPol = [0 30,60];
      s = s(2); % NH12
    else
      dPol = 10:10:90; 
    end
    lat = 0;

    s(1).spdtfs = [];
    [s(1).spdtfs,polang] = extractsp(lat,s(1).Obj); 
    peI = zeros(length(s),length(dPol));
    peA = zeros(length(s),length(dPol)+1);
    ii = 0;
    while ii < length(dPol)
      ii = ii + 1;

      % find comparable angles
      id0 = [];
      id1 = [];
      id2 = [];
      for jj = 1: length(polang)
          t0 = find( round(polang) == round(polang(jj)+dPol(ii)/2) );
          t2 = find( round(polang) == round(polang(jj)+dPol(ii)) );
          if ~isempty(t0) && ~isempty(t2)
              id0 = [id0 t0];
              id1 = [id1 jj];
              id2 = [id2 t2];
          end
      end
      pol2{ii} = (polang(id1)+polang(id2)) /2;

      amt_disp([' Span: ' num2str(dPol(ii)) 'deg']);
      for ll = 1:length(s)

          s(ll).spdtfs = extractsp(lat,s(ll).Obj);

          % superposition
          s(ll).dtfs2{ii} = s(ll).spdtfs(:,id1,:) + s(ll).spdtfs(:,id2,:);

          [s(ll).p1{ii},respang] = baumgartner2014(...
            s(ll).spdtfs(:,id0,:),s(ll).spdtfs,s(ll).fs,'S',s(ll).S,...
            'mrsmsp',MRS,'polsamp',polang);
          s(ll).p2{ii} = baumgartner2014(...
            s(ll).dtfs2{ii},s(ll).spdtfs,s(ll).fs,'S',s(ll).S,...
            'mrsmsp',MRS,'polsamp',polang);

          % RMS Error
          [s(ll).qe1{ii},s(ll).pe1{ii}] = baumgartner2014_pmv2ppp(...
            s(ll).p1{ii},polang(id0),respang);
          [s(ll).qe2{ii},s(ll).pe2{ii}] = baumgartner2014_pmv2ppp(...
            s(ll).p2{ii},pol2{ii},respang);

          % Increse of error
          peI(ll,ii) = s(ll).pe2{ii} - s(ll).pe1{ii};

      end

    end

    amt_cache('set','loudspeakerspan',peI,dPol)
    
  end
    
  peIm = mean(peI,1);
  peIstd = std(peI,1,1);
    
  if flags.do_plot
    
    figure
    p = patch([dPol,fliplr(dPol)],[peIm+peIstd,fliplr(peIm-peIstd)],.7*[1,1,1]);
    set(p,'EdgeColor',.7*[1,1,1]);
    hold on
    h = plot(dPol,peIm,'k');
    set(h,'LineWidth',1)
    set(gca,'XTick',dPol,'XTickLabel',dPol,...
          'YMinorTick','on','Box','on','Layer','top')
    axis([9.8,90.2,-2,27])
    ylabel({'Increase in polar error (deg)'})
    xlabel({'Loudspeaker span (deg)';''})
    
  end
  
end

%% ------ FIG 8 of baumgartner2015jaes ------------------------------------
if flags.do_fig8
  
  [r2,dPol] = amt_cache('get','loudspeakerspan_r2',flags.cachemode);
  
  if isempty(r2)
    MRS = 0;

    s = data_baumgartner2014('pool');

    dPol = 0:10:105; 

    lat = 0;
    runs = 100;

    
    DL = -13:5:7; % panning ratios in dB
    
    s(1).spdtfs = [];
    [s(1).spdtfs,polang] = extractsp(lat,s(1).Obj); 
    r2 = zeros(length(s),length(dPol));
    r2 = [];
    ii = 0;
    while ii < length(dPol) % various spans
      ii = ii + 1;

      disp([' Span: ' num2str(dPol(ii)) 'deg']);

      r2total = nan(length(s),length(DL));
      r2front = nan(length(s),length(DL));
      r2rear = nan(length(s),length(DL));
      for idl = 1:length(DL)

      % find comparable angles
      id1 = []; % id of speaker with smaller polar angle
      id2 = []; % id of speaker with larger polar angle
      for jj = 1: length(polang)
%           t0 = find( round(polang) == round(polang(jj)+ipf*dPol(ii)/polFrac) );
          t2 = find( round(polang) == round(polang(jj)+dPol(ii)) );
          if ~isempty(t2)
%               id0 = [id0 t0];
              id1 = [id1 jj];
              id2 = [id2 t2];
          end
      end

      g = inv([1,1;1,-10^(DL(idl)/20)]) * [1;0]; % derived from db(g1/g2)=DL and g1+g2=1 (chosen arbitrarily since energy preservation is not relevant here)
      
      pol0 = nan(length(id1),1); % panning angles
      for jj = 1:length(id1)
        [L(1,1),L(1,2),L(1,3)] = sph2cart(0,deg2rad(polang(id1(jj))),1);
        [L(2,1),L(2,2),L(2,3)] = sph2cart(0,deg2rad(polang(id2(jj))),1);
        t = g'*L;
        [azi,ele,tmp.r] = cart2sph(t(1),t(2),t(3));
        [tmp.lat,pol0(jj)] = sph2hor(rad2deg(azi),rad2deg(ele));
      end

      for ll = 1:length(s) % various listeners

          s(ll).spdtfs = extractsp(lat,s(ll).Obj);

          % superposition
          s(ll).dtfs2{ii} = g(1)*s(ll).spdtfs(:,id1,:) + g(2)*s(ll).spdtfs(:,id2,:);

          [s(ll).p2{ii},rang] = baumgartner2014(...
            s(ll).dtfs2{ii},s(ll).spdtfs,s(ll).fs,'S',s(ll).S,...
            'mrsmsp',MRS,'polsamp',polang,'rangsamp',1); % phantom

          % total polar range 
          m2 = baumgartner2014_virtualexp(s(ll).p2{ii},pol0,rang,'runs',runs);

          % R2 via correlation coefficient
          r = corrcoef(m2(:,8),m2(:,6));
          r2total(ll,idl) = r(2);

          % restricted to frontal polar range 
          idfront = rang <= 90;
          respangfront = rang(idfront);
          idpol0front = pol0 <= 90;
          pol0front = pol0(idpol0front);
          p = s(ll).p2{ii}(idfront,idpol0front);

          m2front = baumgartner2014_virtualexp(p,pol0front,respangfront,'runs',runs);

          r = corrcoef(m2front(:,8),m2front(:,6));
          r2front(ll,idl) = r(2);

          % restricted to rear polar range 
          idrear = rang >= 90;
          respangrear = rang(idrear);
          idpol0rear = pol0 >= 90;
          pol0rear = pol0(idpol0rear);
          p = s(ll).p2{ii}(idrear,idpol0rear);

          m2rear = baumgartner2014_virtualexp(p,pol0rear,respangrear,'runs',runs);

          r = corrcoef(m2rear(:,8),m2rear(:,6));
          r2rear(ll,idl) = r(2);

      end
      end
      r2.total(:,ii) =  nanmean(r2total,2);
      r2.front(:,ii) =  nanmean(r2front,2); 
      r2.rear(:,ii) =  nanmean(r2rear,2);
    end
 
    amt_cache('set','loudspeakerspan_r2',r2,dPol)

  end
    
  % data extracted from Fig.6 (data:AVG) of Bremen et al. (2010, J Neurosci,
  % 30:194-204) via http://arohatgi.info/WebPlotDigitizer
  bremen2010.pol = 15:15:105;
  bremen2010.r2 = [.85 , .81 , .63 , .38 , .19 , .11 , .21];
  
  if flags.do_plot

    figure
    h(1) = plot(bremen2010.pol,bremen2010.r2,'bo-');
    hold on
    h(2) = plot(dPol,mean(r2.front),'bo-');

    h(3) = plot(dPol,mean(r2.rear),'rs-');
    h(4) = plot(dPol,mean(r2.total),'kd-');

    set(h(1),'MarkerSize',kv.MarkerSize,'MarkerFaceColor','b')
    set(h(2:4),'MarkerSize',kv.MarkerSize,'MarkerFaceColor','w')
    set(gca,'XLim',[-5,110],'YLim',[-.05,1.05])

    leg = legend('Frontal from [18]','Frontal','Rear','Overall','Location','best');
    set(leg,'FontSize',kv.FontSize)

    xlabel({'Loudspeaker span (deg)';''})
    ylabel('\it{r}^{ 2}')
  end
  
end

%% ------ FIG 9 of baumgartner2015jaes ------------------------------------
if flags.do_fig9
  
  SysName{1}  = 'NHK 22.2 (without bottom layer)';
  LSPsetup{1} = [ 0,0 ; 30,0 ; 60,0 ;  90,0 ; 135,0 ; ...
                180,0 ;-30,0 ;-60,0 ; -90,0 ;-135,0 ; ...
                  0,45; 45,45; 90,45; 135,45; 180,45; ...
               -135,45;-90,45;-45,45;   0,90];

  SysName{2}  = 'Samsung 11.2';
  LSPsetup{2} = [ 0,0 ; 60,0 ;  90,0 ; 135,0 ; ...
                       -60,0 ; -90,0 ;-135,0 ; ...
                 45,45;135,45; -45,45;-135,45];

  SysName{3}  = 'Samsung 10.2';
  LSPsetup{3} = [ 0,0 ; 60,0 ;  90,0 ; 135,0 ; ...
                       -60,0 ; -90,0 ;-135,0 ; ...
                 45,45;180,45; -45,45];

  SysName{4}  = 'USC 10.2';
  LSPsetup{4} = [ 0,0 ; 30,0 ; 60,0 ;  115,0 ; ...
                180,0 ;-30,0 ;-60,0 ; -115,0 ; ...
                 45,45;-45,45];

  SysName{5}  = 'Auro-3D 10.1';
  LSPsetup{5} = [ 30,0 ; 30,30 ; 135,30 ; 135,0;...
            0,0 ;-30,0 ;-30,30 ;-135,30 ;-135,0; 0,90];        

  SysName{6}  = 'Auro-3D 9.1';
  LSPsetup{6} = [ 30,0 ; 30,30 ; 135,30 ; 135,0;...
            0,0 ;-30,0 ;-30,30 ;-135,30 ;-135,0]; 
  
  latall = -45:5:45;
  polall = 0:10:180;
          
  pe = amt_cache('get','locaVBAP',flags.cachemode);
  
  if isempty(pe)
    
    MRS = 0;

    s = data_baumgartner2014('pool');
    
    pe = zeros(length(latall),length(polall),length(s),length(LSPsetup),2); % predicted local polar RMS errors
    for ll = 1:length(LSPsetup)
      for aa = 1:length(latall)
        lat = latall(aa);

        for pp = 1:length(polall)
          pol = polall(pp);

          % Select LSP-Triangle and compute VBAP gains
          [source_pos(1),source_pos(2)] = hor2sph(lat,pol);
          Nlsp = length(LSPsetup{ll});
          [g,IDsp] = local_vbap(LSPsetup{ll},source_pos);


          for jj = 1:length(s)

            % Compute binaural impulse response of loudspeaker triple
            dtfs = permute(double(s(jj).Obj.Data.IR),[3 1 2]);
            lsp_hrirs = zeros(length(IDsp),size(dtfs,1),2);
            for ii = 1:length(IDsp)
    %           [lat_sp,pol_sp] = sph2horpolar(LSPsetup{ll}(IDsp(ii),1),LSPsetup{ll}(IDsp(ii),2));
              idx = local_findNearestPoslocaVBAP(...
                LSPsetup{ll}(IDsp(ii),1:2),s(jj).Obj.SourcePosition(:,1:2));
              lsp_hrirs(ii,:,:) = squeeze(dtfs(:,idx,:));
            end
            target(:,1,1) = g*lsp_hrirs(:,:,1);
            target(:,1,2) = g*lsp_hrirs(:,:,2);

            % SP-template
            [spdtfs,polang] = extractsp(lat,s(jj).Obj);

            % Run loca model
            [p,rang] = baumgartner2014(...
                    target,spdtfs,s(jj).fs,'S',s(jj).S,...
                    'lat',lat,'polsamp',polang,'mrsmsp',MRS);

            m = baumgartner2014_virtualexp(p,pol,rang,'runs',1000);
            pe(aa,pp,jj,ll,1) = localizationerror(m,'precPnoquerr');
            [~,pe(aa,pp,jj,ll,2)] = baumgartner2014_pmv2ppp(p,pol,rang);

          end
        end
      end
      amt_disp([num2str(ll) ' of ' num2str(length(LSPsetup)) ' done']);
    end
    amt_cache('set','locaVBAP',pe)
  end
 
  MRS = 0;
  pe_ref = amt_cache('get','locaVBAP_ref',flags.cachemode);
  if isempty(pe_ref)
    
    s = data_baumgartner2014('pool');

    latall = -45:5:45;
    polall = 0:10:180;
    pe_ref = zeros(length(latall),length(polall),length(s),1,2); % predicted local polar RMS errors

    %% Computations

    for jj = 1:length(s)

      dtfs = permute(double(s(jj).Obj.Data.IR),[3 1 2]);

      for aa = 1:length(latall)
        lat = latall(aa);
        for pp = 1:length(polall)
          pol = polall(pp);
          [lat_sp,pol_sp,idx] = local_findNearestPoslocaVBAPref(lat,pol,s(jj).Obj.SourcePosition(:,1:2));
          target = dtfs(:,idx,:);

          % SP-template
          [spdtfs,polang] = extractsp(lat,s(jj).Obj);

          % Run loca model
          [p,rang] = baumgartner2014(...
                  target,spdtfs,s(jj).fs,'S',s(jj).S,...
                  'mrsmsp',MRS,'lat',lat,'polsamp',polang);

          m = baumgartner2014_virtualexp(p,pol,rang,'runs',1000);
          pe_ref(aa,pp,jj,1,1) = localizationerror(m,'precPnoquerr');
          [~,pe_ref(aa,pp,jj,1,2)] = baumgartner2014_pmv2ppp(p,pol,rang);

        end
      end
    end
    
    amt_cache('set','locaVBAP_ref',pe_ref)
  end

  N = length(LSPsetup);
  eRMS = pe_ref(:,:,:,:,2);
  eRMS(:,:,:,2:N+1) = pe(:,:,:,:,2);

  if flags.do_plot

    labels = {'Reference';'\it A';'\it B';'\it C';'\it D';'\it E';'\it F'};
    labels = labels(1:N+1,:);
    
    figure 
    for ll = 1:N+1

      pemean = squeeze(mean(eRMS(:,:,:,ll),3));
      subplot(1,N+2,ll)
      imagesc(latall,polall,pemean')
      set(gca,'YTick',0:30:180,'XTick',-30:30:30)
      axis equal tight
      colormap hot
      if MRS == 0
        ymin = 15.5;
        ymax = 49.5;
      else
        ymin = 15.5;
        ymax = 49.5;
      end
      caxis([ymin ymax])
      if ll==1; 
        ylabel('Polar angle (deg)','FontName','Helvetica'); 
      else 
        set(gca,'YTickLabel',[])
      end

      if ll==4; xlabel('Lateral angle (deg)','FontName','Helvetica'); end

      title(labels{ll},'FontName','Helvetica')

      % Loudspeaker positions
      if ll > 1
        [lat_lsp,pol_lsp] = sph2hor(LSPsetup{ll-1}(:,1),LSPsetup{ll-1}(:,2));
        idlat = abs(lat_lsp) <= max(abs(latall))+1;
        hold on
        h2 = plot(lat_lsp(idlat),pol_lsp(idlat),'wo');
        set(h2,'MarkerSize',2*3.5);
        h1 = plot(lat_lsp(idlat),pol_lsp(idlat),'ko');
        set(h1,'MarkerSize',2*3);
      end
    end

    subplot(1,N+2,N+2)
    y = ymin:1:ymax;
    Ny = length(y);
    pcolor(1:2,y,repmat(y(:),1,2))
    shading flat
    axis tight
    colormap hot
    title({' ';' '})
    set(gca,'XTick',[],'YTick',20:5:45,... %,'TickLength',[0.12,0.12]
      'YDir','normal','YAxisLocation','right','FontSize',kv.FontSize)
    ylabel({'Polar error (deg)'},'FontSize',kv.FontSize)
    set(gca,'Position',get(gca,'Position').*[1.03,1.8,0.3,0.8])
  end
  
end

%% ------ Tab 1 of baumgartner2015jaes ------------------------------------
if flags.do_tab1
  
  results = amt_cache('get','replicatePulkki2001',flags.cachemode);
  [panang_varStrat,nCM_varStrat,p_varStrat,muhat,sigmahat] = amt_cache('get','replicatePulkki2001_varStrat',flags.cachemode);
  if isempty(panang_varStrat)
    exp_baumgartner2015('fig6','no_plot',flags.cachemode)
  end
  
  pulkki01 = data_pulkki2001;
  
  [h1_pul,p1_pul] = kstest((pulkki01(1,:)-muhat(1))/sigmahat(1)); % center data acc. to target distribution and then test similarity to standard normal distribution
  [h2_pul,p2_pul] = kstest((pulkki01(2,:)-muhat(2))/sigmahat(2));
  [h1_pm,p1_pm] = kstest((results.panang_Pmax(1,:)-muhat(1))/sigmahat(1)); % center data acc. to target distribution and then test similarity to standard normal distribution
  [h2_pm,p2_pm] = kstest((results.panang_Pmax(2,:)-muhat(2))/sigmahat(2));
  [h1_cm,p1_cm] = kstest((results.panang_Cen(1,:)-muhat(1))/sigmahat(1)); % center data acc. to target distribution and then test similarity to standard normal distribution
  [h2_cm,p2_cm] = kstest((results.panang_Cen(2,:)-muhat(2))/sigmahat(2));

  amt_disp('p-values of K.S.-test:','documentation');
  amt_disp('Real source at 0 deg:','documentation');
  amt_disp(['  Results Pulkki (2001): p = ' num2str(p1_pul,'%3.2f')],'documentation');
  amt_disp(['  Probability Maximiz.:  p = ' num2str(p1_pm,'%3.2f')],'documentation');
  amt_disp(['  Centroid Match:        p = ' num2str(p1_cm,'%3.2f')],'documentation');
  amt_disp(['  Individual strategy:   p = ' num2str(p_varStrat(1),'%3.2f') ' (#CM = ' num2str(nCM_varStrat) ')'],'documentation');
  amt_disp('Real source at 15 deg:','documentation');
  amt_disp(['  Results Pulkki (2001): p = ' num2str(p2_pul,'%3.2f')],'documentation');
  amt_disp(['  Probability Maximi.:   p = ' num2str(p2_pm,'%3.2f')],'documentation');
  amt_disp(['  Centroid Match:        p = ' num2str(p2_cm,'%3.2f')],'documentation');
  amt_disp(['  Individual strategy:   p = ' num2str(p_varStrat(2),'%3.2f') ' (#CM = ' num2str(nCM_varStrat) ')'],'documentation');
  
end

%% ------ Tab 3 of baumgartner2015jaes ------------------------------------
if flags.do_tab3
  
  pe = amt_cache('get','locaVBAP',flags.cachemode);
  pe_ref = amt_cache('get','locaVBAP_ref',flags.cachemode);
  if isempty(pe)
    exp_baumgartner2014('fig9_baumgartner2015jaes','no_plot',flags.cachemode);
  end
  
  N = size(pe,4); % # loudspeakers
  eRMS = pe_ref(:,:,:,:,2);
  eRMS(:,:,:,2:N+1) = pe(:,:,:,:,2);
  
  labels = {'Reference';'\it A';'\it B';'\it C';'\it D';'\it E';'\it F'};
  labels = labels(1:N+1,:);

  amt_disp('RMS error difference from reference averaged across directions','documentation');
  amt_disp('System  min  mean  max','documentation');
  for ll = 2:N+1
    IeRMS = eRMS(:,:,:,ll) - eRMS(:,:,:,1);
    IeRMS = mean(IeRMS,3); % average across listeners
    amt_disp([labels{ll} ' ' num2str(min(IeRMS(:)),'%2.1f') ' ' num2str(mean(IeRMS(:)),'%2.1f') ' ' num2str(max(IeRMS(:)),'%2.1f')],'documentation');
  end
  
end

end



%% ------------------------------------------------------------------------
%  ---- INTERNAL FUNCTIONS ------------------------------------------------
%  ------------------------------------------------------------------------


function [idx,posN] = local_findNearestPoslocaVBAP(posdesired,posexist)
% FINDNEARESTPOS_LOCAVABAP finds nearest position. Data given in spherical
% coordinates
%
% Usage:    [idx,posN] = findNearestPos(posdesired,posexist)

ds = deg2rad(posdesired);
es = deg2rad(posexist);

[d(:,1),d(:,2),d(:,3)] = sph2cart(ds(:,1),ds(:,2),ones(size(ds,1),1));
[e(:,1),e(:,2),e(:,3)] = sph2cart(es(:,1),es(:,2),ones(size(es,1),1));

D = e-repmat(d,length(es),1);
[Dmin,idx] = min(sum(D.^2,2));

posN = posexist(idx,:);

end

function [latN,polN,idx] = local_findNearestPoslocaVBAPref(lat,pol,aziele)
% FINDNEARESTPOS_LOCAVBAP_REF finds nearest position according to lat. and pol. angle
%
% Usage:    [latN,polN,idx] = findNearestPos(lat,pol,aziele)

[positions(:,1),positions(:,2)] = sph2hor(aziele(:,1),aziele(:,2));
d_lat = abs(lat-positions(:,1));
d_pol = abs(pol-positions(:,2));
d = d_lat+d_pol;
[d_min,idx] = min(d);
latN = positions(idx,1);
polN = positions(idx,2);

end

function [g,IDspeaker] = local_vbap(lsp_coord,source_pos)
%VBAP Returns array of gains for VBAP triplet of speakers.         
%   Usage: [g,IDspeaker] = vbap(speaker_coord,source_pos)
%
%   Input Parameters:
%     lsp_coord  : spherical (azi,ele) coordinates of loudspeakers
%     source_pos : spherical (azi,ele) coordinates of phantom source
%
%   Output Parameters:
%     g          : VBAP gains of loudspeaker triplet
%     IDspeaker  : indices of selected loudspeaker triplet

Nlsp = size(lsp_coord,1);

% Convert to spherical coordinates winth angles in radians
speaker_sph = deg2rad(lsp_coord);
source_sph = deg2rad(source_pos);

% Convert to cartesian coordinates
[speaker_cart(:,1),speaker_cart(:,2),speaker_cart(:,3)] = sph2cart(...
  speaker_sph(:,1),speaker_sph(:,2),ones(Nlsp,1));
[source_cart(1),source_cart(2),source_cart(3)] = sph2cart(...
  source_sph(1),source_sph(2),1);

% Add imaginary speaker below
if min(lsp_coord(:,2)) >= 0
  speaker_cart = [speaker_cart;0,0,-10];
end

% Select lsp. triplet
dt = DelaunayTri(speaker_cart);
ch = convexHull(dt);
% figure; trisurf(ch, dt.X(:,1),dt.X(:,2),dt.X(:,3), 'FaceColor', 'cyan')
d = zeros(length(ch),1);
for ii = 1:length(ch)
  d(ii) = sum(local_dist(source_cart,speaker_cart(ch(ii,:),:)));
end
[~,IDch] = min(d);
IDspeaker = ch(IDch,:);

% Compute lsp. gains
g = source_cart / speaker_cart(IDspeaker,:);
g = g / norm(g);


end

function d = local_dist(x,Y)

d = sqrt(sum((repmat(x,size(Y,1),1)-Y).^2,2));

end