the_lenoz
the_lenoz

Reputation: 3

Result of FFT is not "symmetric"

please, help me to understand this situation! I tried to perform fast Fourier transformation of following numpy array:

[-5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j
  -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j
  -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j
  -5.+0.j -5.+0.j -6.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j
  -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j
  -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -4.+0.j -4.+0.j -4.+0.j -5.+0.j
  -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j
  -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j
  -4.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j
  -5.+0.j -5.+0.j -5.+0.j -4.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j
  -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j
  -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j
  -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j
  -6.+0.j -5.+0.j -6.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j -5.+0.j
  -5.+0.j -5.+0.j]

Dtype of this array: complex128

I use pyFFTW library for FFT, but I tried to use numpy.fft and got same result. Result of this transformation isn't symmetric, here it is:

[-6.38000000e+02+0.j         -5.79558574e+00-0.5239911j
  1.04363210e+00-0.13402821j  1.83512135e+00-4.55809676j
 -3.25037176e+00-1.0153579j   3.95224383e+00-0.40245522j
  4.75811808e-01-1.77333882j  3.45267479e+00+3.76746814j
  1.01366975e+00-3.24830288j -1.09833720e+00+3.58958411j
  8.73456091e-01+4.08582967j -1.52372641e+00-2.35312039j
 -1.14644739e-01+3.97447239j -2.78930648e+00-3.57930658j
 -2.91246590e+00+1.00641126j  2.19137375e+00+0.10173507j
 -1.00000000e+00-3.82842712j  1.29395984e-02-0.11876076j
  2.33232501e+00-2.01762168j -1.82191804e+00+2.49049943j
  4.78502749e+00-1.06511898j -1.81066821e-01+0.19788181j
 -2.25181410e+00+1.670309j    2.21786082e+00+0.0242528j
 -2.24830288e+00+2.59945618j  1.58536431e+00-1.19369906j
 -2.12835416e+00-1.64503003j -8.56097834e-01+1.90434517j
  4.71490768e-01-0.39201004j  3.13004864e-01-1.40281893j
  1.28758293e+00+0.85823986j -3.03623709e+00-1.99571384j
  2.00000000e+00+2.j         -3.95807608e-02+0.59023836j
 -2.63550010e-01-2.51754427j  3.30586002e-01+0.63739274j
 -1.45215883e+00-0.32894978j  1.27897394e+00+0.81978368j
  1.82528107e+00-1.39630437j -9.33697250e-02+0.35537805j
 -1.16591068e+00+0.01366975j  2.17206646e+00+1.83693135j
 -8.25338690e-01+1.9733821j  -4.43868762e-02-2.08774779j
 -1.19123350e+00+1.91554908j -3.05904256e+00+0.01414392j
  1.04345911e+00-0.21322747j -3.55405541e-01-1.87834977j
 -1.00000000e+00-1.82842712j  3.73344081e-03-1.23071773j
  2.36510891e+00-0.01762165j  1.43603094e+00+0.78263587j
  2.17770500e+00-2.7017138j   1.37134006e-01+3.76027055j
 -6.24730429e-01+1.56047564j  1.50752557e+00+1.38483701j
 -1.59945618e+00+2.16591068j -2.35274876e+00-1.76234787j
 -3.00116584e+00+1.30381397j  2.98393628e-01-0.47903243j
 -1.42581443e+00-2.60915189j  6.94056466e-01-3.07062338j
  7.60762111e-01-0.6813852j  -3.72273922e-01-0.57237016j
  6.00000000e+00+0.j         -3.72273922e-01+0.57237016j
  7.60762111e-01+0.6813852j   6.94056466e-01+3.07062338j
 -1.42581443e+00+2.60915189j  2.98393628e-01+0.47903243j
 -3.00116584e+00-1.30381397j -2.35274876e+00+1.76234787j
 -1.59945618e+00-2.16591068j  1.50752557e+00-1.38483701j
 -6.24730429e-01-1.56047564j  1.37134006e-01-3.76027055j
  2.17770500e+00+2.7017138j   1.43603094e+00-0.78263587j
  2.36510891e+00+0.01762165j  3.73344081e-03+1.23071773j
 -1.00000000e+00+1.82842712j -3.55405541e-01+1.87834977j
  1.04345911e+00+0.21322747j -3.05904256e+00-0.01414392j
 -1.19123350e+00-1.91554908j -4.43868762e-02+2.08774779j
 -8.25338690e-01-1.9733821j   2.17206646e+00-1.83693135j
 -1.16591068e+00-0.01366975j -9.33697250e-02-0.35537805j
  1.82528107e+00+1.39630437j  1.27897394e+00-0.81978368j
 -1.45215883e+00+0.32894978j  3.30586002e-01-0.63739274j
 -2.63550010e-01+2.51754427j -3.95807608e-02-0.59023836j
  2.00000000e+00-2.j         -3.03623709e+00+1.99571384j
  1.28758293e+00-0.85823986j  3.13004864e-01+1.40281893j
  4.71490768e-01+0.39201004j -8.56097834e-01-1.90434517j
 -2.12835416e+00+1.64503003j  1.58536431e+00+1.19369906j
 -2.24830288e+00-2.59945618j  2.21786082e+00-0.0242528j
 -2.25181410e+00-1.670309j   -1.81066821e-01-0.19788181j
  4.78502749e+00+1.06511898j -1.82191804e+00-2.49049943j
  2.33232501e+00+2.01762168j  1.29395984e-02+0.11876076j
 -1.00000000e+00+3.82842712j  2.19137375e+00-0.10173507j
 -2.91246590e+00-1.00641126j -2.78930648e+00+3.57930658j
 -1.14644739e-01-3.97447239j -1.52372641e+00+2.35312039j
  8.73456091e-01-4.08582967j -1.09833720e+00-3.58958411j
  1.01366975e+00+3.24830288j  3.45267479e+00-3.76746814j
  4.75811808e-01+1.77333882j  3.95224383e+00+0.40245522j
 -3.25037176e+00+1.0153579j   1.83512135e+00+4.55809676j
  1.04363210e+00+0.13402821j -5.79558574e+00+0.5239911j ]

Here is a graph of phase and amplitude: Here is a graph of phase and amplitude

You can see that phase spectrum is not symmetric and looks "inverted" in right part - zoomed

This is my code in Python:

samplerate = 44100
spectrum = pyfftw.interfaces.numpy_fft.fft(buffer)
amplitude = np.abs(spectrum)
phase = np.angle(spectrum)
t = np.linspace(0, samplerate, buffer.size)
plt.plot(t, amplitude, label="amplitude", linestyle="-")
plt.plot(t, phase, label="phase", linestyle=":")
plt.legend()
plt.show()

As far as I know, FFT spectrum of real data must be symmetric around half of the sampling rate. What's wrong?

Upvotes: 0

Views: 219

Answers (1)

vyktron
vyktron

Reputation: 106

When you perform a Fourier Transform on a real-valued signal, the result is a complex-valued spectrum. This spectrum is "symmetric" around the 0-frequency component (DC component) which is represented by the first element of the spectrum.

After removing the first element, we actually observe that the second half of the spectrum is the flipped complex conjugate of the first half.

Try this :

samplerate = 44100
spectrum = pyfftw.interfaces.numpy_fft.fft(buffer)

first_element = spectrum[0]
spectrum = spectrum[1:]

amplitude = np.abs(spectrum)
phase = np.angle(spectrum)

# Mirror the spectrum
spectrum_reversed = np.conj(spectrum[::-1])
# Test if the reversed spectrum is the same as the original spectrum
print(np.allclose(spectrum_reversed, spectrum))
# Test if the first element is the sum of the signal
print(np.allclose(first_element, np.sum(buffer)))

Upvotes: 2

Related Questions