1. Trang chủ >
  2. Công nghệ thông tin >
  3. Đồ họa >

Tính số lượng bit cần thiết để lấy mẫu

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (898.2 KB, 120 trang )


ln 4096 = y ln2



ln 4096

= y = 12

ln 2



hàm ln gọi là loga tự nhiên (loga cơ số e):

log 2 x =



ln x

ln 2



tơng tự



log B x =



ln x log 10 x

=

ln B log 10 B



(5.9)



Trên cở sở của công thức 5.9 trên dòng lệnh thứ hai ta tính số lợng bit cần

thiết để lấy mẫu, số bít đợc làm tròn xuống bằng số nguyên gần nhất. Công thức

5.9 đợc đa vào chơng trình nh sau:

public satatic int log2(int n) {

return(int) (Math.log(n)/Math.log(2.0));

}f



dòng 5 thực hiện phép nhân vói 2:

N=1<


Lớp futils. Timer : làm chuẩn DFT

Benchmarking là một thủ thuật cho phép thực hiện phần mềm và phần cứng

nối kết với nhau. Một trong những điểm đặc biệt của Java là biên dịch một lần

nhng chạy mọi chỗ, đặc tính này cho phép các byte code đợc thực hiện trên các

"nền" khác nhau của machineJava. Thêm nữa chúng ta có máy ảo Java cho phép

thực hiện trên các phần cứng khác nhau. Sự sắp xếp này cho phép so sánh các

nền phần cứng khác nhau khi ta thi hành các byte code. Benchmarking có thể

đánh giá đợc hiệu quả của thuật toán trên cơ sở lấy thời gian làm đại lợng đo.

Một đặc tính khác nữa đáng quan tâm là thời gian thực hiện đối với hai thuật

toán trên cùng một dữ liệu thì khác nhau .



Nội dung của lớp

package futils.bench;

import java.i0.*;

public class Timer{

public Timer()

pblic void mark()

public void record()

public float elapsed()

public void report(PrintStream pstream)

public void report()

}



Cách sử dụng

Giả sử ta khai báo các biến nh sau:

Timer t1;



Khai báo một biến mới thuộc kiểu lớp Timer (ban đầu đợc thiết lập giá trị 0):

t1=new Timer();



Để đánh dấu một thời điểm tơng tự nh việc bấm đồng hồ bấm giờ.

t1.mark();



64



Để biết đợc tổng số thời gian đã trôi qua với thời điểm đã lấy làm mốc kể từ khi

phơng thức record đợc gọi lần cuối cùng.

t1.record();



Trả về thời gian đợc tính bằng giây:

t1.elapsed();



Hiển thị thời gian trôi qua, đa tới PrintScreen thông qua biến pstream:

t1.report(pstream);



Hiển thị thời gian , đa tới System.out:

t1.report();



Benchmarking

Trong phần này thực hiện tính thời gian thực hiện biến đổi DFT bằng lớp

Timer. Trong ví dụ chúng ta sử dụng một cách tính DFT và chuẩn tắc một phơng

thức. Benchmarking thực hiện biến đổi DFT với số điểm lấy mẫu là 2048 điểm

sẽ cần 55 giây nếu chạy trên máy PPC 601 100MHz và không có bộ biên dịch

JIT. Chúng ta đa ra cách tính DFT trong gói lyon.audio nằm trong lớp

AudioFrame.

public void dft(){

FFT f = new FFT();

double [] doubleData = ulc.getDoubleArray();

double [] psd;

//Time the fft

Timer t1 = new Timer();

t1.mark();

psd=f.dft(doubleData);

//Stop the timer and report.

t1.record();

System.out.println("Time to perform DFT");

t1.record();

f.grapgs();

new DoubleGraph(psd,"psd");

}



IDFT

Biến đổi IDFT là thực hiện quá trình biến đổi ngợc lại với biến đổi DFT, tín

hiệu V(f) trong miền tần số đợc chuyển sang miền thời gian theo biểu thức:



v(t ) = F



1



+



[V ( f )] = V ( f )e 2ift dt





Để giải quyết vấn đề lấy mẫu tín hiệu (theo công thức 5.1). Chúng ta phải

thực hiện biến đổi IDFT đợc tính theo công thức sau:

N

1



V k = 2 / N

e ijk



(5.10)



j=

0



Trong chơng 4 chúng ta đã biết theo công thức Euler thì : e i = cos +sin

Thay thế công thức 5.4a vào trong công thức 5.10 nhận đợc kết quả:



65



N 1



[



]



v k = cos( 2 jk / N ) + i sin( 2 jk / N ) V j

j= 0



(5.11)



Chú ý rằng phép nhân hai số phức đợc tính nh sau:

z1z2=(x1+iy1)(x2+iy2)=x1x2-y1y2+i(x1y2+y1x2)



(5.11a)



Trên cơ sở biểu thức 5.11a ta chia kết quả thành hai phần thực và ảo.

(5.11b)

(5.11c)



Real(z 1z2)=x1x2-y1y2

Imaginary(z 1z2)=x1y2+x2y1



Do chỉ quan tâm đến việc xử lý phần thực của tín hiệu do vậy không cần thiết

tính toán kết quả phần ảo trong 5.11c. Thay thế 5.11b vào trong 5.11:

N 1



[



]



real (v k ) = cos( 2jk / N ) real (V j ) sin ( 2jk / N ) imaginary (V j ) (5.12)

j =0



Tính toán chỉ với phần thực của IDFT cần thực hiện 2N phép nhân và N phép

cộng cho mỗi một chỉ số k. Hãy so sánh 5.12 và 5.5,



Vk =



1

N



N 1



( cos( 2jk / N ) i sin ( 2jk / N ) ) v

j =0



j



Đoạn chơng trình sau đây thực hiện biến đổi IDFT theo công thức 5.12

//assume that r_data and i_data are

// set. Also assume that the real

// value is to be returned

public double[] idft() {

int N= r_data.length;

double twoPiOnN = 2*Math.PI/N;

double twoPijkOn;

double v[] = new double[N];

System.out.println("Executing IDFT on "+N+" points...");

for(int k=0;k
twoPikOnN = twoPiOn*k;

for(int j =0;j
twoPijkOn = twoPikOn*j;

v[k]+ =r_data[j]*Math.cos(twoPIjkON)i_data[j]*Math.sin(twoPijkOn);

}

}

return(v);

}



Tạo dữ liệu mẫu kiểm tra DFT và IDFT

Một numeric check là phần tổ hợp của mọi lớp. Lớp FFT có một phơng thức

gọi là testDFT nhiêm vụ của lớp này là kiểm tra tính đúng đắn của phép biến đổi

DFT và IDFT. Với số lợng mẫu là 8, phơng thức sẽ kiểm tra các dữ liệu đa vào

và ra có tuân theo công thức tính hay không.

public static void testDFT() {

int N = 8;

FFT f = new FFT(N);

double v[];

double x1[] = new double[N];

for (int j=0; j
x1[j] = j;



66



// take dft

f.dft(x1);

v = f.idft();

System.out.println("j\tx1[j]\tre[j]\tim[j]\t v[j]");

for (int j=0; j < N; j++)

System.out.println(

j+"\t"+

x1[j]+"\t"+

f.r_data[j]+"\t"+

f.i_data[j]+"\t"+

v[j]);

}



5.2 FFT

FFT là một họ các thuật toán cho phép tăng tốc độ tính toán DFT:



Vk =



1

N



N 1



e



2ij / N



j =0



vj



Tính toán DFT một cách trực tiếp theo công thức cần 0(N 2) phép nhân trong

khi FFT chỉ cần 0(NlogN) phép nhân. Trong phần này chúng ta đa ra thuật toán

FFT để rút ngắn thời gian thực hiện, thuật toán FFT cơ số 2 còn gọi là thuật toán

Cooley-Tukey. Thuật toán Cooley-Tukey là một trong số các thuật toán FFT đợc

sử dụng rộng rãi nhất. Ta gọi thuật toán có số 2 bởi vì tín hiệu đợc lấy mẫu với

số lợng mẫu là lũy thừa của 2. Thuật toán FFT chia tín hiệu lấy mẫu thành hai

phần, một là tập hợp gồm các mẫu có chỉ số lẻ, hai là tập hợp các mẫu có chỉ số

chẵn. Cách làm này là theo bổ đề của Danielson-Lanczos.

Vk =



[



1

V e k +W k V 0 k

N



]



[0.. N 1]

k



Dới đây là công thức gốc của bổ đề.

Với W=e-2i/N tacó



W ik = W j .W



j ( k 1)



(5.13)



Kết hợp 5.13 cho ta kết quả:

1

Vk =

N



N 1



W



jk



Vj



(5.14)



j= 0



Phân chia vế trái của 5.14 dới dạng hai phần chỉ số chẵn và chỉ số lẻ

N / 2 1



1 N / 2 1 2 jk

Vk = W V2 j + W ( 2 j + 1) k V2 j + 1

N j= 0

j= 0





(5.15)



Công thức 5.15 là tổng của hai thành phần chẵn lẻ, ví dụ nếu j=0,1,2,3... thì

2j=0,2,4,6,8...2j+1=1,3,5,7...

Ta viết lại biểu thức 5.15 dới dạng:

N / 2 1



1 N / 2 1 2 jk

Vk = W V2 j + W 2 jk W kV2 j +1

N j=0

j=0





Do Wk không phụ thuộc vào chỉ số nên ta đa nó ra ngoài tổng.

67



N / 21



1 N / 2 1 2 jk

k

Vk = W V2 j + W W 2 jkV2 j +1

N j=0

j=0





(5.16)



Cuối cùng ta có biểu thức đợc viết gọn lại.



1

N



Vk =



V e + W k V 0

k

k













k [ 0.. N 1]



(5.17)



Từ công thức 5.17 ta nhận thấy có thể chia các mẫu tín hiệu thành các phần

có chỉ số chẵn lẻ. Bổ đề Danielson-Lanczos cho thuật toán chia tổng số mẫu

thành hai, tiếp tục hai nửa này lại đợc chia thành hai tơng ứng với chỉ số chẵn và

lẻ. Quá trình này kết thúc khi mỗi nửa chỉ còn 2 mẫu. Với cách làm này ta giảm

đợc số lợng phép tính từ 0(N2) xuống còn 0(N logN) .

Ví dụ với số lợng mẫu lấy là 8 (N=8) thuật toán chia theo bổ đề có dạng:



Hình 5.1

Cách thông thờng cho phép thực hiện thuật toán theo bổ đề là dùng lời gọi đệ

qui. Tuy nhiên chúng ta đã biết thời gian thực hiện một lời gọi đệ qui dài gấp

khoảng 6 lần một lời gọi thông thờng. Để tránh đợc nhợc điểm này chúng ta sử

dụng thuật toán đảo bít để giảm thời gian thực hiện phép biến đổi. Trên hình 5.2

là thuật toán đảo bít.

Chúng ta có thể thực hiện thuật toán đảo bít bằng chơng trình nh sau:

int bitr(int j){

int ans = 0;

for(int i=0; i< n; i++) {

ans = (ans <<1)+(j&1);

}

return ans;

}



68



Hình 5.2

Phơng thức bitr thực hiện với hai thanh ghi dịch (viết bằng chơng trình) có dạng

sau:

jn jn-1 ...



j1 j0



an an-1 .... a1 a0

Sau khi thực hiện thuật toán ta có kết quả đơn giản hơn nhờ vào tính chất

tuần hoàn của Vk : Vk+N = Vk.



Lớp FFT

Lớp FFT là một lớp có thuộc tính public nằm trong gói lyon.audio . Lớp dựa

vào các gói grapher.Graph để thực hiện các thủ tục về đồ hoạ. Gói grapher

cung cấp một giao diện đơn giản tự động thực hiện thao tác vẽ lên các đồ hình

cần thiết theo một độ chính xác xác định. Bình thờng chỉ có một phơng thức đợc

thực hiện. Graph.graph có thể đợc gọi một cách trực tiếp bởi nó là một phơng

thức tĩnh, và các phép tính toán đợc thực hiện với các mảng dữ liệu kiểu số thực

double.



Nội dung của lớp

package lyon.audio;

import java.io.*;

import java.awt.*;

import grapher.Graph;

import futils.bench.Timer;

public class FFT extends Frame {

public FFT(int N)

public FFT()

public void graphs()

public void graphs(String t)

public static double getMaxValue(double in[])

public static int log2(int n)

public static double[] arrayCopy(double [] in)

public double [] computePDS()

public double []dft(double v[])

public double [] idft()

public double [] getReal()

public double [] getImaginary()

public void forwardFFT(double in_r, double in_i[])



69



public

public

public

public

public

public

public

}



void reverseFFT(double in_r[], double in_i[])

void printArray(double[] v, String title)

void printArray(String title)

static void main(String args[])

static void timeFFT()

static void testFFT()

static void testDFT()



Cách sử dụng

Lớp FFT sử dụng các mảng dữ liệu kiểu số thực double để tính toán. Những

mảng dữ liệu này là phân biệt tách riêng nhau và đợc sử dụng trợ giúp cho các

tính toán khác trong chơng trình. Thêm nữa thuật toán Coley-tukey không giữ lại

các kết quả trung gian của lần tính trớc mà nó chỉ giữ lại kết quả của lần tính

hiện tại. Trong tất cả các tính toán của mình lớp FFT đều sử dụng số thực kiểu

double, và lớp FFT đợc sử dụng cho các mảng một chiều chứa dữ liệu âm thanh

audio.

Giả sử ta khai báo các biến nh sau:

FFT f;

int N=8;

double inputArray[];

String title = "my data title";

double in_r[];

double in_i[];



Tạo ra biến mới thuộc kiểu lớp FFT có hai mảng số thực double nằm bên

trong, mỗi mảng có độ dài N:

f = new FFT(N);



Tạo một biến mới thuộc kiểu FFT nhng không có mảng dữ liệu:

f =new FFT();



Để vẽ đồ hình của các mảng dữ liệu thực và ảo của tín hiệu:

f.graphs();



Vẽ nhng có hiển thị một tiêu đề:

f.setTitle(title);



Nhận đợc giá trị lớn nhất có trong mảng dữ liệu tín hiệu đa vào xử lí:

FFT.getMaxValue(inputArray);



Tính log của số nguyên

Int numberOfBits = FFT.log2(N);



Sao chép lại một mảng số thực kiểu double:

adouble = FFT.arrayCopy(inputArray);



Tính mật độ phổ năng lợng PDS của DFT hay FFT:

aDoubleArray = f.computePSD();



Nhận lại phần thực , phần ảo trong kết quả tính lần cuối cùng:

aDoubleArray = f.getReal();

aDoubleArray = f.getImaginary()



Lu lại IDFT của dữ liệu đã tồn tại và trả lại phần thực của kết quả:

70



aDoubleArray = f.idft();



Để lu lại FFT lần đầu trên hai mảng dữ liệu đa vào.

f.forwardFFT(in_r, in_i);



Lu kết quả IFFT vào hai mảng :

f.reverseFFT(in_r, in_i);



Hiển thị mảng dữ liệu kèm theo một dòng tiêu đề:

f.printArray(aDoubleArray, title);



Hiển thị phần thực cùng với một tiêu đề:

f.printReal(title);



Kiểm tra tính đúng đắn của các phong thức tính DFT,IDFT, FFT, IFFT:

FFT.main();



Tính thời gian cần thiết để thực hiện biến đổi FFT:

FFT.timeFFT();



Kiểm tra FFT và IFFT

Lớp FFT có một phơng thức tĩnh (static method) cho phép ta kiểm tra tính

đúng đắn của các phép biến đổi DFT, IDFT, FFT và IFFT. Phơng thức thực hiện

việc kiểm tra với 2048 mẫu tín hiệu. Để thực hiện việc kiểm tra này ta phải gọi

tới phơng thức main nh sau:

FFT.main();



Đoạn lệnh thực hiện phơng thức main có dạng:

public static void main(String args[]) {

testDFT();

testFFt();

testIFFT();

}



Kiểm tra với số lợng mẫu N=8 là một đờng nghiêng tuyến tính, chia thành

các đoạn đều nhau tăng dần tuần tự. Thời gian thực hiện biến đổi Fourier cho

2048 mẫu đợc lu trong hai mảng số thực kiểu double mỗi mảng có 2048 phần tử,

một mảng dành cho phần thực mảng còn lại dành cho phần ảo. Khi thực hiện

biến đổi với số mẫu N=8 trên màn hình ta nhận đợc kết quả sau:

Executing DFT on 8 points...

Executing IDFT on 8 points...

j



x1[j] re[j] im[j]



0



0.0



3.5



1



1.0



-0.5000000000000004



1.2071067811865475



1.0000000000000016



2



2.0



-0.5000000000000002



0.49999999999999983



2.000000000000006



3



3.0



-0.5



0.20710678118654813



4



4.0



-0.5



-4.2861222383783204E-16 3.999999999999997



5



5.0



-0.5000000000000011



-0.2071067811865488



5.000000000000001



6



6.0



-0.5000000000000019



-0.5000000000000007



6.000000000000001



0.0



v[j]

-9.992007221626409E-16



2.9999999999999973



71



Xem Thêm
Tải bản đầy đủ (.doc) (120 trang)

×