Tôi viết câu trả lời bổ sung này để giải thích nguồn gốc của sự khuếch tán gai khi sử dụng fft và đặc biệt là thảo luận về hướng dẫn scipy.fftpack mà tôi không đồng ý ở một số điểm.
Trong ví dụ này, thời gian ghi tmax=N*T=0.75
. Tín hiệu là sin(50*2*pi*x)+0.5*sin(80*2*pi*x)
. Tín hiệu tần số phải chứa 2 gai ở tần số 50
và 80
với biên độ 1
và 0.5
. Tuy nhiên, nếu tín hiệu được phân tích không có một số nguyên chu kỳ thì hiện tượng khuếch tán có thể xuất hiện do tín hiệu bị cắt ngắn:
- Pike 1:
50*tmax=37.5
=> tần số 50
không phải là bội số của 1/tmax
=> Sự hiện diện của sự khuếch tán do tín hiệu bị cắt ngắn ở tần số này.
- Pike 2:
80*tmax=60
=> tần số 80
là bội số của 1/tmax
=> Không có khuếch tán do tín hiệu bị cắt ở tần số này.
Đây là mã phân tích tín hiệu tương tự như trong hướng dẫn ( sin(50*2*pi*x)+0.5*sin(80*2*pi*x)
) nhưng có sự khác biệt nhỏ:
- Ví dụ scipy.fftpack ban đầu.
- Ví dụ scipy.fftpack ban đầu với số nguyên chu kỳ tín hiệu (
tmax=1.0
thay vì 0.75
để tránh sự khuếch tán bị cắt ngắn).
- Ví dụ scipy.fftpack ban đầu với số nguyên chu kỳ tín hiệu và trong đó ngày và tần số được lấy từ lý thuyết FFT.
Mật mã:
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 positionning of dates')
plt.legend()
plt.grid()
plt.show()
Đầu ra:
Vì nó có thể ở đây, ngay cả khi sử dụng một số nguyên của chu kỳ, một số khuếch tán vẫn còn. Hành vi này là do vị trí ngày và tần suất không hợp lý trong hướng dẫn scipy.fftpack. Do đó, trong lý thuyết về các phép biến đổi Fourier rời rạc:
- tín hiệu nên được đánh giá vào những ngày
t=0,T,...,(N-1)*T
mà T là chu kỳ lấy mẫu và tổng thời lượng của tín hiệu là tmax=N*T
. Lưu ý rằng chúng tôi dừng lại ở tmax-T
.
- các tần số liên quan là
f=0,df,...,(N-1)*df
nơi df=1/tmax=1/(N*T)
là tần số lấy mẫu. Tất cả các hài của tín hiệu phải là bội số của tần số lấy mẫu để tránh hiện tượng khuếch tán.
Trong ví dụ trên, bạn có thể thấy rằng việc sử dụng arange
thay vì linspace
enable để tránh sự khuếch tán bổ sung trong phổ tần số. Hơn nữa, việc sử dụng linspace
phiên bản này cũng dẫn đến sự bù đắp của các gai nằm ở tần số cao hơn một chút so với những gì chúng nên có như có thể thấy trong hình đầu tiên, nơi các gai nằm một chút ở bên phải của các tần số 50
và 80
.
Tôi sẽ chỉ kết luận rằng ví dụ về cách sử dụng nên được thay thế bằng mã sau (theo ý kiến của tôi ít gây hiểu lầm hơn):
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()
Đầu ra (đợt tăng đột biến thứ hai không bị khuếch tán nữa):
Tôi nghĩ rằng câu trả lời này vẫn mang lại một số giải thích bổ sung về cách áp dụng chính xác phép biến đổi Fourier rời rạc. Rõ ràng, câu trả lời của tôi quá dài và luôn có những điều cần nói thêm (chẳng hạn như @ewerlopes đã nói ngắn gọn về bí danh và có thể nói rất nhiều về windowing ) nên tôi sẽ dừng lại. Tôi nghĩ rằng điều rất quan trọng là phải hiểu sâu sắc các nguyên tắc của phép biến đổi Fourier rời rạc khi áp dụng nó bởi vì chúng ta đều biết rất nhiều người đã thêm các yếu tố ở đây và ở đó khi áp dụng nó để đạt được những gì họ muốn.