I have a time domain data of some signal in volts vs time. Now I run this data through FFT and let's say I use the bin size 100Hz. I get an array of values: frequency, real and imaginary numbers. What is the physical value of the real and imaginary data in this case ? In other words I need to measure the signal value in Volts at certain frequency, How do I extract it from the result ?
Edit: The next part is an explanation to the debate whether multiple signals with frequencies that fall into the same bin proportionally increase the fft output.
Here is the FFT calculation routine in Python:
import numpy as np
import pyfftw
from scipy import signal
def fast_FFT(x, y, binSize):
N = len(y)
dt = (x[N - 1] - x[0]) / (N - 1)
window_time = 1 / binSize
window_len = int(window_time / dt)
window = signal.windows.hann(window_len)
acf = len(window) / sum(window)
aligned_array = pyfftw.empty_aligned(window_len, dtype='complex128')
y = y[0:window_len]
aligned_array[...] = y * window * acf
N = len(aligned_array)
dt = (x[N - 1] - x[0]) / (N - 1)
df = 1 / (dt * N)
sampleIndex = np.arange(-N / 2, N / 2)
f = sampleIndex * df
fft = pyfftw.builders.fft(aligned_array)
FT = np.fft.fftshift(fft()) / N
# single sided FFT
positive_f = np.where(f > 0)
f_singleSided = f[positive_f]
FT_singleSided = 2 * FT[positive_f]
return f_singleSided, FT_singleSided
The test code:
import unittest
import numpy as np
import math
from FFT import fast_FFT
import matplotlib.pyplot as plt
class TestFFT(unittest.TestCase):
# Generate the sine wave
def __generate_sine_wave(self, amplitude, frequencies, duration, sampling_rate):
time = np.arange(0, duration, 1 / sampling_rate)
sine_wave = None
for frequency in frequencies:
sw = amplitude * np.sin(2 * np.pi * frequency * time)
if sine_wave is None:
sine_wave = sw
else:
sine_wave = sine_wave + sw
return time, sine_wave
def test_multiple2500(self):
# Create a signal with several frequencies close enough to fall into the same bin
(samples, signal) = self.__generate_sine_wave(1, [50002,50010, 50020, 50030, 50040, 50050], 1, 500000)
(frequency, fft) = fast_FFT(samples, signal, 2500)
f = list(filter(lambda x: x <= 75000, frequency))
fft = fft[:len(f)]
sig = [math.sqrt(c.imag * c.imag + c.real * c.real) for c in fft]
plt.plot(f, sig)
plt.title('Frequency Domain')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Amplitude')
plt.show()
def test_multiple_different_bins(self):
(samples, signal) = self.__generate_sine_wave(1, [20000,30000, 40000, 50000, 60000, 70000], 1, 500000)
(frequency, fft) = fast_FFT(samples, signal, 2500)
f = list(filter(lambda x: x <= 75000, frequency))
fft = fft[:len(f)]
sig = [math.sqrt(c.imag * c.imag + c.real * c.real) for c in fft]
plt.plot(f, sig)
plt.title('Frequency Domain')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Amplitude')
plt.show()
if __name__ == '__main__':
unittest.main()