96
l=k*kk-1 ;
for(j=k; j<N; j+=incr)
{
i=j+ip ;
Tr=xr[i]*wr[l]-xi[i]*wi[l];
Ti=xr[i]*wi[l]+xi[i]*wr[l];
xr[i]=xr[j]-Tr;
xi[i]=xi[j]-Ti;
xr[j]=xr[j]+Tr;
xi[j]=xi[j]+Ti;
}
}
}
kk>>=1;
ip<<=1;
incr<<=1;
}
}
Chú ý rằng trong chương trình 6.1 chúng ta giả thiết là dữ liệu được lưu như
dãy của các ký tự không dấu. Nếu bạn muốn xử lý trên một số dấu phẩy động bạn
cần thay đổi các câu lệnh mở và đọc dữ liệu trong file dữ liệu. Chương trình này
cũng cho phép lựa chọn FFT hoặc IFFT. Cho FFT, chương trình con "WTS( ) "
tính toán và lưu các hệ số dịch xoay trong một LUT được gọi lên vói tham số
"sign" được gán giá trị -1, ví dụ, WTS(wr,wi,N,-1) và cho IFFT,
WTS(wr,wi,N,1). Với IFFT, bạn cần chia dãy ra cho N trong chương trình gọi
hoặc là chương trình chính.
Bài tập 6.2 Kiểm tra chương trình FFT bằng cách làm lại chương trình 6.1.
Chú ý rằng trong trường hợp này bạn phải thêm các giá trị 0 để làm cho các dãy
có chiều dài 2
4
= 16 và tất nhiên là lớn hơn chiều dài dãy nhỏ nhất đòi hỏi là (6 +
5 - 1). Mối tương quan của hai dãy cho kết quả trong một tín hiệu tuần hoàn có
chu kỳ bằng 16.
6.3.2 Thuật toán phân chia tần số.
Thay vì chia dãy vào thành các vị trí chẵn và lẻ, chúng ta sẽ đưa ra một chương
trình giống như chương trình trên nhưng lần này ta bắt đầu từ dãy ra. Chương
trình này bao gồm các bước sau:
97
kn
N
N
k
nN
N
Nk
kn
N
N
k
kn
N
W
N
kfWkf
WkfWkfnF
12/
0
2/
1
2/
12/
0
)
2
()(
)()()(
Bây giờ, chia dãy F(n) thành hai dãy dựa trên giá trị chẵn và lẻ của n.
)]
2
()([)2(
2/
2/).2(
12/
0
kn
N
Nn
N
k
W
N
kfWkfnF
)]
2
()([)12(
)12(
2/
2/).12(
12/
0
nk
N
Nn
N
k
W
N
kfWkfnF
Chú ý rằng 0.1
2
njnN
N
eW
0.1
)12(
2/).12(
nj
Nn
N
eW
Vì vậy
)]
2
()([)2(
2/
12/
0
kn
N
N
k
W
N
kfkfnF
])
2
()([)12(
2/
12/
0
kn
N
k
N
N
k
WW
N
kfkfnF
Đặt f k f k f k
N
10
2
( ) ( ) ( )
f k f k f k
N
W
N
k
11
2
( ) [ ( ) ( )]
Vì vậy
.)()2(
2/
12/
0
10
kn
N
N
k
WkfnF
(6.39)
98
.)()12(
2/
12/
0
11
kn
N
N
k
WkfnF
(6.40)
Các biểu thức (6.39) và (6.40) có thể biểu diễn bằng dưới dạng biểu đồ bướm
như trong hình 6.6.
Chúng ta có thể tiếp tục chia nhỏ các tổng cho trong các biểu thức (6.39) và
(6.40), tiếp tục làm như vậy cho tới khi mỗi tổng giảm xuống chỉ còn lại một phần
tử. Giải thuật này giống như giải thuật thuật toán phân chia thời gian và để lại cho
bạn như một bài tập cho bạn. Một lưu đồ cho FFT phân chia tần số với N = 4 trình
bày trong hình 6.7. Bạn cần chú ý đến bậc của dữ liệu đầu ra là bit được đảo.
Phần mềm thực hiện thuật toán trên thì rất giống phần mềm thực hiện FFT phân
chia miền thời gian, và một chương trình C được cung cấp ở Chương trình 6.2.
Có lẽ bạn sẽ tự hỏi: nếu phân chia miền thời gian đã thực hiện được công việc
thì tại sao lại phải xem xét thêm FFT phân chia tần số. Để trả lời câu hỏi này,
chúng ta sẽ cần xem xét phần kế tiếp, FFT giảm lược.
Chương trình 6.2 “FFTDF” FFT phân chia tần số.
/****************************
* Program developed by: *
* M.A.Sid-Ahmed. *
* ver. 1.0 1992.1994 *
*****************************/
/* FFT - Decimation-in-frequency routine.*/
#define pi 3.141592654
void bit_reversal (unsigned int *, int, int);
void WTS(float *, float *, int, int) ;
void FFT(float *xr, float *xi , float, float, int,
int);
void FFT
(float *xr, float *xi, float *wr, float *wi, int m,
int N)
{
/* FFT algorithm.
Decimation-in-frequency algorithm.
Note :
1. N=2 to the power of m.
99
2. The output arrays are left in bit-reverse
order. You will need to use routine "bit-reversal" to
place them in normal ascending order.
3. The twiddle factors are assumed to be stored in
LUT's wr[j and wiEj. You will need to use routine LUT
for calculating and storing twiddle factors. */
int ip,k,kk,l,incr,iter,j,i;
float Tr,Ti,diffr,diffi;
Hình 6.7 N = 4, phân chia miền tần số FFT.
ip= (N>>1) ;
kk=1;
incr=N;
for(iter=0; iter<m; iter++)
0
1
2
3
4
5
6
7
0
2
4
6
0
2
4
6
0
4
0
4
0
4
0
4
0
0
0
0
0
0
0
0
0
8
4
12
2
10
6
14
1
9
5
13
3
11
7
15
0
8
4
12
2
10
6
14
1
9
5
13
3
11
7
15
0
4
8
12
2
6
12
14
1
5
9
13
3
7
11
15
0
2
4
6
8
10
12
14
1
3
5
7
9
11
13
15
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
n
W
8n
W
4n
W
2n
W
100
{
for(j=0; j<N; j+=incr)
{
i=i+ip;
Tr=xr[i];
Ti=xi[i];
xr[i]=xr[j]-Tr;
xi[i]=xi[j]-Ti;
xr[j]=xr[j]+Tr;
xi[j]=xi[j]+Ti;
}
for(k=1;k<ip; k++)
{
l=k*kk-1;
for(j=k; j<N; j+=incr)
{
i=j+ip;
Tr=xr[j]+xr[i];
Ti=xi[j]+xi[i];
diffr=xr[j]-xr[i];
diffi=xi[j]-xi[i];
xr[j]=Tr;
xi[j]=Ti ;
Tr=diffr*wr[1]-diffi*wi[1];
Ti=diffr*wi[1]+diffi*wr[1];
xr[i]=Tr;
xi[i]=Ti ;
}
}
kk<<=1;
ip>>=1 ;
incr>>=1;
}
}
6.3.3 FFT giảm lược
Vấn đề có thể bắt đầu từ: cho 2
M
điểm dữ liệu, chúng ta sẽ phải làm thế nào
tính toán nhanh nhất khi dùng FFT có 2
L
điểm ra với M
L? Nếu M < L, có một
số bướm sẽ bị giảm lược (xem hình 6.8). Một giải thuật dựa trên tính toán các
phần tử của bướm khi việc tính toán tất cả các phép tính là không cần thiết trong
101
trường hợp M < L gọi là giải thuật giảm lược đầu vào FFT. Trong trường hợp M
> L thuật toán gọi là thuật toán giảm lược đầu ra FFT.
Thuật toán giảm lược đầu vào FFT. Trường hợp này sẽ làm hoàn thiện hơn
thuật toán phân chia tần số. Hình 6.8 giới thiệu trường hợp M = 1 và L = 4. Từ
hình 6.8 chúng ta nhận thấy (L-M) bước đầu tiên có các phần tử bướm và L bước
cuối cùng có toàn bộ các bướm. Sơ đồ này giúp chúng ta thay đổi chương trình
6.2 thành chương trình 6.3.
Chương trình 6.3 "FFTIP.C". Giảm lược đầu vào FFT.
/****************************
* Program developed by: *
* M.A.Sid-Ahmed. *
* ver. 1.0 1992. *
* @ 1994 *
***************************/
/* FFT - input pruning routine. */
void bit_reversal(unsigned int *, int , int);
void WTS(float *, float *, int, int);
void FFTP(float *xr, float *xi, float *, float *,
int,int,int, int);
void FFTP(float *xr, float *xi, float *wr, float *wi,
int m_output, int N_output,
int m_input, int N_input )
{
/* FFT pruning algorithm.
Deimation-in-frequency algorithm.
Note:
1. Noutput=2 to the power of m_output.
N_output=Number of samples in the output sequence.
M_input=Number of samples in the input sequence.
This should also be a multiple of 2.
2. The output arrays are left in bit-reverse order.
You will need to use routine "bit-reversal" to
place them in normal ascending order.
102
3. The twiddle factors are assumed to be stored in
LUT's wr[I and wi[I. You will need to use routine LUT
for calculating and storing twiddle factors. */
int ip,k,kk,l,inc r,iter,j,i;
float Tr,Ti,diffr,diffi;
ip=N_output>>1;
kk=l ;
incr=N_output;
for(iter=0; iter<(m_output-m_input); iter++)
{
for(j=0; j<N_output; j+=incr)
{
i=i+ip ;
xr[i]=xr[j];
xi[i]=xi[j];
}
for(k=l; k<N_input; k++)
{
l =k*kk- 1 ;
for(j=k; j<N_output; j+=incr)
{
i=j+ip ;
xr[i]=xr[j]*wr[l]-xi[j]*wi[l];
xi[i]=xr[j]*wi[l]+xi[j]*wr[l];
}
}
kk<<=1;
ip>>=1;
incr>>=1;
}
0
1
0
2
4
6
8
10
12
14
1
3
5
7
9
11
13
15
0
4
8
12
2
6
10
14
1
5
9
13
3
7
11
15
0
8
4
12
2
10
6
14
1
9
5
13
3
11
7
15
0
8
4
12
2
10
6
14
1
9
5
13
3
11
7
15
W
-
n
W
-
6n
W
-
4n
W
-
2n
103
Hình 6.8 Lưu đồ thuật toán giảm lược đầu vào, N=4
for(iter=(m_output-m_input);iter<m_output;iter++)
{
for(j=0; j<N_output; j+=incr)
{
i=j+ip ;
Tr=xr [i];
Ti =xi [i] ;
xr[i]=xr[j]-Tr;
xi[i]=xi[j]-Ti;
xr[j]=xr[j]+Tr;
xi[j]=xi[j]+Ti;
}
for(k=l; k<ip; k++)
{
l=k*kk-1;
for(j=k; j<N_output; j+=incr)
{
i=j+ip;
Tr=xr[j]+xr[i];
Ti=xi[j]+xi[i];
diffr=xr[j]-xr[i];
diffi=xi[j]-xi[i];
xr[j]=Tr;
xi[j]=Ti ;
Tr=diffr*wr[l]-diffi*wi[l];
Ti=diffr*wi[l]+diffi*wr[l];
xr[i]=Tr;
xi[i]=Ti;
}
104
}
kk<<=l;
ip>>=l;
incr>>=l;
}
}
Bài tập 6.3
1.Cho dãy đầu vào :
x(k) = 1 k = 0,1,2, , 31.
x(k) = 0 các trường hợp còn lại.
Tính 1024 điểm trong phổ tần số dùng chương trình giảm lược đầu vào FFT.
2. Thêm các giá trị 0 vào dãy để làm cho chiều dài dãy thành 1024. Bây giờ
tính FFT scủa dãy dùng chương trình FFT phân chia tần số không giảm lược.
So sánh thời gian xử lý của phần 1 và 2.
Thuật toán FFT giảm lược đầu ra. Giải thuật phân chia miền thời gian thì
thích hợp cho thuật toán giảm lược đầu ra hơn là giải thuật phân chia miền tần số.
Lý do là đầu ra trong giải thuật phân chia miền thời gian không phải sắp xếp lại.
Hình 6.9 giới thiệu trường hợp với M=4 và L=1.
Hình 6.9 Lưu đồ cho giảm lược đầu ra FFT, N = 4.
0
2
4
6
8
10
12
14
1
3
5
7
9
11
13
15
0
4
8
12
2
6
10
14
1
5
9
13
3
7
11
15
0
8
4
12
2
10
6
14
1
9
5
13
3
11
7
15
0
8
4
12
2
10
6
14
1
9
5
13
3
11
7
15
0
1
W
n=0 đến 7
W
n=0 đến 3
W
n=0 đến 1
W
n=0
105
Chương trình 6.4 “FFTOP.C” Giảm lược đầu ra FFT.
/*****************************
* Program developed by: *
* M.A.Sid-Ahmed. *
* ver. 1.0 1992. *
* @ 1994 *
*****************************/
/* FFT - output pruning using Decimation-in-time
routine. */
# define pi 3.141592654
void bit_reversal(unsigned int *, int , int);
void WTS(float *, float *, int, int);
void FFTP(float *xr, float *xi, float *, float *,int,
int, int, int);
void FFTP(float *xr, float *xi, float *wr, float *wi,
int m, int N, int m_output, int N_output)
{
/* FFT output pruning algorithm using
Decimation-in-time.
Note :
1. N=number of input samples
=2 to the power m.
N-output = number of output samples =2 to the power
motput.
2. The input arrays are assumed to be rearranged in
bit-reverse order.
You will need to use routine "bit-reversal" for that
purpose.
3. The twiddle factors are assumed to be stored in
LUT's wr[] and wi[]. You will need to use routine LUT
for calculating and storing twiddle factors.*/
int ip,k,kk,l,incr,iter,j,i;
float Tr,Ti;