1
$\begingroup$

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()

Here is the resulting frequency domain data that shows superposition of all 6 signals

And this is the same but with frequencies that fall in different bins

$\endgroup$

3 Answers 3

1
$\begingroup$

The results of the Fourier Transform(s) generally produce a "spectral density". For the Discrete Fourier Transform the spectrum has the same units as the original signal, i.e. Volts in your case. That's different from the Continuous Fourier Transform, where spectrum would be in $V/Hz$.

If you use symmetric DFT scaling, i.e.

$$X[k] = \frac{1}{\sqrt{N}} \sum_{n=0}^{N-1} x[n] e^{-j2\pi\frac{kn}{N}} \leftrightarrow x[n] = \frac{1}{\sqrt{N}} \sum_{k=0}^{N-1} X[k] e^{j2\pi\frac{nk}{N}} $$

then Perceval's Theorem holds, i.e.

$$ \sum_{n=0}^{N-1} x^2[n] = \sum_{k=0}^{N-1} |X[k]|^2 $$

This means that you can calculate the total energy of the signal in both domains. $x^2[n]$ is the energy in each "time slot" and $|X[k]|^2$ is the energy in each frequency slot.

$\endgroup$
1
$\begingroup$

Compute the magnitude: $$|X_f| = \sqrt{(\Re(X_f))^2 + (\Im(X_f))^2}$$ Depending on the scaling used by your FFT routine, you might have to scale the result by the length of your FFT.

I suggest you try with a single sinusoid with known amplitude and see that you get the expected result.

$\endgroup$
5
  • $\begingroup$ So I tried single sinusoid with amplitude 1 and got 1 point in the FFT at the frequency of the sine wave with amplitude 1. So far so good. then I combined two sine waves with very close frequencies and the results are surprising to me. The FFT appeared to be the aggregate of the amplitudes in the FFT bin. So if the difference between frequencies larger than the bin size I get two spikes on FFT at both frequencies. Now if the difference between the frequencies is smaller than the bin size I get one spike = 1 in that bin. If my signal is combined of 10 in the same band my amplitude is 10. $\endgroup$ Commented Nov 27, 2023 at 22:46
  • $\begingroup$ Two things: 1). because the frequency resolution (aka "bin size") is $d_f = f_s/N$, where $N$ is the length of the FFT, if a sinusoid has a frequency that does not equal a multiple of $d_f$, there will be spectral leakage: the amplitude will spread to adjacent bins (plenty of questions/answers on this subject on this website). 2). If you have two sinusoids that fall in the same frequency bin, both will have spectral leakage, and their amplitudes will also spread into adjacent bins. You can increase frequency precision by zero-padding $\endgroup$
    – Jdip
    Commented Nov 28, 2023 at 5:11
  • 1
    $\begingroup$ I doubt that you would get one spike exactly at 1 in one bin if your signal has two frequencies that fall within the same frequency bin, or 10 for a combination of 10. You definitely should see some leakage. Feel free to edit your question with minimal code and plots to reproduce $\endgroup$
    – Jdip
    Commented Nov 28, 2023 at 5:14
  • $\begingroup$ Added the code and some results. Maybe the spike is not exactly at 6.00000 but still close enough for practical purposes. It all depends one the length and the sampling rate of the signal. $\endgroup$ Commented Nov 29, 2023 at 16:22
  • 1
    $\begingroup$ Right. So your frequency resolution is $d_f = 2500\tt{Hz}$ and your signal contains frequencies that are very close to $20d_f = 50000\tt{Hz}$. Because these $6$ frequencies are so close to being at a multiple of $d_f$, there is minimal spectral leakage. Try instead 3 frequencies that are further apart, but still fall within the same frequency bin, such as $50000, 50500$ and $51000 \tt{Hz}$. You won't see one spike with amplitude $3$, I guarantee. $\endgroup$
    – Jdip
    Commented Nov 29, 2023 at 17:42
1
$\begingroup$

The Fourier transformation attempts to imitate a signal using a selectable number of sin and cos functions. Since the sin/cos functions for $t \to\pm\infty$ do not disappear asymptotically, the signal must first be extended left and right infinitely often. This happens gradually. Let's assume that the signal is 800 samples long.

To avoid jumps, you should first use a hann window (L=800) to ensure that the amplitudes at the beginning and end of the signal become zero. Then FFT makes two modifications that cannot be prevented: first zero-padding up to 1024 samples (more if desired) and then copies of the intermediate result are added infinitely often left and right.

In technical terms, these are several modulations of the signal that create sidebands. This causes a difference to the original signal (wider line widths), so the FFT results are only good approximations.

The frequency array contains the frequencies used for imitation. If the true signal frequencies differ, the imitation can only be approximate.

The other two arrays indicate for which frequencies it is better to use the cos or the sin function. In most cases, the phase shift that can be calculated from this is omitted.

Normally one calculates $\sqrt{sin^2+cos^2}$ because only the amplitude of the replacement frequencies is of interest.

Try FFT with a single signal frequency and you will see the connection between signal amplitude and height of the FFT peak.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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