home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
326.lha
/
KFFT_v1.1
/
fft1
< prev
next >
Wrap
Text File
|
1989-12-23
|
6KB
|
205 lines
\ FFT1 - Fast Fourier Transform JForth* source code.
\
\ KFFT V1.1 (C)Copyright 1989, Jerry Kallaus. All rights reserved.
\ May be freely redistributed for non-commercial use (FREEWARE).
\
\ Conditionally compiles as various floating point and fixed point
\ versions of a Cooley-Tukey radix-2 FFT algorithm.
\ Interface/entry words FFT and IFFT are at the end of this file.
\ File FFTinc contains INCLUDEs for all needed files.
\ File FFTControls contains compilation controls and parameters.
\ File Cmplx contains complex arithmetic and data definition words.
\ File FFT.asm contains support assembly source code and
\ file FFT.cod contains the corresponding 'object' code.
\ Words containing curly braces after the word name use JForth's
\ local variables capability.
\ See accompaning file FFT.doc for details.
\
\ * JForth is a product of Delta Research.
ANEW task-fft1
VARIABLE reversal-fft VARIABLE inv-fft
reversal-fft OFF
\ Variables specific to fixed point versions.
float_fft? NOT .IF
VARIABLE inshift-fft VARIABLE shifts-fft VARIABLE outbits-fft
inshift-fft OFF shifts-fft OFF 16 outbits-fft !
VARIABLE evens-fft VARIABLE odds-fft VARIABLE blk-exp-fft
evens-fft OFF odds-fft ON
.THEN
\ Perform sanity check on fft arguments.
: CHECK.INPUTS.FFT { a m --- } ( a is data addr, m is log2-fft-size )
a 1 AND
IF CR ." FFT odd array address ????" ABORT THEN
m 2 max_log2_fft WITHIN? NOT
IF CR ." FFT size is 2**" m . ." = " m 2** .
." ????"
CR ." Set max_log2_fft for sizes greater than 2**" max_log2_fft .
ABORT
THEN
;
\ Either perform bit reversal of data; or make reversal map if the
\ variable reversal-fft contains address to hold reversal map.
: BIT.REVERSAL { a m | jj n/2 ai aj rend --- }
( a is data addr, m is log2-fft-size)
a m CHECK.INPUTS.FFT
reversal-fft @ -> rend
0 -> jj
m 2** CELLS DUP -> n/2
CELL- 2* 0
DO
jj I > IF
rend IF
jj I rend Z! ( make reversal map )
2CELL rend + -> rend
0 0 rend Z!
ELSE ( else scramble data )
jj I a DUP D+
-> ai DUP -> aj
Z@ ai Z@
aj Z! ai Z!
THEN
THEN
n/2
BEGIN DUP DUP jj <= ( k = jj )
WHILE
jj - NEGATE -> jj ( jj = jj-k )
U2/ ( k = k/2 )
REPEAT
DROP jj + -> jj ( jj = j+k )
2CELL +LOOP
;
asm_fft? NOT .IF
: QUICK.REVERSAL { a r | ai aj --- } ( data-addr reversal-map-addr -- )
r 2CELL- -> r
BEGIN r 2CELL+ DUP -> r Z@ DUP
WHILE
a DUP D+
-> ai DUP -> aj
Z@ ai Z@
aj Z! ai Z!
REPEAT 2DROP
;
.THEN
\ ************************ Begin FFT1 ****************************
\
\ Cooley-Tukey FFT algorithm
: FFT1 { a m | n le le1 ss hi 2 u 2 w --- }
\ ( cmplx-array-address m -- ) ( m is log base 2 of fft size )
\ Byte address indexing used for efficiency.
a m CHECK.INPUTS.FFT
reversal-fft @
IF a reversal-fft @ QUICK.REVERSAL
ELSE a m BIT.REVERSAL
THEN
m 2** ZCELLS -> n
0 -> hi
[ auto_scale_fft? ] .IF shifts-fft OFF .THEN
\ *********************** Begin Outer Loop *************************
m 0
DO
[ auto_scale_fft? ] .IF
I IF ( auto scale-down control: )
[ 14 2** ] LITERAL ( Shift input to new stage right )
hi < IF 1 ELSE 0 THEN ( 0,1 or 2 places depending on )
[ 15 2** ] LITERAL ( highest bit set on output of )
hi < IF 1+ THEN ( last stage. if > 2**14 use 1 )
DUP -> ss shifts-fft +! ( if > 2**15 use 2 )
ELSE inshift-fft @ -> ss ( if stage 0, use inshift-fft )
THEN
0 -> hi
.THEN
[ auto_scale_fft? float_fft? OR NOT ] .IF
I 1 AND odds-fft @ AND ( manual even/odd )
I COMP 1 AND evens-fft @ AND OR -> ss ( stage control )
I IF-NOT inshift-fft @ ss + -> ss
inshift-fft OFF
THEN
.THEN
I 2** DUP -> le1
2* ZCELLS -> le
[ float_fft? w_table_fft? NOT AND ]
.IF
le1 FLOAT pi_fft SWAP F/
ZEXP ( w=[cos,sin] )
.ELSE
I ZCELLS w-table-fft + Z@ ( w=[cos,sin] )
.THEN
inv-fft @ IF-NOT CONJG THEN ( reverse oscilator for forward fft )
-> w
Z1 -> u
\ ************************* Begin Middle Loop ***************
le1 ZCELLS DUP -> le1 0
DO
\ ************************* Begin Inner Loop ****************
[ inner_asm_fft? ]
.IF
u le ss n a I le1 INNER.LOOP
.THEN
[ auto_scale_fft? ] .IF hi OR -> hi .THEN
[ auto_scale_fft? NOT inner_asm_fft? AND ] .IF drop .THEN
[ inner_asm_fft? NOT ] .IF
n I
DO
a I + DUP>R
Z@ ss ZSCALE.DOWN
R@ le1 + DUP>R
Z@ ss ZSCALE.DOWN u Z*
Z2DUP
Z- R> Z!
Z+ R> Z!
le +LOOP
\ ************************ End of Inner Loop **********************
.THEN
w u Z* -> u
ZCELL +LOOP
LOOP
\ ************************* End of Middle Loop **********************
\ ************************* End of Outer Loop **********************
[ auto_scale_fft? ] .IF ( Normalize data to outbits-fft )
m 2** 2* -> n ( Set n to number of cells )
hi ( hi=0 => data all zero => nothing to do )
IF
a n
outbits-fft @ hi NSBITS -
DUP shifts-fft +! ASHIFT.ARRAY
THEN
shifts-fft @ blk-exp-fft +! ( update block-flt-pt exponent )
.THEN
;
\ ************************* End of FFT1 *****************************
\ m is log base 2 of fft-size
: INIT.MAP.FFT { map-addr m --- }
map-addr reversal-fft ! 0 m BIT.REVERSAL ;
: FFT ( cmplx-array-addr m -- ) inv-fft OFF FFT1 ; ( forward fft )
: IFFT ( cmplx-array-addr m -- ) inv-fft ON FFT1 ; ( inverse fft )