Technical discussions related to Audio Signal Processing (digital effects, acoustics, noise reduction, musical signal processing, etc).
Dear All Does anyone here already coded a SNR computation from FFT bins ? I already coded a FFT algo in C, it is ok, but I cannot succeed in coding a SNR extraction from the FFT bins. I use a blackman harris 7 windows (7 bins in signal) My FFT table fft[] represents all fft bins in dB - I search the max bin value from FFT table fft[] - for(-3 bins to +3 bins around the above max bin) I do : InBandSignalLeft += (pow(pow(10,(fft[i])/20)),2.0)) ); - for all other FFT bins (all exept DC and the 7 above bins) I do : InBandNoiseLeft += (pow(pow(10,(fft[i])/20)),2.0)) ); Then : SNR = 20*log10(sqrt(InBandSignalLeft)/sqrt(InBandNoiseLeft)) The above SNR does not provide similar results than spectralab for instance Any help would be greatly appreciated ! Thanks
hello, As far as my knowledge goes, InBandSignalLeft += fft[i] * fft[i]; also, InBandNoiseLeft += fft[i] * fft[i]; and then you can convert it to the dB scale, SNR = 20*log10(sqrt(InBandSignalLeft)/sqrt(InBandNoiseLeft)); you are assuming that every signal component which is not around the viccinity of the peak is noise, you are also assuming that noise is not present in the viccinity of the peak, these may not be necessarily true.... hope this helps... Pradeep On 8/7/07, je0062002 <h...@hotmail.com> wrote: > > Dear All > Does anyone here already coded a SNR computation from FFT bins ? > I already coded a FFT algo in C, it is ok, but I cannot succeed in > coding a SNR extraction from the FFT bins. > > I use a blackman harris 7 windows (7 bins in signal) > My FFT table fft[] represents all fft bins in dB > > - I search the max bin value from FFT table fft[] > > - for(-3 bins to +3 bins around the above max bin) I do : > > InBandSignalLeft += (pow(pow(10,(fft[i])/20)),2.0)) ); > > - for all other FFT bins (all exept DC and the 7 above bins) I do : > > InBandNoiseLeft += (pow(pow(10,(fft[i])/20)),2.0)) ); > > Then : SNR = 20*log10(sqrt(InBandSignalLeft)/sqrt(InBandNoiseLeft)) > > The above SNR does not provide similar results than spectralab for > instance > > Any help would be greatly appreciated ! > Thanks > -- It ain't how hard u can hit, its about how hard u can get hit and keep moving forward, thats how winning is done...
Hello,
below a short example program that I hope does what you expect.
It calculates SNR from the normalized crosscorrelation coefficient, obtained via FFT.
c^2 is the amount of power in a explained by b (and vice versa). The remainder 1-c^2 is
uncorrelated (=noise).
SNR follows as c^2/(1-c^2).
Cheers
Markus
% SNR detection via FFT / correlation
% Markus Nentwig 2007
% this program is in the public domain, provided without any warranty
close all; clear all;
N=65536;
% transmitted signal
a=randn(1, N);
x=[];
y=[];
for SNR_in_dB=-30:5:60
vRatio=power(10, -SNR_in_dB/20);
% construct time shifted, noisy "received" signal
b=circshift(a, [0, -1234])+vRatio*randn(1, N);
% scale to arbitrary amplitude...
a=a*12345;
b=b*23456;
% ... and normalize
ea=sum(a .* conj(a)) / N;
eb=sum(b .* conj(b)) / N;
a=a/sqrt(ea);
b=b/sqrt(eb);
% crosscorrelation
corr=ifft(fft(a) .* conj(fft(b)))/N;
% find peak (should be 1234+1)
maxBin=find(abs(corr)==abs(max(corr)));
c=abs(corr(maxBin));
% c is the ratio of "voltage" in a explained by b and vice versa
% c^2 is the ratio of power => signal
% 1-c^2 is the remaining part unexplained by signal => noise
% note, low SNRs require a longer signal, because part of the noise will randomly correlate
with the reference signal.
SNR=c^2/(1-c^2);
SNR_out_dB=10*log10(SNR);
x=[x, SNR_in_dB];
y=[y, SNR_out_dB];
end
plot(x, y, '+-');
xlabel('SNR in/dB'); ylabel('SNR out/dB');