Chuyển đổi Cosine nhanh qua FFT


15

Tôi muốn thực hiện Biến đổi Cosine nhanh. Tôi đọc trên wikipedia , rằng có một phiên bản nhanh của DCT được tính tương tự như FFT. Tôi đã cố đọc bài báo Makhoul * được trích dẫn , để triển khai FTPACK và FFTW cũng được sử dụng trong Scipy , nhưng tôi không thể trích xuất thuật toán thực sự. Đây là những gì tôi có cho đến nay:

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

Mã 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 

Thử nghiệm 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, "Một biến đổi cosin nhanh trong một và hai chiều," IEEE Trans. Âm thanh. Bài phát biểu Sig. Proc. 28 (1), 27-34 (1980).


2
Bạn đang hỏi nếu mã DCT của bạn là chính xác hay cái gì đó?
Jim Clay

Cảm ơn bạn đã bình luận của bạn. Tôi đã thêm một câu vào đầu. Mục tiêu của tôi là triển khai FCT trên cơ sở FFT.
Framester

Câu trả lời:


18

Tôi đã đọc về vấn đề này và có nhiều cách để làm điều đó, sử dụng kích thước khác nhau N. My Matlab là gỉ, vì vậy đây họ đang có trong Python ( Nlà chiều dài của tín hiệu đầu vào x, karange(N)= ):[0,1,2,...,N-1]

Loại 2 DCT sử dụng FFT 4N và không có ca

Tín hiệu [a, b, c, d]trở thành

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

Sau đó lấy FFT để lấy phổ

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

sau đó vứt bỏ mọi thứ trừ cái đầu tiên [A, B, C, D]và bạn đã hoàn thành:

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

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

Loại 2 DCT sử dụng nhân đôi FFT 2N (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

Loại 2 DCT sử dụng đệm FFT 2N (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

Loại 2 DCT bằng 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

Trên máy của tôi, tất cả đều có cùng tốc độ, vì việc tạo ra exp(-1j*pi*k/(2*N))mất nhiều thời gian hơn 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

2
Câu trả lời tuyệt vời, đã giúp tôi thực hiện rất nhiều! Lưu ý thêm: Phương pháp cuối cùng "Loại 2 DCT sử dụng N FFT" vẫn hoạt động bình thường nếu độ dài tín hiệu là số lẻ; phần tử cuối cùng di chuyển đến phần tử giữa. Tôi đã xác minh toán học và mã cho thực tế này.
Nayuki

1
@Nayuki Bạn đang tạo exp(-1j*pi*k/(2*N))hoặc có một lối tắt đến bước đó?
endolith

Tôi đang tạo exp(-1j*pi*k/(2*N)) của mình , bởi vì một sự thay đổi mẫu quý là cần thiết để làm cho ánh xạ DCT-D-DFT hoạt động. Điều gì khiến bạn hỏi?
Nayuki

Xin chào, làm thế nào điều này sẽ làm việc cho DCT Loại III, để tính toán nghịch đảo của DCT-II?
Jack H

8

x(n)

để cho

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

DCT sau đó được đưa ra bởi

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

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

Đây là mã trong 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));

Biên tập:

Lưu ý: Công thức DCT mà nó đang sử dụng là:

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

Có một số cách để nhân rộng tổng kết để nó có thể không khớp chính xác với các triển khai khác. Chẳng hạn, MATLAB sử dụng:

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

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

Bạn có thể giải thích điều này bằng cách điều chỉnh tỷ lệ đầu ra.


1
y (n) được coi là chiều dài N, không phải chiều dài 2N. Đó là cách bạn có được tốc độ tính toán 4x, bằng cách tính DCT độ dài N từ tín hiệu độ dài N thay vì FFT 2N từ tín hiệu 2N. fourier.eng.hmc.edu/e161/lectures/dct/node2.html www-ee.uta.edu/dip/Cifts/EE5355/Discittle%20 class% 201.pdf
endolith

0

Đối với máy tính khoa học thực sự, lượng sử dụng bộ nhớ cũng rất quan trọng. Do đó, FFT điểm N hấp dẫn hơn đối với tôi. Điều này chỉ có thể do Đối xứng Hermiti của tín hiệu. Makhoul tham khảo được đưa ra ở đây. Và thực sự có thuật toán để tính toán DCT và IDCT hoặc DCT10 và DCT01.
http://ieeexplore.ieee.org/abab/document/1163351/

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.