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
Extracting SNR from FFT
Started by ●August 8, 2007
Reply by ●August 9, 20072007-08-09
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...
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...
Reply by ●August 13, 20072007-08-13
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');
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');