home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hacker Chronicles 2
/
HACKER2.BIN
/
156.TRANSFOR.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1988-05-24
|
16KB
|
439 lines
UNIT Transforms;
INTERFACE
USES
DOS,
{$IFDEF DOSCrt}
DOSCrt,
{$ELSE}
Crt,
{$ENDIF}
TextOps,
Global;
CONST
Fourward = TRUE; {Forward transform}
Inverse = FALSE; {Inverse transform}
Four = TRUE; {Fourier transform}
Hart = FALSE; {Hartley transform}
PROCEDURE Transform ( kind : BOOLEAN;
direction : BOOLEAN);
{----------------------------------------------------------------------------}
{- NOTE: Transform is currently only set up for FFT's, not for FHT's; -}
{- however, routines for both transforms are included in this file. -}
{- -}
{- kind = Four : perform fast Fourier transform -}
{- kind = Hart : perform fast Hartley transform -}
{- -}
{- direction = Fourward : forward transform from time to frequency domain -}
{- direction = Inverse : reverse transform from frequency to time domain -}
{----------------------------------------------------------------------------}
(****************************************************************************)
IMPLEMENTATION
TYPE
polar = RECORD
Mag : REAL;
Ph : REAL;
END; {RECORD}
VAR
n : INTEGER; (* n = 2*NumFreqs-1 *)
power_index : 1..MaxPower; (* Power of two of FFT *)
delta : REAL; (* delta = 1/beta *)
{----------------------------------------------------------------------------}
{- Arg = the counterclockwise angle between the positive half of the -}
{- real axis, and the ray from the origin to the complex number. -}
{- -}
{----------------------------------------------------------------------------}
FUNCTION Arg (v:polar) : REAL;
CONST
epsilon = 1e-9;
VAR
shift : REAL;
BEGIN {Arg}
IF v.Mag>=0
THEN shift:=0
ELSE IF v.Ph>=0
THEN shift:=PI
ELSE shift:=-PI;
IF (abs(v.Mag) <= epsilon)
THEN IF v.Ph>=0
THEN Arg:=+PI/2
ELSE Arg:=-PI/2
ELSE Arg:=arctan(v.Ph/v.Mag)+shift;
END; {Arg}
{----------------------------------------------------------------------------}
{- -}
{- FFT and FHT results are given as real and imaginary parts. Polarform -}
{- converts those values to magnitude and phase (radians) components. -}
{----------------------------------------------------------------------------}
PROCEDURE PolarForm;
CONST
epsilon = 1e-06; (* A tolerance. Any angle <= epsilon2 is 0. *)
VAR
i : INTEGER; (* A counter variable. *)
temp : polar; (* A temporary variable. *)
konst : REAL; (* Magnitude scale factor for transform. *)
BEGIN {PolarForm}
konst:=1/(NumPoints*delta);
FOR i:=0 TO n DO BEGIN
temp.Mag:=TempXPtr^[i];
temp.Ph :=TempYPtr^[i];
TempXPtr^[i]:=sqrt(sqr(temp.Mag)+sqr(temp.Ph))*konst;
TempYPtr^[i]:=Arg (temp);
END; {FOR}
END; {PolarForm}
{----------------------------------------------------------------------------}
{- Timer reads the DOS time; it is used to time the FFT and FHT routines. -}
{----------------------------------------------------------------------------}
FUNCTION timer : REAL;
VAR
hour,min,sec,ms : word;
BEGIN {timer}
GetTime (hour,min,sec,ms);
timer:=hour*3600 + min*60 + sec + ms/100;
END; {timer}
{----------------------------------------------------------------------------}
{- -}
{- Cooley_Tukey_FFT is modified from the FFT algorithm of Numerical -}
{- Analysis, 3rd ed. by Burden & Faires, p. 404. The algorithm is -}
{- based on the Cooley-Tukey FFT algorithm. -}
{- -}
{----------------------------------------------------------------------------}
PROCEDURE Cooley_Tukey_FFT;
TYPE
binary = 0..1;
BinaryArray = ARRAY [0..MaxPower] OF binary;
VAR
big_M : INTEGER;
big_K : INTEGER;
q : INTEGER;
L : INTEGER;
k : BinaryArray;
K2 : INTEGER;
eta : polar;
temp : polar;
i : INTEGER;
j : INTEGER;
BEGIN {Cooley_Tukey_FFT}
OutArrayX^[0]:=1;
OutArrayY^[0]:=0;
FOR i:=1 TO NumFreqs DO BEGIN
OutArrayX^[i]:=cos(i*PI/NumFreqs);
OutArrayY^[i]:=sin(i*PI/NumFreqs);
OutArrayX^[i+NumFreqs]:=-OutArrayX^[i];
OutArrayY^[i+NumFreqs]:=-OutArrayY^[i];
END; {FOR}
big_K:=0;
big_M:=NumFreqs;
q:=power_index;
FOR L:=1 TO succ(power_index) DO BEGIN
WHILE big_K < n DO BEGIN
FOR j:=1 TO big_M DO BEGIN
FOR i:=0 TO power_index DO
k[i]:=binary((big_K AND (1 shl i)) shr i);
K2:=0;
FOR i:=power_index DOWNTO q DO
K2:=K2+(k[i] shl (power_index-i+q));
eta.Mag:=TempXPtr^[big_K+big_M]*OutArrayX^[K2]
-TempYPtr^[big_K+big_M]*OutArrayY^[K2];
eta.Ph :=TempXPtr^[big_K+big_M]*OutArrayY^[K2]
+TempYPtr^[big_K+big_M]*OutArrayX^[K2];
TempXPtr^[big_K+big_M]:=TempXPtr^[big_K]-eta.Mag;
TempYPtr^[big_K+big_M]:=TempYPtr^[big_K]-eta.Ph;
TempXPtr^[big_K]:=TempXPtr^[big_K]+eta.Mag;
TempYPtr^[big_K]:=TempYPtr^[big_K]+eta.Ph;
big_K:=succ(big_K);
END; {FOR}
big_K:=big_K+big_M;
END; {WHILE}
big_K:=0;
big_M:=big_M div 2;
q:=pred(q);
END; {FOR}
WHILE big_K < n DO BEGIN
FOR i:=0 TO power_index DO
k[i]:=binary((big_K AND (1 shl i)) shr i);
j:=0;
FOR i:=0 TO power_index DO
j:=j+(k[i] shl (power_index-i));
IF j>big_K THEN BEGIN
temp.Mag:=TempXPtr^[j];
temp.Ph :=TempYPtr^[j];
TempXPtr^[j]:=TempXPtr^[big_K];
TempYPtr^[j]:=TempYPtr^[big_k];
TempXPtr^[big_K]:=temp.Mag;
TempYPtr^[big_K]:=temp.Ph;
END; {IF}
big_K:=succ(big_K);
END; {WHILE}
END; {Cooley_Tukey_FFT}
{----------------------------------------------------------------------------}
{- -}
{- Fast Hartley Transform (FHT) routine, version 1.00, -}
{- dated 22 November 1986. Appeared in BYTE magazine, April -}
{- 1988. Modified for use in program FFT on 13 April 1988. -}
{- -}
{----------------------------------------------------------------------------}
{----------------------------------------------------------------------------}
{- Start of the Hartley butterfly transform. -}
{----------------------------------------------------------------------------}
{----------------------------------------------------------------------------}
{- FOR k = 1 TO power DO -}
{- 1. Calculate the address of the retrograde index for the sine term -}
{- for the dual place algorithm, if it is required. -}
{- 2. Butterfly transform an index pair. -}
{- 3. INCrement trg_ind, j. -}
{- END - FOR -}
{----------------------------------------------------------------------------}
{----------------------------------------------------------------------------}
{- End of Hartley butterfly. The results are scaled if necessary, and -}
{- then placed back into the data array. -}
{----------------------------------------------------------------------------}
PROCEDURE fht;
TYPE
TNDoubleArray = ARRAY [1..TNArraySize,1..2] OF REAL;
TNDoubleArrayPtr = ^TNDoubleArray;
VAR
i : INTEGER;
j : INTEGER;
k : INTEGER;
trg_ind : INTEGER;
trg_inc : INTEGER;
power : INTEGER;
t_a : INTEGER;
f_a : INTEGER;
i_temp : INTEGER;
section : INTEGER;
s_start : INTEGER;
s_end : INTEGER;
cosine : REAL;
sine : REAL;
accu : TNDoubleArrayPtr;
modify : INTEGER;
{----------------------------------------------------------------------------}
{- Permutation routine. This routine reorders the data before the -}
{- butterfly transform routine is called. -}
{----------------------------------------------------------------------------}
FUNCTION permute (index : INTEGER) : INTEGER;
VAR
i : INTEGER;
j : INTEGER;
BEGIN {permute}
j:=0;
DEC (index,1);
FOR i:=1 TO power_index DO BEGIN
IF Odd (index)
THEN INC (j,SUCC(j))
ELSE INC (j,j);
index:=index div 2;
END; {FOR}
permute:=SUCC(j);
END; {permute}
{----------------------------------------------------------------------------}
{- Main program for the fast Hartley transform. -}
{----------------------------------------------------------------------------}
BEGIN {fht}
DISPOSE (OutArrayX);
DISPOSE (OutArrayY);
NEW (accu);
FillChar (accu^,SizeOf(accu^),0);
power:=1;
f_a:=1;
t_a:=2;
FOR i:=1 TO NumPoints DO
accu^[permute(i),f_a]:=TempXPtr^[i-1];
FOR i:=1 TO power_index DO BEGIN
j:=1;
section:=1;
trg_inc:=NumPoints div (power+power);
REPEAT
trg_ind:=1;
s_start:=SUCC (section*power);
s_end:=SUCC (section)*power;
FOR k:=1 TO power DO BEGIN
IF (s_start = (j+power)) OR (power < 3)
THEN modify:=j+power
ELSE modify:=s_start+s_end-(j+power)+1;
cosine:=cos(2*PI*PRED(trg_ind)/NumPoints);
sine :=sin(2*PI*PRED(trg_ind)/NumPoints);
accu^[j,t_a]:=accu^[j,f_a] +
accu^[(j+power),f_a]*cosine + accu^[modify,f_a]*sine;
accu^[(j+power),t_a]:=accu^[j,f_a] -
accu^[(j+power),f_a]*cosine - accu^[modify,f_a]*sine;
INC (trg_ind,trg_inc);
INC (j,1);
END; {FOR}
INC (j,power);
INC (section,2);
UNTIL j > NumPoints;
INC (power,power);
i_temp:=t_a;
t_a:=f_a;
f_a:=i_temp;
END; {FOR}
FOR i:=1 TO NumPoints DO TempXPtr^[i-1]:=accu^[i,f_a];
DISPOSE (accu);
NEW (OutArrayX);
NEW (OutArrayY);
END; {fht}
{----------------------------------------------------------------------------}
{- Compute the Fourier transform from the FHT algorithm. -}
{----------------------------------------------------------------------------}
PROCEDURE Get_FFT;
VAR
i : INTEGER;
BEGIN {Get_FFT}
i:=1;
WHILE i < NumPoints DO BEGIN
TempXPtr^[i]:=TempXPtr^[i]+TempXPtr^[NumPoints-PRED (i)];
TempYPtr^[i]:=TempXPtr^[i]-TempXPtr^[NumPoints-PRED (i)];
INC (i,2);
END; {FOR}
END; {Get_FFT}
{----------------------------------------------------------------------------}
{- Compute the inverse Fourier transform from the FHT algorithm. -}
{----------------------------------------------------------------------------}
PROCEDURE Get_IFT;
VAR
i : INTEGER;
BEGIN {Get_IFT}
FOR i:=1 TO NumFreqs DO BEGIN
TempXPtr^[i-1] :=0.5*(TempXPtr^[i]+TempYPtr^[i]);
TempXPtr^[NumPoints-i]:=0.5*(TempXPtr^[i]-TempYPtr^[i]);
END; {FOR}
END; {Get_IFT}
{----------------------------------------------------------------------------}
PROCEDURE Transform ( kind : BOOLEAN;
direction : BOOLEAN);
VAR
beta : REAL; (* beta = t,max - t,min *)
i : INTEGER; (* counter variable *)
j : INTEGER; (* counter variable *)
ans : char; (* Apply window? *)
StartTime : REAL; (* Time at beginning of FFT *)
EndTime : REAL; (* Time when finished FFT *)
BEGIN {Transform}
power_index:=round(ln(NumFreqs)/ln(2));
n:=PRED (NumPoints);
{--- Assign data to temporary variables, apply window if desired. ---}
IF direction = Fourward
THEN BEGIN
WriteXY ('Apply window [H/R/N]? ',StartColumn,24);
REPEAT
ans:=ReadKey;
UNTIL UpCase(ans) IN ['N',ENTER,'H','R'];
IF ans = ENTER
THEN Write ('N')
ELSE Write (ans);
FillChar (TempYPtr^,SizeOf(TempYPtr^),0);
TempXPtr^:=ampl^;
CASE UpCase(ans) OF
'H': FOR i:=0 TO n DO
TempXPtr^[i]:=ampl^[i]*0.5*(1-cos(PI*i/NumFreqs));
'R': FOR i:=0 TO n DO
TempXPtr^[i]:=ampl^[i]*0.5*(1-cos(PI*(1+i/NumPoints)));
END; {CASE}
delta:=1/(time^[n]-time^[0]);
END {THEN}
ELSE BEGIN
FOR i:=0 TO n DO BEGIN
TempXPtr^[i]:=mag^[i]*cos(phase^[i]);
TempYPtr^[i]:=mag^[i]*sin(phase^[i]);
END; {FOR}
beta:=(freq^[n]-freq^[0])/n;
delta:=1/(NumPoints*beta);
END; {ELSE}
WriteXY ('Transform in progress ...',StartColumn,24); ClrEOL;
{--- Perform transform on data. ---}
StartTime:=timer;
Cooley_Tukey_FFT;
EndTime:=timer;
GotoXY (StartColumn,22);
Write ('Transform performed in ',(EndTime-StartTime):5:1,' seconds.');
{--- Prepare output arrays. ---}
IF direction = Fourward
THEN BEGIN
PolarForm;
FOR i:=0 TO n DO
freq^[i] :=i*delta;
mag^ :=TempXPtr^;
phase^:=TempYPtr^;
END {THEN}
ELSE BEGIN
time^[0]:=0;
ampl^[0]:=TempXPtr^[0]*beta;
FOR i:=1 TO n DO BEGIN
time^[i]:=i*delta;
ampl^[i]:=TempXPtr^[n-i+1]*beta;
END; {FOR}
END; {ELSE}
END; {Transform}
(****************************************************************************)
BEGIN {Initialization}
END. {UNIT Transforms}