function [ps,pn,pe] = hagerman_estimate( psn1, psn2, psn3 )
% hagerman_estimate - Estimate S, N and error signal from signal mixture
%
% Usage:
%
% Estimate S and N after Hagerman and Olofsson (2004):
%
% [ps, pn] = hagerman_estimate( psn1, psn2 )
%
% Additionally estimate error signal after Olofsson and Hansen
% (2006):
%
% [ps, pn, pe] = hagerman_estimate( psn1, psn2, psn3 )
%
%
% The signals psn1, psn2 and psn3 are the processed versions of the
% signals generated by the script hagerman_generate_signals.m
%
% Return values:
% ps    : estimate of processed target signal
% pn    : estimate of processed noise signal
% pe    : estimate of non-linear and additive distortion
%
% The estimation of the distortion signal is a slight modification
% from the method in Olofsson: Whereas they estimate the PSD, here a
% distortion time signal is estimated from the negative frequencies of
% the spectrum (excluding DC and Nyquist frequency bin to avoid
% leakage from positive frequencies).
%
% Hagerman, B., & Olofsson, Å. (2004). A method to measure the effect
% of noise reduction algorithms using simultaneous speech and
% noise. Acta Acustica United with Acustica, 90(2), 356-361.
%
% Olofsson, Å., & Hansen, M. (2006). Objectively measured and
% subjectively perceived distortion in nonlinear systems. The Journal
% of the Acoustical Society of America, 120(6),
% 3759–3769. https://doi.org/10.1121/1.2372591
%
% Implementation: Giso Grimm, 2019, 2020

  if nargin < 3
    psn3 = [];
  end
  ps = 0.5*(psn1+psn2);
  pn = 0.5*(psn1-psn2);
  if nargout > 2
    % generate FFT of hilbert signal:
    He = fft(psn1+i*psn3);
    % if linear, then negative frequencies are zero. Create error
    % signal from negative frequencies only. Exclude DC and Nyquist
    % to avoid leakage from positive frequencies:
    idx_nyquist = floor(size(He,1)/2+1);
    %He = [0.5*He(1,:);He(end:-1:(idx_nyquist),:)];
    He = [zeros(1,size(He,2));He(end:-1:(idx_nyquist+1),:);zeros(1,size(He,2))];
    pe = realifft(He);
  end


function x = realifft( y )
% REALIFFT - inverse FFT of positive frequencies in y
%
% Usage: x = realifft( y )
%
% Returns inverse FFT or half-complex spectrum. Each column of y is
% taken as a spectrum.
  ;
  channels = size(y,2);
  nbins = size(y,1);
  x = zeros(2*(nbins-1),channels);
  for ch=1:channels
    ytmp = y(:,ch);
    ytmp(1) = real(ytmp(1));
    ytmp(nbins) = real(ytmp(nbins));
    ytmp2 = [ytmp; conj(ytmp(nbins-1:-1:2))];
    x(:,ch) = real(ifft(ytmp2));
  end
