# SNR calculation confusion

Follow up to question and comments posted here

The SNR calculation method posted as answers were implemented in matlab

Implementation of Deve's answer:

% the starting and ending point of speech in samples obtain through Audacity;
% select a portion of the waveform where speech is seen to be present
begin_speech = 25400; end_speech = 26800;

snr_before = mean( data_s(begin_speech:end_speech) .^2) / mean( data_n(begin_speech:end_speech) .^2);
db_snr_before = 10*log10( snr_before );     % same thing, but in dB

% calculation on data after noise reduction follows:
residual_noise = data_s(begin_speech:end_speech) - output(begin_speech:end_speech);
snr_after = mean( data_s(begin_speech:end_speech) .^ 2)/mean( residual_noise .^ 2);
db_snr_after = 10*log10( snr_after );


The result is

db_snr_before = 15.6853
db_snr_after = -22.0388


Implementation of dspGuru's answer:

begin_speech = 25400; end_speech = 26800;

% before noise reduction
DB1 = 10*log10( var(data_n(begin_speech:end_speech)));
DB2 = 10*log10( var(data_s(begin_speech:end_speech)));
db_SNR_before = DB2 - DB1;

% after noise reduction
[data_stnr, fs_stnr, nbits_stnr] = wavread('AdMStry_thru_nr.wav');
Z = output(begin_speech:end_speech) - data_stnr(begin_speech:end_speech);
db_residual_noise = 10*log10( var(Z) );
db_speech = 10*log10( var(data_stnr(begin_speech:end_speech)));
db_SNR_after = db_speech - db_residual_noise;


The result is :

db_SNR_before = 15.6848
db_SNR_after = 0.9252


The begin_speech and end_speech represent those parts of the wavfile, in number of samples, where there is presence of speech for certain (obtained through audacity by observing the waveform directly)

Why is the SNR less after passing through noise reduction?

In the second method (dspGuru), to calculate SNR after noise reduction, to get the Signal value on the numerator, I have passed just the pure speech through the noise reduction algorithm as well. If I do the same thing in the first (Deve) method, the results of the two methods become almost equal

Why is this happening? Why is SNR after less than SNR_before ?

Here is a screenshot of the waveforms: • In your example, is data_n the pure noise signal or is it speech AND noise? – Deve Nov 9 '12 at 8:17
• it's pure noise – user13267 Nov 9 '12 at 13:04
• If looks like there is significant gain in your noise reduction algorithm. I'm not sure if I'm following the calculations correctly, but you may have a normalization problem, where the gain inherent in your algorithm is finding its way into your SNR calculation such that it makes the SNR at the output look worse. – Jason R Nov 9 '12 at 13:54
• Another observation from your data, the "pure speech through noise reduction" appears to be clipped. If this is the case, this will reduce the dynamic range of your signal and negatively affect the SNR. – user2718 Jan 6 '13 at 23:57

## 2 Answers

As Jason R has already mentioned in his comment, the noise reduction algorithm obviously introduces some amplification which renders the SNR estimates we proposed in our earlier answers useless. This becomes clear if we look at how the SNR is calculated.

Let $x_k$ be the speech signal without noise and let $n_k$ be the noise. Then the SNR before noise reduction is $$\gamma_{before} = \frac{\sum x_k^2}{\sum n_k^2}$$

Now the noise reduction (NR) is applied to both signals yielding the pure speech signal after NR $\tilde{y}_k \neq x_k$. Applying NR to the noisy signal produces some new signal $y_k + \tilde{n}_k$. As can be seen from your screenshots $y_k \neq \tilde{y}_k$. If we apply dspGurus method for calculating the SNR after NR we obtain $$\gamma_{after} = \frac{\sum \tilde{y}_k}{\sum [y_k - \tilde{y}_k + \tilde n_k]^2}$$ The denominator not only conatins the residual noise but also an additional error $y_k - \tilde{y}_k$. This leads to a wrong estimation and a much lower SNR value.

To overcome this problem, you could try to normalize the signals. This will be difficult, because obiously the NR algorithm scales the noisy and the noise free signal differently. If you've implemented the algorithm yourself, you should try to fix this.

Another possible solution is to estimate the noise power in a region where the original signal contained silence and to calculate the total signal power in a region that contains noise and signal:

• Take a region from the noisy signal after NR that only contains noise and calculate the mean power denoted as $\sigma_{n}^2$
• Take a region from the noisy signal after NR that contains noise and speech and calculate the mean power denoted as $\sigma_{n,s}^2$

Now the SNR after NR can be estimated as $$\gamma_{after} = \frac{\sigma_{n,s}^2 - \sigma_{n}^2}{\sigma_{n}^2}$$

How good this estimation is, depends on how good the following prerequisites are fulfilled in your case:

• A large number of samples should be used to calculate the mean powers. You used 1401, that's not much.
• Noise and signal after NR have to be uncorrelated. The NR algorithm possibly introduces noise that is a function of the signal. So this condition might not be fulfilled.
• The mean noise power should be constant over time. I think this is fulfilled.
• is it a better idea to take speech portions as well as silence portions when finding (Summation x^2) ? I took a very short section of pure speech because I could see that it contained only speech, but if I take a longer section it will definitely contain silence as well. – user13267 Nov 12 '12 at 0:28
• @user13267 If you're just interested in a comparison of SNR before and after NR, you should take as much samples as possible, i. e. the complete audio file. In the end, silence is a signal as well. – Deve Nov 12 '12 at 10:20

Let $x_k$ be the clean speech signal without noise and let $n_k$ be the noise. Let's assume that the noisy speech signal, $y_k$, can be modeled as:

$$y_k = x_k + n_k$$

Let's assume that the noise reduction algorithm, $NR()$, is a linear operation. From that follow that:

$$NR(y_k) = NR(x_k + n_k) = NR(x_k) + NR(n_k) = \tilde{x}_k + \tilde{n}_k$$

The SNR of the output can thus be calculated as:

$$SNR_{after} = 10log_{10} * (\frac{var(\tilde{x}_k)}{var(\tilde{n}_k)})$$

You can verify if your assumptions are correct by listening to this signal:

$$NR(y_k) - NR(n_k)$$

If the output sounds noise free, then the above SNR calculation is valid.

clc
close all
clear all

% Generate a 'speech' signal
Fs = 8000;
[b,a] = butter(2,[300/(Fs/2) 3300/(Fs/2)]);
innovationSignal = randn(1,Fs);
cleanSpeech = filter(b,a,innovationSignal);
cleanSpeech = 0.3.*cleanSpeech./max(abs(cleanSpeech));

% Specify what the signal components look like before processing
dBSNR = 5;
noisySpeechBeforeNoiseReduction = awgn(cleanSpeech,dBSNR,'measured');
noiseBeforeNoiseReduction = noisySpeechBeforeNoiseReduction - cleanSpeech;

% Let's simulate a noise reduction of 10dB dBSNR = 15;
% Create a 15dB SNR speech signal
noisySpeechAfterNoiseReduction = awgn(cleanSpeech,dBSNR,'measured');

% Subtract clean speech to get the noise component
noiseAfterNoiseReduction =   noisySpeechAfterNoiseReduction - cleanSpeech;

% Simulate noise suppression algo (adds gain and delay)
algoDelayCoeff = [zeros(1,100) 1];
algoGain = 3;
cleanSpeechAfterNoiseReduction = algoGain.*filter(algoDelayCoeff,1,cleanSpeech);
noiseAfterNoiseReduction = algoGain.*filter(algoDelayCoeff,1,noiseAfterNoiseReduction);

% So the output of the NS algo looks like this
outputOfNoiseSupAlgo = cleanSpeechAfterNoiseReduction + noiseAfterNoiseReduction;

% Verify SNR before noise reduction
SNR_before = 10*log10(var(cleanSpeech)/var(noiseBeforeNoiseReduction))

% Verify SNR after noise reduction
SNR_after = 10*log10(var(cleanSpeechAfterNoiseReduction)/var(noiseAfterNoiseReduction))

disp(['SNR improvement: ' num2str(SNR_after - SNR_before)])

• You don't have to post consecutive posts like in a forum... you can simply edit your existing post to update with more info or code. – Lorem Ipsum Nov 16 '12 at 19:32