通过FFT快速进行余弦变换


15

我想实现快速余弦变换。我在Wikipedia上读到,有一个DCT的快速版本,其计算方法与FFT类似。我尝试阅读引用的Makhoul *论文,了解Scipy中也使用的FTPACK和FFTW实现,但是我无法提取实际的算法。这是我到目前为止所拥有的:

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。co 语音信号 程序 28(1),27-34(1980)。


2
您是在问您的DCT代码是否正确吗?
吉姆·克莱

谢谢您的意见。我在开头添加了另一句话。我的目标是在FFT的基础上实现FCT。
Framester 2012年

Answers:


18

我一直在阅读有关这一点,并有多种方式来做到这一点,使用不同大小N.我的Matlab是生疏了,所以在这里,他们是在Python(N输入信号的长度xkarange(N)= )):[01个2ñ-1个]

使用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]

然后扔掉除了first之外的所有东西[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]Ë-Ĵπķ2ñ

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填充的Type 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]2Ë-Ĵπķ2ñ

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*]2Ë-Ĵπķ2ñ

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”仍然可以正常工作;最后一个元素移到中间元素。我已经验证了这一事实的数学和代码。
纳希基(Nayuki)

1
@Nayuki您正在生成exp(-1j*pi*k/(2*N))该步骤吗?
endolith'7

我生成exp(-1j*pi*k/(2*N))在我的代码,因为四分之一样本转变是必要的,使DCT到DFT测绘工作。是什么让你问?
娜雪(Nayuki)

嗨,这对于Type III DCT如何计算DCT-II的逆数呢?
杰克H

8

Xñ

ÿñ={Xññ=01个ñ-1个X2ñ-1个-ññ=ññ+1个2ñ-1个

DCT然后由

Cķ=[RË{Ë-Ĵπķ2ñFFŤ{ÿñ}}

2ñÿñXñXñ

这是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公式是:

Cķ=2ñ=0ñ-1个Xñcosπķ2ñ2ñ+1个

有几种缩放总和的方法,因此它可能与其他实现不完全匹配。例如,MATLAB使用:

Cķ=wķñ=0ñ-1个Xñcosπķ2ñ2ñ+1个

w0=1个ñw1 ...ñ-1个=2ñ

您可以通过适当缩放输出来解决此问题。


1
y(n)应该是N长度,而不是2N长度。通过从N长度信号中计算N长度DCT而不是从2N信号中进行2N FFT,您将获得4倍的计算速度。fourier.eng.hmc.edu/e161/lectures/dct/node2.html www-ee.uta.edu/dip/Courses/EE5355/Discrete%20class%201.pdf
endolith 2013年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.