# Is pythons FFT function broken?

Status
Not open for further replies.

#### wtr

##### Full Member level 5 However now I've stepped back and generated a stimulus. I know that the results I was previously getting is not a symptom of my captured data, but rather the processing.

This generated sinusoidal is then fed into the fft. I change the frequency. Please watch the magnitude. Is specgram broken?

Please run the following python code for yourself and see what happens.

Code Python - [expand]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import numpy as np
from matplotlib import mlab
import matplotlib.pyplot as plt
import matplotlib.animation as animation

def safe_log10(values, minval=1e-16):  # pragma: no cover
"""Safely do log10."""
return np.log10(values.clip(min=minval))

def animate(i):
A = 10
fs = 44100
sample = fs
nfft = 4096

f = 11440 + (i * 10)  # Steps by
# f = 11440 + (i * (fs / nfft))  # Steps by

x = np.arange(sample * 10)
y = A * np.sin(2 * np.pi * f * x / fs)

ax = plt.axes(projection='3d')
spec, freqs, t = mlab.specgram(y, NFFT=nfft, noverlap=0, Fs=fs, mode='magnitude')
X, Y, Z = t[None, :], freqs[:, None], 20.0 * safe_log10(spec)
ax.plot_surface(X, Y, Z, cmap='viridis', cstride=4, rstride=4)
ax.set_xlabel('time (s)')
ax.set_ylabel('frequencies (Hz)')
ax.set_zlabel('amplitude (dB)')
ax.set_zlim(-140, 0)

animation_1 = animation.FuncAnimation(plt.gcf(), animate, interval=100)
plt.show()

#### FlyingDutch However now I've stepped back and generated a stimulus. I know that the results I was previously getting is not a symptom of my captured data, but rather the processing.

This generated sinusoidal is then fed into the fft. I change the frequency. Please watch the magnitude. Is specgram broken?

Please run the following python code for yourself and see what happens.

Code Python - [expand]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import numpy as np
from matplotlib import mlab
import matplotlib.pyplot as plt
import matplotlib.animation as animation

def safe_log10(values, minval=1e-16):  # pragma: no cover
"""Safely do log10."""
return np.log10(values.clip(min=minval))

def animate(i):
A = 10
fs = 44100
sample = fs
nfft = 4096

f = 11440 + (i * 10)  # Steps by
# f = 11440 + (i * (fs / nfft))  # Steps by

x = np.arange(sample * 10)
y = A * np.sin(2 * np.pi * f * x / fs)

ax = plt.axes(projection='3d')
spec, freqs, t = mlab.specgram(y, NFFT=nfft, noverlap=0, Fs=fs, mode='magnitude')
X, Y, Z = t[None, :], freqs[:, None], 20.0 * safe_log10(spec)
ax.plot_surface(X, Y, Z, cmap='viridis', cstride=4, rstride=4)
ax.set_xlabel('time (s)')
ax.set_ylabel('frequencies (Hz)')
ax.set_zlabel('amplitude (dB)')
ax.set_zlim(-140, 0)

animation_1 = animation.FuncAnimation(plt.gcf(), animate, interval=100)
plt.show()

Hello,
I run given code in python - I confirned: amplitude of FFT is c hanging on plot depending on current fequency.

Best Regards

#### kaz1

##### Full Member level 4 However now I've stepped back and generated a stimulus. I know that the results I was previously getting is not a symptom of my captured data, but rather the processing.

This generated sinusoidal is then fed into the fft. I change the frequency. Please watch the magnitude. Is specgram broken?

Please run the following python code for yourself and see what happens.

Code Python - [expand]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import numpy as np
from matplotlib import mlab
import matplotlib.pyplot as plt
import matplotlib.animation as animation

def safe_log10(values, minval=1e-16):  # pragma: no cover
"""Safely do log10."""
return np.log10(values.clip(min=minval))

def animate(i):
A = 10
fs = 44100
sample = fs
nfft = 4096

f = 11440 + (i * 10)  # Steps by
# f = 11440 + (i * (fs / nfft))  # Steps by

x = np.arange(sample * 10)
y = A * np.sin(2 * np.pi * f * x / fs)

ax = plt.axes(projection='3d')
spec, freqs, t = mlab.specgram(y, NFFT=nfft, noverlap=0, Fs=fs, mode='magnitude')
X, Y, Z = t[None, :], freqs[:, None], 20.0 * safe_log10(spec)
ax.plot_surface(X, Y, Z, cmap='viridis', cstride=4, rstride=4)
ax.set_xlabel('time (s)')
ax.set_ylabel('frequencies (Hz)')
ax.set_zlabel('amplitude (dB)')
ax.set_zlim(-140, 0)

animation_1 = animation.FuncAnimation(plt.gcf(), animate, interval=100)
plt.show()

Any FFT will show amplitude differences between tones due to leakage.. If your tones fall exactly on bin centres then you will have no leakage and all power will fall on one bin and then no difference of amplitude is expected.

• wtr

#### KlausST

##### Super Moderator
Staff member Hi,

and it depends on window function - if used.

try to calculate: Amplitude = sqrt ( Amplitude1^2 + Amplitude2^2 + Amplitude3^2 ...)

Where Amplitudes 1, 2, 3 are the "center amplitudes" plus the amplitudes next to it.
(left, center, right)

Klaus

#### kaz1

##### Full Member level 4 Hi,

and it depends on window function - if used.

try to calculate: Amplitude = sqrt ( Amplitude1^2 + Amplitude2^2 + Amplitude3^2 ...)

Where Amplitudes 1, 2, 3 are the "center amplitudes" plus the amplitudes next to it.
(left, center, right)

Klaus
Or compute total power (all the bins). This should be same irrespective of tone location. And it will be same as input power if fft is set to unity gain across input to output.

#### wtr

##### Full Member level 5 Any FFT will show amplitude differences between tones due to leakage.. If your tones fall exactly on bin centres then you will have no leakage and all power will fall on one bin and then no difference of amplitude is expected.
Given that resolution is 30KHz and steps are about 100KHz, then as I jump from one bin to another, I'm aware that I may not be on the center, but shouldn't the worst case scenario be 3DB drop as power is split nearly evenly between bin1 and bin2.

#### kaz1

##### Full Member level 4 Given that resolution is 30KHz and steps are about 100KHz, then as I jump from one bin to another, I'm aware that I may not be on the center, but shouldn't the worst case scenario be 3DB drop as power is split nearly evenly between bin1 and bin2.
The best check for your fft is to check total bins power between one tone test and next as well as check power level of input in both cases.

Status
Not open for further replies.