function varargout = baumgartner2016( target,template,varargin )
%BAUMGARTNER2016 Level-dependent model for localization in sagittal planes
% Usage: [p,rang,tang] = baumgartner2016( target,template )
% [err,pred,m] = baumgartner2016( target,template,errorflag )
%
% Input parameters:
% target : binaural impulse response(s) referring to the directional
% transfer function(s) (DFTs) of the target sound(s).
% template: binaural impulse responses of all available
% listener-specific DTFs of the sagittal plane referring to
% the perceived lateral angle of the target sound
% label: 2-element cell array including labels used for caching.
% Provide listener ID (e.g., 'NH12') in label{1}, and
% target condition information in label{2}.
%
% Output parameters:
% p : predicted probability mass vectors for response angles
% with respect to target positions
% 1st dim: response angle
% 2nd dim: target angle
% rang : polar response angles (after regularization of angular
% sampling)
% tang : polar target angles (usefull if sagittal-plane HRTFs are
% extracted directly from SOFA object)
% err : predicted localization error (acc. to performance measure
% defined in errorflag*
% pred : structure with fields p, rang, tang*
% m : item list from virtual experiment. See
% help localizationerror for format description.
%
% BAUMGARTNER2016(...) is a model for sound-source localization
% in sagittal planes (SPs). It bases on the comparison of internal sound
% representation with a template and results in a probabilistic
% prediction of polar angle response.
%
% BAUMGARTNER2016 accepts the following optional parameters:
%
% 'ID' Listeners ID (important for caching).
%
% 'Condition' Label of experimental condition (also for caching).
%
% 'fs',fs Define the sampling rate of the impulse responses.
% Default value is 48000 Hz.
%
% 'S',S Set the listener-specific sensitivity threshold
% (threshold of the sigmoid link function representing
% the psychometric link between transformation from the
% distance metric and similarity index) to S.
% Default value is 1.
%
% 'lat',lat Set the apparent lateral angle of the target sound to
% lat. Default value is 0 degree (median SP).
%
% 'stim' Define the stimulus (source signal without directional
% features). As default temstim is used.
%
% 'fsstim' Define the sampling rate of the stimulus.
% Default value is 48000 Hz.
%
% 'temstim' Define the dummy stimulus used to create the templates.
% The default is Gaussian white noise with a duration of 170 ms.
%
% 'SPL',L Set the SPL of the stimulus to L dB.
% Default value is 60dB.
%
% 'SPLtem',Lt Set the SPL of the templates to a specific SPL of Lt*dB
% if Lt is a scalar or define a SPL range between
% Lt(1) and Lt(2)*dB if Lt is a two-element vector.
% Default range is 40 to 70dB.
%
% 'flow',flow Set the lowest frequency in the filterbank to
% flow. Default value is 700 Hz.
%
% 'fhigh',fhigh Set the highest frequency in the filterbank to
% fhigh. Default value is 18000 Hz.
%
% 'space',sp Set spacing of auditory filter bands (i.e., distance
% between neighbouring bands) to sp in number of
% equivalent rectangular bandwidths (ERBs).
% Default value is 1 ERB.
%
% 'do',do Set the differential order of the spectral gradient
% extraction to do. Default value is 1 and includes
% restriction to positive gradients inspired by cat DCN
% functionality.
%
% 'bwcoef',bwc Set the binaural weighting coefficient bwc.
% Default value is 13 degrees.
%
% 'polsamp',ps Define the the polar angular sampling of the current
% sagittal plane. As default the sampling of ARIs HRTF
% format at the median SP is used, i.e.,
% ps = [-30:5:70,80,100,110:5:210] degrees.
%
% 'mrsmsp',mrs Set the motoric response scatter mrs within the median
% sagittal plane. Default value is 17 degrees.
%
% 'cohc',cohc OHC scaling factor: 1 denotes normal OHC function (default);
% 0 denotes complete OHC dysfunction.
%
% 'cihc',cihc IHC scaling factor: 1 denotes normal IHC function (default);
% 0 denotes complete IHC dysfunction.
%
% 'fiberTypes',fT Types of the fibers based on spontaneous rate (SR) in
% spikes/s: fT=1 for Low SR; fT=2 for Medium SR;
% fT=3 for High SR. Default is fT = 1:3.
%
% BAUMGARTNER2016 accepts the following flags:
%
% 'zilany2014' Use the model from Zilany et al. (2009,2014) for spectral
% analysis. This is the default.
%
% 'gammatone' Use the Gammatone filterbank for spectral analysis.
%
% 'SPLtemAdapt' Set SPL of templates acc. to target (*Lt*=*L*).
%
% 'NHtem' No adaptation of templates to hearing impairment,
% i.e., templates are processed with cohc=cihc=1 and
% fT = 1:3.
%
% 'ihc' Incorporate the transduction model of inner hair
% cells used by Dau et al. (1996).
%
% 'noihc' Do not incorporate the IHC stage. This is the default.
%
% 'regular' Apply spline interpolation in order to regularize the
% angular sampling of the polar response angle.
% This is the default.
%
% 'noregular' Disable regularization of angular sampling.
%
% 'errorflag' May be one of the error flags defined in
% baumgartner2014pmv2ppp or localizationerror.
%
% 'redoSpectralAnalysis' Flag to redo also spectral analysis based on
% zilany2014 model.
%
% Requirements:
% -------------
%
% 1) SOFA API from http://sourceforge.net/projects/sofacoustics for Matlab (in e.g. thirdparty/SOFA)
%
% 2) Data in hrtf/baumgartner2016
%
%
% See also: data_baumgartner2016,
% exp_baumgartner2016, baumgartner2016calibration,
% baumgartner2014pmv2ppp,
% baumgartner2014virtualexp, localizationerror,
% baumgartner2016spectralanalysis
%
% References:
% R. Baumgartner, P. Majdak, and B. Laback. Modeling the effects of
% sensorineural hearing loss on auditory localization in the median
% plane. Trends in Hearing, 20:1-11, 2016.
%
% M. S. A. Zilany, I. C. Bruce, and L. H. Carney. Updated parameters and
% expanded simulation options for a model of the auditory periphery. The
% Journal of the Acoustical Society of America, 135(1):283-286, Jan.
% 2014.
%
%
% Url: http://amtoolbox.sourceforge.net/data/amt-test/htdocs/amt-0.9.8/doc/models/baumgartner2016.php
% Copyright (C) 2009-2015 Piotr Majdak and Peter L. Søndergaard.
% This file is part of AMToolbox version 0.9.8
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
% AUTHOR: Robert Baumgartner, Acoustics Research Institute, Vienna, Austria
%% Check input options
definput.import={'baumgartner2016'};
posdepnames = {'fs','S','lat','stim','fsstim'};
[flags,kv]=ltfatarghelper(posdepnames,definput,varargin);
% Check default condition label for short stimuli
if length(kv.stim)/kv.fsstim < 0.005 && strcmp(kv.Condition,'Long') % short stimulus
kv.Condition = '';
end
% Extract sagittal-plane HRTFs
if isstruct(target) % Targets given in SOFA format
kv.fs = target.Data.SamplingRate;
[target,tang] = extractsp( kv.lat,target );
end
if isstruct(template) % Template given in SOFA format
[template,kv.polsamp] = extractsp( kv.lat,template );
end
%% Error handling
if size(template,2) ~= length(kv.polsamp)
fprintf('\n Error: Second dimension of template and length of polsamp need to be of the same size! \n')
return
end
%% Stimulus
% flags.temstim = false;
if isempty(kv.stim)
kv.stim = kv.temstim;
% flags.temstim = true;
kv.fsstim = kv.fs;
elseif isempty(kv.fsstim)
kv.fsstim = kv.fs;
end
if flags.do_headphone% || flags.do_drnl
hpfilt = headphonefilter(kv.fs);
kv.stim = lconv(kv.stim,hpfilt(:));
end
%% DTF filtering
if ~isequal(kv.fs,kv.fsstim)
amtdisp('Sorry, sampling rate of stimulus and HRIRs must be the same!')
return
end
tmp = lconv(target,kv.stim);
target = reshape(tmp,[size(tmp,1),size(target,2),size(target,3)]); % workaround for lconv bug
tmp = lconv(template,kv.temstim);
template = reshape(tmp,[size(tmp,1),size(template,2),size(template,3)]); % workaround for lconv bug
%% Cochlear filter bank -> internal representations
if flags.do_redoSpectralAnalysis
redoSAflag = 'redo';
else
redoSAflag = 'normal';
end
% Target profile
[mreptar,fc] = baumgartner2016spectralanalysis(target,kv.SPL,'target',...
'argimport',flags,kv,redoSAflag);
% Template profile
if flags.do_NHtem
kv.cohc = 1;
kv.cihc = 1;
kv.fiberTypes = 1:3;
end
if flags.do_SPLtemAdapt
kv.SPLtem = kv.SPL;
end
if isscalar(kv.SPLtem) % all templates represented at a fixed SPL
mreptem = baumgartner2016spectralanalysis(template,kv.SPLtem,'template',...
'argimport',flags,kv,redoSAflag);
else % average across SPL range
mreptem = baumgartner2016spectralanalysis(template,kv.SPLtem(1),'template',...
'argimport',flags,kv,redoSAflag);
SPLtemRange = kv.SPLtem(1):10:kv.SPLtem(2);
for ii = 2:length(SPLtemRange)
mreptem = mreptem + ...
baumgartner2016spectralanalysis(template,SPLtemRange(ii),'template',...
'argimport',flags,kv,redoSAflag);
end
mreptem = mreptem/length(SPLtemRange);
end
%% Positive spectral gradient extraction
if kv.do == 1 && flags.do_psge
% duration-dependence of c2 (inhibitory strength)
if length(kv.stim)/kv.fs < 5e-3 % halfen if shorter than 5ms
c2 = kv.psgeshort;
else
c2 = 1;
end
if flags.do_gammatone
greptar = baumgartner2014gradientextraction(mreptar,fc,c2);
greptem = baumgartner2014gradientextraction(mreptem,fc);
else % zilany
greptar = baumgartner2016gradientextraction(mreptar,fc,'argimport',flags,kv);
greptem = baumgartner2016gradientextraction(mreptem,fc,'argimport',flags,kv);
end
else
amtdisp('Cue extraction different to baumgartner2014','progress')
if kv.do == 1 && flags.do_dcn% DCN inspired feature extraction
for ch = 1:size(mreptar,3)
greptem(:,:,ch) = dcn(mreptem(:,:,ch),fc);
greptar(:,:,ch) = dcn(mreptar(:,:,ch),fc);
end
elseif kv.do == 2 % proposed by Zakarauskas & Cynader (1993)
greptem = diff(mreptem,kv.do);
greptar = diff(mreptar,kv.do);
else
greptem = mreptem;
greptar = mreptar;
end
end
%% Comparison process
if flags.do_isd && not(flags.do_intensityweighting) && not(flags.do_diff)
if flags.do_gammatone
sigma = baumgartner2014comparisonprocess(greptar,greptem);
else % zilany
sigma = baumgartner2016comparisonprocess(greptar,greptem);
end
else
amtdisp('Comparison process different to baumgartner2014','progress')
if flags.do_diff
greptar = diff(greptar);
greptem = diff(greptem);
end
sigma=zeros(size(mreptem,2),size(mreptar,2),size(mreptem,3)); % init
for ch = 1:size(mreptar,3)
for it = 1:size(mreptar,2)
if flags.do_isd
isd = repmat(greptar(:,it,ch),[1,size(greptem(:,:,ch),2),1]) - greptem(:,:,ch);
% isd = zscore(repmat(greptar(:,it,ch),[1,size(greptem(:,:,ch),2),1])) - zscore(greptem(:,:,ch));
if kv.do == 0
sigma(:,it,ch) = sqrt(squeeze(var(isd))); % standard dev. across frequencies (Middlebrooks, 1999)
else
if isnan(nanmean(abs(isd)))
sigma(:,it,ch) = 0;
else
if flags.do_intensityweighting
Ifw = mreptar(:,it,ch)/max(mreptar(:,it,ch));
isd = isd.*repmat(Ifw,1,size(isd,2));
end
% if flags.do_dcn
% isd(isd>kv.SimThresh) = nan;
% end
sigma(:,it,ch) = nanmean(abs(isd)); % L1-norm across frequencies
% sigma(:,it,ch) = sigma(:,it,ch)/max(sigma(:,it,ch));
% sigma(:,it,ch) = sigma(:,it,ch)/std(sigma(:,it,ch))/4;
% sigma(:,it,ch) = sqrt(sigma(:,it,ch));
end
end
elseif flags.do_corr
if sum(greptar(:,it,ch)==0) == length(greptar(:,it,ch))
sigma(:,it,ch) = 0;
else
r = corrcoef([greptar(:,it,ch) greptem(:,:,ch)]); % in case of NAN use flag: 'rows','pairwise' (but very slow!!!)
sigma(:,it,ch) = r(1,2:end);
end
end
end
end
% sigma = (sigma+eps)./repmat(sum(sigma+eps)/size(sigma,1),[size(sigma,1),1,1]); % scale to simplify calibration
% sigma = (sigma+eps)./repmat(std(sigma+eps),[size(sigma,1),1,1]); % scale to simplify calibration
end
%% OPTIMAL FT SELECTION
Ntang = size(mreptar,2);
if flags.do_ftopt
% Var 1: Winner takes it all
% si = max(si_ft,[],4);
% Var 2: Select for each target the SI distribution of the fiber type
% yielding the minimum internal distance metric (sigma)
if length(kv.fiberTypes) == 3
sigma_ft = sigma;
sigma = sigma_ft(:,:,:,1,:); % init with ft=1
N = zeros(Ntang * size(mreptar,3),3);
N(:,1) = 1;
for ch = 1:size(mreptar,3)
for it = 1:Ntang
for ft = 2:3
if min(sigma_ft(:,it,ch,ft,:)) < min(sigma(:,it,ch,:,:))
sigma(:,it,ch,:,:) = sigma_ft(:,it,ch,ft,:);
N(it+(ch-1)*Ntang,ft) = 1;
end
end
end
end
N(:,2) = max(N(:,2) - N(:,3),0);
N(:,1) = N(:,1) - (N(:,2)+N(:,3));
N = sum(N);
% amtdisp(['Selected fiber type: ' num2str(N(1),'%i') 'low, ' num2str(N(2),'%i') ' mid, ' num2str(N(3),'%i') ' high'],'progress')
fileID = fopen(fullfile(amtbasepath,'modelstages','baumgartner2016fiberTypeCounter'),'a');
fprintf(fileID,'%i, %i, %i\n',N(1),N(2),N(3));
fclose(fileID);
end
end
%% Evaluation of multiple looks
if size(sigma,5) > 1
sigma = mean(sigma,5);
end
% Histogram approach
% Nframes = size(sigma,5);
% sigma_ml = sigma;
% sigma = zeros(size(sigma_ml,1),Ntang,size(mreptar,3));
% for ch = 1:size(mreptar,3)
% for itang = 1:Ntang
% for itime = 1:Nframes
% [tmp,Imin] = min(sigma_ml(:,itang,ch,1,itime));
% sigma(Imin,itang,ch) = sigma(Imin,itang,ch) + 1;
% end
% end
% end
% si = sigma.^kv.S;
% else
%% Normalization of sigma
% sigma = 225 * sigma./repmat(sum(sigma,1),[size(sigma,1),1,1]); % factor 225 in order to maintain previous range of S
%% Similarity estimation
if flags.do_isd && flags.do_sigmoid
% duration-dependence of gamma (degree of selectivity)
if length(kv.stim)/kv.fs < 5e-3 % halfen if shorter than 5ms
kv.gamma = kv.gamma*kv.gammashortfact;
end
% duration-dependence of sensitivity
if length(kv.stim)/kv.fs < 5e-3 % halfen if shorter than 5ms
kv.S = kv.S*kv.Sshortfact;
end
if not(flags.do_gammatone)
sigma = 10*sigma;
end
si = baumgartner2014similarityestimation(sigma,'S',kv.S,'gamma',kv.gamma);
else
amtdisp('Similarity estimation different to baumgartner2014','progress')
if flags.do_zilany2014 && not(flags.do_sigmoid || flags.do_dcn)
sigma = sigma/10;
end
si=zeros(size(sigma)); % init
for ch = 1:size(mreptar,3)
for it = 1:size(mreptar,2)
if flags.do_isd
if flags.do_sigmoid
si(:,it,ch) = 1+eps - (1+exp(-kv.gamma*(sigma(:,it,ch)-10*kv.S))).^-1;
elseif flags.do_exp
si(:,it,ch) = real(exp(-sigma(:,it,ch)./kv.S));
elseif flags.do_Gauss
si(:,it,ch) = real(exp(-(sigma(:,it,ch)./kv.S).^2));
else
si(:,it,ch) = interp1([0,kv.SimDL,kv.S,1e10],[1,1,0,0],sigma(:,it,ch),'cubic');
end
elseif flags.do_corr
if flags.do_exp
si(:,it,ch) = real(exp( (sigma(:,it,ch) - 1)./kv.S ));
elseif flags.do_Gauss
si(:,it,ch) = real(exp(-((sigma(:,it,ch) - 1)./kv.S).^2));
else % power law relationship
si(:,it,ch) = real(sigma(:,it,ch).^kv.S);
end
end
end
end
end
% end
%% Binaural weighting
si = baumgartner2014binauralweighting(si,'lat',kv.lat,'bwcoef',kv.bwcoef);
%% Interpolation, prior, sensorimotor mapping
if kv.prior==0
[si,rang] = baumgartner2014sensorimotormapping(si,...
'rangsamp',kv.rangsamp,'polsamp',kv.polsamp,'lat',kv.lat,'mrsmsp',kv.mrsmsp,...
flags.regularization,flags.motoricresponsescatter);
else
% amtdisp('Sensorimotor mapping different to baumgartner2014','progress')
if flags.do_regular
rang0 = ceil(min(kv.polsamp)*0.2)*5; % ceil to 5 deg
rang = rang0:kv.rangsamp:max(kv.polsamp);
siint = zeros(length(rang),size(si,2));
for tt = 1:size(si,2)
siint(:,tt) = interp1(kv.polsamp,si(:,tt),rang,'spline');
end
si = siint;
si(si<0) = 0; % SIs must be positive (necessary due to spline interp)
else
rang = kv.polsamp;
end
% Individual prior distribution
if min(kv.priordist.x) > -90
kv.priordist.x = [-90;kv.priordist.x(:)];
kv.priordist.y = [1;kv.priordist.y(:)];
end
if max(kv.priordist.x) < 270
kv.priordist.x = [kv.priordist.x(:);270];
kv.priordist.y = [kv.priordist.y(:);1];
end
priordist = interp1(kv.priordist.x,kv.priordist.y,rang,'linear') .^ kv.prior;
si = si.*repmat(priordist(:),1,size(si,2));
% % Prior expectation (Pratt effect)
% poltrans = (mod(rang,180)-90)/180;
% prior = exp(kv.prior*abs(poltrans));
% si = si.*repmat(prior(:),1,size(si,2));
% Sensorimotor mapping
if flags.do_mrs && flags.do_regular && kv.mrsmsp > 0
angbelow = -90:5:min(rang)-5;
angabove = max(rang)+5:5:265;
rang = [angbelow,rang,angabove];
si = [zeros(length(angbelow),size(si,2)) ; si ; zeros(length(angabove),size(si,2))];
mrs = kv.mrsmsp/cos(deg2rad(kv.lat)); % direction dependent scatter (derivation: const. length rel. to the circumferences of circles considered as cross sections of a unit sphere)
x = 0:2*pi/72:2*pi-2*pi/72;
kappa = 1/deg2rad(mrs)^2; % concentration parameter (~1/sigma^2 of normpdf)
mrspdf = exp(kappa*cos(x)) / (2*pi*besseli(0,kappa)); % von Mises PDF
for tt = 1:size(si,2)
si(:,tt) = pconv(si(:,tt),mrspdf(:));
end
end
end
%% Normalization to PMV
p = si ./ repmat(sum(si)+eps,size(si,1),1);
%% Performance measures
if not(isempty(flags.errorflag)) % Simulate virtual experiments
m = baumgartner2014virtualexp(p,tang,rang,'targetset',kv.exptang);
err = localizationerror(m,flags.errorflag);
elseif not(isempty(flags.ppp)) % Calculate directly via probabilities
if flags.do_QE_PE_EB
[err.qe,err.pe,err.pb] = baumgartner2014pmv2ppp(p,tang,rang,'exptang',kv.exptang);
else
err = baumgartner2014pmv2ppp(p,tang,rang,flags.ppp,'exptang',kv.exptang);
end
end
%% Output
if isempty([flags.errorflag,flags.ppp])
varargout{1} = p;
if nargout >= 2
varargout{2} = rang;
if nargout >= 3
try
varargout{3} = tang;
catch
amtdisp('SOFA Object of target DTFs is required to output target angles.')
end
end
end
else
varargout{1} = err;
if nargout > 1
varargout{2} = struct('p',p,'rang',rang,'tang',tang);
if nargout > 2
if not(exist('m','var'))
m = baumgartner2014virtualexp(p,tang,rang);
end
varargout{3} = m;
end
end
end
end
% function t4 = psge(an,fc,c2)
% %DCN Phenomenological model of dorsal cochlear nucleus (DCN)
% % Usage: out = dcn(in)
% %
% % Input parameters:
% % an : spectral profile in dB
% %
% % Output parameters:
% % t4 : activity of type IV unit
%
% %% Parameter Settings
% % c2 = 1; % inhibitory coupling between type II and type IV neurons
% c4 = 1; % coupling between an and type IV neuron
% dilatation = 1; % of tonotopical 1-ERB-spacing between type IV and II neurons
%
% erb = audfiltbw(fc);
%
% %% Calculations
% Nb = size(an,1); % # auditory bands
% dt4t2 = round(mean(erb(2:end)./diff(fc))*dilatation); % tonotopical distance between type IV and II neurons
% t4 = zeros(Nb-dt4t2,size(an,2),size(an,3)); % type IV output
% for b = 1:Nb-dt4t2
% t4(b,:,:) = c4 * an(b+dt4t2,:,:) - c2 * an(b,:,:);
% end
%
% t4 = (t4 + c2*abs(t4))/2; %disp('only rising edges')
% % t4(t4<0) = nan;
% end
function P = dcn(an,fc)
%DCN Phenomenological model of dorsal cochlear nucleus (DCN)
% Usage: P = dcn(an,fc)
%
% Input parameters:
% an : spectral profile in dB
%
% Output parameters:
% P : activity of principal cell
%% Parameter Settings (Table 2, Lomakin & Davis, 2008)
% offsets in octaves
c.WtoI2 = .3;
c.WtoP = .2;
c.I2toP = -.1;
% bandwidth in octaves
bw.ANtoW = 2.5; % effectively .83 due to Gaussian distribution
bw.ANtoI2 = .4;
bw.ANtoP = .4;
bw.WtoI2 = 2.2; % from Fig. 7
bw.WtoP = 2.2; % from Fig. 7
bw.I2toP = .2;
% # projections times strength
Ns.ANtoW = 140*.05;
Ns.ANtoI2 = 48*.55;
Ns.ANtoP = 48*.25;
Ns.WtoI2 = 15*1.4;
Ns.WtoP = 15*.6; % from page 514
Ns.I2toP = 21*2.25;
% non-specific afferents (NSA) leading to spontaneous activity
nsa = 3000; % spikes/s
%% Parameter Settings (Table 1, Reiss & Young, 2005)
% % offsets in octaves
% c.WtoI2 = .3;
% c.WtoP = .05;
% c.I2toP = -.1;
% % bandwidth in octaves
% bw.ANtoI2 = .2;
% bw.ANtoW = 2.0;
% bw.ANtoP = .24;
% bw.WtoI2 = 0.1;%0.05;
% bw.WtoP = 0.1;
% bw.I2toP = .2;
% % # projections times strength
% Ns.ANtoI2 = 23.1;
% Ns.ANtoW = 10.8;
% Ns.ANtoP = 2.75;
% Ns.WtoI2 = 7;
% Ns.WtoP = 0;
% Ns.I2toP = 47.25;
% % non-specific afferents (NSA) leading to spontaneous activity
% nsa = 0; % spikes/s
%% Calculations
Nf = length(fc);
% df = mean(diff(fc));
W = nan(size(an));
for ii = 1:Nf
nANtoW = fc >= fc(ii)*2^(-bw.ANtoW/2) & fc <= fc(ii)*2^(bw.ANtoW/2);
win = gausswin(sum(nANtoW)); win = win/sum(win);
W(ii,:) = Ns.ANtoW * win' * an(nANtoW,:);
% W(ii,:) = Ns.ANtoW*mean(an(nANtoW,:));
end
% W = max(W,0);
I2 = nan(size(an));
for ii = 1:Nf
nANtoI2 = fc >= fc(ii)*2^(-bw.ANtoI2/2) & fc <= fc(ii)*2^(bw.ANtoI2/2);
win = gausswin(sum(nANtoI2)); win = win/sum(win);
ANtoI2(ii,:) = Ns.ANtoI2 * win' * an(nANtoI2,:);
nWtoI2 = fc >= fc(ii)*2^(c.WtoI2-bw.WtoI2/2) & fc <= fc(ii)*2^(c.WtoI2+bw.WtoI2/2);
if sum(nWtoI2) == 0; nWtoI2(end) = 1; end % for high fc
win = gausswin(sum(nWtoI2)); win = win/sum(win);
WtoI2(ii,:) = Ns.WtoI2 * win' * W(nWtoI2,:);
I2(ii,:) = ANtoI2(ii,:) - WtoI2(ii,:);
% I2(ii,:) = Ns.ANtoI2*mean(an(nANtoI2,:)) - Ns.WtoI2*mean(an(nWtoI2,:));
end
% I2 = max(I2,0);
ANtoP = nan(size(an));
WtoP = ANtoP;
I2toP = ANtoP;
P = nan(size(an));
for ii = 1:Nf
nANtoP = fc >= fc(ii)*2^(-bw.ANtoP/2) & fc <= fc(ii)*2^(bw.ANtoP/2);
win = gausswin(sum(nANtoP)); win = win/sum(win);
ANtoP(ii,:) = Ns.ANtoP * win' * an(nANtoP,:);
nWtoP = fc >= fc(ii)*2^(c.WtoP-bw.WtoP/2) & fc <= fc(ii)*2^(c.WtoP+bw.WtoP/2);
win = gausswin(sum(nWtoP)); win = win/sum(win);
WtoP(ii,:) = Ns.WtoP * win' * W(nWtoP,:);
nI2toP = fc >= fc(ii)*2^(c.I2toP-bw.I2toP/2) & fc <= fc(ii)*2^(c.I2toP+bw.I2toP/2);
win = gausswin(sum(nI2toP)); win = win/sum(win);
I2toP(ii,:) = Ns.I2toP * win' * I2(nI2toP,:);
P(ii,:) = nsa + ANtoP(ii,:) - WtoP(ii,:) - I2toP(ii,:);
% P(ii,:) = nsa + Ns.ANtoP*mean(an(nANtoP,:)) - Ns.WtoP*mean(W(nWtoP,:)) - Ns.I2toP*mean(I2(nI2toP,:));
end
% P = P/max(P(:));
% P(P<0.4) = nan;
% P = P(1:90,:);
% P = max(P,0);
end
function v = nanmean (X, varargin)
% NANMEAN
% v = nanmean (X)
n = sum (~isnan(X), varargin{:});
n(n == 0) = NaN;
X(isnan(X)) = 0;
v = sum (X, varargin{:}) ./ n;
end