2
$\begingroup$

I have a program which plots data obtained in a NI USB DAQ realtime to a spectrogram plot using the surf function. I'd like to improve the appearance of the plot using some sort of windowing function. My questions are: Which windowing function is the best to use for this? and How do I implement it? Here's a sample of my current code:

fprintf('Initializing DAQ\n');
s = daq.createSession ('ni');
addAnalogInputChannel(s, 'Dev1','ai1', 'Voltage'); 


s.NumberOfScans = Fs*Record_Time;
s.Rate = Fs;
s.Channels.Range = [-1 1];
s.DurationInSeconds = 5;

Spect_nFFT = 2^8;
num_overlap = 19*round(Spect_nFFT/20);
start_sample = 1;

DataRdy = true;
% Run in background session

Lh = s.addlistener('DataAvailable', @(src,event) CaptureData(event.TimeStamps, event.Data));
s.NotifyWhenDataAvailableExceeds = 100000*.1;
s.IsContinuous = true;
s.startBackground();
NFFT = 2^nextpow2(L);
P = zeros(8193,50);
F = Fs/2*linspace(0,1,NFFT/2+1);
g=0;

while g==0

    while DataRdy == 0
        pause(.01)
    end
    pause(.5)

    Min_Threshold = 10^12;

    start_sample = 1;
    NFFT = 2^nextpow2(L); % Next power of 2 from length of myRecording
    FFT_Out = fft(myRecording(start_sample:end),NFFT)/size(myRecording(start_sample:end),1);
    FFT_Out = FFT_Out(1:NFFT/2+1);

    A = sqrt(FFT_Out.*conj(FFT_Out));
    P = [P(:,2:end), sqrt(FFT_Out.*conj(FFT_Out))];
    P(P<=max(max(P))/Min_Threshold)=max(max(P))/Min_Threshold;
    surf(1:size(P,2),F,10*log10(P),'edgecolor','none'); axis tight; 


    % Create updating spectrogram
    view(0,90); 

    xlabel('Time'); 
    ylabel('Hz');


    drawnow;

    DataRdy = 0;
    uicontrol('Style', 'pushbutton', 'String', 'Exit',...
    'Position', [20 20 50 20],...
    'Callback', 'g=g+1');

end
delete(Lh);
stop(s);

Thanks for any help!

$\endgroup$
  • $\begingroup$ Do you really need to window your time-domain data? Don't forget, the spectrum you obtain after windowing will not be the true spectrum of your original input signal. Is that really what you want? $\endgroup$ – Richard Lyons Sep 17 '15 at 11:25
3
$\begingroup$

Windowing is nothing more than element-wise multiplication of your signal by window function.

Let's assume that you want to apply Hanning window. In your case signal is stored inside myRecording(start_sample:end).

  • Create the window values vector of your signal length: win = hann(length(myRecording(start_sample:end)))
  • Multiply by your signal and store it in variable: sig = win.*size(myRecording(start_sample:end).
  • Perform the FFT, but keep in mind that now you cannot simply normalize but your signal length (as you do within FFT function), but you should (very simply speaking) divide by sum of your window values: sum(win). Probably you will notice that in case of no window applied = rectangular window, that is also true.

Answering second part of your question, which window to choose? You can start from this great white paper (on figure 8 you have recomendations for different window types): Windowing: Optimizing FFTs Using Window Functions.

enter image description here

Just keep in mind that if you you increase side-lobe attenuation then you also make your main-lobe wider (worse frequency resolution). Hanning is a good start.

For more info you can refer to literature:

Harris F.J. - On the Use of Windows for Harmonic Analysis with the Discrete Fourier Transform Heinzel G. - Spectrum and spectral density estimation by the DFT

Also I've noticed in your code that you are normalizing by the number of samples and then taking only first half of your spectrum. That's perfectly ok, but you must also multiply amplitude by 2 in order to compensate for removing of half of your energy in components above $\frac{f_s}{2}$

In case you have more queries you can search for questions and answers regarding windowing and leakage - you will find plenty.

$\endgroup$
  • $\begingroup$ Could you please elaborate on how you get myRecording for the loop? Is it an output of @CaptureData ? I am trying to find a way of plotting the data in real time, but in such a way that the plot wouldn't get slower and slower as more data comes in. So tricks like drawnow, etc might be appropriate. I think I would need to get the data outside of addlistener for this to work, and what you are doing with myRecording seems like what I need. Thanks. $\endgroup$ – Mike Sep 16 '15 at 21:08

protected by jojek Sep 16 '15 at 21:09

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.