home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga ACS 1997 #2
/
amigaacscoverdisc
/
utilities
/
shareware
/
music
/
gfft-2.03
/
source
/
gfft-2.03-source.lha
/
okwindow.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-01-02
|
9KB
|
311 lines
/***************************************************************************
* Copyright (C) 1994 Charles P. Peterson *
* 4007 Enchanted Sun, San Antonio, Texas 78244-1254 *
* Email: Charles_P_Peterson@fcircus.sat.tx.us *
* *
* This is free software with NO WARRANTY. *
* See gfft.c, or run program itself, for details. *
* Support is available for a fee. *
***************************************************************************
*
* Program: gfft--General FFT analysis
* File: okwindow.c
* Purpose: apply window function to a segment of data
* Author: Charles Peterson (CPP)
* History: 30-August-1993 CPP; Created.
* Comment: The formulae (and terminology) for the most windows is
* from "On the Use of Windows for Harmonic Analysis with the
* Discrete Fourier Transform", by Fredric J. Harris,
* pp. 172-204 in 'Modern Spectrum Analysis, II', edited
* by Stanislav B. Kesler (IEEE Press, New York, 1986).
* This classic compendium and comparison of windows was
* originally published in 'Proc. IEEE', vol. 66, pp. 51-83,
* Jan. 1978.
*
* The formulae for the Parzen, Welch, and Hann[-ing] windows
* are taken from 'Numerical Recipes in C', by Press, Flannery,
* Teukolsky, and Vetterling (Cambridge University Press,
* Cambridge (UK) and New York City, 1988), p. 442.
*
*/
#include <math.h>
#ifdef _AMIGA
#ifdef _M68881
#include <m68881.h>
#endif
#endif
#include "gfft.h"
#include "settings.h"
#define SQUARE(x) ((x) * (x))
void triangle_window (float *vector, ULONG data_count);
void parzen_window (float *vector, ULONG data_count);
void hann_window (float *vector, ULONG data_count);
void hamming_window (float *vector, ULONG data_count);
void welch_window (float *vector, ULONG data_count);
void blackman_harris_74db_window (float *vector, ULONG data_count);
void blackman_harris_92db_window (float *vector, ULONG data_count);
static void blackman_window_n (float *vector, ULONG data_count,
float a0, float a1, float a2, float a3);
static float *Window_Vector = NULL; /* window vector reused if possible */
static unsigned long last_count = 0;
static last_window_type = RECTANGLE_WINDOW;
static double window_gain2 = 1.0;
static double sum_of_window_squares;
static void window_vector__make (ULONG data_count);
void ok_window (float *indata, ULONG data_count)
{
ULONG i;
/*
* Create new window vector if old one...
* doesn't exist
* is inapplicable
*/
if (Window_Vector == NULL ||
last_count != data_count ||
last_window_type != WindowType)
{
window_vector__make (data_count);
}
/*
* OK, now apply the window
*/
if (WindowType == RECTANGLE_WINDOW) return;
for (i = 0; i < data_count; i++)
{
indata[i] *= Window_Vector[i];
}
return;
}
static void window_vector__make (ULONG data_count)
{
if (WindowType == RECTANGLE_WINDOW) /* This is special cased */
{
if (Window_Vector) gfree (Window_Vector);
Window_Vector = NULL; /* This is VERY important! */
sum_of_window_squares = data_count;
window_gain2 = 1.0;
}
else
{
/*
* Allocate new memory if
* none allocated before
* current allocation is wrong size (in that case, free old memory too)
*/
if (Window_Vector != NULL && data_count != last_count)
{
gfree (Window_Vector);
Window_Vector = NULL;
Window_Vector = gmalloc (data_count * sizeof (float),
NOTHING_SPECIAL);
}
else if (Window_Vector == NULL)
{
Window_Vector = gmalloc (data_count * sizeof (float),
NOTHING_SPECIAL);
} /* else, Window_Vector must be the right size already */
sum_of_window_squares = 0.0;
switch (WindowType)
{
case TRIANGLE_WINDOW:
triangle_window (Window_Vector, data_count);
break;
case BLACKMAN_HARRIS_74DB_WINDOW:
blackman_harris_74db_window (Window_Vector, data_count);
break;
case BLACKMAN_HARRIS_92DB_WINDOW:
blackman_harris_92db_window (Window_Vector, data_count);
break;
case HANN_WINDOW:
hann_window (Window_Vector, data_count);
break;
case HAMMING_WINDOW:
hamming_window (Window_Vector, data_count);
break;
case WELCH_WINDOW:
welch_window (Window_Vector, data_count);
break;
case PARZEN_WINDOW:
parzen_window (Window_Vector, data_count);
break;
}
window_gain2 = sum_of_window_squares / data_count;
}
last_count = data_count;
last_window_type = WindowType;
}
double ok_window__gain2 (void)
{
return window_gain2; /* return hidden value */
}
void triangle_window (float *vector, ULONG data_count)
{
ULONG i;
float half_count = data_count / 2;
/* float half_divisor = (data_count-1.0) / 2.0; */
/* The above would reach unity at two points nearest center */
/* The following never reaches unity...unity is at virtual center */
/* ...which can only be met if window size is odd */
/* Harris uses the following as well, but see note at end of function */
float half_divisor = (data_count / 2);
for (i = 0; i < half_count; i++)
{
vector[i] = i / half_divisor;
sum_of_window_squares += SQUARE(vector[i]);
}
for (i = half_count; i < data_count; i++)
{
vector[i] = ((data_count-1) - i) / half_divisor;
sum_of_window_squares += SQUARE(vector[i]);
}
/*
* Based partially on Harris, op. cit., p. 180.
* But, in the upper part of equation 23b, he appears to be
* 'off by 1' in the upper range for n, which (I believe) should be:
* n = 0, 1, ..., (N/2 - 1), as I have done here...
* He indicates the lower range correctly as beginning with N/2, which
* is consistent with my interpretation.
*/
}
void blackman_harris_74db_window (float *vector, ULONG data_count)
{
blackman_window_n (vector, data_count,
#ifdef _FFP
0.40217, 0.49703, 0.09392, 0.00183);
#else
0.40217F, 0.49703F, 0.09392F, 0.00183F);
#endif
/*
* Terms from Harris, op. cit., p. 186
*/
}
void blackman_harris_92db_window (float *vector, ULONG data_count)
{
blackman_window_n (vector, data_count,
#ifdef _FFP
0.35875, 0.48829, 0.14128, 0.001168);
#else
0.35875F, 0.48829F, 0.14128F, 0.001168F);
#endif
/*
* Terms from Harris, op. cit., p. 186
*/
}
void hamming_window (float *vector, ULONG data_count)
{
blackman_window_n (vector, data_count,
#ifdef _FFP
0.54, 0.46, 0.0, 0.0);
#else
0.54F, 0.46F, 0.0F, 0.0F);
#endif
/*
* Terms from Harris, op. cit., p. 183
*/
}
static void blackman_window_n (float *vector, ULONG data_count,
float a0, float a1, float a2, float a3)
{
ULONG i;
float pi_term = 2.0F * PI / data_count;
for (i = 0; i < data_count; i++)
{
vector[i] = a0 -
a1 * cos (pi_term * i) +
((a2 != 0.0) ? a2 * cos (pi_term * (2 * i)) : 0.0F) -
((a3 != 0.0) ? a3 * cos (pi_term * (3 * i)) : 0.0F);
sum_of_window_squares += SQUARE(vector[i]);
}
}
void parzen_window (float *vector, ULONG data_count)
{
ULONG i;
for (i = 0; i < data_count; i++)
{
vector[i] = 1.0F - (fabs (i - 0.5F * (data_count - 1)) /
(0.5F * (data_count + 1)));
sum_of_window_squares += SQUARE(vector[i]);
}
/*
* The formula is taken from Press, et. al, op. cit., p. 442.
* Harris identifies a similarly constructed (but not identical) window
* as the Riesz window on p. 186.
*/
}
void hann_window (float *vector, ULONG data_count)
{
ULONG i;
for (i = 0; i < data_count; i++)
{
vector[i] = 0.5F * (1.0F - cos ( (2.0F * ((float) PI) * i) /
(data_count - 1)));
/*
* From Press, et. al, op. cit., p 442.
* In eq. (27b), p. 181, Harris (op. cit.) seems to be "off by 1" in
* his divisor, though he gives a footnote identifying the true name,
* which is used here (not Hanning, which comes from Hann-ing).
*/
sum_of_window_squares += SQUARE(vector[i]);
}
}
void welch_window (float *vector, ULONG data_count)
{
ULONG i;
float upper_factor = 0.5F * (data_count - 1);
float lower_factor = 0.5F * (data_count + 1);
for (i = 0; i < data_count; i++)
{
float factor = (i - upper_factor) / lower_factor;
/*
* From Press, et. al, op. cit., p. 442.
*/
vector[i] = 1.0F - SQUARE(factor);
sum_of_window_squares += SQUARE(vector[i]);
}
}
/**************** Now, this is special cased away ************************\
void rectangle (float *vector, ULONG data_count)
{
ULONG i;
for (i = 0; i < data_count; i++)
{
vector[i] = 1.0;
}
sum_of_window_squares = data_count;
}
\*************************************************************************/