How to Obtain the Frequencies of Each Value in an Fft

How to determine frequencies values from an FFT

Generally for an FFT result, the array index corresponds to the discretised frequency "block" and the value is just the magnitude. Since you probably want to know the peak frequency and not the amplitude, the exact value of the latter is not that important.

The general steps are:

  1. get the array
  2. get the size of the array [1]
  3. find the max value in array [1]
  4. get the index of the max value [3]
  5. calculate frequency interval = sampleRate / size [2] / 2
  6. calculate the max frequency = index [4] * frequency interval
  7. return the frequency [6]

How to get frequency from fft result?

The complex data is interleaved, with real components at even indices and imaginary components at odd indices, i.e. the real components are at index 2*i, the imaginary components are at index 2*i+1.

To get the magnitude of the spectrum at index i, you want:

re = fft[2*i];
im = fft[2*i+1];
magnitude[i] = sqrt(re*re+im*im);

Then you can plot magnitude[i] for i = 0 to N / 2 to get the power spectrum. Depending on the nature of your audio input you should see one or more peaks in the spectrum.

To get the approximate frequency of any given peak you can convert the index of the peak as follows:

freq = i * Fs / N;

where:

freq = frequency in Hz
i = index of peak
Fs = sample rate in Hz (e.g. 44100 Hz, or whatever you are using)
N = size of FFT (e.g. 1024 in your case)

Note: if you have not previously applied a suitable window function to the time-domain input data then you will get a certain amount of spectral leakage and the power spectrum will look rather "smeared".


To expand on this further, here is pseudo-code for a complete example where we take audio data and identify the frequency of the largest peak:

N = 1024          // size of FFT and sample window
Fs = 44100 // sample rate = 44.1 kHz
data[N] // input PCM data buffer
fft[N * 2] // FFT complex buffer (interleaved real/imag)
magnitude[N / 2] // power spectrum

// capture audio in data[] buffer
// ...

// apply window function to data[]
// ...

// copy real input data to complex FFT buffer
for i = 0 to N - 1
fft[2*i] = data[i]
fft[2*i+1] = 0

// perform in-place complex-to-complex FFT on fft[] buffer
// ...

// calculate power spectrum (magnitude) values from fft[]
for i = 0 to N / 2 - 1
re = fft[2*i]
im = fft[2*i+1]
magnitude[i] = sqrt(re*re+im*im)

// find largest peak in power spectrum
max_magnitude = -INF
max_index = -1
for i = 0 to N / 2 - 1
if magnitude[i] > max_magnitude
max_magnitude = magnitude[i]
max_index = i

// convert index of largest peak to frequency
freq = max_index * Fs / N

how to extract frequency associated with fft values in python

np.fft.fftfreq tells you the frequencies associated with the coefficients:

import numpy as np

x = np.array([1,2,1,0,1,2,1,0])
w = np.fft.fft(x)
freqs = np.fft.fftfreq(len(x))

for coef,freq in zip(w,freqs):
if coef:
print('{c:>6} * exp(2 pi i t * {f})'.format(c=coef,f=freq))

# (8+0j) * exp(2 pi i t * 0.0)
# -4j * exp(2 pi i t * 0.25)
# 4j * exp(2 pi i t * -0.25)

The OP asks how to find the frequency in Hertz.
I believe the formula is frequency (Hz) = abs(fft_freq * frame_rate).

Here is some code that demonstrates that.

First, we make a wave file at 440 Hz:

import math
import wave
import struct

if __name__ == '__main__':
# http://stackoverflow.com/questions/3637350/how-to-write-stereo-wav-files-in-python
# http://www.sonicspot.com/guide/wavefiles.html
freq = 440.0
data_size = 40000
fname = "test.wav"
frate = 11025.0
amp = 64000.0
nchannels = 1
sampwidth = 2
framerate = int(frate)
nframes = data_size
comptype = "NONE"
compname = "not compressed"
data = [math.sin(2 * math.pi * freq * (x / frate))
for x in range(data_size)]
wav_file = wave.open(fname, 'w')
wav_file.setparams(
(nchannels, sampwidth, framerate, nframes, comptype, compname))
for v in data:
wav_file.writeframes(struct.pack('h', int(v * amp / 2)))
wav_file.close()

This creates the file test.wav.
Now we read in the data, FFT it, find the coefficient with maximum power,
and find the corresponding fft frequency, and then convert to Hertz:

import wave
import struct
import numpy as np

if __name__ == '__main__':
data_size = 40000
fname = "test.wav"
frate = 11025.0
wav_file = wave.open(fname, 'r')
data = wav_file.readframes(data_size)
wav_file.close()
data = struct.unpack('{n}h'.format(n=data_size), data)
data = np.array(data)

w = np.fft.fft(data)
freqs = np.fft.fftfreq(len(w))
print(freqs.min(), freqs.max())
# (-0.5, 0.499975)

# Find the peak in the coefficients
idx = np.argmax(np.abs(w))
freq = freqs[idx]
freq_in_hertz = abs(freq * frate)
print(freq_in_hertz)
# 439.8975

How can I get DFT/FFT output frequencies in Hertz?

You need to find the peak magnitude then work out the corresponding frequency:

  • calculate the magnitude of each DFT output bin: magnitude = sqrt(re*re+im*im)
  • find the bin with the largest magnitude, call its index i_max.
  • calculate the equivalent frequency of this bin: freq = i_max * Fs / N, here Fs = sample rate (Hz) and N = no of points in FFT.

See this answer for a more detailed explanation of how bin indices and frequency are related.

How to figure out the frequencies in an fft output?

what frequencies does these amplitudes correspond to?

I'm not sure exactly where you got that example, and why it would be dividing by noofbins>>1. The correct formula for the frequencies of each bins is given by:

for (int i=0; i<(noofbins>>1); i++) {
freq[i]=((i*samplingfreq)/noofbins);
}

This will give you frequencies from 0 to the Nyquist frequency (half of the sampling frequency). In your specific case, that would be from 0 to 50Hz (in increments of 100/64 = 1.5625Hz).

Is there any way of refining the fft about the frequency of interest without lowering the sampling frequency [...]?

Capturing more data, that is increasing the number of samples used as input to the FFT, will result in a better frequency resolution of the FFT. For example, using 128 samples (slightly more than 1 second worth of data) instead of 64, would bring the frequency increments from 1.5625Hz down to 0.78125Hz. Further increasing the number of samples to 256 (about 2.5 seconds) would reduce the frequency increment to ~0.39Hz.

Calculate Frequency from sound input using FFT

The frequency corresponding to a given FFT bin index is given by:

f = i * Fs / N;

where:

Fs = sample rate (Hz)
N = FFT size
i = bin index

So for your peak index maxIndex and FFT size blockSize the frequency of the peak will be:

f = maxIndex * Fs / blockSize;

See this answer for more details.

How to find the frequency from FFT data in MATLAB

Instead of using the FFT directly you can use MATLAB's periodogram function, which takes care of a lot of the housekeeping for you, and which will plot the X (frequency axis) correctly if you supply the sample rate. See e.g. this answer.

For clarification though, the index of the FFT corresponds to frequency, and the magnitude of the complex value at each frequency (index) tells you the amplitude of the signal at that frequency.



Related Topics



Leave a reply



Submit