การแปลง Cosine อย่างรวดเร็วผ่าน FFT


15

ฉันต้องการใช้การแปลงโคไซน์อย่างรวดเร็ว ฉันอ่านวิกิพีเดียว่ามีรุ่น DCT ที่รวดเร็วซึ่งคำนวณได้คล้ายกับ FFT ฉันพยายามอ่านMakhoul * paper ที่อ้างถึงสำหรับการใช้งาน FTPACK และ FFTW ที่ใช้ในScipyแต่ฉันไม่สามารถแยกอัลกอริทึมจริงได้ นี่คือสิ่งที่ฉันมี:

รหัส 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])

รหัส 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 

ทดลองใช้ 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 "การแปลงโคไซน์ที่รวดเร็วในหนึ่งและสองมิติ" IEEE Trans Acoust Speech Sig พร 28 (1), 27-34 (1980)


2
คุณกำลังถามว่ารหัส DCT ของคุณถูกต้องหรือไม่?
Jim Clay

ขอบคุณสำหรับความคิดเห็นของคุณ ฉันเพิ่มประโยคอื่นในตอนแรก เป้าหมายของฉันคือการใช้ FCT บนพื้นฐานของ FFT
Framester

คำตอบ:


18

Nxkarange(N)[0,1,2,...,ยังไม่มีข้อความ-1]

พิมพ์ 2 DCT โดยใช้ 4N FFT และไม่มีกะการทำงาน

สัญญาณ[a, b, c, d]จะกลายเป็น

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

จากนั้นใช้ FFT เพื่อรับสเปกตรัม

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

จากนั้นให้ทิ้งทุกอย่างยกเว้นสิ่งแรก[A, B, C, D]และทำเสร็จแล้ว:

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

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

พิมพ์ 2 DCT โดยใช้มิร์เรอร์ 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]อี-Jπk2ยังไม่มีข้อความ

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

พิมพ์ 2 DCT โดยใช้เบาะ 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]2อี-Jπk2ยังไม่มีข้อความ

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

Y = fft(y)[:N]

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

พิมพ์ 2 DCT โดยใช้ N FFT (Makhoul)

[a, b, c, d, e, f][a, c, e, f, d, b][A, B, C, D, C*, B*]2อี-Jπk2ยังไม่มีข้อความ

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

บนเครื่องของฉันสิ่งเหล่านี้ล้วนมีความเร็วเท่ากันเนื่องจากการสร้างexp(-1j*pi*k/(2*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
คำตอบที่ดีช่วยด้วยการใช้งานของฉันมาก! หมายเหตุเพิ่มเติม: วิธีสุดท้าย "ประเภท 2 DCT โดยใช้ N FFT" ยังคงทำงานได้อย่างถูกต้องหากความยาวของสัญญาณคี่; องค์ประกอบสุดท้ายจะย้ายไปที่องค์ประกอบกลาง ฉันได้ตรวจสอบคณิตศาสตร์และรหัสสำหรับข้อเท็จจริงนี้แล้ว
Nayuki

1
@Nayuki คุณกำลังสร้างexp(-1j*pi*k/(2*N))หรือมีทางลัดไปยังขั้นตอนนั้นหรือไม่?
endolith

ฉันกำลังสร้างexp(-1j*pi*k/(2*N))ในรหัสของฉันเพราะการเปลี่ยนตัวอย่างไตรมาสจำเป็นต้องทำให้การแมป DCT-to-DFT ทำงานได้ คุณถามอะไร
Nayuki

สวัสดีวิธีนี้จะใช้งานกับ Type III DCT เพื่อคำนวณการผกผันของ DCT-II ได้อย่างไร
แจ็คเอช

8

x(n)

ปล่อย

Y(n)={x(n),n=0,1,...,ยังไม่มีข้อความ-1x(2ยังไม่มีข้อความ-1-n),n=ยังไม่มีข้อความ,ยังไม่มีข้อความ+1,...,2ยังไม่มีข้อความ-1

DCT จะได้รับจากนั้น

(k)=Rอี{อี-Jπk2ยังไม่มีข้อความFFT{Y(n)}}

2ยังไม่มีข้อความY(n)x(n)x(n)

นี่คือรหัสใน 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));

แก้ไข:

หมายเหตุ: สูตร DCT ที่ใช้คือ:

(k)=2Σn=0ยังไม่มีข้อความ-1x(n)cos(πk2ยังไม่มีข้อความ(2n+1))

มีหลายวิธีในการปรับขนาดของผลรวมดังนั้นจึงอาจไม่ตรงกับการใช้งานอื่น ๆ ตัวอย่างเช่น MATLAB ใช้:

(k)=W(k)Σn=0ยังไม่มีข้อความ-1x(n)cos(πk2ยังไม่มีข้อความ(2n+1))

W(0)=1ยังไม่มีข้อความW(1 ...ยังไม่มีข้อความ-1)=2ยังไม่มีข้อความ

คุณสามารถบัญชีเรื่องนี้ได้โดยการปรับขนาดผลลัพธ์


1
y (n) ควรจะเป็นความยาว N ไม่ใช่ความยาว 2N นั่นคือวิธีที่คุณได้รับความเร็วในการคำนวณ 4x โดยการคำนวณ DCT N- ความยาวจากสัญญาณ N ความยาวแทน 2N FFT จากสัญญาณ 2N fourier.eng.hmc.edu/e161/lectures/dct/node2.html www-ee.uta.edu/dip/Courses/EE5355/Discrete%20class%201.pdf
endolith

0

สำหรับการคำนวณทางวิทยาศาสตร์ที่แท้จริงปริมาณการใช้หน่วยความจำก็มีความสำคัญเช่นกัน ดังนั้นประเด็น N FFT จึงน่าสนใจยิ่งกว่าสำหรับฉัน สิ่งนี้เป็นไปได้เนื่องจาก Hermitian Symmetry ของสัญญาณ Makhoul อ้างอิงได้รับที่นี่ และมีอัลกอริทึมสำหรับการคำนวณ DCT และ IDCT หรือ DCT10 และ DCT01
http://ieeexplore.ieee.org/abstract/document/1163351/

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.