if Depth < 2 then {производим какие-либо действия} |
FFT(d, Src, Dest) |
1/sqrt(N) * Sum(k=0.. N - 1 ; EiT(2*Pi(j*k/N)) * Src^[k]) |
unit cplx; interface type PReal = ^TReal; TReal = extended; PComplex = ^TComplex; TComplex = record r : TReal; i : TReal; end; function MakeComplex(x, y: TReal): TComplex; function Sum(x, y: TComplex) : TComplex; function Difference(x, y: TComplex) : TComplex; function Product(x, y: TComplex): TComplex; function TimesReal(x: TComplex; y: TReal): TComplex; function PlusReal(x: TComplex; y: TReal): TComplex; function EiT(t: TReal):TComplex; function ComplexToStr(x: TComplex): string; function AbsSquared(x: TComplex): TReal; implementation uses SysUtils; function MakeComplex(x, y: TReal): TComplex; begin with result do begin r:=x; i:= y; end; end; function Sum(x, y: TComplex) : TComplex; begin with result do begin r:= x.r + y.r; i:= x.i + y.i; end; end; function Difference(x, y: TComplex) : TComplex; begin with result do begin r:= x.r - y.r; i:= x.i - y.i; end; end; function EiT(t: TReal): TComplex; begin with result do begin r:= cos(t); i:= sin(t); end; end; function Product(x, y: TComplex): TComplex; begin with result do begin r:= x.r * y.r - x.i * y.i; i:= x.r * y.i + x.i * y.r; end; end; function TimesReal(x: TComplex; y: TReal): TComplex; begin with result do begin r:= x.r * y; i:= x.i * y; end; end; function PlusReal(x: TComplex; y: TReal): TComplex; begin with result do begin r:= x.r + y; i:= x.i; end; end; function ComplexToStr(x: TComplex): string; begin result:= FloatToStr(x.r) + ' + ' + FloatToStr(x.i) + 'i'; end; function AbsSquared(x: TComplex): TReal; begin result:= x.r*x.r + x.i*x.i; end; end. |
unit cplxfft1; interface uses Cplx; type PScalar = ^TScalar; TScalar = TComplex; {Легко получаем преобразование в реальную величину} PScalars = ^TScalars; TScalars = array[0..High(integer) div SizeOf(TScalar) - 1] of TScalar; const TrigTableDepth: word = 0; TrigTable : PScalars = nil; procedure InitTrigTable(Depth: word); procedure FFT(Depth: word; Src: PScalars; Dest: PScalars); {Перед вызовом Src и Dest ТРЕБУЕТСЯ распределение (integer(1) shl Depth) * SizeOf(TScalar) байт памяти!} implementation procedure DoFFT(Depth: word; Src: PScalars; SrcSpacing: word; Dest: PScalars); {рекурсивная часть, вызываемая при готовности FFT} var j, N: integer; Temp: TScalar; Shift: word; begin if Depth = 0 then begin Dest^[0]:= Src^[0]; exit; end; N:= integer(1) shl (Depth - 1); DoFFT(Depth - 1, Src, SrcSpacing * 2, Dest); DoFFT(Depth - 1, @Src^[SrcSpacing], SrcSpacing * 2, @Dest^[N] ); Shift:= TrigTableDepth - Depth; for j:= 0 to N - 1 do begin Temp:= Product(TrigTable^[j shl Shift], Dest^[j + N]); Dest^[j + N]:= Difference(Dest^[j], Temp); Dest^[j] := Sum(Dest^[j], Temp); end; end; procedure FFT(Depth: word; Src: PScalars; Dest: PScalars); var j, N: integer; Normalizer: extended; begin N:= integer(1) shl depth; if Depth TrigTableDepth then InitTrigTable(Depth); DoFFT(Depth, Src, 1, Dest); Normalizer:= 1 / sqrt(N) ; for j:=0 to N - 1 do Dest^[j]:= TimesReal(Dest^[j], Normalizer); end; procedure InitTrigTable(Depth: word); var j, N: integer; begin N:= integer(1) shl depth; ReAllocMem(TrigTable, N * SizeOf(TScalar)); for j:=0 to N - 1 do TrigTable^[j]:= EiT(-(2*Pi)*j/N); TrigTableDepth:= Depth; end; initialization ; finalization ReAllocMem(TrigTable, 0); end. |
unit DemoForm; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; Edit1: TEdit; Label1: TLabel; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} uses cplx, cplxfft1, MMSystem; procedure TForm1.Button1Click(Sender: TObject); var j: integer; s:string; src, dest: PScalars; norm: extended; d,N,count:integer; st,et: longint; begin d:= StrToIntDef(edit1.text, -1) ; if d <1 then raise exception.Create('глубина рекурсии должны быть положительным целым числом'); N:= integer(1) shl d ; GetMem(Src, N*Sizeof(TScalar)); GetMem(Dest, N*SizeOf(TScalar)); for j:=0 to N-1 do begin src^[j]:= MakeComplex(random, random); end; begin st:= timeGetTime; FFT(d, Src, dest); et:= timeGetTime; end; Memo1.Lines.Add('N = ' + IntToStr(N)); Memo1.Lines.Add('норма ожидания: ' +#9+ FloatToStr(N*2/3)); norm:=0; for j:=0 to N-1 do norm:= norm + AbsSquared(src^[j]); Memo1.Lines.Add('Норма данных: '+#9+FloatToStr(norm)); norm:=0; for j:=0 to N-1 do norm:= norm + AbsSquared(dest^[j]); Memo1.Lines.Add('Норма FT: '+#9#9+FloatToStr(norm)); Memo1.Lines.Add('Время расчета FFT: '+#9 + inttostr(et - st) + ' мс.'); Memo1.Lines.Add(' '); FreeMem(Src); FreeMem(DEst); end; end. |
unit cplxfft2; interface type PScalar = ^TScalar; TScalar = extended; PScalars = ^TScalars; TScalars = array[0..High(integer) div SizeOf(TScalar) - 1] of TScalar; const TrigTableDepth: word = 0; CosTable : PScalars = nil; SinTable : PScalars = nil; procedure InitTrigTables(Depth: word); procedure FFT(Depth: word; SrcR, SrcI: PScalars; DestR, DestI: PScalars); {Перед вызовом Src и Dest ТРЕБУЕТСЯ распределение (integer(1) shl Depth) * SizeOf(TScalar) байт памяти!} implementation procedure DoFFT(Depth: word; SrcR, SrcI: PScalars; SrcSpacing: word; DestR, DestI: PScalars); {рекурсивная часть, вызываемая при готовности FFT} var j, N: integer; TempR, TempI: TScalar; Shift: word; c, s: extended; begin if Depth = 0 then begin DestR^[0]:= SrcR^[0]; DestI^[0]:= SrcI^[0]; exit; end; N:= integer(1) shl (Depth - 1); DoFFT(Depth - 1, SrcR, SrcI, SrcSpacing * 2, DestR, DestI); DoFFT(Depth - 1, @SrcR^[srcSpacing], @SrcI^[SrcSpacing], SrcSpacing * 2, @DestR^[N], @DestI^[N]); Shift:= TrigTableDepth - Depth; for j:= 0 to N - 1 do begin c:= CosTable^[j shl Shift]; s:= SinTable^[j shl Shift]; TempR:= c * DestR^[j + N] - s * DestI^[j + N]; TempI:= c * DestI^[j + N] + s * DestR^[j + N]; DestR^[j + N]:= DestR^[j] - TempR; DestI^[j + N]:= DestI^[j] - TempI; DestR^[j]:= DestR^[j] + TempR; DestI^[j]:= DestI^[j] + TempI; end; end; procedure FFT(Depth: word; SrcR, SrcI: PScalars; DestR, DestI: PScalars); var j, N: integer; Normalizer: extended; begin N:= integer(1) shl depth; if Depth TrigTableDepth then InitTrigTables(Depth); DoFFT(Depth, SrcR, SrcI, 1, DestR, DestI); Normalizer:= 1 / sqrt(N) ; for j:=0 to N - 1 do begin DestR^[j]:= DestR^[j] * Normalizer; DestI^[j]:= DestI^[j] * Normalizer; end; end; procedure InitTrigTables(Depth: word); var j, N: integer; begin N:= integer(1) shl depth; ReAllocMem(CosTable, N * SizeOf(TScalar)); ReAllocMem(SinTable, N * SizeOf(TScalar)); for j:=0 to N - 1 do begin CosTable^[j]:= cos(-(2*Pi)*j/N); SinTable^[j]:= sin(-(2*Pi)*j/N); end; TrigTableDepth:= Depth; end; initialization ; finalization ReAllocMem(CosTable, 0); ReAllocMem(SinTable, 0); end. |
unit demofrm; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, cplxfft2, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; Edit1: TEdit; Label1: TLabel; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} uses MMSystem; procedure TForm1.Button1Click(Sender: TObject); var SR, SI, DR, DI: PScalars; j,d,N:integer; st, et: longint; norm: extended; begin d:= StrToIntDef(edit1.text, -1) ; if d <1 then raise exception.Create('глубина рекурсии должны быть положительным целым числом'); N:= integer(1) shl d; GetMem(SR, N * SizeOf(TScalar)); GetMem(SI, N * SizeOf(TScalar)); GetMem(DR, N * SizeOf(TScalar)); GetMem(DI, N * SizeOf(TScalar)); for j:=0 to N - 1 do begin SR^[j]:=random; SI^[j]:=random; end; st:= timeGetTime; FFT(d, SR, SI, DR, DI); et:= timeGetTime; memo1.Lines.Add('N = '+inttostr(N)); memo1.Lines.Add('норма ожидания: '+#9+FloatToStr(N*2/3)); norm:=0; for j:=0 to N - 1 do norm:= norm + SR^[j]*SR^[j] + SI^[j]*SI^[j]; memo1.Lines.Add('норма данных: '+#9+FloatToStr(norm)); norm:=0; for j:=0 to N - 1 do norm:= norm + DR^[j]*DR^[j] + DI^[j]*DI^[j]; memo1.Lines.Add('норма FT: '+#9#9+FloatToStr(norm)); memo1.Lines.Add('Время расчета FFT: '+#9+inttostr(et-st)); memo1.Lines.add(''); (*for j:=0 to N - 1 do Memo1.Lines.Add(FloatToStr(SR^[j]) + ' + ' + FloatToStr(SI^[j]) + 'i'); for j:=0 to N - 1 do Memo1.Lines.Add(FloatToStr(DR^[j]) + ' + ' + FloatToStr(DI^[j]) + 'i');*) FreeMem(SR, N * SizeOf(TScalar)); FreeMem(SI, N * SizeOf(TScalar)); FreeMem(DR, N * SizeOf(TScalar)); FreeMem(DI, N * SizeOf(TScalar)); end; end. |