FFT ile Hızlı Kosinüs Dönüşümü


15

Hızlı Kosinüs Dönüşümünü uygulamak istiyorum. Vikipedi'de , DCT'nin FFT'ye benzer şekilde hesaplanan hızlı bir sürümü olduğunu okudum . Ben gösterdi okumaya çalıştım Makhoul * kağıt, aynı zamanda kullanılan FTPACK ve FFTW uygulamaları için scipy , ama aslında algoritmayı ayıklamak mümkün değildi. Şimdiye kadar sahip olduğum şey bu:

FFT kodu:

def fft(x):
    if x.size ==1:
        return x
    N = x.size
    x0 = my_fft(x[0:N:2])
    x1 = my_fft(x[0+1:N:2])
    k = numpy.arange(N/2)
    e = numpy.exp(-2j*numpy.pi*k/N)
    l = x0 + x1 * e
    r = x0 - x1 * e  
    return numpy.hstack([l,r])

DCT kodu:

def dct(x):
    k = 0
    N = x.size
    xk = numpy.zeros(N)
    for k in range(N):     
        for n in range(N):
            xn = x[n]
            xk[k] += xn*numpy.cos(numpy.pi/N*(n+1/2.0)*k)
    return xk 

FCT denemesi:

def my_fct(x):
    if x.size ==1:
        return x
    N = x.size
    x0 = my_fct(x[0:N:2]) # have to be set to zero?
    x1 = my_fct(x[0+1:N:2])
    k = numpy.arange(N/2)
    n = # ???
    c = numpy.cos(numpy.pi/N*(n+1/2.0)*k)
    l = x0 #???
    r = x0 #???
    return numpy.hstack([l,r])

* J. Makhoul, "Bir ve iki boyutta hızlı bir kosinüs dönüşümü," IEEE Trans. Acoust. Konuşma Sig. Proc. 28 (1), 27-34 (1980) 'de tarif edilmiştir.


2
DCT kodunuzun doğru olup olmadığını mı soruyorsunuz?
Jim Clay

Yorumlarınız için teşekkür ederim. Başlangıçta bir cümle daha ekledim. Amacım FCT'yi FFT temelinde uygulamak.
Framester

Yanıtlar:


18

Nxkarange(N)[0,1,2,...,N1]

4N FFT kullanan ve vardiyasız tip 2 DCT

Sinyal [a, b, c, d]olur

[0, a, 0, b, 0, c, 0, d, 0, d, 0, c, 0, b, 0, a].

Sonra spektrumu almak için FFT'yi alın

[A, B, C, D, 0, -D, -C, -B, -A, -B, -C, -D, 0, D, C, B]

sonra ilkinden başka her şeyi atın [A, B, C, D]ve işiniz bitti:

u = zeros(4 * N)
u[1:2*N:2] = x
u[2*N+1::2] = x[::-1]

U = fft(u)[:N]
return U.real

2N FFT yansıtılmış kullanarak Tip 2 DCT (Makhoul)

[a, b, c, d]olur [a, b, c, d, d, c, b, a]. Almak için FFT alın [A, B, C, D, 0, D*, C*, B*], sonra her şeyi atmak ama[A, B, C, D] ile çarpınejπk2NDCT'yi elde etmek için ( yarım örnek kaydırma ):

y = empty(2*N)
y[:N] = x
y[N:] = x[::-1]

Y = fft(y)[:N]

Y *= exp(-1j*pi*k/(2*N))
return Y.real

2N FFT dolgulu tip 2 DCT (Makhoul)

[a, b, c, d]olur [a, b, c, d, 0, 0, 0, 0]. Almak için FFT alın [A, B, C, D, E, D*, C*, B*], sonra her şeyi atın ama[A, B, C, D] ile çarpın2ejπk2N

y = zeros(2*N)
y[:N] = x

Y = fft(y)[:N]

Y *= 2 * exp(-1j*pi*k/(2*N))
return Y.real

N FFT (Makhoul) kullanan Tip 2 DCT

[a, b, c, d, e, f][a, c, e, f, d, b][A, B, C, D, C*, B*]2ejπk2N

v = empty_like(x)
v[:(N-1)//2+1] = x[::2]

if N % 2: # odd length
    v[(N-1)//2+1:] = x[-2::-2]
else: # even length
    v[(N-1)//2+1:] = x[::-2]

V = fft(v)

V *= 2 * exp(-1j*pi*k/(2*N))
return V.real

Makinemde, bunların hepsi kabaca aynı hızda, çünkü üretim exp(-1j*pi*k/(2*N))FFT'den daha uzun sürüyor. : D

In [99]: timeit dct2_4nfft(a)
10 loops, best of 3: 23.6 ms per loop

In [100]: timeit dct2_2nfft_1(a)
10 loops, best of 3: 20.1 ms per loop

In [101]: timeit dct2_2nfft_2(a)
10 loops, best of 3: 20.8 ms per loop

In [102]: timeit dct2_nfft(a)
100 loops, best of 3: 16.4 ms per loop

In [103]: timeit scipy.fftpack.dct(a, 2)
100 loops, best of 3: 3 ms per loop

2
Harika cevap, benim uygulama ile çok yardımcı oldu! Ek not: Sinyal uzunluğu tek ise, son yöntem olan "N FFT kullanan Tip 2 DCT" hala düzgün çalışır; son öğe orta elemana taşınır. Bu gerçeğin matematik ve kodunu doğruladım.
Nayuki

1
@Nayuki Oluşturuyor musunuz yoksa exp(-1j*pi*k/(2*N))bu adım için bir kısayol var mı?
endolith

Ben elde ediyorum exp(-1j*pi*k/(2*N))benim de kod çeyrek örnek vardiya DCT-to-DFT haritalama çalışması için gerekli olduğundan,. Sizi ne soruyor?
Nayuki

Merhaba, bu Tip III DCT için DCT-II'nin tersini hesaplamak için nasıl çalışır?
Jack H

8

x(n) giriş olduğunu )

İzin Vermek

y(n)={x(n),n=0,1,...,N1x(2N1n),n=N,N+1,...,2N1

DCT daha sonra

C(k)=Re{ejπk2NFFT{y(n)}}

2Ny(n)x(n)x(n)

İşte MATLAB'daki kod.

function C = fdct(x)
    N = length(x);
    y = zeros(1,2*N);
    y(1:N) = x;
    y(N+1:2*N) = fliplr(x);
    Y = fft(y);
    k=0:N-1;
    C = real(exp(-j.* pi.*k./(2*N)).*Y(1:N));

Düzenle:

Not: Bunun kullandığı DCT formülü:

C(k)=2Σn=0N--1x(n)marul(πk2N-(2n+1))

Toplamı ölçeklendirmenin birkaç yolu vardır, bu nedenle diğer uygulamalarla tam olarak eşleşmeyebilir. Örneğin, MATLAB şunları kullanır:

C(k)=w(k)Σn=0N--1x(n)marul(πk2N-(2n+1))

w(0)=1N-w(1 ...N--1)=2N-

Çıkışı uygun şekilde ölçekleyerek bunu hesaba katabilirsiniz.


1
y (n) 'nin 2-uzunluk değil, N-uzunluk olduğu varsayılır. 2N sinyalinden 2N FFT yerine N-uzunluk sinyalinden N-uzunluk DCT'yi hesaplayarak 4x hesaplama hızını bu şekilde elde edersiniz. fourier.eng.hmc.edu/e161/lectures/dct/node2.html www-ee.uta.edu/dip/Courses/EE5355/Discrete%20class%201.pdf
Endolit

0

Gerçek bilimsel hesaplama için bellek kullanım miktarı da önemlidir. Bu nedenle N noktası FFT benim için daha çekici. Bu sadece sinyalin Hermitian Simetrisi nedeniyle mümkündür. Makhoul referansı burada verilmiştir. Ve aslında DCT ve IDCT veya DCT10 ve DCT01 hesaplamak için algoritmaya sahiptir.
http://ieeexplore.ieee.org/abstract/document/1163351/

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.