Implementação da equação da Wikipedia para o DFT


10

Eu estava escrevendo uma implementação simples de transformação de Fourier e observei a equação DFT na wikipedia para referência , quando notei que estava fazendo algo diferente e, depois de pensar nisso, senti que a versão da wikipedia deveria estar errada, porque é muito simples pensar em uma sinal que quando Fourier transformado (com essa equação) retornará um espectro incorreto: Como a equação envolve o sinal ao redor do plano complexo apenas uma vez (devido àn/Ncom ), qualquer sinal que seja periódico um número par de vezes (ao envolver o plano complexo) não terá espectro, pois os picos comuns (ao redor do círculo unitário) que apareceriam durante uma DFT serão cancelam-se mutuamente (quando um número par deles aparecer).0 0<n<N-1

Para verificar isso, escrevi um código que produzia a seguinte imagem, que parece confirmar o que meus pensamentos. insira a descrição da imagem aqui

"Tempo usando a equação" usa a equação com um vetor de tempo (portanto, o tempo no qual foi amostrado, por exemplo). Pode ser encontrado na função abaixo.

Xf=n=0 0N-1xn(cos(2πftn)-Eupecado(2πftn))
ttnxnft

A equação da Wikipedia, vinculada acima, é copiada aqui para referência: Pode ser encontrado na função .

Xf=n=0 0N-1xn(cos(2πfnN)-Eupecado(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()

Obviamente, parece bastante improvável que eu tenha encontrado aleatoriamente um erro em uma página wiki de alto perfil. Mas não vejo erro no que fiz?


Para entender melhor o significado de uma DFT, recomendo que você leia meus dois primeiros artigos no blog: "A natureza exponencial do círculo de unidades complexas" ( dsprelated.com/showarticle/754.php ) e "Interpretação gráfica da DFT: centróides de raízes ponderadas da unidade "( dsprelated.com/showarticle/768.php ).
precisa saber é o seguinte

Obrigado, vou dar uma olhada. Sinceramente, estou muito surpreso com a atenção que isso tem quando tudo se deve a um bug muito bobo no meu código.
Nimitz14

Também estou surpreso. O contínuo vs discreto é um grande negócio embora. Meu blog é sobre o caso discreto, sem qualquer referência ao caso contínuo, que é diferente de ensinar o caso discreto como uma versão de amostra do caso contínuo.
precisa saber é o seguinte

Respostas:


16

Você tem um bug ft2. Você está incrementando ie freqjuntos. Não é assim que você deseja que sua soma funcione. Eu brinquei com consertá-lo, mas ficou confuso. Decidi reescrevê-lo de uma perspectiva discreta, em vez de tentar usar a terminologia contínua. Na DFT, a taxa de amostragem é irrelevante. O que importa é quantas amostras são usadas ( N). Os números do compartimento ( k) correspondem à frequência em unidades de ciclos por quadro. Tentei manter o código o mais intacto possível para que ele permanecesse facilmente compreensível. Também desenrolei os loops de cálculo da DFT para, esperançosamente, revelar sua natureza um pouco melhor.

Espero que isto ajude.

Ced

importar numpy como np
importar matplotlib.pyplot como plt 

def ft (t, s, fs):
    freq_step = fs / len (s)
    freqs = np.arange (0, fs / 2, freq_step)
    S = []
    para freqs em 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)
    retornar S, freqs

def ft3 (s, N): # Forma mais eficiente da equação wikipedia

    S = []

    fatia = 0,0
    sliver = 2 * np.pi / float (N) 

    para k na faixa (N / 2):

        sum_real = 0.0    
        sum_imag = 0.0
        angle = 0.0
        para n na faixa (N):
            sum_real + = s [n] * np.cos (ângulo)
            sum_imag + = -s [n] * np.sin (ângulo)
            ângulo + = fatia

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

    retornar S

def ft4 (s, N): # Usando a equação da wikipedia

    S = []

    para k na faixa (N / 2):

        sum_real = 0.0    
        sum_imag = 0.0
        para n na faixa (N):
            sum_real + = s [n] * np.cos (2 * np.pi * k * n / flutuante (N))
            sum_imag + = -s [n] * np.sin (2 * np.pi * k * n / flutuante (N))

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

    retornar S

def ft5 (s, N): # Raízes da soma ponderada da unidade

    sliver = 2 * np.pi / float (N) 

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

    angle = 0.0
    para r na faixa (N):
        root_real [r] = np.cos (ângulo)
        root_imag [r] = -np.sin (ângulo)
        ângulo + = lasca

    S = []

    para k na faixa (N / 2):

        sum_real = 0.0    
        sum_imag = 0.0
        r = 0

        para n na faixa (N):
            sum_real + = s [n] * root_real [r]
            sum_imag + = s [n] * imagem_ raiz [r]
            r + = k
            se r> = N: r - = N

        tmpsum = np.sqrt (soma_real * soma_real + soma_imag * soma_imag)
        S.append (tmpsum)

    retornar S

def main ():

    N = 200
    fs = 100,0

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

    f = 5,0
    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 ('Sinal no domínio do tempo')
    ax.set_xlabel ('t')
    ax.plot (t, y)

    S, freqs = pés (t, y, fs) 

    ax = fig.add_subplot (312)
    ax.set_xticks (np.arange (0, freqs [-1], 2)) 
    ax.set_title ('Tempo usando a equação')
    ax.set_xlabel ('frequência')
    ax.plot (freqs, S)

    S = ft3 (y, N) 
    ax = fig.add_subplot (313)
    ax.set_title ('Usando a equação do Wiki')
    ax.set_xlabel ('frequência')
    ax.set_xticks (np.arange (0, freqs [-1], 2)) 
    imprimir len (S), len (freqs)
    ax.plot (freqs, S)

    plt.tight_layout ()
    plt.show ()

a Principal()

insira a descrição da imagem aqui


btw você provavelmente estava tendo problemas porque meu código assumido python3;)
Nimitz14

1
@ Nimitz14, não é grande coisa. Eu adicionei o "float ()" e um monte de ".0" s nos números. Seu código funcionou bem, a única coisa que precisei remover foi a instrução "plt.style.use ('ggplot')".
precisa saber é o seguinte

1
@ Nimitz14, esqueci de mencionar, adicionei uma rotina ft5 ao código que pré-calcula as raízes dos valores da unidade e realmente mostra como o DFT é calculado usando as mesmas raízes para cada posição.
quer

4

Eu não vou olhar através do seu código. a página da wikipedia parece boa, mas é um bom exemplo da "guerra de formatação" ou "guerra de notação" ou "guerra de estilo" entre matemáticos e engenheiros elétricos. algumas delas, acho que as pessoas de matemática estão certas. EEs nunca deveriam ter adotado "j"para a unidade imaginária. isto dito, esta é uma expressão melhor da DFT e a inversa é:

DFT:

X[k]=n=0 0N-1x[n]e-j2πnk/N

iDFT:

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

porque engenheiros elétricos que fazem DSP gostam de usar x[n] como uma sequência de amostras em "tempo" e X[k]como a sequência de amostras discretas em "frequência". os matemáticos podem gostar mais disso:

DFT:

Xk=n=0 0N-1xne-Eu2πnk/N

iDFT:

xn=1Nk=0 0N-1XkeEu2πnk/N

e isso é o mesmo que a página da Wikipedia.

pode ser necessário prestar mais atenção ao uso de + ou - no expoente e como isso se traduz em + ou - contra o pecado() prazo.


3
Se usássemos i em vez de j, não poderíamos dizer ELI, o homem do ICE. ELJ, o homem da JCE, não tem o mesmo anel. A civilização seria ameaçada

1
Elias, o homem do suco?
22418 Robert Bristow-Johnsonson

@ user28715 Bem, eu, nesse caso, é atual e não a raiz quadrada de menos 1 .... youtube.com/watch?v=2yqjMiFUMlA
Peter K.

0

Voltei a isso e tentei derivar a versão discreta que ajudou a fazer as coisas mais sensatas:

De alguma forma fktn=f(n,k,N)

fk=fsNk e tn=TNn

fs=NT

assim

fktn=fsNkTNn=NTNkTNn=knN

Feito!

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.