DSPRelated.com
Forums

Extracting SNR from FFT

Started by je0062002 August 8, 2007
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 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;
Ne536;

% 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)=s(max(corr)));
cs(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*log10(SNR);
x=[x, SNR_in_dB];
y=[y, SNR_out_dB];
end

plot(x, y, '+-');
xlabel('SNR in/dB'); ylabel('SNR out/dB');