shithub: opus

ref: 1ee139bca076a1a3606a8a924a698d356d40cbb8
dir: /doc/opus_compare.m/

View raw version
%% Tests bit-stream compliance for the Opus codec
%% x: Signal from the Opus reference implementation (float or fixed)
%% y: Signal from the decoder under test
%% stereo: 0 for mono, 1 for stereo
function [err, NMR] = opus_compare(x, y, stereo)

% Bands on which we compute the pseudo-NMR (Bark-derived CELT bands)
b = 2*[0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,34,40,48,60,78,100];
d = diff(b);

% Per-band SNR threshold
T = 50-.7*[1:21];

% Noise floor
N = 10 .^ ((10-0.6*[1:21])/10);

% Error signal
e=x-y;

%Add a +/- 1 dead zone on the error
e = e - min(1, max(-1, e));

% Compute spectrum of original and error
if (stereo)
  X=(abs(specgram(x(1:2:end),480))+abs(specgram(x(2:2:end),480)))/2;
  E=(abs(specgram(e(1:2:end),480))+abs(specgram(e(2:2:end),480)))/2;
else
  X=abs(specgram(x,480));
  E=abs(specgram(e,480));
endif

% Group energy per band
for k=1:21
   Xb(k,:) = sum(X(b(k)+1:b(k+1),:).^2)/d(k)+1;
   Eb(k,:) = sum(E(b(k)+1:b(k+1),:).^2)/d(k)+1;
end

% Frequency masking (low to high) with 10 dB/Bark slope
Xb = filter(1, [1, -.1], Xb);
% Frequency masking (high to low) with 15 dB/Bark slope
Xb(end:-1:1,:) = filter(1, [1, -.03], Xb(end:-1:1,:));

% Temporal masking with 5 dB/5 ms slope
Xb = filter(1, [1, -.3], Xb')';

% NMR threshold
T0 = ones(length(Eb), 1)*(10.^((T)/10));

% Time-frequency SNR
NMR = (Xb./Eb)';

%Picking only errors in the 90th percentile
tmp = Eb(:);
thresh = sort(tmp)(round(.90*length(tmp)));
weight = Eb'>thresh;

printf("Average pseudo-NMR: %3.2f dB\n", mean(mean(10*log10(NMR))));

if (sum(sum(weight))<1)
   printf("Mismatch level: below noise floor\n");
   err = -100;
else
   M = (T0./NMR) .* weight;

   err = 10*log10(sum(sum(M)) / sum(sum(weight)));

   printf("Weighted mismatch: %3.2f dB\n", err);
endif

printf("\n");

if (err < 0)
   printf("**Decoder PASSES test (mismatch < 0 dB)\n");
else
   printf("**Decoder FAILS test (mismatch >= 0 dB)\n");
endif