SNR 计算混乱

信息处理 matlab 信噪比
2022-02-08 10:26:02

跟进此处发布的问题和评论

作为答案发布的 SNR 计算方法在 matlab 中实现

德夫回答的实施:

% 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 );

结果是

db_snr_before = 15.6853
db_snr_after = -22.0388

dspGuru 答案的实现:

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;

结果是:

db_SNR_before = 15.6848    
db_SNR_after = 0.9252

begin_speech 和 end_speech 代表 wavfile 的那些部分,以样本数表示,其中存在确定的语音(通过直接观察波形通过大胆获得)

为什么经过降噪后信噪比变小了?

在第二种方法(dspGuru)中,为了计算降噪后的信噪比,得到分子上的信号值,我也通过降噪算法只传递了纯语音。如果我在第一种(Deve)方法中做同样的事情,两种方法的结果几乎相等

为什么会这样?为什么 SNR after 小于 SNR_before ?

这是波形的屏幕截图:

在此处输入图像描述

2个回答

正如 Jason R 在他的评论中已经提到的那样,降噪算法显然引入了一些放大,这使得我们在之前的答案中提出的 SNR 估计毫无用处。如果我们看一下 SNR 是如何计算的,这一点就会变得很清楚。

为没有噪声的语音信号,令为噪声。那么降噪前的 SNR 为 xknk

γbefore=xk2nk2

现在降噪 (NR) 应用于两个信号,在 NR之后产生纯语音信号。将 NR 应用于噪声信号会产生一些新信号从您的屏幕截图中可以看出如果我们应用 dspGurus 方法计算 NR 之后的 SNR,我们得到 分母不仅包含残余噪声,还包含一个额外的误差这会导致错误的估计和低得多的 SNR 值。y~kxkyk+n~kyky~k

γafter=y~k[yky~k+n~k]2
yky~k

为了克服这个问题,您可以尝试对信号进行归一化。这将是困难的,因为显然 NR 算法以不同的方式缩放有噪声和无噪声信号。如果你自己实现了算法,你应该尝试解决这个问题。

另一种可能的解决方案是估计原始信号包含静音的区域中的噪声功率,并计算包含噪声信号的区域中的总信号功率:

  • 从 NR 之后的噪声信号中取一个仅包含噪声的区域,并计算平均功率,表示为σn2
  • 从 NR 之后的噪声信号中取一个包含噪声和语音的区域,并计算平均功率,表示为σn,s2

现在 NR 之后的 SNR 可以估计为

γafter=σn,s2σn2σn2

这个估计有多好,取决于在您的情况下满足以下先决条件的好坏:

  • 应该使用大量样本来计算平均功率。你用的是1401,不多。
  • NR 后的噪声和信号必须是不相关的。NR 算法可能会引入作为信号函数的噪声。所以这个条件可能不成立。
  • 平均噪声功率应随时间保持不变。我认为这已经实现了。

xk是没有噪声的干净语音信号,让nk成为噪音。让我们假设嘈杂的语音信号,yk, 可以建模为:

yk=xk+nk

让我们假设降噪算法,NR(), 是线性运算。从那以后:

NR(yk)=NR(xk+nk)=NR(xk)+NR(nk)=x~k+n~k

因此,输出的 SNR 可以计算为:

SNRafter=10log10(var(x~k)var(n~k))

您可以通过收听此信号来验证您的假设是否正确:

NR(yk)NR(nk)

如果输出听起来没有噪音,那么上面的 SNR 计算是有效的。

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)])