Loading [MathJax]/jax/output/CommonHTML/jax.js
본문 바로가기

푸리에 변환, 신호/푸리에 변환의 모든 것

07-1. FFT 유도

반응형

 

이 페이지에서는 DFT를 고속 계산하게 해 주는 쿨리-튜키 알고리즘을 소개한다.

쿨리-튜키 알고리즘은 분할정복(Divide and Conquer)기반 알고리즘이다.

 

분할정복은 O(N2)의 계산량을 O(NlogN)으로 만들어주는 대표적인 알고리즘 유형이다. 

N개의 데이터를 N2개씩의 데이터로 나누면서 계산해서 계산량을 줄이면서도, 원래의 결괏값이 나오도록 하는 알고리즘인데, 꽤 이해하기 힘든 알고리즘이다.

 

분할 정복 알고리즘

분할정복 알고리즘이 성립하려면, N개의 데이터를 N2씩 2개로 나눠서 계산한 후 상수 시간 안에 합쳐서, 원래 N개일 때의 계산과 동일해야 한다.  또한, 데이터가 2개일 때의 계산이 간단해야 한다.

 

분할 정복 알고리즘을 적용할 수 있는 조건

  • 조건 1: 1/2개의 데이터로 나눠서 계산 후 상수 시간 안에 합쳐서 원래 N개일 때의 계산 값으로 도출 가능
  • 조건 2: 2개의 데이터에 대해서 상수 시간 안에 계산 가능

[그림 1] 분할정복 알고리즘 적용가능 조건

N개일 때의 계산량이, N2개에 대해 각각 계산하게 되면 N22으로 줄어들게 된다. (계산식이 이렇게 될 수 있는 조건이라야 한다. ) 이렇게 분할해서 바로 계산하는 것이 아니고, 분할한 데이터에 대해서 끝에 2개의 데이터가 될 때까지 계속 분할한다. 

 

1/2로 분할한 데이터를 다시 또 각각 1/2로 분할하는 것을 계속하면, 끝내는 2개의 데이터에 대해서 계산하는 단계까지 내려갈 것이고, 이 2개의 데이터에 대해서 계산한 것을 이제는 위쪽으로 보내서 합치면서 원래 N일 때의 계산을 수행하게 된다.

 이렇게 하게 되면, 분할하는데 logN번 수행되고(2개씩 나눴으니깐), 분할한 후 합칠 때 N개에 대한 상수 시간의 계산이 소요되기에 한 레이어당 N개의 계산. 따라서 NlogN번의 계산으로 결괏값을 계산할 수 있다.

 

DFT에 대한 분할정복 알고리즘 적용

DFT 수식은 위의 분할정복 알고리즘을 적용할 수 있는 2가지 조건을 만족한다. 

 

  • 조건 1: 1/2개의 데이터로 나눠서 계산 후 상수 시간 안에 합쳐서 원래 N개일 때의 계산 값으로 도출 가능
  • 조건 2: 2개의 데이터에 대해서 상수 시간 안에 계산 가능
위 조건에 맞게끔 DFT의 식을 변형시켜 적용한 것이 쿨리-튜키 알고리즘이다.

 

DFT 식으로부터 분할정복 형태가 되도록 유도해보자.

 

먼저 길이 N인 y(n) 데이터를 2개로 나눠보자. 여기서 N은 짝수로 가정.

하나는 n이 짝수인 것, 그리고 다른 하나는 홀수로 나누면 정확하게 2개로 나눌 수 있을 것이다. (DFT 수식에 사용된 W 함수가 짝수, 홀수에 따라 구분되는 특성이 있기에 짝/홀수로 나누는 것임)

 

 

짝수로 구성된 것을 p(n), 홀수로 구성된 것을 q(n)이라 하자.

 

p(n)=y(2n),q(n)=y(2n+1),0nN21

 

이제 N개의 원소를 가진 데이터 y(n)의 DFT식을 p(n)과 q(n)을 이용해서 표현하면,

 

Y(k)=N1n=0y(n)ei2πNkn=N1n=eveny(n)ei2πNkn+N1n=oddy(n)ei2πNkn=N21n=0y(2n)ei2πNk(2n)+N21n=0y(2n+1)ei2πNk(2n+1)=N21n=0p(n)ei2πN2kn+N21n=0q(n)ei2πNk(2n)ei2πNk=N21n=0p(n)ei2πN2kn+ei2πNkN21n=0q(n)ei2πN2kn,0kn1

 

식(2)에서 유도된 제일 마지막 식을 보면,  N2개의 짝수항에 대한 DFT와, 홀수항에 대한 DFT식을 더하는 형태이다. 더 정확하게는, 짝수항 DFT와 어떤 상수값(ei2πNk)이 곱해진 홀수항 DFT의 합으로, 짝수항에 대한 DFT를 P(k), 홀수항에 대한 DFT를 Q(k)라 하면 (식 2)는 다음과 같이 쓸 수 있다.

 

Y(k)=P(k)+ei2πNkQ(k),0kN1

 

즉, N개 데이터에 대한 DFT식이, N2개의 두 DFT 식의 합으로 표현된 것으로, 분할정복의 기본 조건 형태를 만족하게끔 변형이 된 것이다.

 

식의 유도과정을 좀 더 자세히 보자.

그런데, (식 2) 및 (식 3)이 왜 계산량을 적게 하는지, 그리고 왜 이렇게 나눈 것이 의미가 있는 걸까?

 

(식 3)에서 Wk=ei2πNk로 놓고, k=0에서부터 하나씩 써보자.

 

Y(0)=P(0)+W0Q(0)Y(1)=P(1)+W1Q(1)...Y(N1)=P(N1)+W(N1)Q(N1)

 

(식 4)에서는 총 N번의 곱셈 연산과 N번의 덧셈 연산이 일어난다. Y(0) 계산을 위해 1번씩, Y(1)을 위해 1번... 이렇게 Y(7)까지 구하려면 N번의 곱셈과 N번의 덧셈을 하면 된다.

알고리즘의 연산량을 계산할 때 N+N은 그냥 O(N)이기에 그냥 N번 연산이 일어난다고 계산하자. (P와 Q에 대해서는, 이 단계에서는 이미 계산되어 있다고 가정하는 것이다.)

 

즉, N개에 원소에 대해서 2로 나눴을 때 연산량이 N회 발생.

 

이제 P와 Q를 구하기 위해서, P와 Q를 각각 절반으로 나눠서 계산하자. P를 절반으로 나는 것을 A, B라 하고, Q를 절반으로 나는 것을 C, D라고 하면,

 

P(0)=A(0)+W0B(0)P(1)=A(1)+W1B(1)...P(N21)=A(N21)+W(N21)Q(N21)

Q(0)=C(0)+W0D(0)Q(1)=C(1)+W1D(1)...Q(N21)=C(N21)+W(N21)D(N21)

 

P와 Q를 구하기 위해서도 역시 N번의 연산이 필요.

 

이러한 과정을 원소가 2개가 될 때까지 계속하게 되고, 원소가 2개씩 남았을 때도 역시 N번의 연산 필요.

 

N에서부터 시작해서 2개씩 나눠서 최종 원소가 2개 남을 때까지 수행되는 횟수는 log2N

 

따라서, 전체 연산 횟수는 NlogN이 된다. (밑 2는 생략해서 표시)

 


(식  3)에서, DFT값의 주기성과 복소지수함수의 성질을 이용하면, 좀 더 단순화시켜서 N2logN의 횟수에 계산이 되도록 할 수 있다.

 

(식 3)에서 P(k)와 Q(k)는 각각 N2개의 원소에 대한 DFT이다. 따라서, N2 주기에 따라 같은 값을 가진다. (DFT라는 것이 N을 한 주기로 해서 계산되는 것이기에, Y(0) = Y(0+N)과 같이 N을 주기로 해서 같은 값을 가진다.)

따라서, P(k)=P(k+N2)이고, Q(k)=Q(k+N2)이다.

 

또한 복소지수함수의 성질에 의해서 ei2πN(k+N2)=ei2πNkei2πNN2=ei2πNkeiπ=ei2πNk가 된다.

(eiπ=1이다. 계산은 eiπ=cosπisinπ=1)

 

이제 (식 3)을 다음과 같이 쓸 수 있다.

Y(k)=P(k)+ei2πNkQ(k),0kN21Y(k+N2)=P(k)ei2πNkQ(k),0kN21

 

(식 4)에서 ei2πNk=Wk로 놓으면,

Y(k)=P(k)+WkQ(k),0kN21Y(k+N2)=P(k)WkQ(k),0kN21

 


(식 5)에 대해서 N=8의 경우를 예로 들어보자.

 

Y(0)=P(0)+W0Q(0)Y(1)=P(1)+W1Q(1)Y(2)=P(2)+W2Q(2)Y(3)=P(3)+W3Q(3)Y(4)=P(0)W0Q(0)Y(5)=P(1)+W1Q(1)Y(6)=P(2)+W2Q(2)Y(7)=P(3)+W3Q(3)

 

Y(0)~Y(3)까지는 (식 5)의 윗 식을, Y(4)~Y(7)까지는 (식 5)의 아랫 식을 이용한 것이다.

즉, Y(0)~Y(7)까지의 값을 4개의 P, W, Q값을 가지고 계산할 수 있는 것이다. 

 

위 식을 보면 대칭적인 규칙을 가지고 있다. 

그래프로 그려보면 그 규칙이 잘 보인다.

Y(0)=P(0)+W0Q(0)를 그래프로 표현한 것이다. 

Y(1)=P(1)+W1Q(1) 까지 넣어서 그려보자.

Y(2)Y(3)까지 그리면,

 

Y(4)=P(0)W0Q(0)로, 다시 Y(0)를 구할 때 사용했던 P(0),W0,Q(0)를 이용하면서, 덧셈이 아니라 뺄셈을 수행한다.

 이제 남은 Y(5)~Y(7)까지를 다 그려 넣으면,

 


P(0)~P(3)Q(0)~Q(3)도 동일한 과정으로 구할 수 있다. 

 

P(0)~P(3)를 구하는데 사용되는 데이터를 p(0)~p(3)라고하고, p(0)~p(3)에서 짝수항을 u, 홀수항을 v로 표현하면, 

u(0)=p(0)u(1)=p(2)v(0)=p(1)v(1)=p(3)

 

이제 P(0)~P(3)을 (식 5)에서 N=4를 넣고, uv에 대한 DFT값인 UV를 이용하여 표현하면, 

 

P(0)=U(0)+W0V(0)P(1)=U(1)+W1V(1)P(2)=U(0)W0V(0)P(3)=U(1)W1V(1) 

 

P(0)~P(3)를 구하는 것을 그래프로 그리면 다음과 같다.

 

마찬가지로 Q(0)~Q(3)에 대해도 P(0)~P(3)를 구하는 것과 유사하게 구할 수 있다.

Q(0)~Q(3)를 구하는데 사용될 데이터를 q(0)~q(3)라고 하고, 짝수항을 r, 홀수항을 s로 표현하면,

 

Q(0)=R(0)+W0S(0)Q(1)=R(1)+W1S(1)Q(2)=R(0)W0S(0)Q(3)=R(1)W1S(1)

 


이제 U,V,R,S를 구하는 것은, 각각 y(n)의 2개의 데이터를 이용해서 구하면 된다.

 

2개 데이터를 이용해서 DFT 값을 구하는 것은, 실제 DFT 식에 넣어보면 굉장히 단순한 실수연산으로 변환이 된다.

 

길이가 2인 x(n)에 대한 DFT 값 X(k)를 구하는 것을 생각해보자. DFT식은,

 

X(k)=1n=0x(n)ei2π2kn=x(0)ei2π2k0+x(1)ei2π2k1=x(0)+x(1)eiπk

 

여기서 k의 값 {0,1}을 차례로 대입해서 계산해보면,

 

k=0의 경우, X(0)=x(0)+x(1)eiπ0=x(0)+x(1)  --> e0=1이기에,

k=1의 경우, X(1)=x(0)+x(1)eiπ1=x(0)x(1)  --> eiπ=1이기에

 

정리하면, 

 

X(0)=x(0)+x(1)X(1)=x(0)x(1)

 

2개 포인트에 대한 DFT 계산은, 이처럼 두 개 값의 덧셈과 뺄셈으로 간단히 계산될 수 있다. 

 


이처럼, 8개 데이터에 대한 FFT의 최종 값 Y(k)의 계산은,

  • 3단계: Y(k) 값은, 4 포인트에 대한 FFT값인 P(k)와 Q(k)에 의해서 계산되고,
  • 2단계: P(k)와 Q(k)는, 2 포인트에 대한 FFT 값인 U(k), V(k), R(k), S(k)에 의해 계산되고,
  • 1단계: U(k), V(k), R(k), S(k)는, 원래 주어진 y(n)에 의해 계산된다.
실제 계산을 할 때 제일 아랫단에서의 y(n)에 의해 U(k), V(k), R(k), S(k)를 구하는 것이 제일 먼저 진행되기 때문에, 이 과정을 1단계로 표현한 것임

(식 5)가 FFT의 수식이고 알고리즘의 전부다.

 

식만 봐서는 어떻게 계산되는지 감이 잘 안 잡히고, 위에서 8개 포인트의 데이터에 대한 수식을 예로 들었으나, 아직 완벽하게 이해되지 않을 수 있다. 

 

실제 8개 포인트 데이터에 대한 FFT 계산을 손으로 한 단계씩 계산해보면, 어떻게 계산이 되는지 체득할 수 있을 것이다.  다음 페이지에서 그렇게 계산해볼 것이다.

 

-끝-

 이전글: 07. FFT (Fast Fourier Transform, 고속 푸리에 변환)
 다음글: 07-2. FFT 예제를 손으로 풀어보며 이해하기
 다음다음글: 07-3. 엑셀에서 FFT 계산하기 (엑셀 자체 FFT 기능)

 

반응형