136 lines
2.5 KiB
Matlab
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;
|