Escrevo esta resposta adicional para explicar as origens da difusão dos picos ao usar FFT e, especialmente, discuto o tutorial scipy.fftpack do qual discordo em algum ponto.
Neste exemplo, o tempo de gravação tmax=N*T=0.75
. O sinal é sin(50*2*pi*x) + 0.5*sin(80*2*pi*x)
. O sinal de frequência deve conter dois picos em frequências 50
e 80
com amplitudes 1
e 0.5
. No entanto, se o sinal analisado não tiver um número inteiro de períodos, a difusão pode aparecer devido ao truncamento do sinal:
- Pike 1:
50*tmax=37.5
=> frequência 50
não é um múltiplo de 1/tmax
=> Presença de difusão devido ao truncamento do sinal nesta frequência.
- Pike 2:
80*tmax=60
=> frequência 80
é um múltiplo de 1/tmax
=> Sem difusão devido ao truncamento do sinal nesta frequência.
Aqui está um código que analisa o mesmo sinal do tutorial ( sin(50*2*pi*x) + 0.5*sin(80*2*pi*x)
), mas com pequenas diferenças:
- O exemplo original do scipy.fftpack.
- O exemplo scipy.fftpack original com um número inteiro de períodos de sinal (em
tmax=1.0
vez de 0.75
para evitar a difusão do truncamento).
- O exemplo scipy.fftpack original com um número inteiro de períodos de sinal e onde as datas e frequências são tiradas da teoria FFT.
O código:
import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack
N = 600
tmax = 3/4
T = tmax / N
x1 = np.linspace(0.0, N*T, N)
y1 = np.sin(50.0 * 2.0*np.pi*x1) + 0.5*np.sin(80.0 * 2.0*np.pi*x1)
yf1 = scipy.fftpack.fft(y1)
xf1 = np.linspace(0.0, 1.0/(2.0*T), N//2)
tmax = 1
T = tmax / N
x2 = np.linspace(0.0, N*T, N)
y2 = np.sin(50.0 * 2.0*np.pi*x2) + 0.5*np.sin(80.0 * 2.0*np.pi*x2)
yf2 = scipy.fftpack.fft(y2)
xf2 = np.linspace(0.0, 1.0/(2.0*T), N//2)
tmax = 1
T = tmax / N
x3 = T * np.arange(N)
y3 = np.sin(50.0 * 2.0*np.pi*x3) + 0.5*np.sin(80.0 * 2.0*np.pi*x3)
yf3 = scipy.fftpack.fft(y3)
xf3 = 1/(N*T) * np.arange(N)[:N//2]
fig, ax = plt.subplots()
ax.plot(xf1, 2.0/N * np.abs(yf1[:N//2]), label='fftpack tutorial')
ax.plot(xf2, 2.0/N * np.abs(yf2[:N//2]), label='Integer number of periods')
ax.plot(xf3, 2.0/N * np.abs(yf3[:N//2]), label='Correct positioning of dates')
plt.legend()
plt.grid()
plt.show()
Resultado:
Como pode ser aqui, mesmo usando um número inteiro de períodos, alguma difusão ainda permanece. Esse comportamento é devido a um posicionamento incorreto de datas e frequências no tutorial scipy.fftpack. Portanto, na teoria das transformadas discretas de Fourier:
- o sinal deve ser avaliado em datas em
t=0,T,...,(N-1)*T
que T é o período de amostragem e a duração total do sinal é tmax=N*T
. Observe que paramos em tmax-T
.
- as frequências associadas são
f=0,df,...,(N-1)*df
onde df=1/tmax=1/(N*T)
está a frequência de amostragem. Todos os harmônicos do sinal devem ser múltiplos da frequência de amostragem para evitar a difusão.
No exemplo acima, você pode ver que o uso de em arange
vez de linspace
permite evitar difusão adicional no espectro de frequência. Além disso, o uso da linspace
versão também leva a um deslocamento dos picos que estão localizados em frequências ligeiramente mais altas do que deveriam ser, como pode ser visto na primeira foto, onde os picos estão um pouco à direita das frequências 50
e 80
.
Vou apenas concluir que o exemplo de uso deve ser substituído pelo seguinte código (que é menos enganoso na minha opinião):
import numpy as np
from scipy.fftpack import fft
N = 600
T = 1.0 / 800.0
x = T*np.arange(N)
y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)
yf = fft(y)
xf = 1/(N*T)*np.arange(N//2)
import matplotlib.pyplot as plt
plt.plot(xf, 2.0/N * np.abs(yf[0:N//2]))
plt.grid()
plt.show()
Resultado (o segundo pico não é mais difundido):
Acho que essa resposta ainda traz algumas explicações adicionais sobre como aplicar corretamente a transformada discreta de Fourier. Obviamente, minha resposta é muito longa e sempre há coisas adicionais a dizer ( ewerlopes falou brevemente sobre aliasing, por exemplo, e muito pode ser dito sobre janelamento ), então vou parar.
Eu acho que é muito importante entender profundamente os princípios da transformada discreta de Fourier ao aplicá-la, porque todos nós sabemos que muitas pessoas adicionam fatores aqui e ali ao aplicá-la para obter o que desejam.