Vẽ một biến đổi Fourier nhanh trong Python


97

Tôi có quyền truy cập vào NumPy và SciPy và muốn tạo FFT đơn giản của một tập dữ liệu. Tôi có hai danh sách, một danh sách là ycác giá trị và danh sách kia là dấu thời gian cho các ygiá trị đó.

Cách đơn giản nhất để cung cấp các danh sách này vào phương pháp SciPy hoặc NumPy và vẽ biểu đồ FFT kết quả là gì?

Tôi đã tìm kiếm các ví dụ, nhưng tất cả chúng đều dựa vào việc tạo một tập hợp dữ liệu giả với một số điểm dữ liệu và tần suất nhất định, v.v. và không thực sự chỉ ra cách thực hiện chỉ với một tập dữ liệu và dấu thời gian tương ứng .

Tôi đã thử ví dụ sau:

from scipy.fftpack import fft

# Number of samplepoints
N = 600

# Sample spacing
T = 1.0 / 800.0
x = np.linspace(0.0, N*T, 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 = np.linspace(0.0, 1.0/(2.0*T), N/2)
import matplotlib.pyplot as plt
plt.plot(xf, 2.0/N * np.abs(yf[0:N/2]))
plt.grid()
plt.show()

Nhưng khi tôi thay đổi đối số của ffttập dữ liệu và vẽ biểu đồ của nó, tôi nhận được kết quả cực kỳ kỳ lạ và có vẻ như tỷ lệ tần suất có thể bị tắt. Tôi không chắc chắn.

Đây là một pastebin dữ liệu mà tôi đang cố gắng FFT

http://pastebin.com/0WhjjMkb http://pastebin.com/ksM4FvZS

Khi tôi sử dụng fft()toàn bộ mọi thứ, nó chỉ có một mức tăng đột biến lớn ở mức 0 và không có gì khác.

Đây là mã của tôi:

## Perform FFT with SciPy
signalFFT = fft(yInterp)

## Get power spectral density
signalPSD = np.abs(signalFFT) ** 2

## Get frequencies corresponding to signal PSD
fftFreq = fftfreq(len(signalPSD), spacing)

## Get positive half of frequencies
i = fftfreq>0

##
plt.figurefigsize = (8, 4));
plt.plot(fftFreq[i], 10*np.log10(signalPSD[i]));
#plt.xlim(0, 100);
plt.xlabel('Frequency [Hz]');
plt.ylabel('PSD [dB]')

Khoảng cách chỉ bằng xInterp[1]-xInterp[0].


cho chúng tôi biết bạn đã thử những gì, cách nó không thành công và các ví dụ mà bạn đang làm việc.
Paul H

tôi đã đăng ví dụ mà tôi đã thử cũng như những gì tôi nghĩ về nó, tôi nghĩ rằng tôi chỉ đang bối rối về cách lập biểu đồ đầu ra một cách chính xác.
user3123955 09/09

đó là một ví dụ tuyệt vời, nhưng vấn đề chính xác là gì? mã đó hoạt động tốt cho tôi. là cốt truyện đơn giản là không hiển thị?
Paul H

cụ thể là bạn đang sử dụng loại đối số nào (chúng tôi cần xem ít nhất một số dữ liệu của bạn)
Paul H

tôi đã thêm pastebin của trục x và y, dữ liệu x tính bằng giây và dữ liệu y chỉ là phép đọc cảm biến. Khi tôi đặt các danh sách dữ liệu vào ví dụ FFT nó chỉ có một cành lớn tại zero
user3123955

Câu trả lời:


101

Vì vậy, tôi chạy một dạng mã tương đương về mặt chức năng của bạn trong một sổ ghi chép IPython:

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack

# Number of samplepoints
N = 600
# sample spacing
T = 1.0 / 800.0
x = np.linspace(0.0, N*T, N)
y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)
yf = scipy.fftpack.fft(y)
xf = np.linspace(0.0, 1.0/(2.0*T), N/2)

fig, ax = plt.subplots()
ax.plot(xf, 2.0/N * np.abs(yf[:N//2]))
plt.show()

Tôi nhận được những gì tôi tin là đầu ra rất hợp lý.

nhập mô tả hình ảnh ở đây

Đã lâu hơn tôi quan tâm phải thừa nhận kể từ khi tôi còn học ở trường kỹ thuật khi nghĩ về xử lý tín hiệu, nhưng mức tăng đột biến ở mức 50 và 80 là chính xác những gì tôi mong đợi. Vậy vấn đề là gì?

Đáp lại dữ liệu thô và nhận xét được đăng

Vấn đề ở đây là bạn không có dữ liệu định kỳ. Bạn phải luôn kiểm tra dữ liệu mà bạn cung cấp vào bất kỳ thuật toán nào để đảm bảo rằng dữ liệu đó phù hợp.

import pandas
import matplotlib.pyplot as plt
#import seaborn
%matplotlib inline

# the OP's data
x = pandas.read_csv('http://pastebin.com/raw.php?i=ksM4FvZS', skiprows=2, header=None).values
y = pandas.read_csv('http://pastebin.com/raw.php?i=0WhjjMkb', skiprows=2, header=None).values
fig, ax = plt.subplots()
ax.plot(x, y)

nhập mô tả hình ảnh ở đây


1
Nó không phải là ví dụ sai, nó là tôi không biết làm thế nào để lấy nó và áp dụng nó vào dữ liệu của tôi.
user3123955 09/09

@ user3123955, đúng. đó là lý do tại sao chúng tôi cần xem dữ liệu của bạn và dữ liệu đó thất bại như thế nào nếu chúng tôi sẽ giúp bạn.
Paul H

tôi đã thêm pastebin
user3123955

2
@ user3123955, vậy bạn mong đợi thuật toán FFT nào sẽ làm được điều đó? bạn cần dọn dẹp dữ liệu của mình.
Paul H

6
@PaulH không nên biên độ ở tần số 50 Hzđược 1và ở tần số 80 Hzđược 0.5?
Furqan Hashim

24

Điều quan trọng về fft là nó chỉ có thể được áp dụng cho dữ liệu trong đó dấu thời gian là đồng nhất ( tức là lấy mẫu đồng nhất về thời gian, như những gì bạn đã trình bày ở trên).

Trong trường hợp lấy mẫu không đồng nhất, vui lòng sử dụng một hàm để điều chỉnh dữ liệu. Có một số hướng dẫn và chức năng để lựa chọn:

https://github.com/tiagopereira/python_tips/wiki/Scipy%3A-curve-fitting http://docs.scipy.org/doc/numpy/reference/generated/numpy.polyfit.html

Nếu điều chỉnh không phải là một tùy chọn, bạn có thể sử dụng trực tiếp một số dạng nội suy để nội suy dữ liệu thành một mẫu thống nhất:

https://docs.scipy.org/doc/scipy-0.14.0/reference/tutorial/interpolate.html

Khi bạn có các mẫu đồng phục, bạn sẽ chỉ phải lo lắng về khoảng thời gian ( t[1] - t[0]) của các mẫu của bạn. Trong trường hợp này, bạn có thể sử dụng trực tiếp các hàm fft

Y    = numpy.fft.fft(y)
freq = numpy.fft.fftfreq(len(y), t[1] - t[0])

pylab.figure()
pylab.plot( freq, numpy.abs(Y) )
pylab.figure()
pylab.plot(freq, numpy.angle(Y) )
pylab.show()

Điều này sẽ giải quyết vấn đề của bạn.


2
Tôi đã nội suy dữ liệu của mình để có khoảng cách đều, Bạn có thể cho tôi biết chính xác fftfreq làm gì không? tại sao nó cần trục x của tôi? tại sao bạn vẽ đồ thị của Y và góc? Góc có phải là pha không? Pha tương đối với cái gì? Khi tôi làm điều này với dữ liệu của mình, nó chỉ có một đỉnh khổng lồ ở 0Hz và tắt rất nhanh, nhưng tôi đang cung cấp cho nó dữ liệu không có độ chênh lệch liên tục (tôi thực hiện một dải thông lớn trên dữ liệu với các cạnh từ 0,15 Gz đến 12Hz để loại bỏ sự bù đắp không đổi, dù sao dữ liệu của tôi cũng không được lớn hơn 4 Hz vì vậy dải tần sẽ khiến tôi mất thông tin).
user3123955 09/09

2
1. fftfreqcung cấp cho bạn các thành phần tần số tương ứng với dữ liệu của bạn. Nếu bạn vẽ biểu đồ, freqbạn sẽ thấy rằng trục x không phải là một hàm liên tục tăng. Bạn sẽ phải đảm bảo rằng bạn có các thành phần tần số phù hợp trong trục x. Bạn có thể xem sách hướng dẫn: docs.scipy.org/doc/numpy/reference/generated/…
ssm

2
2. Hầu hết mọi người sẽ thích nhìn vào độ lớn và pha của fft. Thật khó để giải thích trong một câu thông tin pha sẽ cho bạn biết gì, nhưng tất cả những gì tôi có thể nói là nó có ý nghĩa khi bạn kết hợp các tín hiệu. Khi bạn kết hợp các tín hiệu có cùng tần số cùng pha, chúng sẽ khuếch đại, trong khi lệch pha 180 độ, chúng sẽ suy giảm. Điều này trở nên quan trọng khi bạn thiết kế bộ khuếch đại hoặc bất kỳ thiết bị nào có phản hồi.
ssm

2
3. Nói chung, tần số thấp nhất của bạn thực tế sẽ không có pha, và nó liên quan đến điều này. Khi tín hiệu di chuyển qua hệ thống của bạn, mọi tần số sẽ di chuyển với một vận tốc khác nhau. Đây là vận tốc pha. Biểu đồ giai đoạn cung cấp cho bạn thông tin này. Tôi không biết bạn đang làm việc với ystem gì, vì vậy không thể đưa ra câu trả lời chắc chắn cho bạn. Đối với những câu hỏi như vậy, tốt hơn là bạn nên đọc về điều khiển phản hồi, điện tử tương tự, xử lý tín hiệu kỹ thuật số, lý thuyết trường điện từ, v.v. hoặc thứ gì đó cụ thể hơn cho hệ thống của bạn.
ssm

4
4. Thay vì sử dụng của bạn dữ liệu, tại sao không bạn bắt đầu bằng cách tạo ra các tín hiệu riêng của mình: t = linspace(0, 10, 1000); ys = [ (1.0/i)*sin(i*t) for i in arange(10)]; y = reduce(lambda m, n: m+n, ys). Sau đó, vẽ đồ thị của từng ysvà tổng yvà lấy fft của từng thành phần. Bạn sẽ tự tin với lập trình của mình. Sau đó, bạn có thể đánh giá tính xác thực của kết quả của bạn. Nếu tín hiệu bạn đang cố gắng phân tích là tín hiệu đầu tiên bạn từng thực hiện thì bạn sẽ luôn cảm thấy rằng mình đang làm sai điều gì đó ...
ssm

12

Mức tăng đột biến cao mà bạn có là do phần DC (không thay đổi, tức là freq = 0) của tín hiệu. Đó là một vấn đề về quy mô. Nếu bạn muốn xem nội dung tần số không phải DC, để hình dung, bạn có thể cần vẽ đồ thị từ độ lệch 1 chứ không phải từ độ lệch 0 của FFT của tín hiệu.

Sửa đổi ví dụ được đưa ra ở trên bởi @PaulH

import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack

# Number of samplepoints
N = 600
# sample spacing
T = 1.0 / 800.0
x = np.linspace(0.0, N*T, N)
y = 10 + np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)
yf = scipy.fftpack.fft(y)
xf = np.linspace(0.0, 1.0/(2.0*T), N/2)

plt.subplot(2, 1, 1)
plt.plot(xf, 2.0/N * np.abs(yf[0:N/2]))
plt.subplot(2, 1, 2)
plt.plot(xf[1:], 2.0/N * np.abs(yf[0:N/2])[1:])

Các ô đầu ra: Ploting tín hiệu FFT với DC và sau đó khi loại bỏ nó (bỏ qua freq = 0)

Một cách khác, là trực quan hóa dữ liệu trong quy mô nhật ký:

Sử dụng:

plt.semilogy(xf, 2.0/N * np.abs(yf[0:N/2]))

Sẽ hiển thị: nhập mô tả hình ảnh ở đây


Có, nó tính bằng Hz. Trong mã, định nghĩa của xfánh xạ thùng fft với tần số.
hesham_EE

1
Đẹp! Và làm thế nào về trục y? Biên độ? Cảm ơn bạn nhiều hesham_EE
Victor Aguiar

Đúng, trục y là giá trị tuyệt đối của fft phức. Lưu ý việc sử dụngnp.abs()
hesham_EE

8

Cũng giống như một phần bổ sung cho các câu trả lời đã được đưa ra, tôi muốn chỉ ra rằng thường thì điều quan trọng là phải xem xét kích thước của các thùng cho FFT. Sẽ rất hợp lý nếu bạn kiểm tra một loạt các giá trị và chọn một giá trị phù hợp hơn với ứng dụng của bạn. Thông thường, nó có cùng độ lớn của số lượng mẫu. Điều này đã được giả định bởi hầu hết các câu trả lời được đưa ra và tạo ra kết quả tuyệt vời và hợp lý. Trong trường hợp một người muốn khám phá điều đó, đây là phiên bản mã của tôi:

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack

fig = plt.figure(figsize=[14,4])
N = 600           # Number of samplepoints
Fs = 800.0
T = 1.0 / Fs      # N_samps*T (#samples x sample period) is the sample spacing.
N_fft = 80        # Number of bins (chooses granularity)
x = np.linspace(0, N*T, N)     # the interval
y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)   # the signal

# removing the mean of the signal
mean_removed = np.ones_like(y)*np.mean(y)
y = y - mean_removed

# Compute the fft.
yf = scipy.fftpack.fft(y,n=N_fft)
xf = np.arange(0,Fs,Fs/N_fft)

##### Plot the fft #####
ax = plt.subplot(121)
pt, = ax.plot(xf,np.abs(yf), lw=2.0, c='b')
p = plt.Rectangle((Fs/2, 0), Fs/2, ax.get_ylim()[1], facecolor="grey", fill=True, alpha=0.75, hatch="/", zorder=3)
ax.add_patch(p)
ax.set_xlim((ax.get_xlim()[0],Fs))
ax.set_title('FFT', fontsize= 16, fontweight="bold")
ax.set_ylabel('FFT magnitude (power)')
ax.set_xlabel('Frequency (Hz)')
plt.legend((p,), ('mirrowed',))
ax.grid()

##### Close up on the graph of fft#######
# This is the same histogram above, but truncated at the max frequence + an offset. 
offset = 1    # just to help the visualization. Nothing important.
ax2 = fig.add_subplot(122)
ax2.plot(xf,np.abs(yf), lw=2.0, c='b')
ax2.set_xticks(xf)
ax2.set_xlim(-1,int(Fs/6)+offset)
ax2.set_title('FFT close-up', fontsize= 16, fontweight="bold")
ax2.set_ylabel('FFT magnitude (power) - log')
ax2.set_xlabel('Frequency (Hz)')
ax2.hold(True)
ax2.grid()

plt.yscale('log')

các ô đầu ra: nhập mô tả hình ảnh ở đây


6

Tôi đã xây dựng một chức năng xử lý FFT của các tín hiệu thực. Phần thưởng bổ sung trong chức năng của tôi so với các thông báo ở trên là bạn nhận được biên độ THỰC TẾ của tín hiệu. Ngoài ra, do giả định là tín hiệu thực, FFT là đối xứng nên chúng ta chỉ có thể vẽ đồ thị phía dương của trục x:

import matplotlib.pyplot as plt
import numpy as np
import warnings


def fftPlot(sig, dt=None, plot=True):
    # here it's assumes analytic signal (real signal...)- so only half of the axis is required

    if dt is None:
        dt = 1
        t = np.arange(0, sig.shape[-1])
        xLabel = 'samples'
    else:
        t = np.arange(0, sig.shape[-1]) * dt
        xLabel = 'freq [Hz]'

    if sig.shape[0] % 2 != 0:
        warnings.warn("signal prefered to be even in size, autoFixing it...")
        t = t[0:-1]
        sig = sig[0:-1]

    sigFFT = np.fft.fft(sig) / t.shape[0]  # divided by size t for coherent magnitude

    freq = np.fft.fftfreq(t.shape[0], d=dt)

    # plot analytic signal - right half of freq axis needed only...
    firstNegInd = np.argmax(freq < 0)
    freqAxisPos = freq[0:firstNegInd]
    sigFFTPos = 2 * sigFFT[0:firstNegInd]  # *2 because of magnitude of analytic signal

    if plot:
        plt.figure()
        plt.plot(freqAxisPos, np.abs(sigFFTPos))
        plt.xlabel(xLabel)
        plt.ylabel('mag')
        plt.title('Analytic FFT plot')
        plt.show()

    return sigFFTPos, freqAxisPos


if __name__ == "__main__":
    dt = 1 / 1000

    # build a signal within nyquist - the result will be the positive FFT with actual magnitude
    f0 = 200  # [Hz]
    t = np.arange(0, 1 + dt, dt)
    sig = 1 * np.sin(2 * np.pi * f0 * t) + \
        10 * np.sin(2 * np.pi * f0 / 2 * t) + \
        3 * np.sin(2 * np.pi * f0 / 4 * t) +\
        7.5 * np.sin(2 * np.pi * f0 / 5 * t)

    # res in freqs
    fftPlot(sig, dt=dt)
    # res in samples (if freqs axis is unknown)
    fftPlot(sig)

kết quả đồ thị FFT phân tích


4

Đã có những giải pháp tuyệt vời trên trang này, nhưng tất cả đều giả định rằng tập dữ liệu được lấy mẫu / phân phối đồng nhất / đồng đều. Tôi sẽ cố gắng cung cấp một ví dụ tổng quát hơn về dữ liệu được lấy mẫu ngẫu nhiên. Tôi cũng sẽ sử dụng hướng dẫn MATLAB này làm ví dụ:

Thêm các mô-đun bắt buộc:

import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack
import scipy.signal

Tạo dữ liệu mẫu:

N = 600 # number of samples
t = np.random.uniform(0.0, 1.0, N) # assuming the time start is 0.0 and time end is 1.0
S = 1.0 * np.sin(50.0 * 2 * np.pi * t) + 0.5 * np.sin(80.0 * 2 * np.pi * t) 
X = S + 0.01 * np.random.randn(N) # adding noise

Sắp xếp tập dữ liệu:

order = np.argsort(t)
ts = np.array(t)[order]
Xs = np.array(X)[order]

Lấy mẫu lại:

T = (t.max() - t.min()) / N # average period 
Fs = 1 / T # average sample rate frequency
f = Fs * np.arange(0, N // 2 + 1) / N; # resampled frequency vector
X_new, t_new = scipy.signal.resample(Xs, N, ts)

vẽ biểu đồ dữ liệu và dữ liệu được lấy mẫu lại:

plt.xlim(0, 0.1)
plt.plot(t_new, X_new, label="resampled")
plt.plot(ts, Xs, label="org")
plt.legend()
plt.ylabel("X")
plt.xlabel("t")

nhập mô tả hình ảnh ở đây

bây giờ đang tính fft:

Y = scipy.fftpack.fft(X_new)
P2 = np.abs(Y / N)
P1 = P2[0 : N // 2 + 1]
P1[1 : -2] = 2 * P1[1 : -2]

plt.ylabel("Y")
plt.xlabel("f")
plt.plot(f, P1)

nhập mô tả hình ảnh ở đây

Tái bút : Cuối cùng, tôi đã có thời gian để triển khai một thuật toán chuẩn hơn để có được biến đổi Fourier của dữ liệu được phân phối không đồng đều. Bạn có thể thấy mã, mô tả và sổ ghi chép Jupyter mẫu tại đây .


Tôi không thấy bất kỳ điều gì trong tài liệu đề xuất resamplexử lý thời gian mẫu không thống nhất. Nó chấp nhận một tham số thời gian (không được sử dụng trong ví dụ), nhưng điều đó dường như cũng giả định thời gian mẫu đồng nhất.
2699

@ user2699 , ví dụ này có thể hữu ích
Foad

@ user2699 Đã chỉnh sửa mã. sẽ đánh giá cao nếu bạn có thể xem và cho tôi biết nếu điều này là ổn ngay bây giờ.
Foad

1
'scipy.signal.resample` sử dụng phương thức FFT để lấy mẫu lại dữ liệu. Không có ý nghĩa gì nếu sử dụng nó để lấy mẫu lại dữ liệu không đồng nhất để có được FFT đồng nhất.
2699

1
Có những ưu và nhược điểm đối với tất cả các phương pháp bạn đã đưa ra (mặc dù lưu ý rằng sklearn.utils.resamplekhông thực hiện nội suy). Nếu bạn muốn thảo luận về các tùy chọn có sẵn để tìm tần số của một tín hiệu được lấy mẫu không đều, hoặc giá trị của các loại nội suy khác nhau, vui lòng bắt đầu một câu hỏi khác. Cả hai đều là những chủ đề thú vị, nhưng cũng nằm ngoài phạm vi câu trả lời về cách lập biểu đồ FFT.
user2699 16/1218

4

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ố 5080với biên độ 10.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ố 50khô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ố 80là 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ỏ:

  1. Ví dụ scipy.fftpack ban đầu.
  2. Ví dụ scipy.fftpack ban đầu với số nguyên chu kỳ tín hiệu ( tmax=1.0thay vì 0.75để tránh sự khuếch tán bị cắt ngắn).
  3. 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

# 1. Linspace
N = 600
# sample spacing
tmax = 3/4
T = tmax / N # =1.0 / 800.0
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)

# 2. Integer number of periods
tmax = 1
T = tmax / N # sample spacing
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)

# 3. Correct positionning of dates relatively to FFT theory (arange instead of linspace)
tmax = 1
T = tmax / N # sample spacing
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()
# Plotting only the left part of the spectrum to not show aliasing
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)*Tmà 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)*dfnơ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 arangethay vì linspaceenable để tránh sự khuếch tán bổ sung trong phổ tần số. Hơn nữa, việc sử dụng linspacephiê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ố 5080.

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
# Number of sample points
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.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.