FFTによる高速コサイン変換


15

高速コサイン変換を実装したい。ウィキペディアで、FFTと同様に計算されるDCTの高速バージョンがあることを読みました。Scipyでも使用されているFTPACKおよびFFTWの実装について、引用されたMakhoul *の論文を読みましたが、実際のアルゴリズムを抽出できませんでした。これは私がこれまでに持っているものです:

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。アコースト。スピーチシグ。手続き 28(1)、27-34(1980)。


2
DCTコードが正しいかどうかを尋ねていますか?
ジム・クレイ

コメントしてくださってありがとうございます。最初に別の文を追加しました。私の目的は、FFTに基づいてFCTを実装することです。
フレームスター

回答:


18

Nxkarange(N)[012N1]

4N FFTを使用し、シフトを使用しないタイプ2 DCT

信号[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

2N FFTミラーリングを使用したタイプ2 DCT(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]ejπ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

2N FFTパディングを使用したタイプ2 DCT(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]2ejπ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を使用したタイプ2 DCT(Makhoul)

[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

私のマシンで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
すばらしい答え、私の実装に大いに役立ちました!追記:信号長が奇数の場合、最後の方法「N FFTを使用したタイプ2 DCT」は引き続き正常に機能します。最後の要素が中央の要素に移動します。この事実の数学とコードを検証しました。
ナユキ

1
@Nayuki生成していますexp(-1j*pi*k/(2*N))か、またはそのステップへのショートカットはありますか?
エンドリス

DCTからDFTへのマッピングを機能させるには1/4サンプルのシフトが必要なのでexp(-1j*pi*k/(2*N))コードで生成しています。何があなたに尋ねますか?
ナユキ

こんにちは、DCT-IIの逆を計算するために、これはType III DCTでどのように機能しますか?
ジャックH

8

バツn

させる

yn={バツnn=01N1バツ2N1nn=NN+12N1

DCTは次のように与えられます

Ck=Re{ejπk2NFFT{yn}}

2Nynバツnバツ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式は次のとおりです。

Ck=2n=0N1バツncosπk2N2n+1

合計をスケーリングする方法はいくつかあるため、他の実装と正確に一致しない場合があります。たとえば、MATLABは以下を使用します。

Ck=wkn=0N1バツncosπk2N2n+1

w0=1Nw1 ...N1=2N

これは、出力を適切にスケーリングすることで説明できます。


1
y(n)は、2Nの長さではなく、Nの長さであると想定されています。これは、2N信号から2N FFTを計算する代わりに、N-length信号からN-length DCTを計算することにより、4倍の計算速度を得る方法です。fourier.eng.hmc.edu/e161/lectures/dct/node2.html www-ee.uta.edu/dip/Courses/EE5355/Discrete%20class%201.pdf
endolith

0

真の科学計算では、メモリ使用量も重要です。したがって、NポイントFFTは私にとってより魅力的です。これは、信号のエルミート対称性によってのみ可能です。参照Makhoulをここに示します。そして実際には、DCTとIDCTまたはDCT10とDCT01を計算するアルゴリズムがあります。
http://ieeexplore.ieee.org/abstract/document/1163351/

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.