Roberto Valenzuela
Roberto Valenzuela

Reputation: 21

"Casting complex values to real discards the imaginary part" using fft

I want to know what is wrong with the code.

I just want to made a fourier transform graph and change the values by sliders.

But this is what happened to my graph.

image 1

I just want to made a Parametric EQ graph interface like this, only the graph part with the sliders

image 2

Here the source code:

import matplotlib as mpl
import matplotlib.pyplot as plt
from numpy import pi, sin
import numpy as np
from matplotlib.widgets import Slider, Button, RadioButtons
import scipy.fftpack
"""import warnings
warnings.simplefilter("ignore",np.ComplexWarning)"""


# Eq many times calcule
def fermi(A1, F1, A2, F2):
    peak1 = A1 * sin(2.0 * pi * F1 * x)
    pFl = A2 * sin(2.0 * pi * F2 * x)
    y = peak1 + pFl
    yf = scipy.fftpack.fft(y)
    
    return yf

fig = plt.figure(figsize=(5, 5))

# Create main axis
ax = fig.add_subplot(111)
ax.set_xlim([0,30])
ax.set_ylim([-2, 10])
fig.subplots_adjust(bottom=0.5, top=0.95)

# Create axes for sliders
ax_a1 = fig.add_axes([0.3, 0.10, 0.4, 0.05])
ax_a1.spines['top'].set_visible(True)
ax_a1.spines['right'].set_visible(True)

ax_f1 = fig.add_axes([0.3, 0.01, 0.4, 0.05])
ax_f1.spines['top'].set_visible(True)
ax_f1.spines['right'].set_visible(True)

ax_a2 = fig.add_axes([0.3, 0.20, 0.4, 0.05])
ax_a2.spines['top'].set_visible(True)
ax_a2.spines['right'].set_visible(True)

ax_f2 = fig.add_axes([0.3, 0.30, 0.4, 0.05])
ax_f2.spines['top'].set_visible(True)
ax_f2.spines['right'].set_visible(True)

# Create sliders
s_a1 = Slider(ax=ax_a1, label='amp1 ', valmin=-2, valmax=6, valinit=0, valfmt=' %1.1f eV', facecolor='#cc7000')
s_f1 = Slider(ax=ax_f1, label='f1 ', valmin=0, valmax=30, valinit=1.5, valfmt=' %i K', facecolor='#cc7000')
s_a2 = Slider(ax=ax_a2, label='amp2 ', valmin=-2, valmax=6, valinit=0, valfmt=' %1.1f eV', facecolor='#cc7000')
s_f2 = Slider(ax=ax_f2, label='f2 ', valmin=0, valmax=30, valinit=3.946, valfmt=' %i K', facecolor='#cc7000')


N = 10500
T = 1.0/ 800.0
# Plot default data
x = np.linspace(-0, 30, 1000)
a1_0 = 5
f1_0 = 0
a2_0 = 0
f2_0 = 0
y = fermi(a1_0, f1_0, a2_0, f2_0)
f_d, = ax.plot(x, y, linewidth=0.5, color='#000000')


# Update values
def update(val):
    aa1 = s_a1.val
    ff1 = s_f1.val
    aa2 = s_a2.val
    ff2 = s_f2.val
    f_d.set_data(x.real, (fermi(aa1, ff1, aa2, ff2)).imag)
    fig.canvas.draw_idle()
    

s_a1.on_changed(update)
s_f1.on_changed(update)
s_a2.on_changed(update)
s_f2.on_changed(update)
    
plt.show()

I suspect the error is in the function fermi.

Upvotes: 2

Views: 1774

Answers (1)

SleuthEye
SleuthEye

Reputation: 14579

The function fermi looks fine by itself. However it is important to note that the FFT results are complex numbers. Matplotlib on the other hand plots real-valued data and doesn't know what to do with complex numbers. It then issues the warning that you saw, as it throws away the imaginary part of your data before plotting.

For your specific application it looks like the (real-valued) magnitude of the FFT might be more what you're after. If you are only ever going to need the magnitude of the FFT, you could change your fermi function to only return the computed magnitude:

yf = np.abs(scipy.fftpack.fft(y))

Upvotes: 1

Related Questions