2
$\begingroup$

I am using this as my reference: https://www.mathworks.com/help/deeplearning/ug/denoise-speech-using-deep-learning-networks.html

Add washing machine noise to the speech signal. Set the noise power such that the signal-to-noise ratio (SNR) is zero dB.

noise = audioread("WashingMachine-16-8-mono-1000secs.mp3");

% Extract a noise segment from a random location in the noise file ind = randi(numel(noise) - numel(cleanAudio) + 1,1,1); noiseSegment = noise(ind:ind + numel(cleanAudio) - 1);

speechPower = sum(cleanAudio.^2); noisePower = sum(noiseSegment.^2); noisyAudio = cleanAudio + sqrt(speechPower/noisePower)*noiseSegment;

If I understand the method correctly, assuming both the signal and noise values are within range +/-1.0, it should not really matter what the average level of the signal and noise are. The combined signal will have SNR of 0 dB. I want to construct an audio file that contains sine tone as the signal and some recorded noise wav file as the noise. This is an outline of how I am doing it so far (in matlab):

clear; clc; close all
Fs = 48000;
td = 5;      % seconds
ns = td * Fs;
T = 1/Fs;   
F = 1000;   % sine wave frequency
t = (0:ns -1)*T;
Amp = 0.05;      
signal = Amp * sin(2*pi*F*t);
signal = signal';    % match array dimension with noise file

[noise_file, Fs] = audioread('noisy.wav');

speechPower = sum(signal.^2);
noisePower = sum(noise_file.^2);

x_snr = 251.1886;   % multiplier = 10^(desired_snr/10), eg: 10^(24/10) = 251.1886

noisyAudio_xdB = signal + sqrt(speechPower/(x_snr * noisePower) ).*noise_file;

audiowrite('noisy_file.wav', noisyAudio_20dB_2ch, Fs);  
  1. Is my thinking correct so far? Will this give me an audio file with 24 dB SNR?
  2. Is matlab's R = snr(X, Fs, N) function a good way to verify this? According to matlab help,
R = snr(X, Fs, N) computes the signal to noise ratio (snr) in dBc, of
the real sinusoidal input signal, X, with sampling rate, Fs, and number
of harmonics, N, to exclude from computation when computing snr.  The
default value of Fs is 1.  The default value of N is 6 and includes the
fundamental frequency.  

For 0 dB and 10 dB SNR files that I created, this function gave me SNR values of -0.3111 and 9.7008 respectively which are close, but since these are calculation generated noise files I was hoping the SNR would be even closer than this. Is this an acceptable margin of error for this snr function?

  1. Is the way I calculated the multiplier above [multiplier = 10^(desired_snr/10)] correct? I think this is the correct way since I am calculating SNR using power (or maybe more correctly, energy) of the digital audio signals [sum(signal.^2);] but I just want to make sure its not multiplier = 10^(desired_snr/20).
$\endgroup$

1 Answer 1

1
$\begingroup$

It appears to be correct, assuming we define SNR as the total power in the signal relative to the total power in the noise although I would proceed a little differently. To note briefly first, the SNR of actual concern may be quite different from this depending on the bandwidth of interest and the noise density within that bandwidth (for example the noise file may have strong noise components at frequencies well away from an area or concern that could be filtered out with no effect to the signal- although we would measure it as noise perhaps unfairly).

Here are my thoughts assuming we stick with the simpler first definition:

"Signal" as speech is being represented as a tone, and the level is manually set. The assumption with the subsequent scaling that the OP proceeds to do is that the speech power and the noise power are the same, but this isn't clear that's the case. That said, I would omit setting Amp and simply normalize the two as follows, allowing for the later introduction of any arbitrary speech file:

speech_scale = std(signal)
noise_scale = std(noise_file)

We can then ensure the two are the same power as follows (and this can then be combined as one line with setting the SNR as done next; I did it separately to make the operations clearer):

noise = speech_scale/noise_scale * noise_file

This has scaled the rms magnitude (as the square root of the power quantity). If we want or need the power, it would not be the sum of all the samples squared (that is the energy) but the average of that (mean sum of squares). The results would be proportionally the same, but doing the mean sum of squares can keep large waveforms from growing to unmanageable levels). Still there is no need as we'll see next to actually compute the power.

To set the SNR, we want the speech signal to be 24 dB higher. There is no need for us to convert anything to power since we can work with magnitude quantities directly in the conversion to dB levels (using 20Log10(magnitude ratio) instead of 10Log10(power ratio)). Therefore, we increase the signal magnitude by 24 dB as follows:

signal = signal * 10**(24/20)   

And the noisy audio waveform would then be:

noisyAudio_24dB = signal + noise

The estimates for the SNR are reasonable and will depend on the total number of samples involved. As another option to measure SNR, consider using the correlation coefficient given you have a known reference waveform. I detail the relationship between SNR and correlation coefficient at this post. What is useful about doing it this way and not the estimate with the case of a sine wave is that it can then function with any reference (known) waveform as signal.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.