VCL Wrapper for Installing FFTW into Borland C++Builder

 

 

Overview:  This package (I’ll call it FFTWBCB) makes it easier to use FFTW in Borland C++ Builder (BCB).  It is easy enough to use FFTW directly, by including all of the FFTW source files in your project, or by building a library file.  But BCB is “component” oriented, and it makes sense to turn FFTW into such a component when working in BCB.

 

Description of use: Once you’ve installed FFTWBCB, the following example code would perform an FFT:

 

  CFFT1->FFTDataSize = datasize;

  CFFT1->FFTWeighting = TCFFT::Cheby;

  CFFT1->SidelobeLevel = 50;

  CFFT1->GPL = true;

  CFFT1->CreatePlan(fftsize);

  CFFT1->FFT(p);

 

In the above, it is assumed that CFFT1 is the component that you’ve dropped on a form.  You can also create one manually, of course, using “new”.  The variable “p” above is a pointer to type complex<double>.  The following example would create such a variable, and initialize it with a sine wave:

 

#define COMPLEX complex<double>

#define datasize 512

#define fftsize  1024

  // Create a test sine-wave input signal

  COMPLEX *p = (COMPLEX*)calloc(fftsize, sizeof(COMPLEX));

  for(int i=0; i<datasize; i++){

    float fi = (float)i * 8.0 * 3.1415926 / datasize;

    p[i] = COMPLEX(sin(fi), cos(fi));

  }

  // Zero-pad to the full FFT size

  for(int i=datasize; i<fftsize; i++){

    p[i] = COMPLEX(0,0);

  }

 

In “fftw.h” the data type “fftw_complex” is defined.  If you use that in your code rather than complex<double> as is used above, you’ll save some of the overhead associated with FFTWBCB.

 

FFTWBCB does provide sidelobe reduction weighting functions that aren’t provided by FFTW itself.  The available weighting functions are:

 

 

 

Reasons you might not want to use FFTWBCB: If you’re using FFTW, you likely are concerned about speed.  FFTW is tremendously optimized; the VCL wrapper is not.  After running a few quick benchmarks (comparing to Matlab 6.5, which uses FFTW) it seems that there’s about a 20% to 30% overhead cost associated with using FFTWBCB.  So if speed is paramount you may prefer to link directly to the FFTW routines.  Also, FFTW has features that FFTWBCB doesn’t – for example, FFTW provides two-dimensional FFT’s.  I haven’t added VCL wrappers for that yet.  Still, if you’re at all comfortable working with BCB components, you can probably add to FFTWBCB any of those functions that FFTW provides that FFTWBCB currently lacks.  And at the very least, you can view FFTWBCB as an example BCB program that successfully includes, links, and runs FFTW.

 

GPL Flag: FFTWBCB actually includes two FFT’s: a very simple unoptimized FFT, and FFTW.  If you can conform to the GPL (which FFTW is released under) then you will certainly want to use FFTW (set the GPL flag to true).  If you can’t conform to GPL then you can still use FFTWBCB – set the GPL flag to false, and FFTWBCB will use the slower non-GPL FFT.  This means you can write code the same for GPL or non-GPL use; just be sure to set the GPL flag appropriately.  I’ll do more benchmarks soon, but for FFT sizes that are a power of two, the difference is probably two or three to one.  For FFT sizes that aren’t a power of two, the difference will be much higher – as much as a factor of a thousand or more, depending on the exact FFT size you are performing.

 

Installation: FFTWBCB must be installed after installing FFTW (available at www.fftw.org).  Two versions of FFTWBCB are provided -- one for BCB versions 5.0 and the other for BCB 6.0.  In either case unzip FFTWBCB into the FFTW directory.  That is, if you installed FFTW into directory c:\fftw-2.1.3 (for example), then you must unzip FFTWBCB into c:\fftw-2.1.3.  If you’ve done this correctly, you should then have a new “VCL” subdirectory under fftw-2.1.3.  Be sure to preserve path names when unzipping.

 

For BCB 5.0 load bcb5\FFTBCB.BPK.  Compile and install the component.  It should appear on the “Samples” component tab.

 

For BCB 6.0, load FFTWBCB6.bpg.  Right-click on fftbcb.bpl and select “install”, and do the same for fftbcbrw.bpl.  The reason for the two versions is that in BCB 6.0 Borland upgraded the STL libraries.  The changes were significant enough that some programs written under BCB 5.0 didn’t compile or run easily under BCB 6.0.  So Borland included a compiler directive “_USE_OLD_RW_STL” that made BCB 6.0 use the same STL as BCB 5.0.  Unfortunately, you can’t mix and match.  If you compiled FFTWBCB using the new STL, it couldn’t be used in a program that used the old STL, and vice versa.  So, two FFTWBCB versions are provided -- one using the old STL and one using the new.

 

Licensing, Liabilities, Warranties, etc.

First of all, note that the FFTW is issued under the Gnu Public License (GPL).  Software you write that uses FFTWBCB (and specifies “GPL = true” as described below) will then include FFTW.  If such software is distributed, it must abide by the GPL requirements as set forth in the GPL itself.

 

FFTWBCB (not including the FFTW code!) may be used any way you like, and may be copied and distributed without restrictions, but it is absolutely and entirely “as is” software, with no warranties of any kind.  Under no circumstances may the author or distributors of this software be held liable for any damages that occur for any reason related or unrelated to this software, its use or misuse, etc.  If you don’t agree to these restrictions, please don’t use the software.

 

 

 

FFTWBCB Functions and Properties

 

 

PROPERTIES:

 

TFFTDirection FFTDirection

 

TPlanType PlanType

This property sets the FFTW plan type.  See the FFTW documentation for more information.

 

TFFTWeighting FFTWeighting

 

 

int FFTDataSize:

This property defines the size of the data, ignoring “zero-padding”. Quite often an FFT is zero padded to a length longer than the input data.  If you’ve zero-padded your data, the weighting function must be applied to the actual data samples only – not to the zeros that you’ve added.  The FFTDataSize property defines the size of the data (and therefore the size of the weighting function).  It is also used in normalization.  Note that the size of the FFT itself is defined by the FFTW “plan”, which is defined in the CreatePlan function.  Also note that the size of the input array must be equal to the FFT size, not just the data size.  That is, if you want to zero-pad the input, the array you pass in to FFTWBCB must actually include the zeros.

 

float SidelobeLevel

The Taylor and Chebychev weighting functions both allow the specification of how low to drive the sidelobes.  The SidelobeLevel property lets you specify the sidelobe reductions.  SideLobe level should be a positive value, indicating the dB suppression the weighting function should provide.  Note that the weighting function may or may not achieve the specified level of sidelobe suppression, depending on the suppression requested and FFT or window sizes involved.

 

int TaylorN

Taylor weighting requires an additional parameter, usually just referred to as “N” in descriptions of Taylor weighting.  The TaylorN property lets you defined this parameter.

 

TNormalization Normalization

The output of the FFT often needs to be normalized.  Different Fourier Transform definitions provide for different normalizations.  By default the FFTW output is simply the sum of the product of the input and the complex exponential corresponding to the different frequencies the FFT evaluates.  Normalization is nothing more than a scale factor, and is obviously trivial to apply – just multiply all of the output values from the FFT by a given scale factor.  The only difficulty is in determining what scale factor to apply.  FFTWBCB provides a few common normalization factors – convenient if the factor you need is included:

 

 

In all of the normalization factors, “N” refers to the size of the FFT.  The normalization factor is a factor by which the data are multiplied by after performing the FFT.  If ConstantPower is specified, the sum of the squares of the input will equal the sum of the squares of the output.  If ConstantAmplitude is specified, a sine wave of amplitude one input will yield an FFT output of amplitude one (regardless of zero padding, but sidelobe reduction weighting functions will reduce the output amplitude).  If None (no weighting) is specified, then an input sine wave of amplitude one will produce an FFT output of amplitude equal to the number of input data points.  Normalization can be trickier than it might seem when doing zero-padding and/or sidelobe reduction.  When in doubt, I suggest you don’t use any normalization, (i.e. “Normalization = None”), and examine the input and output and determine what scaling factor makes sense for your application.

 

bool GPL

Set to true to use the (much) faster FFTW; set to false to use a non-GPL FFT.

 

 

 

FUNCTIONS:

 

bool CreatePlan(int N)

This initializes FFTWBCB to perform an FFT of size N.  This must be called before calling any of the FFT functions.

 

bool DestroyPlan()

Destroys the plan; see FFTW documentation.

 

FFT Functions:

The following functions all perform an FFT on the input array.  The functions with one parameter place the output of the FFT in the same array as the input; the versions with two parameters (“in” and “out”) put the output of the FFT in “out”, and do not modify the input array.

bool FFT(fftw_complex *in, fftw_complex *out)

bool FFT(complex<double> *in, complex<double> *out)

bool FFT(complex<float> *in, complex<float> *out)

bool FFT(fftw_complex *in)

bool FFT(complex<double> *in)

bool FFT(complex<float> *in)