denoising-historical-data/PQevalAudio/MOV/PQmovEHS.m
2021-08-30 18:42:12 +03:00

136 lines
2.5 KiB
Matlab

function EHS = PQmovEHS (xR, xT, X2)
% Calculate the EHS MOV values
% P. Kabal $Revision: 1.2 $ $Date: 2004/02/05 04:26:19 $
persistent NF Nadv NL M Hw
if (isempty (NL))
NF = 2048;
Nadv = NF / 2;
Fs = 48000;
Fmax = 9000;
NL = 2^(PQ_log2(NF * Fmax / Fs));
M = NL;
Hw = (1 / M) * sqrt(8 / 3) * PQHannWin (M);
end
EnThr = 8000;
kmax = NL + M - 1;
EnRef = xR(Nadv+1:NF-1+1) * xR(Nadv+1:NF-1+1)';
EnTest = xT(Nadv+1:NF-1+1) * xT(Nadv+1:NF-1+1)';
% Set the return value to be negative for small energy frames
if (EnRef < EnThr & EnTest < EnThr)
EHS = -1;
return;
end
% Allocate storage
D = zeros (1, kmax);
% Differences of log values
for (k = 0:kmax-1)
D(k+1) = log (X2(2,k+1) / X2(1,k+1));
end
% Correlation computation
C = PQ_Corr (D, NL, M);
% Normalize the correlations
Cn = PQ_NCorr (C, D, NL, M);
Cnm = (1 / NL) * sum (Cn(1:NL));
% Window the correlation
Cw = Hw .* (Cn - Cnm);
% DFT
cp = PQRFFT (Cw, NL, 1);
% Squared magnitude
c2 = PQRFFTMSq (cp, NL);
% Search for a peak after a valley
EHS = PQ_FindPeak (c2, NL/2+1);
%----------------------------------------
function log2 = PQ_log2 (a)
log2 = 0;
m = 1;
while (m < a)
log2 = log2 + 1;
m = 2 * m;
end
log2 = log2 - 1;
%----------
function C = PQ_Corr (D, NL, M)
% Correlation calculation
% Direct computation of the correlation
% for (i = 0:NL-1)
% s = 0;
% for (j = 0:M-1)
% s = s + D(j+1) * D(i+j+1);
% end
% C(i+1) = s;
% end
% Calculate the correlation indirectly
NFFT = 2 * NL;
D0 = [D(1:M) zeros(1,NFFT-M)];
D1 = [D(1:M+NL-1) zeros(1,NFFT-(M+NL-1))];
% DFTs of the zero-padded sequences
d0 = PQRFFT (D0, NFFT, 1);
d1 = PQRFFT (D1, NFFT, 1);
% Multiply (complex) sequences
dx(0+1) = d0(0+1) * d1(0+1);
for (n = 1:NFFT/2-1)
m = NFFT/2 + n;
dx(n+1) = d0(n+1) * d1(n+1) + d0(m+1) * d1(m+1);
dx(m+1) = d0(n+1) * d1(m+1) - d0(m+1) * d1(n+1);
end
dx(NFFT/2+1) = d0(NFFT/2+1) * d1(NFFT/2+1);
% Inverse DFT
Cx = PQRFFT (dx, NFFT, -1);
C = Cx(1:NL);
%----------
function Cn = PQ_NCorr (C, D, NL, M)
% Normalize the correlation
Cn = zeros (1, NL);
s0 = C(0+1);
sj = s0;
Cn(0+1) = 1;
for (i = 1:NL-1)
sj = sj + (D(i+M-1+1)^2 - D(i-1+1)^2);
d = s0 * sj;
if (d <= 0)
Cn(i+1) = 1;
else
Cn(i+1) = C(i+1) / sqrt (d);
end
end
%----------
function EHS = PQ_FindPeak (c2, N)
% Search for a peak after a valley
cprev = c2(0+1);
cmax = 0;
for (n = 1:N-1)
if (c2(n+1) > cprev) % Rising from a valley
if (c2(n+1) > cmax)
cmax = c2(n+1);
end
end
end
EHS = cmax;