15

I want to know the frequency of data. I had a little bit idea that it can be done using FFT, but I am not sure how to do it. Once I passed the entire data to FFT, then it is giving me 2 peaks, but how can I get the frequency?

Thanks a lot in advance.

Steve Tjoa
  • 59,122
  • 18
  • 90
  • 101
Michael
  • 361
  • 2
  • 3
  • 9
  • 1
    FFT will give you frequency of sinusoidal components of your signal. If you want to measure frequency of real signal (any shape) than you have to forget about FFT and use sample scanning for zero crossing , or peak peak search etc ... depend quite a bit on the shape and offset of your signal. btw on FFT you got 2 peeks one is the mirror of the first one if the input signal is on real domain) so ignore the second half of FFT – Spektre Mar 18 '14 at 09:59

6 Answers6

17

Here's what you're probably looking for:

When you talk about computing the frequency of a signal, you probably aren't so interested in the component sine waves. This is what the FFT gives you. For example, if you sum sin(2*pi*10x)+sin(2*pi*15x)+sin(2*pi*20x)+sin(2*pi*25x), you probably want to detect the "frequency" as 5 (take a look at the graph of this function). However, the FFT of this signal will detect the magnitude of 0 for the frequency 5.

What you are probably more interested in is the periodicity of the signal. That is, the interval at which the signal becomes most like itself. So most likely what you want is the autocorrelation. Look it up. This will essentially give you a measure of how self-similar the signal is to itself after being shifted over by a certain amount. So if you find a peak in the autocorrelation, that would indicate that the signal matches up well with itself when shifted over that amount. There's a lot of cool math behind it, look it up if you are interested, but if you just want it to work, just do this:

  1. Window the signal, using a smooth window (a cosine will do. The window should be at least twice as large as the largest period you want to detect. 3 times as large will give better results). (see http://zone.ni.com/devzone/cda/tut/p/id/4844 if you are confused).

  2. Take the FFT (however, make sure the FFT size is twice as big as the window, with the second half being padded with zeroes. If the FFT size is only the size of the window, you will effectively be taking the circular autocorrelation, which is not what you want. see https://en.wikipedia.org/wiki/Discrete_Fourier_transform#Circular_convolution_theorem_and_cross-correlation_theorem )

  3. Replace all coefficients of the FFT with their square value (real^2+imag^2). This is effectively taking the autocorrelation.

  4. Take the iFFT

  5. Find the largest peak in the iFFT. This is the strongest periodicity of the waveform. You can actually be a little more clever in which peak you pick, but for most purposes this should be enough. To find the frequency, you just take f=1/T.

Krenair
  • 570
  • 5
  • 21
Jeremy Salwen
  • 8,061
  • 5
  • 50
  • 73
  • Thanks for the clear answer here, looked at a lot of info on this subject and this cleared things up for me a little more. – Adamski Aug 27 '14 at 12:59
13

Suppose x[n] = cos(2*pi*f0*n/fs) where f0 is the frequency of your sinusoid in Hertz, n=0:N-1, and fs is the sampling rate of x in samples per second.

Let X = fft(x). Both x and X have length N. Suppose X has two peaks at n0 and N-n0.

Then the sinusoid frequency is f0 = fs*n0/N Hertz.

Example: fs = 8000 samples per second, N = 16000 samples. Therefore, x lasts two seconds long.

Suppose X = fft(x) has peaks at 2000 and 14000 (=16000-2000). Therefore, f0 = 8000*2000/16000 = 1000 Hz.

Steve Tjoa
  • 59,122
  • 18
  • 90
  • 101
  • This is correct. Note however that often the data given by fft algorithms is misaligned due to the fft design (butterfly network). It has to be shifted first before interpreting the values. – ypnos Nov 20 '10 at 01:25
8

If you have a signal with one frequency (for instance:

y = sin(2 pi f t)

With:

  • y time signal
  • f the central frequency
  • t time

Then you'll get two peaks, one at a frequency corresponding to f, and one at a frequency corresponding to -f.

So, to get to a frequency, can discard the negative frequency part. It is located after the positive frequency part. Furthermore, the first element in the array is a dc-offset, so the frequency is 0. (Beware that this offset is usually much more than 0, so the other frequency components might get dwarved by it.)

In code: (I've written it in python, but it should be equally simple in c#):

import numpy as np
from pylab import * 
x = np.random.rand(100) # create 100 random numbers of which we want the fourier transform
x = x - mean(x) # make sure the average is zero, so we don't get a huge DC offset.
dt = 0.1 #[s] 1/the sampling rate
fftx = np.fft.fft(x) # the frequency transformed part
# now discard anything  that we do not need..
fftx = fftx[range(int(len(fftx)/2))]
# now create the frequency axis: it runs from 0 to the sampling rate /2
freq_fftx = np.linspace(0,2/dt,len(fftx))
# and plot a power spectrum
plot(freq_fftx,abs(fftx)**2)
show()

Now the frequency is located at the largest peak.

Dirklinux
  • 1,075
  • 1
  • 11
  • 19
6

If you are looking at the magnitude results from an FFT of the type most common used, then a strong sinusoidal frequency component of real data will show up in two places, once in the bottom half, plus its complex conjugate mirror image in the top half. Those two peaks both represent the same spectral peak and same frequency (for strictly real data). If the FFT result bin numbers start at 0 (zero), then the frequency of the sinusoidal component represented by the bin in the bottom half of the FFT result is most likely.

Frequency_of_Peak = Data_Sample_Rate * Bin_number_of_Peak / Length_of_FFT ;

Make sure to work out your proper units within the above equation (to get units of cycles per second, per fortnight, per kiloparsec, etc.)

Note that unless the wavelength of the data is an exact integer submultiple of the FFT length, the actual peak will be between bins, thus distributing energy among multiple nearby FFT result bins. So you may have to interpolate to better estimate the frequency peak. Common interpolation methods to find a more precise frequency estimate are 3-point parabolic and Sinc convolution (which is nearly the same as using a zero-padded longer FFT).

hotpaw2
  • 70,107
  • 14
  • 90
  • 153
1

Assuming you use a discrete Fourier transform to look at frequencies, then you have to be careful about how to interpret the normalized frequencies back into physical ones (i.e. Hz).

According to the FFTW tutorial on how to calculate the power spectrum of a signal:

#include <rfftw.h>
...
{
     fftw_real in[N], out[N], power_spectrum[N/2+1];
     rfftw_plan p;
     int k;
     ...
     p = rfftw_create_plan(N, FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE);
     ...
     rfftw_one(p, in, out);
     power_spectrum[0] = out[0]*out[0];  /* DC component */
     for (k = 1; k < (N+1)/2; ++k)  /* (k < N/2 rounded up) */
          power_spectrum[k] = out[k]*out[k] + out[N-k]*out[N-k];
     if (N % 2 == 0) /* N is even */
          power_spectrum[N/2] = out[N/2]*out[N/2];  /* Nyquist freq. */
     ...
     rfftw_destroy_plan(p);
}

Note it handles data lengths that are not even. Note particularly if the data length is given, FFTW will give you a "bin" corresponding to the Nyquist frequency (sample rate divided by 2). Otherwise, you don't get it (i.e. the last bin is just below Nyquist).

A MATLAB example is similar, but they are choosing the length of 1000 (an even number) for the example:

N = length(x);
xdft = fft(x);
xdft = xdft(1:N/2+1);
psdx = (1/(Fs*N)).*abs(xdft).^2;
psdx(2:end-1) = 2*psdx(2:end-1);
freq = 0:Fs/length(x):Fs/2;

In general, it can be implementation (of the DFT) dependent. You should create a test pure sine wave at a known frequency and then make sure the calculation gives the same number.

darda
  • 3,597
  • 6
  • 36
  • 49
-9

Frequency = speed/wavelength.

Wavelength is the distance between the two peaks.

Ian
  • 1
  • Two peaks in the *frequency* domain. – Steve Tjoa Nov 20 '10 at 00:53
  • Steve: Not quite. If your data is truly periodic with a single maximum, then the distance between peaks will give you exactly 1/f. However, usually you are dealing with semi-periodic data, for which standard mathematical analysis applied to periodic data doesn't work. – Jeremy Salwen Jun 09 '11 at 04:51
  • What I meant in my earlier comment was that the author has obtained two peaks in the frequency domain. This answer is incorrectly interpreting two peaks to be in the time domain. – Steve Tjoa Oct 02 '11 at 17:36