home *** CD-ROM | disk | FTP | other *** search
- include? sqrt ju:sqrt ( fast and speedy integer square root)
- include? X* 4th:fft/X*.ASM ( assembler complex multiply)
-
- anew task-FFT
-
- \ FFT.JF
-
- \ This text file contains a fixed-point Fast Fourier Transform
- \ program written in JForth. To make the FFT words,
- \ two libraries were created containing complex math and vector
- \ words.
-
- \ This code was published in the Dr. Dobb's Journal special
- \ FORTH issue in 1984.
- \ Copyright (c) 1984 Joe Barnhart
-
-
-
-
- FORTH DEFINITIONS DECIMAL
-
- : 4DROP 2DROP 2DROP ;
-
- ( du< )
- ( for systems that don't have du< normally... )
-
- FORTH DEFINITIONS DECIMAL
-
- : FFT-DU<
- ROT SWAP 2DUP U<
- IF 4DROP -1
- ELSE = >R U< R> AND
- THEN ;
-
-
- : SQR
- DUP M* ;
-
- ( complex data type and operations )
-
- : COMPLEX@ 2@ ; ( addr --- x )
- : COMPLEX! 2! ; ( x addr --- )
-
- : XVARIABLE ( --- )
- CREATE CELL 2* HERE OVER ( two elements per complex no.)
- ERASE ALLOT ( initialized to zero )
- DOES> ;
-
- : XCONSTANT ( x --- )
- CREATE HERE CELL 2* 2DUP ( two elements per cmplx )
- ERASE ALLOT COMPLEX! ( save TOS into addr )
- DOES> COMPLEX@ ; ( return complex constant)
-
- ( complex stack words )
-
- : COMPLEXDUP 2DUP ; ( x --- x x )
- : XSWAP 2SWAP ; ( x1 x2 --- x2 x1 )
- : COMPLEXDROP 2DROP ; ( x --- )
- : XOVER 2OVER ; ( x1 x2 --- x1 x2 x1 )
- : X2DUP 2OVER 2OVER ; ( x1 x2 --- x1 x2 x1 x2 )
-
-
-
-
-
-
-
-
-
- ( complex add, subtract, magnitude )
-
- : X+ ROT + >R + R> ; ( x1 x2 --- x1+x2 )
- : X- ROT SWAP - >R - R> ; ( x1 x2 --- x1-x2 )
- : X2/ 2/ SWAP 2/ SWAP ; ( x --- x/2 )
- : |X|^2 DUP * SWAP DUP * SWAP + ; ( x --- s )
- : |X| |X|^2 SQRT ; ( x --- mag_x )
- : X' SWAP NEGATE SWAP ; ( x --- x_conjugate )
- : X0= 0= SWAP 0= AND ; ( x --- t/f )
-
-
-
-
-
-
-
- ( complex multiply )
-
- \ This works. Use it if the included assembler version gives you trouble.
-
- \ : X* >R X2DUP ( x1 x2 n --- x1*x2/n )
- \ ROT R@ */ ( real part = )
- \ ROT ROT R@ */ - ( re1*re2 - im1*im2 )
- \ R> SWAP >R >R ( save partial result)
- \ ROT ROT R@ */ ( re2*im1 )
- \ ROT ROT R> */ + ( + re1*im2 )
- \ R> ; ( imag real --- )
-
-
-
-
-
- \ Stack indexing is used to keep the original data available as
- \ the complex product is built. When the product is complete, the
- \ original data is popped off the stack and the product pushed
- \ onto it.
- ( more complex operations )
-
- : X*! OVER >R >R ( ^x1 ^x2 n --- x2 <-- x2*x1/n)
- COMPLEX@ ROT COMPLEX@ R> ( form x1*x2/n )
- X* R> COMPLEX! ; ( save it into x2^ )
-
- : X/ >R XSWAP XOVER ( x1 x2 n --- n*x1/x2 )
- X' R@ X* ( x1*x2' )
- XSWAP |X| DUP R@ */ ( sqr|x2| )
- SWAP OVER R@ SWAP */ ( real part )
- ROT ROT R> SWAP */ SWAP ; ( imag part )
-
-
-
-
-
- ( Vector definition )
-
- : VECTOR ( order scale word_size --- )
- CREATE ROT 2DUP , , ( store order, then wsize )
- ROT , ( then store scale )
- * DUP , ( bytes of entry storage )
- HERE OVER ERASE ( erase vector )
- ALLOT ( allot dictionary for entries)
- DOES> ; ( return address of base )
-
-
-
- \ This data structure holds a vector that contains "order"
- \ entries. Legal indicies are in the range of 1 to "order".
- \ "Scale" is used in numeric operations on entries, and the
- \ "word_size" field describes the number of bytes per entry.
- ( vector operations )
-
- : &ORDER ( vector_descriptor --- order_of_vector )
- @ ;
-
- : &ESIZE ( vec_desc --- size_of_entries )
- CELL+ @ ;
-
- : &SCALE ( vec_desc --- scale_of_vec )
- CELL 2* + @ ;
-
- : &SIZE ( vec_desc --- size_of_data_area )
- CELL DUP 2* + + @ ;
-
-
-
- ( matrix operations, cont. )
-
- : [I] ( index vec_desc --- addr_of_entry )
- DUP >R &ORDER ( save vec_desc, get entrysize)
- OVER < OVER 1 < OR ABORT" Vector bounds exceeded... [I]"
- 1- R@ &ESIZE * ( index * entrysize )
- CELL 4 * + R> + ; ( +offset to entries )
-
-
-
- \ This word calculates a storage address given a column number
- \ and a matrix descriptor. If the desired address is outside
- \ of the alloted vector storage area, an exception is gener-
- \ ated. This word is usually followed by "@" or "!". The follow-
- \ ing screen contains an equivalent definition for 68000 Forth.
-
-
-
- ( complex vector defs )
-
- : XVECTOR ( order scale --- )
- CELL 2* VECTOR ; ( declare a vector with two words/ent.)
-
- : X@V ( index vec_desc --- x )
- [I] COMPLEX@ ; ( fetch vector entry pointed by index)
-
- : X!V ( x index vec_desc --- )
- [I] COMPLEX! ; ( store into vector at position index)
-
- \ print an xvector in table form
-
- : XVECTOR.
- CR DUP @ ." NUMBER OF SAMPLES:" SPACE . CR
- CR ." REAL" CR
- DUP>R DUP @ SWAP 16 + SWAP 0 DO
- DUP I CELL 2* * + @ CELL 2* .R
- I 1+ CELL 2* MOD NOT IF CR THEN
- LOOP ." IMAGINARY" CR
- DROP R> DUP @ SWAP 20 + SWAP 0 DO
- DUP I CELL 2* * + @ CELL 2* .R
- I 1+ CELL 2* MOD NOT IF CR THEN
- LOOP
- DROP
- ;
-
-
- ( FFT constants and variables )
-
- 10000 CONSTANT 10K ( scaling constant )
- VARIABLE DIRECTION ( direction of fft )
- VARIABLE VEC ( current vector base)
- VARIABLE N ( points in fft )
- XVARIABLE U ( cmplx angle counter)
- XVARIABLE W ( cmplx angle incr)
-
-
-
-
-
-
-
-
- ( bit reversal of vector )
-
- : V[I][J] ( i j --- [i] [j] )
- VEC @ [I] SWAP ( calculate first addr )
- VEC @ [I] SWAP ; ( then second addr )
-
- : XSWAPV ( i j --- )
- V[I][J] ( calculate addresses )
- 2DUP SWAP >R >R ( save one copy on ret stack)
- COMPLEX@ ROT COMPLEX@ R> COMPLEX! R> COMPLEX! ; ( swap cmplx numbers )
-
-
-
-
-
-
- ( bit reversal, cont. )
-
- : BIT-REVERSE ( --- )
- N @ 1 SWAP 1 DO ( for i=1 to size of vector )
- DUP I > IF ( compare indicies )
- DUP I XSWAPV ( swap vector entries )
- THEN
- N @ 2/ SWAP ( let incr=points/2 )
- BEGIN 2DUP < ( while incr < indx )
- WHILE OVER - SWAP 2/ SWAP ( indx=indx-incr, incr=incr/2)
- REPEAT + ( indx=indx+incr )
- LOOP DROP ; ( drop indx )
-
-
-
-
- ( butterfly calculation )
- : BFLY ( j i --- )
- V[I][J] 2DUP >R >R ( calc actual addresses )
- COMPLEX@ U COMPLEX@ 10K X* ( form temp product )
- ROT COMPLEX@ XSWAP X2DUP ( prepare stack for + and - )
- X- >R >R X+ R> R> ( Fi-temp, Fi+temp )
- DIRECTION @ ( test for fwd/inv transform )
- IF XSWAP ( IFFT, no divide )
- ELSE X2/ XSWAP X2/ ( FFT, divide by POINTS???)
- THEN R> COMPLEX! R> COMPLEX! ; ( store products )
-
-
-
-
- ( 2** and log2 )
-
- : 2** ( n --- 2**n )
- 0 MAX CELL 8 * 1- MIN ( limit input data )
- 1 SWAP 0 DO 2* LOOP ; ( DON'T loop if n=0 )
-
- : LOG2 ( n --- log2[n] )
- DUP 0= ABORT" Can't take log of zero. "
- 0 SWAP ( limit one word integer )
- BEGIN DUP 0> ( test upper bit )
- WHILE 2* SWAP 1+ SWAP ( if zero, shift and incr count)
- REPEAT DROP ( done, drop remainder )
- CELL 8 * 1- SWAP - ; ( return log base 2 of input)
-
-
-
- ( table of cosines and sines for 2**0 to 2**8 )
- CREATE WTAB
- 9 , CELL 2* , 10000 , 32 , ( entries, wsize, scale, data)
- -10000 , 00000 , 00000 , -10000 , 07071 , -07071 ,
- 09239 , -03827 , 09808 , -01951 , 09952 , -00980 ,
- 09988 , -00491 , 09997 , -00245 , 09999 , -00123 ,
-
-
- \ This is a table of cosines and sines for angles of pi/n where n
- \ is an integral power of two. The first entry is pi/1, cos is -1
- \ and sin is 0. Next is pi/2, cos is 0 and sin is 1. Entries up
- \ to pi/256 currently, but it can be extended for larger FFT's.
- \ Conjugates of the sine and cosine values are used in this table.
-
-
- ( inner-loop )
-
- : INNER-LOOP ( startpt increment --- )
- DUP 2/ ( --s in in/2) ( increment/2 is bfly offset)
- ROT N @ 1+ SWAP ( -- inc inc/2) ( limits are startpt...N )
- DO
- I 2DUP + ( --inc inc/2 i inc/2+i) ( do a butterfly computation )
- BFLY OVER ( -- in in/2 in) ( between I and I+offset )
- +LOOP 2DROP ; ( increment loop )
-
- ( fft-kernel )
-
- : FFT-KERNEL ( --- ) ( N, VEC, must be set )
- N @ LOG2 1+ 1 ( do for i=1 to log2[N]-1 )
- DO
- 0 10K U COMPLEX! ( init U to 1+j0 )
- I WTAB X@V ( get 1/-arg[pi/I])
- DIRECTION @ IF X' THEN W COMPLEX! ( !!!!take conjugate if IFFT )
- I 2** DUP 2/ 1+ 1 ( increment and offset counter)
- DO I OVER INNER-LOOP ( figure innermost loop )
- W U 10K X*! ( set new value for angle )
- LOOP DROP ( drop increment value )
- LOOP ;
-
-
- ( fft and ifft )
-
- : INIT ( vector --- )
- DUP VEC !
- &ORDER N ! ; ( initialize size variable)
-
- : DO-VECTOR ( vector --- )
- INIT ( initialize size field )
- BIT-REVERSE ( bit swap input )
- FFT-KERNEL ; ( perform butterflies )
-
- : FFT 0 DIRECTION ! DO-VECTOR ;
- : IFFT -1 DIRECTION ! DO-VECTOR ;
-
-
-
-
-
- ( plotting words for complex vector )
-
- VARIABLE MAG 256 MAG ! ( diff between max and min )
- VARIABLE MINI -128 MINI ! ( min value in vector )
- VARIABLE PLOTBUF 68 ALLOT ( buffer for building image )
- VARIABLE INTERVAL 1 INTERVAL ! ( allows skipping points )
- VARIABLE FUNC ' NOOP FUNC ! ( controls RE, IM, or MAG plot)
-
- : CHAR-MAP ( n --- n )
- MINI @ -
- 70 MAG @ */ ; ( map into character coord. )
-
-
-
-
-
- ( put char into buffer before printing line )
-
- : BUF! ( char n --- )
- 69 MIN 0 MAX ( limit access to buffer )
- PLOTBUF SWAP ROT FILL ; ( store character into buffer)
-
- : ?BUF! ( char n --- )
- DUP 69 <= OVER 0 >= AND ( check for out-of-bounds )
- IF PLOTBUF + C! ( if in bounds, print char )
- ELSE 2DROP
- THEN ;
-
-
-
-
-
- ( plot one line )
-
- : PLOTDAT ( n --- )
- PLOTBUF 70 32 FILL ( blank out plotter buffer )
- ASCII : 0 CHAR-MAP ?BUF! ( "zero" line if in range )
- ASCII * SWAP CHAR-MAP BUF! ( plot character for data )
- PLOTBUF 70 -TRAILING TYPE ; ( print the plot buffer )
-
- : PLOTINDX ( n --- )
- 5 .R ( print index number )
- SPACE ASCII | EMIT ; ( and right-hand bar )
-
-
-
-
-
- ( plot entire vector )
-
- : PLOT ( vec_desc --- )
- CR DUP &ORDER 1+ 1 ( do for each entry in vector)
- DO I PLOTINDX ( get entry )
- I OVER X@V ( get entry )
- FUNC @ EXECUTE ( leave RE, IM, or MAG )
- PLOTDAT CR ( plot value )
- INTERVAL @ +LOOP ( loop by arbitrary increment)
- CR DROP ; ( drop vec. descriptor )
-
-
-
-
-
-
- ( plot real, imag, or magnitude of vector )
-
- : RE SWAP DROP ; ( leave real part )
- : IM DROP ; ( leave imag part )
-
- : PLOTMAG ['] |X| FUNC ! PLOT ; ( plot magnitude value)
- : PLOTRE ['] RE FUNC ! PLOT ; ( plot real part )
- : PLOTIM ['] IM FUNC ! PLOT ; ( plot imag part )
-
-
-
-
-
-
-
-
- ( load data from stack )
- ( TOS is vector descriptor, next is number of points, then )
- ( scale factor, data points follow )
- ( data-on-stack order #points name -- )
- : VECTOR!
- OVER >R ( -- order #points name, save #points )
- SWAP OVER ! ( -- order name, #points assigned to vector)
- SWAP OVER ( -- name order name )
- CELL 2* + ! ( -- name, stores order at 8+ vector address)
- 1 R> -DO ( for each vector entry, )
- SWAP OVER ( -- name data-point-from-stack name)
- 0 ROT ( -- name name 0 data-pt, set imag part to zero )
- I ( -- name name 0 data-pt ith )
- 4 ROLL ( -- name 0 data-pt ith name )
- X!V ( -- name 0, store into vector at ith position)
- 1 -LOOP DROP ; ( work backwards thru vector )
-
-
- ( one cosine term, 32 data points )
-
- 32 128 XVECTOR COSWAVE
- 0 128 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0
- 128 32 COSWAVE VECTOR!
-
-
- ( After IFFT, should leave a cosine wave in the real array and)
- ( a sine wave in the imag array. )
-
- ( five cosine terms, 32 data points )
-
- 32 128 XVECTOR SQUARE
- 0 128 0 40 0 14 0 3
- 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0
- 0 0 0 0 0 0 0 0
- 128 32 SQUARE VECTOR!
-
-
- ( After IFFT, should leave something like a square wave in the)
- ( imaginary array. )
-
- \ add a constant across the board to a vector, used for testing and fun.
- : ADDCONSTANT ( C ADR -- )
- DUP @ 1+ ( count)
- 1 DO
- OVER DUP >R >R
- I OVER X@V R> R> X+
- I 3 PICK X!V
- LOOP
- 2DROP
- ;
-
- \ 32 BENCH.FFT takes
- \ 14.84 seconds with X* coded in forth,
- \ 6.28 seconds with the assembler version of X* !!!
-
- : BENCH.FFT
- 0 DO
- SQUARE IFFT
- SQUARE FFT
- LOOP
- ;
-