function [varargout] = reijniers2014_metrics(doa, varargin)
%REIJNIERS2014_METRICS - extract localization metrics
% Usage: [mean_error, bias] = reijniers2014_metrics(doa, parameters)
%
% Input parameters:
% doa: Struct in returned from the reijiniers2014's model with
% estimated and real directions of arrival
%
% REIJNIERS2014_METRICS(...) returns psychoacoustic performance
% parameters for experimental response patterns.
% doa is a struct where actual and estimated directions of arrival must
% be provided. If no input params are provided the returned metrics
% resemble the ones provided in the original paper, see Reijiners et al. (2014).
% This script is a wrapper for localizationerror.
%
% If parameter is provided, reijniers2014_metric is a wrapper for localizationerror
% with the parameter as the localization error.
%
% See also: demo_reijniers2014 reijniers2014 localizationerror
%
% References:
% R. Barumerli, P. Majdak, R. Baumgartner, J. Reijniers, M. Geronazzo,
% and F. Avanzini. Predicting directional sound-localization of human
% listeners in both horizontal and vertical dimensions. In Audio
% Engineering Society Convention 148. Audio Engineering Society, 2020.
%
% R. Barumerli, P. Majdak, R. Baumgartner, M. Geronazzo, and F. Avanzini.
% Evaluation of a human sound localization model based on bayesian
% inference. In Forum Acusticum, 2020.
%
% J. Reijniers, D. Vanderleist, C. Jin, C. S., and H. Peremans. An
% ideal-observer model of human sound localization. Biological
% Cybernetics, 108:169--181, 2014.
%
%
% Url: http://amtoolbox.org/amt-1.2.0/doc/modelstages/reijniers2014_metrics.php
% Copyright (C) 2009-2022 Piotr Majdak, Clara Hollomey, and the AMT team.
% This file is part of Auditory Modeling Toolbox (AMT) version 1.2.0
%
% 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: Michael Sattler and Roberto Barumerli (adapted from code provided by Jonas Reijniers)
if isempty(varargin)
nargout=2;
num_src = size(doa.est, 1);
num_exp = size(doa.est, 2);
error = zeros(num_src, num_exp);
for e = 1 : num_exp
for s = 1 : num_src
% calculate great circle error
% (x*y)=|x|*|y|cos(theta)
x = doa.real(s,:);
y = squeeze(doa.est(s,e,:));
% NOTE: not accounting for distance!
% error(i,j) = acos(x*y'/(norm(x)*norm(y)));
error(s, e) = rad2deg(acos(x*y));
end
end
% calculate ensemble values
mean_error = sum(error,2)/num_exp;
% calculate summed estimated direction
bias = squeeze(sum(doa.est,2));
if size(bias,2) == 1
bias = bias';
end
for s=1:num_src
bias(s,:) = bias(s,:)/norm(bias(s,:)) - doa.real(s,:);
end
varargout{1}=mean_error;
varargout{2}=bias;
elseif strcmp(varargin{1}, 'middle_metrics')
% lateral_bias
exp.accL = reijniers2014_metrics(doa, 'accL');
% lateral_rms_error
exp.rmsL = reijniers2014_metrics(doa, 'rmsL');
% elevation_bias
exp.accE = reijniers2014_metrics(doa, 'accE');
% local_rms_polar
exp.rmsP = ...
reijniers2014_metrics(doa, 'rmsPmedianlocal');
% quadrant_err
exp.querr = ...
reijniers2014_metrics(doa, 'querrMiddlebrooks');
varargout{1} = exp;
else
%% compute the metric relying on localizationerror.m
definput.import={'localizationerror'};
[flags,kv]=ltfatarghelper({'f','r'},definput,varargin);
doa_real = SOFAconvertCoordinates(doa.real, 'cartesian', 'spherical');
[lat_real,pol_real]=sph2horpolar(doa_real(:,1),doa_real(:,2));
doa.est = squeeze(doa.est);
if size(doa.est, 3) ~= 1 % remove third dimension relative to repetition of experiments
num_exp = size(doa.est, 2);
doa_est = [];
for i = 1:size(doa.est, 2)
est = squeeze(doa.est(:,i,:));
doa_est = [doa_est; est];
end
else
if(size(doa.est, 1) == size(doa.real, 1))
num_exp = 1;
else
num_exp = size(doa.est, 1);
end
doa_est = doa.est;
end
doa_est = SOFAconvertCoordinates(doa_est, 'cartesian', 'spherical');
[lat_est,pol_est] = sph2horpolar(doa_est(:,1),doa_est(:,2));
m = zeros(size(doa_real, 1)*num_exp, 8);
m(:, 1:2) = repmat(doa_real(:, [1 2]), num_exp, 1);
m(:, 3:4) = doa_est(:, [1 2]);
m(:, 5:6) = repmat([lat_real,pol_real], num_exp, 1);
m(:, 7:8) = [lat_est,pol_est];
% workaround since sph2horpolar can return complex numbers due to
% numerical approximations
m = real(m);
if (strcmp(flags.errorflag, 'perMacpherson2003'))
[varargout{1}, meta, par] = localizationerror(m, kv.f, kv.r, flags.errorflag);
else
[varargout{1}, meta, par] = localizationerror(m, flags.errorflag);
end
if (strcmp(flags.errorflag, 'sirpMacpherson2000'))
varargout{2}=meta;
end
if length(varargout) > 1
varargout{2}=meta;
end
if length(varargout) > 2
varargout{3}=par;
end
end