[comp.sources.misc] v05i080: Unix and Turbo-C General Purpose FFT

sampson@killer.DALLAS.TX.US (Steve Sampson) (12/14/88)

Posting-number: Volume 5, Issue 80
Submitted-by: "Steve Sampson" <sampson@killer.DALLAS.TX.US>
Archive-name: fft2

This archive contains source for both a Unix and MS-DOS General Purpose
FFT program.  I've posted earlier versions before, but consider them
obsolete.  This all can be improved on I'm sure.  Have fun with it.

#! /bin/sh
# Contents:  uread.doc ufft.c usine.c upulse.c read.doc makefile fft.c
#   sine.c pulse.c
# Wrapped by sampson@killer.DALLAS.TX on Fri Dec 09 23:04:22 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f uread.doc -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"uread.doc\"
else
echo shar: Extracting \"uread.doc\" \(5220 characters\)
sed "s/^X//" >uread.doc <<'END_OF_uread.doc'
X5 September 1988
X
XFFT Program for Unix C compiler
XSteve Sampson, Box 45668, Tinker AFB, OK 73145
Xsampson@killer	(TAC Trained)
X
X
X   This Unix version of the FFT program uses a general purpose display routine,
Xand the number of samples is based on the amount of memory.  This version can
Xalso be used in MS-DOS (if you change the file modes to "rb" and "wb").
X
XThe original Byte Magazine program (see references below) was designed for real
Xdata only.  In my experiments I needed to preserve both real and imaginary
Xdata.  If you feed the FFT real data only, then the output will be a mirror
Ximage, and you can ignore the left side.  Two signal generators are included.
XOne generates sine waves (sine) and the other generates pulses (pulse).  Some
Xpapers I found on the subject of FFTs are included at the end.  There are
Xseveral books devoted to the subject also.
X
XFor the Unix example try:
X
X	sine 16 in
X	1000
X	3000
X
XWhich will sample the 1 Khz data every 333 microseconds (1 / 3 Khz).  Note: The
Xsample frequency should be greater than 2 times the input frequency (Nyquist
Xand all that...).
X
XThen run fft:
X
X	fft 16 in out
X
XAnd you should see a display like so:
X
X0	|=======				      (-1500.0 Hz)
X1	|=====					      (-1312.5 Hz)
X2	|====					      (-1125.0 Hz)
X3	|====					       (-937.0 Hz)
X4	|===					       (-750.0 Hz)
X5	|===					       (-562.5 Hz)
X6	|===					       (-375.0 Hz)
X7	|===					       (-187.5 Hz)
X8	|====		<-------   DC			(000.0 Hz)
X9	|====		<-------   Fundamental		(187.5 Hz)
X10	|======		<-------   Second Harmonic	(375.0 Hz)
X11	|========					(562.5 Hz)
X12	|==============					(750.0 Hz)
X13	|========================================================
X14	|============================		    (1125.0 Hz)	^
X15	|===========				    (1312.5 Hz)	|
X								|
X				[13 - 8 (center)] * 187.5 = 937.0 Hz
X
XThe fundamental display frequency is:
X
X	T  = Time Increment Between Samples
X	N  = Number Of Samples
X	Tp = N * T
X
X	Then F = 1 / Tp
X
X	In the example above, the time increment between samples is
X	1 / 3000 or 333 microseconds.  N = 16, so Tp = 5333 microseconds
X	and 1 / .005333 is 187.5 Hz.
X
X	Therefore each filter is a multiple of 187.5 Hertz.  Filter 8 in this
X	example is center, so that would be zero, 9 would be one, etc.
X
XIn this case the sample interval didn't work so good for the frequency and
Xshows the limitation of the Discrete Fourier Transform in representing a
Xcontinuous signal.  A better sample rate for 1000 Hz would be 4000 Hz,
Xin which case T = 250 ms, Tp = 4 ms, and F = 250 Hz.  1000 / 250 = 4.  The
Xpower should all be in filter 12 (8 + 4) in this example.
X
XLet's run it and see:
X
X	sine 16 in
X	1000
X	4000
X
X	fft 16 in out
X
X0	|
X1	|
X2	|
X3	|
X4	|
X5	|
X6	|
X7	|
X8	|
X9	|
X10	|
X11	|
X12	|========================================================
X13	|
X14	|
X15	|
X
XWell what do you know...
X
XThe output data file can be used by other programs as needed.
X
XBy using negative frequencies in 'sine' you can generate opening targets:
X
X	sine 16 in
X	-1000
X	3000
X
X	fft 16 in out
X
XProduces:
X
X0	|=======
X1	|===========
X2	|============================
X3	|=======================================================
X4	|==============
X5	|========
X6	|======
X7	|====
X8	|====		<-------- Zero Hertz (DC)
X9	|===
X10	|===
X11	|===
X12	|===
X13	|====
X14	|====
X15	|=====
X
XYou can see in these examples where weighting functions would be nice.
X
XFor an example of what happens when the imaginary data is not input
X(ie, zeros put in) for a 1000 Hz frequency at 3000 Hz sample rate:
X
X0	|===============
X1	|==================
X2	|===================================
X3	|========================================================
X4	|===========
X5	|====
X6	|==
X7	|=				Delete this part
X---------------------------------------------------------------------
X8	|
X9	|=
X10	|==
X11	|====
X12	|===========
X13	|=======================================================
X14	|===================================
X15	|==================
X
XThe left side is redundant and can be deleted.  This is what the original
XByte Magazine article did.
X
XFor generating pulses, a second program 'pulse' is provided.  It pre-loads
Ximaginary data with zeros.   For example:
X
X	pulse 16 in
X	.000006
X	.0000008
X
XIs a radar with a 6 microsecond pulse and 800 nanosecond range gates.
X
X	fft 16 in out
X
XWill produce:
X
X0	|
X1	|=======
X2	|
X3	|========
X4	|
X5	|============
X6	|
X7	|===================================
X8	|========================================================
X9	|===================================
X10	|
X11	|============
X12	|
X13	|========
X14	|
X15	|=======
X
XThe more filters you use, the prettier it looks.
X
X
XFFT References
X--------------
X
X1.	Fast Fourier Transforms On Your Home Computer, William D. Stanley,
X	Steven J. Peterson, BYTE Magazine, December 1978.  Basic idea comes
X	from this program.
X
X2.	8052 Microcomputer simplifies FFT Design, Arnold Rosenberg,
X	Electronics, May 5, 1983.  Used a bit reverse table idea based on the
X	routine in this program.
X
X3.	A Fast Fourier Transform for the 8080, Robert D. Fusfeld,
X	Dr. Dobbs, Number 44.  Gave me some ideas.
X
X4.	A Guided Tour of the Fast Fourier Transform, G. D. Bergland,
X	IEEE Spectrum, July 1969.  Math!
X
X5.	FFT - Shortcut to Fourier Analysis, Richard Klahn, Richard R. Shively,
X	Electronics, April 15 1968. Math!
X
X/* EOF */
END_OF_uread.doc
if test 5220 -ne `wc -c <uread.doc`; then
    echo shar: \"uread.doc\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f ufft.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"ufft.c\"
else
echo shar: Extracting \"ufft.c\" \(5897 characters\)
sed "s/^X//" >ufft.c <<'END_OF_ufft.c'
X/*
X *	fft.c
X *
X *	Unix Version 2.4 by Steve Sampson, Public Domain, September 1988
X *
X *	This program produces a Frequency Domain display from the Time Domain
X *	data input; using the Fast Fourier Transform.
X *
X *	The Real data is generated by the in-phase (I) channel, and the
X *	Imaginary data is produced by the quadrature-phase (Q) channel of
X *	a Doppler Radar receiver.  The middle filter is zero Hz.  Closing
X *	targets are displayed to the right, and Opening targets to the left.
X *
X *	Note: With Imaginary data set to zero the output is a mirror image.
X *
X *	Usage:	fft samples input output
X *		1. samples is a variable power of two.
X *		2. Input is (samples * sizeof(double)) characters.
X *		3. Output is (samples * sizeof(double)) characters.
X *		4. Standard error is help or debugging messages.
X *
X *	See also: readme.doc, pulse.c, and sine.c.
X */
X
X/* Includes */
X
X#include <stdio.h>
X#include <malloc.h>
X#include <math.h>
X
X/* Defines */
X
X#define	TWO_PI	(2.0 * 3.14159265358979324)	/* alias 360 deg */
X#define	Chunk	(Samples * sizeof(double))
X
X#define	sine(x)		Sine[(x)]
X#define	cosine(x)	Sine[((x) + (Samples >> 2)) % Samples]
X
X/* Globals, Forward declarations */
X
Xstatic int	Samples, Power;
Xstatic double	*Real, *Imag, Maxn, magnitude();
Xstatic void	scale(), fft(), max_amp(), display(), err_report();
X
Xstatic int	permute();
Xstatic double	*Sine;
Xstatic void	build_trig();
X
Xstatic FILE	*Fpi, *Fpo;
X
X
X/* The program */
X
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	if (argc != 4)
X		err_report(0);
X
X	Samples = abs(atoi(*++argv));
X	Power = log10((double)Samples) / log10(2.0);
X
X	/* Allocate memory for the variable arrays */
X
X	if ((Real = (double *)malloc(Chunk)) == NULL)
X		err_report(1);
X
X	if ((Imag = (double *)malloc(Chunk)) == NULL)
X		err_report(2);
X
X	if ((Sine = (double *)malloc(Chunk)) == NULL)
X		err_report(3);
X
X	/* open the data files */
X
X	if ((Fpi = fopen(*++argv, "r")) == NULL)
X		err_report(4);
X
X	if ((Fpo = fopen(*++argv, "w")) == NULL)
X		err_report(5);
X
X	/* read in the data from the input file */
X
X	fread(Real, sizeof(double), Samples, Fpi);
X	fread(Imag, sizeof(double), Samples, Fpi);
X	fclose(Fpi);
X
X	build_trig();
X	scale();
X	fft();
X	display();
X
X	/* write the frequency domain data to the standard output */
X
X	fwrite(Real, sizeof(double), Samples, Fpo);
X	fwrite(Imag, sizeof(double), Samples, Fpo);
X	fclose(Fpo);
X
X	/* free up memory and let's get back to our favorite shell */
X
X	free((char *)Real);
X	free((char *)Imag);
X	free((char *)Sine);
X
X	exit(0);
X}
X
X
Xstatic void err_report(n)
Xint	n;
X{
X	switch (n)  {
X	case 0:
X		fprintf(stderr, "Usage: fft samples in_file out_file\n");
X		fprintf(stderr, "Where samples is a power of two\n");
X		break;
X	case 1:
X		fprintf(stderr, "fft: Out of memory getting real space\n");
X		break;
X	case 2:
X		fprintf(stderr, "fft: Out of memory getting imag space\n");
X		free((char *)Real);
X		break;
X	case 3:
X		fprintf(stderr, "fft: Out of memory getting sine space\n");
X		free((char *)Real);
X		free((char *)Imag);
X		break;
X	case 4:
X		fprintf(stderr,"fft: Unable to open data input file\n");
X		free((char *)Real);
X		free((char *)Imag);
X		free((char *)Sine);
X		break;
X	case 5:
X		fprintf(stderr,"fft: Unable to open data output file\n");
X		fclose(Fpi);
X		free((char *)Real);
X		free((char *)Imag);
X		free((char *)Sine);
X		break;
X	}
X
X	exit(1);
X}
X
X
Xstatic void scale()
X{
X	register int	loop;
X
X	for (loop = 0; loop < Samples; loop++)  {
X		Real[loop] /= Samples;
X		Imag[loop] /= Samples;
X	}
X}
X
X
Xstatic void fft()
X{
X	register int	loop, loop1, loop2;
X	unsigned	i1;			/* going to right shift this */
X	int		i2, i3, i4, y;
X	double		a1, a2, b1, b2, z1, z2;
X
X	i1 = Samples >> 1;
X	i2 = 1;
X
X	/* perform the butterfly's */
X
X	for (loop = 0; loop < Power; loop++)  {
X		i3 = 0;
X		i4 = i1;
X
X		for (loop1 = 0; loop1 < i2; loop1++)  {
X			y = permute(i3 / (int)i1);
X			z1 =  cosine(y);
X			z2 = -sine(y);
X
X			for (loop2 = i3; loop2 < i4; loop2++)  {
X
X				a1 = Real[loop2];
X				a2 = Imag[loop2];
X
X				b1  = z1*Real[loop2+i1] - z2*Imag[loop2+i1];
X				b2  = z2*Real[loop2+i1] + z1*Imag[loop2+i1];
X
X				Real[loop2] = a1 + b1;
X				Imag[loop2] = a2 + b2;
X
X				Real[loop2+i1] = a1 - b1;
X				Imag[loop2+i1] = a2 - b2;
X			}
X
X			i3 += (i1 << 1);
X			i4 += (i1 << 1);
X		}
X
X		i1 >>= 1;
X		i2 <<= 1;
X	}
X}
X
X/*
X *	Display the frequency domain.
X *
X *	The filters are aranged so that DC is in the middle filter.
X *	Thus -Doppler is on the left, +Doppler on the right.
X */
X
Xstatic void display()
X{
X	register int	loop, offset;
X	int		n, x;
X
X	max_amp();
X	n = Samples >> 1;
X
X	for (loop = n; loop < Samples; loop++)  {
X		x = (int)(magnitude(loop) * 59.0 / Maxn);
X		printf("%d\t|", loop - n);
X		offset = 0;
X		while (++offset <= x)
X			putchar('=');
X
X		putchar('\n');
X	}
X
X	for (loop = 0; loop < n; loop++)  {
X		x = (int)(magnitude(loop) * 59.0 / Maxn);
X		printf("%d\t|", loop + n);
X		offset = 0;
X		while (++offset <= x)
X			putchar('=');
X
X		putchar('\n');
X	}
X}
X
X/*
X *	Find maximum amplitude
X */
X
Xstatic void max_amp()
X{
X	register int	loop;
X	double		mag;
X
X	Maxn = 0.0;
X	for (loop = 0; loop < Samples; loop++)  {
X		if ((mag = magnitude(loop)) > Maxn)
X			Maxn = mag;
X	}
X}
X
X/*
X *	Calculate Power Magnitude
X */
X
Xstatic double magnitude(n)
Xint	n;
X{
X	n = permute(n);
X	return hypot(Real[n], Imag[n]);
X}
X
X/*
X *	Bit reverse the number
X *
X *	Change 11100000b to 00000111b or vice-versa
X */
X
Xstatic int permute(index)
Xint	index;
X{
X	register int	loop;
X	unsigned	n1;
X	int		result;
X
X	n1 = Samples;
X	result = 0;
X
X	for (loop = 0; loop < Power; loop++)  {
X		n1 >>= 1;
X		if (index < n1)
X			continue;
X
X		/* Unix has a truncation problem with pow() */
X
X		result += (int)(pow(2.0, (double)loop) + .05);
X		index -= n1;
X	}
X
X	return result;
X}
X
X/*
X *	Pre-compute the sine and cosine tables
X */
X
Xstatic void build_trig()
X{
X	register int	loop;
X	double		angle, increment;
X
X	angle = 0.0;
X	increment = TWO_PI / (double)Samples;
X
X	for (loop = 0; loop < Samples; loop++)  {
X		Sine[loop] = sin(angle);
X		angle += increment;
X	}
X}
X
X/* EOF */
END_OF_ufft.c
if test 5897 -ne `wc -c <ufft.c`; then
    echo shar: \"ufft.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f usine.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"usine.c\"
else
echo shar: Extracting \"usine.c\" \(1763 characters\)
sed "s/^X//" >usine.c <<'END_OF_usine.c'
X/*
X *	sine.c
X *
X *	Unix Version 2.4 by Steve Sampson, Public Domain, September 1988
X *
X *	This program is used to generate time domain sinewave data
X *	for fft.c.  If you want an opening target - negate the
X *	test frequency.
X */
X
X#include <stdio.h>
X#include <malloc.h>
X#include <math.h>
X
X#define	TWO_PI	(2.0 * 3.14159265358979324)
X#define Chunk	(Samples * sizeof(double))
X
Xstatic double	Sample, Freq, Time, *Real, *Imag;
Xstatic int	Samples;
Xstatic void	err_report();
Xstatic FILE	*Fp;
X
X
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	register int	loop;
X
X	if (argc != 3)
X		err_report(0);
X
X	Samples = abs(atoi(*++argv));
X
X	if ((Real = (double *)malloc(Chunk)) == NULL)
X		err_report(1);
X
X	if ((Imag = (double *)malloc(Chunk)) == NULL)
X		err_report(2);
X
X	printf("Input The Test Frequency (Hz) ? ");
X	scanf("%lf", &Freq);
X	printf("Input The Sampling Frequency (Hz) ? ");
X	scanf("%lf", &Sample);
X	Sample = 1.0 / Sample;
X
X	Time = 0.0;
X	for (loop = 0; loop < Samples; loop++)  {
X		Real[loop] =  sin(TWO_PI * Freq * Time);
X		Imag[loop] = -cos(TWO_PI * Freq * Time);
X		Time += Sample;
X	}
X
X	if ((Fp = fopen(*++argv, "w")) == NULL)
X		err_report(3);
X
X	fwrite(Real, sizeof(double), Samples, Fp);
X	fwrite(Imag, sizeof(double), Samples, Fp);
X	fclose(Fp);
X
X	putchar('\n');
X
X	free((char *)Real);
X	free((char *)Imag);
X
X	exit(0);
X}
X
X
Xstatic void err_report(n)
Xint	n;
X{
X	switch (n)  {
X	case 0:
X		fprintf(stderr,"Usage: sine samples output_file\n");
X		fprintf(stderr,"Where samples is a power of two\n");
X		break;
X	case 1:
X		fprintf(stderr,"sine: Out of memory getting real space\n");
X		break;
X	case 2:
X		fprintf(stderr,"sine: Out of memory getting imag space\n");
X		free((char *)Real);
X		break;
X	case 3:
X		fprintf(stderr,"sine: Unable to create write file\n");
X	}
X
X	exit(1);
X}
X
X/* EOF */
END_OF_usine.c
if test 1763 -ne `wc -c <usine.c`; then
    echo shar: \"usine.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f upulse.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"upulse.c\"
else
echo shar: Extracting \"upulse.c\" \(1613 characters\)
sed "s/^X//" >upulse.c <<'END_OF_upulse.c'
X/*
X *	pulse.c
X *
X *	Unix Version 2.4 by Steve Sampson, Public Domain, September 1988
X *
X *	This program is used to generate time domain pulse data	for fft.c.
X */
X
X#include <stdio.h>
X#include <malloc.h>
X
X#define	Chunk	(Samples * sizeof(double))
X
Xstatic double	Sample, Pw, Time, *Real, *Imag;
Xstatic int	Samples;
Xstatic void	err_report();
Xstatic FILE	*Fp;
X
X
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	register int	loop;
X
X	if (argc != 3)
X		err_report(0);
X
X	Samples = abs(atoi(*++argv));
X
X	if ((Real = (double *)malloc(Chunk)) == NULL)
X		err_report(1);
X
X	if ((Imag = (double *)malloc(Chunk)) == NULL)
X		err_report(2);
X
X	printf("Input The Pulse Width (Seconds) ? ");
X	scanf("%lf", &Pw);
X	printf("Input The Sampling Time (Seconds) ? ");
X	scanf("%lf", &Sample);
X
X	Time = 0.0;
X	for (loop = 0; loop < Samples; loop++)  {
X		if (Time < Pw)
X			Real[loop] = 1.0;
X		else
X			Real[loop] = 0.0;
X
X		Imag[loop] = 0.0;
X		Time += Sample;
X	}
X
X	if ((Fp = fopen(*++argv, "w")) == NULL)
X		err_report(3);
X
X	fwrite(Real, sizeof(double), Samples, Fp);
X	fwrite(Imag, sizeof(double), Samples, Fp);
X	fclose(Fp);
X
X	putchar('\n');
X
X	free((char *)Real);
X	free((char *)Imag);
X
X	exit(0);
X}
X
X
Xstatic void err_report(n)
Xint	n;
X{
X	switch (n)  {
X	case 0:
X		fprintf(stderr,"Usage: pulse samples output_file\n");
X		fprintf(stderr,"Where samples is a power of two\n");
X		break;
X	case 1:
X		fprintf(stderr,"pulse: Out of memory getting real space\n");
X		break;
X	case 2:
X		fprintf(stderr,"pulse: Out of memory getting imag space\n");
X		free((char *)Real);
X		break;
X	case 3:
X		fprintf(stderr,"pulse: Unable to create write file\n");
X	}
X
X	exit(1);
X}
X
X/* EOF */
END_OF_upulse.c
if test 1613 -ne `wc -c <upulse.c`; then
    echo shar: \"upulse.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f read.doc -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"read.doc\"
else
echo shar: Extracting \"read.doc\" \(5665 characters\)
sed "s/^X//" >read.doc <<'END_OF_read.doc'
X
X
X			     FFT Program for Turbo-C
X
X				       By
X
X			         Steve Sampson
X
X
X			   Version 2.6, November 1988
X
X
X   The FFT program and test signal generators included in the archive, can be
Xused to perform signal analysis in the frequency domain, using samples in the
Xtime domain.  Historically the applications have ranged from music to radar.
XI recently have been doing some research in the radar field using this FFT to
Xperform relative velocity measurements.  This program can be further refined
Xto meet your needs.
X
X   I initially uploaded a fairly basic program, and through feedback have
Xmade some improvements.  It's pretty complete now as far as a start for making
Xyour own specific version.  Earlier Unix compatability has been removed in
Xfavor of IBM graphics adaptors.
X
X   This program uses graphics to present a 256 filter window.  My current
Xapplication required complex data and resulted in 256 complex points.  You may
Xuse this with real data which results in 128 significant points.  If you feed
Xthe FFT real data only (Imaginary data set to zero), then the output will be a
Xmirror image, and you can ignore the left side.
X
XSome papers I found on the subject of FFTs are included at the end.  There are
Xseveral books devoted to the subject also.
X
XFor an example try:
X
X	sine in
X	1000
X	3000
X
XWhich will sample the 1 Khz data every 333 microseconds (1 / 3 Khz).  Note: The
Xsample frequency should be greater than 2 times the input frequency (Nyquist
Xand all that...).
X
XThen run fft like so:
X
X	fft in
X
XAnd you should see a graphics display which has filters 0 through 255 on the
XX axis, and power on the Y axis.  All DC power in the time samples will appear
Xin filter 128.  The fundamental display frequency is shown in filter 129 and
Xcan be computed as follows:
X
X	T  = Time Increment Between Samples
X	N  = Number Of Samples (256)
X	Tp = N * T
X
X	Then F = 1 / Tp
X
X	In the example above, the time increment between samples is
X	1 / 3000 or 333 microseconds.  N = 256, so Tp = 85 milliseconds
X	and 1 / .005333 is 11.7 Hz per filter.
X
X	Therefore each filter is a multiple of 11.7 Hertz.
X
X	Filter 126			-23.4 Hz
X	Filter 127			-11.7 Hz
X	Filter 128	DC		 00.0 Hz
X	Filter 129	Fundamental	 11.7 Hz
X	Filter 130	Second Harmonic  23.4 Hz
X
XIn this case you'll find the sampling interval didn't work very well for the
Xinput frequency.  The display shows the power spread out over several filters.
XThis is a limitation of the Discrete Fourier Transform in representing a
Xcontinuous signal.
X
XA better sample rate for 1000 Hz would be 4000 Hz, in which case T = 250 ms,
XTp = 64 milliseconds, and F = 15.625 Hz.  1000 / 15.625 = 64.  All of the
Xpower should then appear in filter 192 (128 + 64) in this example.
X
XRun it and see using:
X
X	sine in
X	1000
X	4000
X
X	fft in
X
XBy using negative frequencies in 'sine' you can generate opening targets:
X
X	sine in
X	-1000
X	3000
X
X	fft in
X
XYou can see in these examples where weighting functions would be useful.  For
Xinstance using weighting you could greatly attenuate the sidebands.  Usually
Xthe main lobe becomes a little wider however.  The current version does not
Xperform any weighting.
X
XFor generating pulses, a second program 'pulse' is provided.  It pre-loads
Ximaginary data with zeros.   For example:
X
X	pulse in
X	.000006
X	.0000008
X
X	fft in
X
XSimulates a radar with a 6 microsecond pulse and 800 nanosecond range gates,
Xand produces the typical pulse spectrum display.
X
X
XHow to run the FFT program
X--------------------------
X
XThe program auto-detects CGA, EGA, and VGA graphics adaptors.  The CGA version
Xcursor line is hard to see though.  VGA is untested.
X
XWhen the program is run, a ruler line is drawn with tick marks every 5 filters.
XAlso "Computing FFT" is displayed at the top of the screen.  The program is now
Xbusy computing the FFT and will not do anything useful until finished.
X
XWhen the FFT computation is complete, the power plot will be performed and a
Xverticle cursor line will appear.  "Computing FFT" will be replaced with
X"Filter # 128".  The program is then ready for input of commands.
X
XThe commands are:
X
X	ESC		Escapes back to MS-DOS
X	LEFT		Moves the cursor left
X	RIGHT		Moves the cursor right
X	CTRLLEFT	Moves the cursor 10 filters left
X	CTRLRIGHT	Moves the cursor 10 filters right
X	HOME		Moves the cursor to filter 0
X	END		Moves the cursor to filter 255
X	F1		Prints the display on an Epson/IBM Compatable printer
X
XA bee-bop when F1 is pressed means the printer has a problem (paper, power...).
X
X
XHow to compile the programs
X---------------------------
X
XI use a Hard Disk configured per the Borland Manuals.  If this is your settup
Xalso; do this:
X
X	1.  Copy the archive contents into any directory.
X	2.  Run \TURBOC\MAKE
X	3.  Three programs are made: fft.exe, sine.exe, and pulse.exe.
X
XIf you have any other system specific changes, then consult the makefile and
XBorland manuals.  I can also be reached at the address below.
X
X
XFFT References
X--------------
X
X1.	Fast Fourier Transforms On Your Home Computer, William D. Stanley,
X	Steven J. Peterson, BYTE Magazine, December 1978.  Basic idea comes
X	from this program.
X
X2.	8052 Microcomputer simplifies FFT Design, Arnold Rosenberg,
X	Electronics, May 5, 1983.  Used a bit reverse table based on the
X	routine in this program.
X
X3.	A Fast Fourier Transform for the 8080, Robert D. Fusfeld,
X	Dr. Dobbs, Number 44.  Gave me some ideas.
X
X4.	A Guided Tour of the Fast Fourier Transform, G. D. Bergland,
X	IEEE Spectrum, July 1969.
X
X5.	FFT - Shortcut to Fourier Analysis, Richard Klahn, Richard R. Shively,
X	Electronics, April 15 1968.
X
X---
XAll programs are entered into the Public Domain, No rights reserved.
XSteve Sampson, Box 45668, Tinker AFB, OK, 73145
X75136,626
END_OF_read.doc
if test 5665 -ne `wc -c <read.doc`; then
    echo shar: \"read.doc\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"makefile\"
else
echo shar: Extracting \"makefile\" \(874 characters\)
sed "s/^X//" >makefile <<'END_OF_makefile'
X#
X#	Makefile for FFT small model
X#
X#	Version 2.6, Public Domain by Steve Sampson, November 1988
X#
X#	See readme.doc file
X#
X
XMOD = s
XLIB = \turboc\lib
XINC = \turboc\include
X
Xall:
X	make fft
X	make sine
X	make pulse
X	make clean
X
Xfft:	fft.obj
X	tcc -c -f -m$(MOD) -L$(LIB) -I$(INC) fft.c
X	\turboc\bgiobj \turboc\examples\cga
X	\turboc\bgiobj \turboc\examples\egavga
X	tlink /x /c $(LIB)\C0$(MOD) fft cga egavga, fft,, \
X	$(LIB)\emu $(LIB)\math$(MOD) $(LIB)\C$(MOD) $(LIB)\graphics
X
Xsine:	sine.obj
X	tcc -c -f -m$(MOD) -L$(LIB) -I$(INC) sine.c
X	tlink /x /c $(LIB)\C0$(MOD) sine, sine,, \
X	$(LIB)\emu $(LIB)\math$(MOD) $(LIB)\C$(MOD)
X
Xpulse:	pulse.obj
X	tcc -c -f -m$(MOD) -L$(LIB) -I$(INC) pulse.c
X	tlink /x /c $(LIB)\C0$(MOD) pulse, pulse,, \
X	$(LIB)\emu $(LIB)\math$(MOD) $(LIB)\C$(MOD)
X
Xclean:
X	del *.obj
X
X#
X#	Dependancies
X#
X
Xfft.obj: fft.c
Xsine.obj: sine.c
Xpulse.obj: pulse.c
X
X# EOF
END_OF_makefile
if test 874 -ne `wc -c <makefile`; then
    echo shar: \"makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f fft.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"fft.c\"
else
echo shar: Extracting \"fft.c\" \(15702 characters\)
sed "s/^X//" >fft.c <<'END_OF_fft.c'
X/*
X *	fft.c
X *
X *	Version 2.6 by Steve Sampson, Public Domain, November 1988
X *
X *	This program produces a Frequency Domain display from the Time Domain
X *	data input; using the Fast Fourier Transform.
X *
X *	Runs in @ 30 seconds on a 5 MHz PC XT Clone without 8087.
X *
X *	The Real data is generated by the in-phase (I) channel, and the
X *	Imaginary data is produced by the quadrature-phase (Q) channel of
X *	a Doppler Radar receiver.  The middle filter is zero Hz.  Closing
X *	targets are displayed to the right, and Opening targets to the left.
X *
X *	Note: With Imaginary data set to zero the output is a mirror image.
X *
X *	Usage:	fft input
X *		1. samples is 256.
X *		2. Input is (samples * sizeof(double)) characters.
X *		3. Standard error is help or debugging messages.
X *
X *	Auto detects CGA, EGA, and VGA in Turbo-C graphics mode.
X *
X *	See also: readme.doc, pulse.c, and sine.c.
X */
X
X/* Includes */
X
X#include <stdio.h>
X#include <alloc.h>
X#include <math.h>
X
X#include <conio.h>
X#include <dos.h>
X#include <bios.h>
X#include <graphics.h>
X#include <string.h>
X#include <stdlib.h>
X
X/* Defines */
X
X#define	SAMPLES		256
X#define	POWER		8	/* 2 to the 8th power is 256 */
X
X#define ESC		27	/* exit program */
X#define LEFTKEY		331	/* cursor left */
X#define RIGHTKEY	333	/* cursor right */
X#define CTRLLEFTKEY	371	/* cursor 10 left */
X#define CTRLRIGHTKEY	372	/* cursor 10 right */
X#define HOMEKEY		327	/* cursor at filter 0 */
X#define ENDKEY		335	/* cursor at filter 255 */
X#define F1		315	/* print screen */
X
X#define	TOP		50
X#define	LEFT		64
X#define	RIGHT		575
X#define	MIDDLE		192
X#define	TEXTX		160
X#define	TEXTXN		304
X#define	TEXTY		25
X
X/*
X *	Fixed constants should be used in the macros for speed.
X *
X *	A cosine wave leads a sine wave by 90 degrees, so offset into
X *	the lookup table 1/4 the way into it (256 / 4 = 64).  Using
X *	modulo 256, lookups will wrap around to zero for numbers greater
X *	than 255.  (cosine(200) = Sine[264 % 256] = Sine[8]).
X */
X
X#define	permute(x)	Br_table[(x)]
X#define	sine(x)		Sine[(x)]
X#define cosine(x)	Sine[((x) + 64) % 256]
X
X/* Globals, Forward declarations */
X
Xdouble	Real[SAMPLES], Imag[SAMPLES], Maxn, magnitude();
Xint	GraphDriver = DETECT, GraphMode, Primary, Cursor, Length;
Xint	Bottom, Left, PrintChar(), PrintScreen(), getkey();
Xvoid	*Save, quit(), beep(), build_window(), commands(), bee_bop();
Xvoid	scale(), fft(), max_amp(), display();
X
X/*
X *	Bit Reverse Table for size 256
X *	Lookup saves 20 seconds in Turbo-C over the pow() function.
X *
X *	Br_table[x] = x inverted (eg. 00000001 flipped to 10000000)
X */
X
Xunsigned char Br_table[] = {
X	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0,
X	0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
X	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4,
X	0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
X	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc,
X	0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
X	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca,
X	0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
X	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6,
X	0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
X	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1,
X	0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
X	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
X	0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
X	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd,
X	0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
X	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3,
X	0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
X	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7,
X	0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
X	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf,
X	0x3f, 0xbf, 0x7f, 0xff
X};
X
X/*
X *	Sine/Cosine Table for size 256, Lookup saves 9 seconds in Turbo-C
X *
X *	Sine[n] = sin(x), x = x + (2Pi / 256)
X */
X
Xfloat	Sine[] = {
X	0.000000, 0.024541, 0.049068, 0.073565,	0.098017, 0.122411,
X	0.146730, 0.170962, 0.195090, 0.219101, 0.242980, 0.266713,
X	0.290285, 0.313682, 0.336890, 0.359895, 0.382683, 0.405241,
X	0.427555, 0.449611, 0.471397, 0.492898, 0.514103, 0.534998,
X	0.555570, 0.575808, 0.595699, 0.615232,	0.634393, 0.653173,
X	0.671559, 0.689541, 0.707107, 0.724247, 0.740951, 0.757209,
X	0.773010, 0.788346, 0.803208, 0.817585, 0.831470, 0.844854,
X	0.857729, 0.870087, 0.881921, 0.893224, 0.903989, 0.914210,
X	0.923880, 0.932993, 0.941544, 0.949528,	0.956940, 0.963776,
X	0.970031, 0.975702, 0.980785, 0.985278, 0.989177, 0.992480,
X	0.995185, 0.997290, 0.998795, 0.999699,	1.000000, 0.999699,
X	0.998795, 0.997290, 0.995185, 0.992480, 0.989177, 0.985278,
X	0.980785, 0.975702, 0.970031, 0.963776,	0.956940, 0.949528,
X	0.941544, 0.932993, 0.923880, 0.914210, 0.903989, 0.893224,
X	0.881921, 0.870087, 0.857729, 0.844854,	0.831470, 0.817585,
X	0.803208, 0.788346, 0.773010, 0.757209, 0.740951, 0.724247,
X	0.707107, 0.689541, 0.671559, 0.653173,	0.634393, 0.615232,
X	0.595699, 0.575808, 0.555570, 0.534998, 0.514103, 0.492898,
X	0.471397, 0.449611, 0.427555, 0.405241, 0.382683, 0.359895,
X	0.336890, 0.313682, 0.290285, 0.266713, 0.242980, 0.219101,
X	0.195090, 0.170962, 0.146730, 0.122411,	0.098017, 0.073565,
X	0.049068, 0.024541, 0.000000, -0.024541, -0.049068, -0.073565,
X	-0.098017, -0.122411, -0.146730, -0.170962, -0.195090, -0.219101,
X	-0.242980, -0.266713, -0.290285, -0.313682, -0.336890, -0.359895,
X	-0.382683, -0.405241, -0.427555, -0.449611, -0.471397, -0.492898,
X	-0.514103, -0.534998, -0.555570, -0.575808, -0.595699, -0.615232,
X	-0.634393, -0.653173, -0.671559, -0.689541, -0.707107, -0.724247,
X	-0.740951, -0.757209, -0.773010, -0.788346, -0.803208, -0.817585,
X	-0.831470, -0.844854, -0.857729, -0.870087, -0.881921, -0.893224,
X	-0.903989, -0.914210, -0.923880, -0.932993, -0.941544, -0.949528,
X	-0.956940, -0.963776, -0.970031, -0.975702, -0.980785, -0.985278,
X	-0.989177, -0.992480, -0.995185, -0.997290, -0.998795, -0.999699,
X	-1.000000, -0.999699, -0.998795, -0.997290, -0.995185, -0.992480,
X	-0.989177, -0.985278, -0.980785, -0.975702, -0.970031, -0.963776,
X	-0.956940, -0.949528, -0.941544, -0.932993, -0.923880, -0.914210,
X	-0.903989, -0.893224, -0.881921, -0.870087, -0.857729, -0.844854,
X	-0.831470, -0.817585, -0.803208, -0.788346, -0.773010, -0.757209,
X	-0.740951, -0.724247, -0.707107, -0.689541, -0.671559, -0.653173,
X	-0.634393, -0.615232, -0.595699, -0.575808, -0.555570, -0.534998,
X	-0.514103, -0.492898, -0.471397, -0.449611, -0.427555, -0.405241,
X	-0.382683, -0.359895, -0.336890, -0.313682, -0.290285, -0.266713,
X	-0.242980, -0.219101, -0.195090, -0.170962, -0.146730, -0.122411,
X	-0.098017, -0.073565, -0.049068, -0.024541
X};
X
XFILE	*Fpi, *Fpo;
X
X
X/* The program */
X
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	if (argc != 2)  {
X		fprintf(stderr, "Usage: fft input_file\n");
X		exit(1);
X	}
X
X	setcbrk(1);		/* Allow Control-C checking */
X	ctrlbrk(quit);		/* Execute quit() if Control-C detected */
X
X	/* open the data file */
X
X	if ((Fpi = fopen(*++argv, "rb")) == NULL)  {
X		fprintf(stderr,"fft: Unable to open data input file\n");
X		exit(1);
X	}
X
X	/* read in the data */
X
X	fread(Real, sizeof(double), SAMPLES, Fpi);
X	fread(Imag, sizeof(double), SAMPLES, Fpi);
X	fclose(Fpi);
X
X	build_window();
X	scale();
X	fft();
X	display();
X
X	/* wait for keyboard commands */
X
X	commands();
X}
X
X
Xvoid scale()
X{
X	register int	loop;
X
X	for (loop = 0; loop < SAMPLES; loop++)  {
X		Real[loop] /= SAMPLES;
X		Imag[loop] /= SAMPLES;
X	}
X}
X
X
Xvoid fft()
X{
X	register int	loop, loop1, loop2;
X	unsigned	i1;			/* going to right shift this */
X	int		i2, i3, i4, y;
X	double		a1, a2, b1, b2, z1, z2;
X
X	i1 = SAMPLES >> 1;
X	i2 = 1;
X
X	/* perform the butterfly's */
X
X	for (loop = 0; loop < POWER; loop++)  {
X		i3 = 0;
X		i4 = i1;
X
X		for (loop1 = 0; loop1 < i2; loop1++)  {
X			y = permute(i3 / (int)i1);
X			z1 =  cosine(y);
X			z2 = -sine(y);
X
X			for (loop2 = i3; loop2 < i4; loop2++)  {
X
X				a1 = Real[loop2];
X				a2 = Imag[loop2];
X
X				b1  = z1*Real[loop2+i1] - z2*Imag[loop2+i1];
X				b2  = z2*Real[loop2+i1] + z1*Imag[loop2+i1];
X
X				Real[loop2] = a1 + b1;
X				Imag[loop2] = a2 + b2;
X
X				Real[loop2+i1] = a1 - b1;
X				Imag[loop2+i1] = a2 - b2;
X			}
X
X			i3 += (i1 << 1);
X			i4 += (i1 << 1);
X		}
X
X		i1 >>= 1;
X		i2 <<= 1;
X	}
X}
X
X/*
X *	Display the frequency domain.
X *
X *	The filters are aranged so that DC is in the middle filter.
X *	Thus -Doppler is on the left, +Doppler on the right.
X */
X
Xvoid display()
X{
X	register int	loop, offset;
X	int		n, x;
X
X	n = SAMPLES >> 1;
X	max_amp();
X
X	/*
X	 *	Graphics screen horizontal configuration:
X	 *
X	 *	| 64 pixels | 512 pixels | 64 pixels |
X	 *	|   margin  |   picture  |   margin  |
X	 *
X	 *	Spectral lines are two bits wide
X	 */
X
X	for (loop = n, offset = LEFT; loop < SAMPLES; loop++, offset++)  {
X		x = (int)(magnitude(loop) * Length / Maxn);
X		bar((offset + loop - n), Bottom - x, (offset + loop - n) + 1, Bottom);
X	}
X
X	for (loop = 0, offset = MIDDLE; loop < n; loop++, offset++)  {
X		x = (int)(magnitude(loop) * Length / Maxn);
X		bar((offset + loop + n), Bottom - x, (offset + loop + n) + 1, Bottom);
X	}
X}
X
X/*
X *	Find maximum amplitude
X */
X
Xvoid max_amp()
X{
X	register int	loop;
X	double		mag;
X
X	Maxn = 0.0;
X	for (loop = 0; loop < SAMPLES; loop++)  {
X		if ((mag = magnitude(loop)) > Maxn)
X			Maxn = mag;
X	}
X}
X
X/*
X *	Calculate Power Magnitude
X */
X
Xdouble magnitude(n)
Xint	n;
X{
X	n = permute(n);
X	return hypot(Real[n], Imag[n]);
X}
X
Xvoid build_window()
X{
X	unsigned i_size;
X
X	/* settup graphics mode */
X
X	registerbgidriver(CGA_driver);
X	registerbgidriver(EGAVGA_driver);
X
X	initgraph(&GraphDriver, &GraphMode, "");
X
X	if (graphresult() != grOk)  {
X		fprintf(stderr, "fft: %s\n", grapherrormsg(graphresult()));
X		exit(1);
X	}
X
X	if ((i_size = getgraphmode()) != CGAHI)
X		setbkcolor(BLACK);
X
X	switch (i_size)  {
X	case CGAHI:
X		Primary = WHITE;
X		Cursor  = WHITE;
X		Length  = 100.0;
X		Bottom  = 150;
X		break;
X	case EGAHI:
X		Primary = LIGHTGRAY;
X		Cursor  = LIGHTGREEN;
X		Length  = 250.0;
X		Bottom  = 300;
X		break;
X	case VGAHI:
X		Primary = LIGHTGRAY;
X		Cursor  = LIGHTGREEN;
X		Length  = 380.0;
X		Bottom  = 430;
X	}
X
X	setcolor(Primary);
X	setfillstyle(SOLID_FILL, Primary);
X	settextjustify(LEFT_TEXT, TOP_TEXT);
X	settextstyle(DEFAULT_FONT, HORIZ_DIR, 2);
X
X	cleardevice();
X
X	outtextxy(TEXTX, TEXTY, "Computing FFT");
X
X	/* Draw ruler line */
X
X	line(LEFT, Bottom + 5, RIGHT, Bottom + 5);
X	for (i_size = LEFT; i_size <= RIGHT ; i_size += 10)  {
X		line(i_size, Bottom + 5, i_size, Bottom + 10);
X		line(i_size + 1, Bottom + 5, i_size + 1, Bottom + 10);
X	}
X
X	/* create under-cursor memory */
X
X	i_size = imagesize(LEFT, TOP, LEFT + 1, Bottom);
X	Save   = malloc(i_size);
X}
X
Xvoid commands()
X{
X	int	key, filter;
X	char	string[4];
X
X	setcolor(BLACK);	/* erase text */
X	outtextxy(TEXTX, TEXTY, "Computing FFT");
X	setcolor(Primary);
X
X	Left   = 320;
X	filter = 128;
X	strcpy(string, "128");
X	outtextxy(TEXTX, TEXTY, "Filter # 128");
X	getimage(Left, TOP, Left + 1, Bottom, Save);
X	setfillstyle(SOLID_FILL, Cursor);
X	bar(Left, TOP, Left + 1, Bottom);
X
X	for (;;)  {
X		while (bioskey(1) == 0)		/* wait for key press */
X			;
X		key = getkey();
X
X		switch(key)  {		/* find out which key was pressed */
X		case HOMEKEY:
Xj1:			putimage(Left, TOP, Save, COPY_PUT);
X			filter = 0;
X			Left = LEFT;
X			getimage(Left, TOP, Left + 1, Bottom, Save);
X			bar(Left, TOP, Left + 1, Bottom);
X
X			setcolor(BLACK);	/* erase old text */
X			outtextxy(TEXTXN, TEXTY, string);
X			setcolor(Primary);
X
X			sprintf(string, "%d", filter);
X			outtextxy(TEXTXN, TEXTY, string);
X			break;
X		case ENDKEY:
Xj2:			putimage(Left, TOP, Save, COPY_PUT);
X			filter = 255;
X			Left = RIGHT - 1;
X			getimage(Left, TOP, Left + 1, Bottom, Save);
X			bar(Left, TOP, Left + 1, Bottom);
X
X			setcolor(BLACK);	/* erase old text */
X			outtextxy(TEXTXN, TEXTY, string);
X			setcolor(Primary);
X
X			sprintf(string, "%d", filter);
X			outtextxy(TEXTXN, TEXTY, string);
X			break;
X		case CTRLLEFTKEY:
X			if (filter <= 9)
X				goto j1;
X
X			putimage(Left, TOP, Save, COPY_PUT);
X			Left -= 20;
X			filter -= 10;
X			getimage(Left, TOP, Left + 1, Bottom, Save);
X			bar(Left, TOP, Left + 1, Bottom);
X
X			setcolor(BLACK);	/* erase old text */
X			outtextxy(TEXTXN, TEXTY, string);
X			setcolor(Primary);
X
X			sprintf(string, "%d", filter);
X			outtextxy(TEXTXN, TEXTY, string);
X			break;
X		case LEFTKEY:
X			if (filter <= 0)  {
X				beep();
X				break;
X			}
X
X			putimage(Left, TOP, Save, COPY_PUT);
X			Left -= 2;
X			filter--;
X			getimage(Left, TOP, Left + 1, Bottom, Save);
X			bar(Left, TOP, Left + 1, Bottom);
X
X			setcolor(BLACK);	/* erase old text */
X			outtextxy(TEXTXN, TEXTY, string);
X			setcolor(Primary);
X
X			sprintf(string, "%d", filter);
X			outtextxy(TEXTXN, TEXTY, string);
X			break;
X		case CTRLRIGHTKEY:
X			if (filter >= 245)
X				goto j2;
X
X			putimage(Left, TOP, Save, COPY_PUT);
X			Left += 20;
X			filter += 10;
X			getimage(Left, TOP, Left + 1, Bottom, Save);
X			bar(Left, TOP, Left + 1, Bottom);
X
X			setcolor(BLACK);	/* erase old text */
X			outtextxy(TEXTXN, TEXTY, string);
X			setcolor(Primary);
X
X			sprintf(string, "%d", filter);
X			outtextxy(TEXTXN, TEXTY, string);
X			break;
X		case RIGHTKEY:
X			if (filter >= 255)  {
X				beep();
X				break;
X			}
X
X			putimage(Left, TOP, Save, COPY_PUT);
X			Left += 2;
X			filter++;
X			getimage(Left, TOP, Left + 1, Bottom, Save);
X			bar(Left, TOP, Left + 1, Bottom);
X
X			setcolor(BLACK);	/* erase old text */
X			outtextxy(TEXTXN, TEXTY, string);
X			setcolor(Primary);
X
X			sprintf(string, "%d", filter);
X			outtextxy(TEXTXN, TEXTY, string);
X			break;
X		case F1:
X			if (PrintScreen())
X				bee_bop();
X			break;
X		case ESC:
X			quit();
X		default:
X			beep();
X		}
X	}
X}
X
Xvoid beep()
X{
X	sound(200);
X	delay(125);
X	nosound();
X}
X
Xvoid bee_bop()
X{
X	sound(1000);
X	delay(80);
X	sound(200);
X	delay(160);
X	sound(1000);
X	nosound();
X}
X
X/*
X *	Return to MS-DOS operating system
X */
X
Xvoid quit()
X{
X	sound(1000);
X	delay(250);
X	nosound();
X
X	closegraph();
X
X	free((char *)Save);
X
X	exit(0);
X}
X
X/*
X *	Dumps a screen to printer in Double Density landscape format.
X *	This routine is from the Borland Programming Forum on CompuServe.
X *
X *	returns TRUE on error
X */
X
Xint PrintScreen()
X{
X	int			X,Y,YOfs;
X	int			BitData,MaxBits;
X	unsigned int		Height,Width;
X	struct viewporttype 	Vport;
X
X	getviewsettings(&Vport);
X	Width  = Vport.bottom - Vport.top;
X	Height = (Vport.right + 1) - Vport.left;
X
X	if (PrintChar(27))
X		return (1);
X
X	if (PrintChar('3'))
X		return (1);
X
X	if (PrintChar(24))	/* 24/216 inch line spacing */
X		return (1);
X
X	Y = 0;
X	while (Y < Height)  {
X		if (PrintChar(27))
X			return (1);
X
X		if (PrintChar('L'))	/* Double Density */
X			return (1);
X
X		if (PrintChar(Width & 0xff))
X			return (1);
X
X		if (PrintChar(Width >> 8))
X			return (1);
X
X		for (X = Width - 1; X >= 0; X--)  {
X			BitData = 0;
X			if ((Y + 7) <= Height)
X				MaxBits = 7;
X			else
X				MaxBits = Height - Y;
X
X			for (YOfs = 0; YOfs <= MaxBits; YOfs++)  {
X				BitData = BitData << 1;
X				if (getpixel(YOfs + Y, X) > 0)
X					BitData++;
X			}
X
X			if (PrintChar(BitData))
X				return (1);
X		}
X
X		if (PrintChar('\r'))
X			return (1);
X
X		if (PrintChar('\n'))
X			return (1);
X
X		Y += 8;
X	}
X
X	PrintChar(12);		/* formfeed */
X
X	return (0);
X}
X
X/*
X *	returns TRUE on error
X */
X
Xint PrintChar(out)
Xint	out;
X{
X	unsigned char	ret;
X
X	ret = biosprint(0, out, 0);
X	if ((ret & 0x29) || !(ret & 0x10))
X		return 1;
X	else
X		return 0;
X}
X
Xint getkey()
X{
X	int	key, lo, hi;
X
X	key = bioskey(0);
X	lo = key & 0x00FF;
X	hi = (key & 0xFF00) >> 8;
X
X	return((lo == 0) ? hi + 256 : lo);
X}
X
X/* EOF */
END_OF_fft.c
if test 15702 -ne `wc -c <fft.c`; then
    echo shar: \"fft.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f sine.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"sine.c\"
else
echo shar: Extracting \"sine.c\" \(1139 characters\)
sed "s/^X//" >sine.c <<'END_OF_sine.c'
X/*
X *	sine.c
X *
X *	Version 2.6 by Steve Sampson, Public Domain, November 1988
X *
X *	This program is used to generate time domain sinewave data
X *	for fft.c.  If you want an opening target - negate the
X *	test frequency.
X */
X
X#include <stdio.h>
X#include <alloc.h>
X#include <math.h>
X
X#define	SAMPLES	256
X#define	TWO_PI	(2.0 * 3.14159265358979324)
X
Xdouble	Sample, Freq, Time, Real[SAMPLES], Imag[SAMPLES];
XFILE	*Fp;
X
X
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	register int	loop;
X
X	if (argc != 2)  {
X		fprintf(stderr,"Usage: sine output_file\n");
X		exit(1);
X	}
X
X	printf("Input The Test Frequency (Hz) ? ");
X	scanf("%lf", &Freq);
X	printf("Input The Sampling Frequency (Hz) ? ");
X	scanf("%lf", &Sample);
X
X	Sample = 1.0 / Sample;
X	Time   = 0.0;
X
X	for (loop = 0; loop < SAMPLES; loop++)  {
X		Real[loop] =  sin(TWO_PI * Freq * Time);
X		Imag[loop] = -cos(TWO_PI * Freq * Time);
X		Time += Sample;
X	}
X
X	if ((Fp = fopen(*++argv, "wb")) == NULL)  {
X		fprintf(stderr,"sine: Unable to create write file\n");
X		exit(1);
X	}
X
X	fwrite(Real, sizeof(double), SAMPLES, Fp);
X	fwrite(Imag, sizeof(double), SAMPLES, Fp);
X	fclose(Fp);
X
X	putchar('\n');
X
X	exit(0);
X}
END_OF_sine.c
if test 1139 -ne `wc -c <sine.c`; then
    echo shar: \"sine.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f pulse.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"pulse.c\"
else
echo shar: Extracting \"pulse.c\" \(985 characters\)
sed "s/^X//" >pulse.c <<'END_OF_pulse.c'
X/*
X *	pulse.c
X *
X *	Version 2.6 by Steve Sampson, Public Domain, November 1988
X *
X *	This program is used to generate time domain pulse data	for fft.c.
X */
X
X#include <stdio.h>
X#include <alloc.h>
X
X#define SAMPLES	256
X
Xdouble	Sample, Pw, Time, Real[SAMPLES], Imag[SAMPLES];
XFILE	*Fp;
X
X
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	register int	loop;
X
X	if (argc != 2)  {
X		fprintf(stderr,"Usage: pulse output_file\n");
X		exit(1);
X	}
X
X	printf("Input The Pulse Width (Seconds) ? ");
X	scanf("%lf", &Pw);
X	printf("Input The Sampling Time (Seconds) ? ");
X	scanf("%lf", &Sample);
X
X	Time = 0.0;
X
X	for (loop = 0; loop < SAMPLES; loop++)  {
X		if (Time < Pw)
X			Real[loop] = 1.0;
X		else
X			Real[loop] = 0.0;
X
X		Imag[loop] = 0.0;
X		Time += Sample;
X	}
X
X	if ((Fp = fopen(*++argv, "wb")) == NULL)  {
X		fprintf(stderr,"pulse: Unable to create write file\n");
X		exit(1);
X	}
X
X	fwrite(Real, sizeof(double), SAMPLES, Fp);
X	fwrite(Imag, sizeof(double), SAMPLES, Fp);
X	fclose(Fp);
X
X	putchar('\n');
X
X	exit(0);
X}
END_OF_pulse.c
if test 985 -ne `wc -c <pulse.c`; then
    echo shar: \"pulse.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0