Discrete Fourier Transform

The maximum sampling rate of ADC converter in ADuC7020 chip on
FORTHstamp is 1 MSPS, which is more than adequate to sample audio
signals.  A condenser microphone powered by 3.3V power supply through a
2k resister can be connected directly to the input of one ADC channel and
you get a perfect Audio Spectrum Analyzer.  The FORTH source code can
be downloaded to eForth system on FORTHstamp through HyperTerminal
and the ADCC command shows a continuing audio spectrum.
( DFT128.F, 23feb06cht)
( DFT.F, 23feb06cht)
DECIMAL
: 2DROP DROP DROP ;
: BREAK CR .S KEY $1B = ABORT" DONE" ;
VARIABLE XS                             ( square of scaled angle )
VARIABLE INDEX
VARIABLE SUM
: CIRCLE 128 ;
: SINE_TABLE $10000 ;
: COSINE_TABLE $10080 ;
: TRANSFORM_INPUT $10400 ;
: TRANSFORM_OUTPUT $10600 ;

: KN ( n1 n2 -- n3, n3=10000-n1*x*x/n2 where x is the angle )
XS @ SWAP /                     ( x*x/n2 )
NEGATE 10000 */                   ( -n1*x*x/n2 )
10000 +                           ( 10000-n1*x*x/n2 )
;

: (SIN) ( x -- sine*10K, x in radian*10K )
DUP DUP 10000 */                  ( x*x scaled by 10K )
XS !                            ( save it in XS )
10000 72 KN                       ( last term )
42 KN 20 KN 6 KN                ( terms 3, 2, and 1 )
10000 */                          ( times x )
;

: (COS) ( x -- cosine*10K, x in radian*10K )
DUP 10000 */ XS !                 ( compute and save x*x )
10000 56 KN 30 KN 12 KN 2 KN      ( serial expansion )
;

: SIN ( degree -- sine*10K )
31415 64 */                       ( convert to radian )
(SIN) 2047 10000 */                          ( compute sine )
;

: COS ( degree -- cosine*10K )
31415 64 */
(COS) 2047 10000 */
;

: FILL_SINE_TABLE
0 SINE_TABLE
32 FOR
       OVER SIN
       OVER 2DUP !
       2DUP SINE_TABLE - SINE_TABLE CIRCLE 2* + SWAP - !
       SWAP NEGATE SWAP
       2DUP SINE_TABLE - SINE_TABLE CIRCLE 2* + + !
       SINE_TABLE - SINE_TABLE CIRCLE 4 * + SWAP - !
       CELL+ SWAP 1+ SWAP
NEXT
2DROP
SINE_TABLE DUP CIRCLE 4 * + 256 CMOVE ;

FILL_SINE_TABLE

: SHOW_TABLE ( a n -- )
FOR AFT R@ 1+ 7 AND IF ELSE CR DUP 8 U.R THEN
       DUP @ 9 .R
       CELL+
THEN NEXT
DROP ;

: SINE_SUM ( INDEX -- )
>R TRANSFORM_INPUT 0 R>
0 SUM !
127 FOR  >R
       OVER @ OVER SINE_TABLE + @ * SUM +!
       4 R@ D+ $1FF AND
       R>
NEXT
2DROP DROP ;

: COSINE_SUM ( INDEX -- )
>R TRANSFORM_INPUT 0 R>
0 SUM !
127 FOR  >R
       OVER @ OVER COSINE_TABLE + @ * SUM +!
       4 R@ D+ $1FF AND
       R>
NEXT
2DROP DROP ;

: SINE_TRANSFORM
0 TRANSFORM_OUTPUT
64 FOR
       OVER SINE_SUM
       SUM @ 32768 / DUP *
       OVER !
       4 4 D+
NEXT
2DROP ;

: COSINE_TRANSFORM
0 TRANSFORM_OUTPUT
32 FOR
       OVER COSINE_SUM
       SUM @ 32768 / DUP *
       OVER +!
       4 4 D+
NEXT
2DROP ;

VARIABLE THRESHOLD
VARIABLE AVERAGE

: SHOW_TRANSFORM
$1B EMIT ." [0;0H" ( home )
$800000 THRESHOLD !
23 FOR TRANSFORM_OUTPUT
       CR 64 FOR
               DUP @ THRESHOLD @ U<
               IF $20 ELSE $2A THEN EMIT
               CELL+
       NEXT
       DROP
       THRESHOLD @ 1 RSHIFT THRESHOLD !
NEXT
CR ." 0--------10--------20--------30--------40--------50---------60---"
;
: READ_ADC ( -- n )
0 AVERAGE @ FOR AFT
       $E3 ADCCON !
       BEGIN ADCCON @ 3 AND WHILE REPEAT
       ADCDAT @ +
THEN NEXT
AVERAGE @ / 16RSHIFT ;
: ADC_INPUT TRANSFORM_INPUT
127 FOR READ_ADC OVER ! CELL+ WAIT
NEXT DROP ;
: DFT SINE_TRANSFORM COSINE_TRANSFORM SHOW_TRANSFORM ;
: ADCC BEGIN ADC_INPUT DFT ?KEY UNTIL ;
8 AVREAGE !
4 ADCCP !
Discrete Fourier Transform of Audio Signals