Triển khai phương trình Wikipedia cho DFT


10

Tôi đã viết một triển khai biến đổi phạm vi đơn giản và xem phương trình DFT trên wikipedia để tham khảo , khi tôi nhận thấy rằng tôi đang làm một cái gì đó khác biệt, và sau khi nghĩ về nó, cảm thấy rằng phiên bản wikipedia phải sai vì nghĩ rất đơn giản tín hiệu khi biến đổi phạm vi (với phương trình đó) sẽ trả về phổ không chính xác: Bởi vì phương trình chỉ bao bọc tín hiệu xung quanh mặt phẳng phức (do với ), bất kỳ tín hiệu nào là định kỳ số lần chẵn (trong khi bọc mặt phẳng phức) sẽ không có phổ như các đỉnh thông thường (trong khi đi vòng tròn đơn vị) sẽ xuất hiện trong một DFT sẽ triệt tiêu lẫn nhau (khi số chẵn của chúng xuất hiện).n/N0<n<N1

Để kiểm tra điều này tôi đã viết một số mã tạo ra hình ảnh sau đây, dường như để xác nhận suy nghĩ của tôi. nhập mô tả hình ảnh ở đây

"Thời gian sử dụng phương trình" sử dụng phương trình với vector về thời gian (vì vậy thời gian mà tại đó được lấy mẫu chẳng hạn). Nó có thể được tìm thấy trong các chức năng dưới đây.

Xf=n=0N1xn(cos(2πftn)isin(2πftn))
ttnxnft

Phương trình wikipedia, được liên kết ở trên, được sao chép ở đây để tham khảo: Nó có thể được tìm thấy trong hàm .

Xf=n=0N1xn(cos(2πfnN)isin(2πfnN))
ft2
import numpy as np
import matplotlib.pyplot as plt 
plt.style.use('ggplot')

def ft(t, s, fs):
    freq_step = fs / len(s)
    freqs = np.arange(0, fs/2 + freq_step, freq_step)
    S = []
    for freq in freqs:
        real = np.sum(s * np.cos(2*np.pi*freq * t)) 
        compl = np.sum(- s * np.sin(2*np.pi*freq * t)) 
        tmpsum = (real**2 + compl**2) ** 0.5 
        S.append(tmpsum)
    return S, freqs

def ft2(s, fs):  # Using wikipedia equation
    nump=len(s)
    freq_step = fs / nump
    freqs = np.arange(0, fs/2 + freq_step, freq_step)
    S = []
    for i, freq in enumerate(freqs):
        real = np.sum(s * np.cos(2*np.pi*freq * i/nump))
        compl = np.sum(- s * np.sin(2*np.pi*freq * i/nump))
        tmpsum = (real**2 + compl**2) ** 0.5 
        S.append(tmpsum)
    return S, freqs


def main():
    f = 5 
    fs = 100 
    t = np.linspace(0, 2, 200)
    y = np.sin(2*np.pi*f*t) + np.cos(2*np.pi*f*2*t)

    fig = plt.figure()
    ax = fig.add_subplot(311)
    ax.set_title('Signal in time domain')
    ax.set_xlabel('t')
    ax.plot(t, y)

    S, freqs = ft(t, y, fs) 

    ax = fig.add_subplot(312)
    ax.set_xticks(np.arange(0, freqs[-1], 2)) 
    ax.set_title('Time using equation')
    ax.set_xlabel('frequency')
    ax.plot(freqs, S)

    S, freqs = ft2(y, fs) 
    ax = fig.add_subplot(313)
    ax.set_title('Using Wiki equation')
    ax.set_xlabel('frequency')
    ax.set_xticks(np.arange(0, freqs[-1], 2)) 
    ax.plot(freqs, S)

    plt.tight_layout()
    plt.show()

main()

Rõ ràng là có vẻ như tôi không thể ngẫu nhiên tìm thấy một lỗi trên một trang wiki cấu hình cao như vậy. Nhưng tôi không thể thấy một sai lầm trong những gì tôi đã làm?


Để hiểu sâu hơn về ý nghĩa của DFT, tôi khuyên bạn nên đọc hai bài viết trên blog đầu tiên của tôi: "Bản chất theo cấp số nhân của Vòng tròn đơn vị phức tạp" ( dsprelated.com/showarticle/754.php ) và "Giải thích đồ họa DFT: Centroids của rễ thống nhất có trọng số "( dsprelated.com/showarticle/768.php ).
Cedron Dawg

Cảm ơn tôi sẽ xem. Tôi thực sự rất ngạc nhiên về sự chú ý này khi tất cả là do một lỗi rất ngớ ngẩn trong mã của tôi.
Nimitz14

Tôi cũng ngạc nhiên. Điều liên tục vs rời rạc là một vấn đề lớn mặc dù. Blog của tôi là tất cả về trường hợp rời rạc mà không có bất kỳ tham chiếu nào đến trường hợp liên tục khác với việc dạy trường hợp rời rạc như một phiên bản được lấy mẫu của trường hợp liên tục.
Cedron Dawg

Câu trả lời:


16

Bạn có một lỗi trong ft2. Bạn đang gia tăng i, và freqcùng nhau. Đó không phải là cách bạn muốn tổng kết của bạn làm việc. Tôi đã loay hoay với việc sửa nó, nhưng nó trở nên lộn xộn. Tôi quyết định viết lại nó từ một quan điểm riêng biệt thay vì cố gắng sử dụng thuật ngữ liên tục. Trong DFT, tỷ lệ lấy mẫu là không liên quan. Vấn đề là có bao nhiêu mẫu được sử dụng ( N). Các số bin ( k) sau đó tương ứng với tần số tính theo đơn vị chu kỳ trên mỗi khung. Tôi đã cố gắng giữ cho mã của bạn càng nguyên vẹn càng tốt để nó vẫn dễ hiểu đối với bạn. Tôi cũng tháo các vòng lặp tính toán DFT để hy vọng tiết lộ bản chất của chúng tốt hơn một chút.

Hi vọng điêu nay co ich.

Ced

nhập numpy như np
nhập matplotlib.pyplot dưới dạng plt 

def ft (t, s, fs):
    freq_step = fs / len (s)
    freqs = np.arange (0, fs / 2, freq_step)
    S = []
    cho freq trong freqs:
        thực = np.sum (s * np.cos (2 * np.pi * freq * t)) 
        phàn nàn = np.sum (- s * np.sin (2 * np.pi * freq * t)) 
        tmpsum = (thực ** 2 + phàn nàn ** 2) ** 0,5 
        S.append (tmpsum)
    trả lại S, freqs

def ft3 (s, N): # Dạng phương trình wikipedia hiệu quả hơn

    S = []

    lát = 0,0
    mảnh = 2 * np.pi / float (N) 

    cho k trong phạm vi (N / 2):

        tổng_real = 0,0    
        tổng_imag = 0,0
        góc = 0,0
        cho n trong phạm vi (N):
            sum_real + = s [n] * np.cos (góc)
            sum_imag + = -s [n] * np.sin (góc)
            góc + = lát

        lát + = mảnh
        tmpsum = (sum_real ** 2 + sum_imag ** 2) ** 0,5 
        S.append (tmpsum)

    trả lại S

def ft4 (s, N): # Sử dụng phương trình wikipedia

    S = []

    cho k trong phạm vi (N / 2):

        tổng_real = 0,0    
        tổng_imag = 0,0
        cho n trong phạm vi (N):
            sum_real + = s [n] * np.cos (2 * np.pi * k * n / float (N))
            sum_imag + = -s [n] * np.sin (2 * np.pi * k * n / float (N))

        tmpsum = (sum_real ** 2 + sum_imag ** 2) ** 0,5 
        S.append (tmpsum)

    trả lại S

def ft5 (s, N): # Rễ của Unity weighted Sum

    mảnh = 2 * np.pi / float (N) 

    root_real = np.zeros (N)
    root_imag = np.zeros (N)

    góc = 0,0
    cho r trong phạm vi (N):
        root_real [r] = np.cos (góc)
        root_imag [r] = -np.sin (góc)
        góc + = cúi

    S = []

    cho k trong phạm vi (N / 2):

        tổng_real = 0,0    
        tổng_imag = 0,0
        r = 0

        cho n trong phạm vi (N):
            sum_real + = s [n] * root_real [r]
            sum_imag + = s [n] * root_imag [r]
            r + = k
            nếu r> = N: r - = N

        tmpsum = np.sqrt (sum_real * sum_real + sum_imag * sum_imag)
        S.append (tmpsum)

    trả lại S

def chính ():

    N = 200
    fs = 100,0

    time_step = 1.0 / fs
    t = np.arange (0, N * time_step, time_step)

    f = 5,0
    y = np.sin (2 * np.pi * f * t) + np.cos (2 * np.pi * f * 2 * t)

    fig = plt.f hình ()
    ax = fig.add_subplot (311)
    ax.set_title ('Tín hiệu trong miền thời gian')
    ax.set_xlabel ('t')
    ax.plot (t, y)

    S, freqs = ft (t, y, fs) 

    ax = fig.add_subplot (312)
    ax.set_xticks (np.arange (0, freqs [-1], 2)) 
    ax.set_title ('Thời gian sử dụng phương trình')
    ax.set_xlabel ('tần số')
    ax.plot (freqs, S)

    S = ft3 (y, N) 
    ax = fig.add_subplot (313)
    ax.set_title ('Sử dụng phương trình Wiki')
    ax.set_xlabel ('tần số')
    ax.set_xticks (np.arange (0, freqs [-1], 2)) 
    in len (S), len (freqs)
    ax.plot (freqs, S)

    plt.tight_layout ()
    plt.show ()

chủ yếu()

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


btw bạn có thể đã gặp vấn đề vì mã của tôi giả sử python3;)
Nimitz14

1
@ Nimitz14, Không phải là một vấn đề lớn. Tôi đã thêm "float ()" và một loạt các ".0" trên các số. Mã của bạn chạy tốt, điều duy nhất tôi phải xóa là câu lệnh "plt.style.use ('ggplot')".
Cedron Dawg

1
@ Nimitz14, tôi quên đề cập, tôi đã thêm một thói quen ft5 vào mã tính toán trước các gốc của các giá trị thống nhất và thực sự cho thấy cách tính DFT bằng cách sử dụng cùng một gốc cho mỗi thùng.
Cedron Dawg

4

tôi sẽ không xem qua mã của bạn Trang wikipedia có vẻ ổn, nhưng đây một ví dụ điển hình về "chiến tranh định dạng" hoặc "chiến tranh ký hiệu" hoặc "chiến tranh phong cách" giữa các nhà toán học và kỹ sư điện. Một số trong đó, tôi nghĩ rằng những người toán học là đúng. Các EE nên không bao giờ chấp nhận " " cho đơn vị tưởng tượng. điều đó nói rằng, đây là một biểu hiện tốt hơn của DFT và ngược lại là:j

DFT:

X[k]=n=0N1x[n]ej2πnk/N

iDFT:

x[n]=1Nk=0N1X[k]ej2πnk/N

bởi vì các kỹ sư điện làm DSP thích sử dụng làm chuỗi các mẫu trong "thời gian" và làm chuỗi các mẫu rời rạc theo "tần số". các nhà toán học có thể thích điều này tốt hơn:x[n]X[k]

DFT:

Xk=n=0N1xnei2πnk/N

iDFT:

xn=1Nk=0N1Xkei2πnk/N

và đó là giống như trang wikipedia.

bạn có thể cần chú ý nhiều hơn đến việc sử dụng hoặc theo số mũ và cách dịch thành hoặc chống lại thuật ngữ .++sin()


3
Nếu chúng tôi sử dụng i thay vì j, chúng tôi không thể nói ELI người đàn ông ICE. ELJ người đàn ông JCE không có chiếc nhẫn tương tự. Nền văn minh sẽ bị đe dọa

1
Elijah người đàn ông nước trái cây?
robert bristow-johnson

@ user28715 Chà, tôi trong trường hợp đó hiện tại không phải là căn bậc hai của âm 1 .... youtube.com/watch?v=2yqjMiFUMlA
Peter K.

0

Tôi đã quay lại vấn đề này và thử tạo ra phiên bản rời rạc giúp mọi thứ trở nên ý nghĩa hơn:

Bằng cách nào đófktn=f(n,k,N)

fk=fsNktn=TNn

fs=NT

Vì thế

fktn=fsNkTNn=NTNkTNn=knN

Làm xong!

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.