fftw snr example
Hi dkumar,
Here is some help from a digital designer.
1 - You don't need to quantize it. Quantizing is equivalent to adding quantization noise, would you agree? So, since matlab handles double values, and the fftw libraries that it uses also do (
www.fftw.org), there is no point in doing any quantization, and you still measure a higher SNR.
In case your question was related to scaling the signal to the interval from -1 to 1, if you only want to have the SNR measure, you also don't need it. If you would like to plot the magnitude of the fft, then you should scale it and divide by the number of samples that you gave to the fft function, and (I think) multiply everything by 2.
2 - The fft is an efficient algorithm (or set of algorithms) for calculating the N complex samples (equally spaced from 0 to 2*pi*(N/(N+1))) of the frequency domain of a signal, from a set of N samples from the time domain.
So, after calling the fft function in matlab, you get complex values. If you want to have the magnitude, use "abs(fft(...))". If you want to have it in dB, use "20*log10(abs(fft(...)))". If you want to have the phase, use "angle(fft(...))".
For calculating the SNR, I would prefer to use linear, as numeric integration of the noise spectrum power can be calculated by a simple sum of values from abs(fft(...)).
3 and 4 - Here are my recommendations:
- Use linear, instead of logarithmic, i.e. use values from abs(fft())
- Since you work with analog, be careful, as your maximum could be either at the frequency of your sine wave stimulus, or at DC. Running "plot(linspace(0, 2*pi*(N/(N+1)), N), abs(fft(...)))" can help you checking that.
- Be sure to have coherent sampling, i.e. the set of values that you provide to the fft contains exactly an integer number of periods of your sine wave. You can notice it in the plot of the fft, when your sine wave is a single, thin and tall line, instead of a not so tall, fat "mountain". This could be difficult to have in analog domain, I am not sure, so, you might think about using some windowing function on your data (Hanning, for example). I never used windowinf funtions but I can also tell you that providing a greater amount of data to the fft helps you reaching coherent sampling.
- When you see that the energy of your sine wave is only one sample of the fft plot (or only 3, if you use certain windowing functions), you can proceed to the following step.
Now I should add some sample code:
N = length(data);
sp = (eps + abs(fft(data))) * 2 / N; % Using eps, machine epsilon, you avoid getting -inf dB because of the fft getting to 0, even after you divide it by N, the number of samples that you provided to the fft function. Use eps and not realmin
s = ...; %Provide the index to your sine wave position, in sp
bw = ...; % provide the index to the end of your bandwidth of interest (could be pi, less than that, or a sub-multiple, in case you have some oversampling in your system)
sig_pow = 20*log10(sp(s)); % signal power
sp(s) = (sp(s-1) + sp(s+1)) / 2; % remove signal from the fft spectrum
noise_and_harms_power = 10*log10(sum(sp(2:bw).^2); % for calculating SINAD later, which I think is your SNDR
% I think you should use 2:bw, to avoid DC, as we also do in digital
harms = 0;
for h=2*(s-1):s-1:bw
harms = harms + sp(h+1)^2; % integrate the power of the harmonics
sp(h+1) = (sp(h) + sp(h+2)) / 2; % remove the harmonics from the fft spectrum
end
thd = -sig_pow + 10*log10(harms); % Total harmonic distortion
snr = sig_pow - 10*log10(sp(2:bw).^2); % snr calculation
--
I hope I have helped you.
rmiguel