Fast Cosine Transform via FFT

15

Saya ingin menerapkan Fast Cosine Transform. Saya membaca di wikipedia , bahwa ada versi cepat dari DCT yang juga dihitung untuk FFT. Saya mencoba membaca makalah yang dikutip Makhoul *, untuk implementasi FTPACK dan FFTW yang juga digunakan dalam Scipy , tetapi saya tidak dapat mengekstrak algoritma yang sebenarnya. Inilah yang saya miliki sejauh ini:

Kode FFT:

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])

Kode DCT:

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 

Uji coba FCT:

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, "Transformasi kosinus cepat dalam satu dan dua dimensi," IEEE Trans. Acoust. Pidato Sig. Proc 28 (1), 27-34 (1980).

Framester
sumber
2
Apakah Anda bertanya apakah kode DCT Anda benar atau sesuatu?
Jim Clay
Terima kasih atas komentar anda Saya menambahkan kalimat lain di awal. Tujuan saya adalah untuk mengimplementasikan FCT berdasarkan FFT.
Framester

Jawaban:

18

Saya telah membaca tentang ini dan ada beberapa cara untuk melakukannya, menggunakan ukuran yang berbeda N. saya Matlab adalah berkarat, jadi di sini mereka berada di Python ( Nadalah panjang sinyal input x, kadalah arange(N)= ):[0,1,2,...,N-1]

Tipe 2 DCT menggunakan 4N FFT dan tanpa shift

Sinyal [a, b, c, d]menjadi

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

Kemudian ambil FFT untuk mendapatkan spektrum

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

lalu buang semuanya kecuali yang pertama [A, B, C, D], dan Anda selesai:

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

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

Tipe 2 DCT menggunakan cermin 2N FFT (Makhoul)

[a, b, c, d][a, b, c, d, d, c, b, a][A, B, C, D, 0, D*, C*, B*][A, B, C, D]e-jπk2N

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

Tipe 2 DCT menggunakan bantalan 2N FFT (Makhoul)

[a, b, c, d][a, b, c, d, 0, 0, 0, 0][A, B, C, D, E, D*, C*, B*][A, B, C, D]2e-jπk2N

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

Y = fft(y)[:N]

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

Tipe 2 DCT menggunakan N FFT (Makhoul)

[a, b, c, d, e, f][a, c, e, f, d, b][A, B, C, D, C*, B*]2e-jπ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

Di mesin saya, ini semua kira-kira kecepatan yang sama, karena menghasilkan exp(-1j*pi*k/(2*N))membutuhkan waktu lebih lama daripada FFT. : 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
endolit
sumber
2
Jawaban yang bagus, banyak membantu implementasi saya! Catatan tambahan: Metode terakhir "Tipe 2 DCT menggunakan N FFT" masih berfungsi dengan baik jika panjang sinyal aneh; elemen terakhir bergerak ke elemen tengah. Saya telah memverifikasi matematika dan kode untuk fakta ini.
Nayuki
1
@Nayuki Apakah Anda menghasilkan exp(-1j*pi*k/(2*N))atau apakah ada jalan pintas ke langkah itu?
endolith
Saya menghasilkan exp(-1j*pi*k/(2*N))dalam kode saya , karena pergeseran seperempat sampel diperlukan untuk membuat pemetaan DCT-ke-DFT berfungsi. Apa yang membuatmu bertanya?
Nayuki
Hai, bagaimana ini akan bekerja untuk DCT Tipe III, untuk menghitung kebalikan dari DCT-II?
Jack H
8

x(n)

membiarkan

y(n)={x(n),n=0,1,...,N-1x(2N-1-n),n=N,N+1,...,2N-1

DCT kemudian diberikan oleh

C(k)=Re{e-jπk2NFFT{y(n)}}

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

Berikut kode di MATLAB.

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));

Edit:

Catatan: Formula DCT yang digunakan adalah:

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

Ada beberapa cara penskalaan penjumlahan sehingga mungkin tidak cocok persis dengan implementasi lainnya. Misalnya, MATLAB menggunakan:

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

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

Anda dapat menjelaskan ini dengan menskalakan output dengan benar.

Jason B
sumber
1
y (n) seharusnya panjang N, bukan panjang 2N. Begitulah cara Anda mendapatkan kecepatan komputasi 4x, dengan menghitung DCT N-length dari sinyal N-length bukannya FFT 2N dari sinyal 2N. fourier.eng.hmc.edu/e161/lectures/dct/node2.html www-ee.uta.edu/dip/Courses/EE5355/Discrete%20class%201.pdf
endolit
0

Untuk komputasi ilmiah sejati, jumlah penggunaan memori juga penting. Oleh karena itu titik N FFT lebih menarik bagi saya. Ini hanya mungkin karena Simetri Hermit dari sinyal. Referensi Makhoul diberikan di sini. Dan sebenarnya memiliki algoritma untuk menghitung DCT dan IDCT atau DCT10 dan DCT01.
http://ieeexplore.ieee.org/abstract/document/1163351/

Hasbestein
sumber