Швидка косинальна трансформація через FFT


15

Я хочу здійснити Швидку косину трансформацію. Я прочитав у Вікіпедії , що існує швидка версія DCT, яка обчислюється аналогічно FFT. Я намагався прочитати цитований папір Makhoul * для реалізації 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. Махоул, "Швидке косинусне перетворення в одному та двох вимірах", IEEE Trans. Акустично. Виступ Зиг. Зб. 28 (1), 27-34 (1980).


2
Ви питаєте, чи правильний ваш код DCT чи щось таке?
Джим Клей

Дякую за ваші коментарі. Я додав ще одне речення на початку. Моя мета - запровадити ПКТ на основі ЗВТ.
Framester

Відповіді:


18

Я читав про це , і є кілька способів зробити це, використовуючи різного розміру N. Мій Matlab іржавий, так що тут вони знаходяться в Python ( Nце довжина вхідного сигналу x, kє arange(N)= ):[0,1,2,...,N1]

DCT типу 2, використовуючи 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

DCT типу 2 з використанням дзеркального відображення 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]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

DCT типу 2 за допомогою 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]2ejπk2N

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

Y = fft(y)[:N]

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

DCT типу 2 з використанням N FFT (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
Чудова відповідь, дуже допомогла з моєю реалізацією! Додаткова примітка: Останній метод "Тип 2 DCT за допомогою N FFT" все ще працює належним чином, якщо довжина сигналу непарна; останній елемент переміщується до середнього елемента. Я перевірив математику та код цього факту.
Наюкі

1
@Nayuki Ви генеруєте exp(-1j*pi*k/(2*N))чи є ярлик до цього кроку?
ендоліт

Я генерую exp(-1j*pi*k/(2*N))свій код , тому що для зйомки DCT-DFT для роботи картографування DCT-DFT необхідний зсув четвертої вибірки. Що змушує вас запитати?
Наюкі

Привіт, як би це працювало для типу III DCT, щоб обчислити інверсію DCT-II?
Джек Н

8

х(н)

дозволяти

у(н)={х(н),н=0,1,...,N-1х(2N-1-н),н=N,N+1,...,2N-1

Тоді DCT дає

С(к)=Rе{е-jπк2NЖЖТ{у(н)}}

2Nу(н)х(н)х(н)

Ось код у 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, яку він використовує:

С(к)=2н=0N-1х(н)cos(πк2N(2н+1))

Існує кілька способів масштабування підсумків, щоб воно не відповідало точно іншим реалізаціям. Наприклад, MATLAB використовує:

С(к)=ш(к)н=0N-1х(н)cos(πк2N(2н+1))

ш(0)=1Nш(1 ...N-1)=2N

Ви можете пояснити це правильним масштабуванням результатів.


1
y (n) повинен бути N-довжиною, а не 2N-довжиною. Ось так ви отримуєте 4-кратну швидкість обчислення, обчислюючи N-довжину DCT від сигналу N-довжини замість 2N FFT від 2N-сигналу. fourier.eng.hmc.edu/e161/lectures/dct/node2.html www-ee.uta.edu/dip/Courses/EE5355/Discrete%20class%201.pdf
ендоліти

0

Для справжніх наукових обчислень важливий і обсяг використання пам'яті. Тому N точка FFT для мене більш приваблива. Це можливо лише завдяки ермітовій симетрії сигналу. Посилання Махоула наведено тут. І насправді є алгоритм обчислення DCT і IDCT або DCT10 і DCT01.
http://ieeexplore.ieee.org/abrief/document/1163351/

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.