Schnelle Cosinustransformation über FFT


15

Ich möchte die schnelle Kosinustransformation implementieren. Ich habe auf Wikipedia gelesen , dass es eine schnelle Version der DCT gibt, die ähnlich wie die FFT berechnet wird. Ich habe versucht, das zitierte Makhoul * -Papier für die FTPACK- und FFTW-Implementierungen zu lesen , die auch in Scipy verwendet werden , aber ich konnte den tatsächlichen Algorithmus nicht extrahieren. Das habe ich bisher:

FFT-Code:

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-Code:

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-Studie:

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, "Eine schnelle Cosinustransformation in einer und zwei Dimensionen", IEEE Trans. Akust. Speech Sig. Proc. 28 (1), 27 & ndash; 34 (1980).


2
Fragen Sie, ob Ihr DCT-Code korrekt ist?
Jim Clay

Vielen Dank für Ihre Kommentare. Ich habe am Anfang einen weiteren Satz hinzugefügt. Mein Ziel ist es, die FCT auf Basis der FFT umzusetzen.
Framester

Antworten:


18

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

Typ 2 DCT mit 4N FFT und ohne Schichten

Signal [a, b, c, d]wird

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

Nehmen Sie dann die FFT, um das Spektrum zu erhalten

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

dann wirf alles weg, bis auf das erste [A, B, C, D], und du bist fertig:

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

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

Typ 2 DCT mit gespiegelter 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

Typ 2 DCT mit 2N FFT gepolstert (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

Typ 2 DCT mit N FFT (Makhoul)

Signal [a, b, c, d, e, f]wird [a, c, e, f, d, b], dann nimm die FFT um zu bekommen [A, B, C, D, C*, B*]. Mit multiplizieren2e-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

Auf meinem Computer sind diese ungefähr gleich schnell, da das Generieren exp(-1j*pi*k/(2*N))länger dauert als die 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
Tolle Antwort, hat mir bei der Umsetzung sehr geholfen! Zusätzlicher Hinweis: Die letzte Methode "Typ 2 DCT unter Verwendung von N FFT" funktioniert immer noch ordnungsgemäß, wenn die Signallänge ungerade ist. Das letzte Element wird zum mittleren Element verschoben. Ich habe die Mathematik und den Code für diese Tatsache überprüft.
Nayuki

1
@Nayuki Erzeugst du exp(-1j*pi*k/(2*N))oder gibt es eine Verknüpfung zu diesem Schritt?
Endolith

Ich generiere exp(-1j*pi*k/(2*N))in meinem Code , weil eine Viertelstichprobenverschiebung erforderlich ist, damit das DCT-zu-DFT-Mapping funktioniert. Warum fragst du?
Nayuki

Hallo, wie würde das für den Typ III DCT funktionieren, um die Inverse des DCT-II zu berechnen?
Jack H

8

x(n)

Lassen

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

Die DCT wird dann von gegeben

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

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

Hier ist der Code in 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));

Bearbeiten:

Hinweis: Die verwendete DCT-Formel lautet:

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

Es gibt verschiedene Möglichkeiten, die Summe zu skalieren, sodass sie möglicherweise nicht genau mit anderen Implementierungen übereinstimmt. Zum Beispiel verwendet MATLAB:

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

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

Sie können dies berücksichtigen, indem Sie die Ausgabe richtig skalieren.


1
y (n) soll N-Länge sein, nicht 2N-Länge. Auf diese Weise erhalten Sie die 4-fache Rechengeschwindigkeit, indem Sie die DCT mit N-Länge aus dem Signal mit N-Länge anstelle der 2N-FFT aus dem 2N-Signal berechnen. fourier.eng.hmc.edu/e161/lectures/dct/node2.html www-ee.uta.edu/dip/Courses/EE5355/Discrete%20class%201.pdf
endolith

0

Für echtes wissenschaftliches Rechnen ist auch der Umfang der Speichernutzung wichtig. Daher ist die N-Punkt-FFT für mich attraktiver. Dies ist nur aufgrund der hermitischen Symmetrie des Signals möglich. Die Referenz Makhoul ist hier angegeben. Und tatsächlich hat der Algorithmus zur Berechnung von DCT und IDCT oder DCT10 und DCT01.
http://ieeexplore.ieee.org/abstract/document/1163351/

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.