TimeFreqFFTTest.c

Go to the documentation of this file.
00001 /*
00002 *  Copyright (C) 2007 Bernd Machenschalk, Duncan Brown, Jolien Creighton
00003 *
00004 *  This program is free software; you can redistribute it and/or modify
00005 *  it under the terms of the GNU General Public License as published by
00006 *  the Free Software Foundation; either version 2 of the License, or
00007 *  (at your option) any later version.
00008 *
00009 *  This program is distributed in the hope that it will be useful,
00010 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 *  GNU General Public License for more details.
00013 *
00014 *  You should have received a copy of the GNU General Public License
00015 *  along with with program; see the file COPYING. If not, write to the
00016 *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00017 *  MA  02111-1307  USA
00018 */
00019 
00020 /**** <lalVerbatim file="TimeFreqFFTTestCV">
00021  * $Id: TimeFreqFFTTest.c,v 1.9 2008/07/08 22:13:24 kipp Exp $
00022  **** </lalVerbatim> */
00023 
00024 /**** <lalLaTeX>
00025  * 
00026  * \subsection{Program \texttt{TimeFreqFFTTest.c}}
00027  * \label{ss:TimeFreqFFTTest.c}
00028  * 
00029  * Tests the routines in \verb+TimeFreqFFT.h+.
00030  * 
00031  * \subsection*{Usage}
00032  * \begin{verbatim}
00033  * TimeFreqFFTTest [options]
00034  * Options:
00035  *   -h         print this message
00036  *   -q         quiet: run silently
00037  *   -v         verbose: print extra information
00038  *   -d level   set lalDebugLevel to level
00039  * \end{verbatim}
00040  * 
00041  * \subsubsection*{Description}
00042  * \subsubsection*{Exit codes}
00043  * \begin{tabular}{|c|l|}
00044  * \hline
00045  * Code & Explanation                   \\
00046  * \hline
00047  * \tt 0 & Success, normal exit.         \\
00048  * \tt 1 & Subroutine failed.            \\
00049  * \tt 2 & PSD estimation tolerance exceeded \\
00050  * \hline
00051  * \end{tabular}
00052  * 
00053  * \subsubsection*{Uses}
00054  * \subsubsection*{Notes}
00055  * 
00056  * \vfill{\footnotesize\input{TimeFreqFFTTestCV}}
00057  * 
00058  **** </lalLaTeX> */
00059 
00060 #include <stdio.h>
00061 #include <stdlib.h>
00062 #include <math.h>
00063 
00064 #ifdef HAVE_UNISTD_H
00065 #include <unistd.h>
00066 #endif
00067 
00068 #include <lal/LALStdlib.h>
00069 #include <lal/LALConstants.h>
00070 #include <lal/LALStdio.h>
00071 #include <lal/AVFactories.h>
00072 #include <lal/Units.h>
00073 #include <lal/Random.h>
00074 #include <lal/PrintFTSeries.h>
00075 #include <lal/TimeFreqFFT.h>
00076 #include <lal/LALMoment.h>
00077 
00078 #include <lal/LALRCSID.h>
00079 NRCSID (TIMEFREQFFTTESTC,"$Id: TimeFreqFFTTest.c,v 1.9 2008/07/08 22:13:24 kipp Exp $");
00080 
00081 #define CODES_(x) #x
00082 #define CODES(x) CODES_(x)
00083 
00084 extern char *optarg;
00085 extern int   optind;
00086 
00087 int lalDebugLevel = 0;
00088 int verbose       = 0;
00089 
00090 static void
00091 Usage( const char *program, int exitflag );
00092 
00093 static void
00094 ParseOptions( int argc, char *argv[] );
00095 
00096 static void
00097 TestStatus( LALStatus *status, const char *expectedCodes, int exitCode );
00098 
00099 static void
00100 ClearStatus( LALStatus *status );
00101 
00102 
00103 int main( int argc, char *argv[] )
00104 {
00105   const UINT4 n  = 65536;
00106   const REAL4 dt = 1.0 / 16384.0;
00107   static LALStatus status;
00108 
00109   static REAL4TimeSeries         x;
00110   static COMPLEX8FrequencySeries X;
00111 
00112   static REAL4TimeSeries         y;
00113   static REAL4FrequencySeries    Y;
00114 
00115   static COMPLEX8TimeSeries      z;
00116   static COMPLEX8FrequencySeries Z;
00117 
00118   RealFFTPlan    *fwdRealPlan    = NULL;
00119   RealFFTPlan    *revRealPlan    = NULL;
00120   ComplexFFTPlan *fwdComplexPlan = NULL;
00121   ComplexFFTPlan *revComplexPlan = NULL;
00122   RandomParams   *randpar        = NULL;
00123 
00124   AverageSpectrumParams avgSpecParams;
00125 
00126   UINT4 srate[] = { 4096, 9000 };
00127   UINT4 npts[] = { 262144, 1048576 };
00128   REAL4 var[] = { 5, 16 };
00129 
00130   UINT4 j, sr, np, vr;
00131 
00132   CHAR fname[2048];
00133 
00134   ParseOptions( argc, argv );
00135 
00136   LALSCreateVector( &status, &x.data, n );
00137   TestStatus( &status, CODES( 0 ), 1 );
00138   LALCCreateVector( &status, &X.data, n / 2 + 1 );
00139   TestStatus( &status, CODES( 0 ), 1 );
00140 
00141   LALCCreateVector( &status, &z.data, n );
00142   TestStatus( &status, CODES( 0 ), 1 );
00143   LALCCreateVector( &status, &Z.data, n );
00144   TestStatus( &status, CODES( 0 ), 1 );
00145 
00146   LALCreateForwardRealFFTPlan( &status, &fwdRealPlan, n, 0 );
00147   TestStatus( &status, CODES( 0 ), 1 );
00148   LALCreateReverseRealFFTPlan( &status, &revRealPlan, n, 0 );
00149   TestStatus( &status, CODES( 0 ), 1 );
00150   LALCreateForwardComplexFFTPlan( &status, &fwdComplexPlan, n, 0 );
00151   TestStatus( &status, CODES( 0 ), 1 );
00152   LALCreateReverseComplexFFTPlan( &status, &revComplexPlan, n, 0 );
00153   TestStatus( &status, CODES( 0 ), 1 );
00154 
00155   LALCreateRandomParams( &status, &randpar, 100 );
00156   TestStatus( &status, CODES( 0 ), 1 );
00157 
00158 
00159   /*
00160    *
00161    * Try the real transform.
00162    *
00163    */
00164   
00165 
00166   x.f0 = 0;
00167   x.deltaT = dt;
00168   x.sampleUnits = lalMeterUnit;
00169   LALSnprintf( x.name, sizeof( x.name ), "x" );
00170   LALNormalDeviates( &status, x.data, randpar );
00171   TestStatus( &status, CODES( 0 ), 1 );
00172   for ( j = 0; j < n; ++j ) /* add a 60 Hz line */
00173   {
00174     REAL4 t = j * dt;
00175     x.data->data[j] += 0.1 * cos( LAL_TWOPI * 60.0 * t );
00176   }
00177   LALSPrintTimeSeries( &x, "x.out" );
00178 
00179   LALSnprintf( X.name, sizeof( X.name ), "X" );
00180   LALTimeFreqRealFFT( &status, &X, &x, fwdRealPlan );
00181   TestStatus( &status, CODES( 0 ), 1 );
00182   LALCPrintFrequencySeries( &X, "X.out" );
00183 
00184   LALFreqTimeRealFFT( &status, &x, &X, revRealPlan );
00185   TestStatus( &status, CODES( 0 ), 1 );
00186   LALSPrintTimeSeries( &x, "xx.out" );
00187 
00188 
00189   /*
00190    *
00191    * Try the average power spectum.
00192    *
00193    */
00194 
00195 
00196   avgSpecParams.method = useMean;
00197 
00198   for ( np = 0; np < sizeof(npts)/sizeof(*npts) ; ++np )
00199   {
00200     /* length of time series for 7 segments, overlapped by 1/2 segment */
00201     UINT4 tsLength = npts[np] * 7 - 6 * npts[np] / 2;
00202     LALCreateVector( &status, &y.data, tsLength );
00203     TestStatus( &status, CODES( 0 ), 1 );
00204     LALCreateVector( &status, &Y.data, npts[np] / 2 + 1  );
00205     TestStatus( &status, CODES( 0 ), 1 );
00206     avgSpecParams.overlap = npts[np] / 2;
00207 
00208     /* create the window */
00209     avgSpecParams.window = XLALCreateHannREAL4Window(npts[np]);
00210     avgSpecParams.plan = NULL;
00211     LALCreateForwardRealFFTPlan( &status, &avgSpecParams.plan, npts[np], 0 );
00212     TestStatus( &status, CODES( 0 ), 1 );
00213 
00214     for ( sr = 0; sr < sizeof(srate)/sizeof(*srate) ; ++sr )
00215     {
00216       /* set the sample rate of the time series */
00217       y.deltaT = 1.0 / (REAL8) srate[sr];
00218       for ( vr = 0; vr < sizeof(var)/sizeof(*var) ; ++vr )
00219       {
00220         REAL4 eps = 1e-6; /* very conservative fp precision */
00221         REAL4 Sfk = 2.0 * var[vr] * var[vr] * y.deltaT;
00222         REAL4 sfk = 0;
00223         REAL4 lbn;
00224         REAL4 sig;
00225         REAL4 ssq;
00226         REAL4 tol;
00227 
00228         /* create the data */
00229         LALNormalDeviates( &status, y.data, randpar );
00230         TestStatus( &status, CODES( 0 ), 1 );
00231         ssq = 0;
00232         for ( j = 0; j < y.data->length; ++j )
00233         {
00234           y.data->data[j] *= var[vr];
00235           ssq += y.data->data[j] * y.data->data[j];
00236         }
00237         
00238         /* compute tolerance for comparison */
00239         lbn = log( y.data->length ) / log( 2 );
00240         sig = sqrt( 2.5 * lbn * eps * eps * ssq / y.data->length );
00241         tol = 5 * sig;
00242         
00243         /* compute the psd and find the average */
00244         LALREAL4AverageSpectrum( &status, &Y, &y, &avgSpecParams );
00245         TestStatus( &status, CODES( 0 ), 1 );
00246         LALSMoment( &status, &sfk, Y.data, 1 );
00247         TestStatus( &status, CODES( 0 ), 1 );
00248 
00249         /* check the result */
00250         if ( fabs(Sfk-sfk) > tol )
00251         {
00252           fprintf( stderr, "FAIL: PSD estimate appears incorrect\n");
00253           fprintf( stderr, "expected %e, got %e ", Sfk, sfk );
00254           fprintf( stderr, "(difference = %e, tolerance = %e)\n", 
00255               fabs(Sfk-sfk), tol );
00256           exit(2);
00257         }
00258 
00259       }
00260     }
00261 
00262     /* destroy structures that need to be resized */
00263     LALDestroyRealFFTPlan( &status, &avgSpecParams.plan );
00264     TestStatus( &status, CODES( 0 ), 1 );
00265     XLALDestroyREAL4Window( avgSpecParams.window );
00266     LALDestroyVector( &status, &y.data );
00267     TestStatus( &status, CODES( 0 ), 1 );
00268     LALDestroyVector( &status, &Y.data );
00269     TestStatus( &status, CODES( 0 ), 1 );
00270   }
00271 
00272   
00273   /*
00274    *
00275    * Try the complex transform.
00276    *
00277    */
00278 
00279 
00280   z.f0 = 0;
00281   z.deltaT = dt;
00282   z.sampleUnits = lalVoltUnit;
00283   LALSnprintf( z.name, sizeof( z.name ), "z" );
00284   { /* dirty hack */
00285     REAL4Vector tmp;
00286     tmp.length = 2 * z.data->length;
00287     tmp.data   = (REAL4 *)z.data->data;
00288     LALNormalDeviates( &status, &tmp, randpar );
00289   }
00290   for ( j = 0; j < n; ++j ) /* add a 50 Hz line and a 500 Hz ringdown */
00291   {
00292     REAL4 t = j * dt;
00293     z.data->data[j].re += 0.2 * cos( LAL_TWOPI * 50.0 * t );
00294     z.data->data[j].im += exp( -t ) * sin( LAL_TWOPI * 500.0 * t );
00295   }
00296   LALCPrintTimeSeries( &z, "z.out" );
00297   TestStatus( &status, CODES( 0 ), 1 );
00298 
00299   LALSnprintf( Z.name, sizeof( Z.name ), "Z" );
00300   LALTimeFreqComplexFFT( &status, &Z, &z, fwdComplexPlan );
00301   TestStatus( &status, CODES( 0 ), 1 );
00302   LALCPrintFrequencySeries( &Z, "Z.out" );
00303 
00304   LALFreqTimeComplexFFT( &status, &z, &Z, revComplexPlan );
00305   TestStatus( &status, CODES( 0 ), 1 );
00306   LALCPrintTimeSeries( &z, "zz.out" );
00307 
00308   LALDestroyRandomParams( &status, &randpar );
00309   TestStatus( &status, CODES( 0 ), 1 );
00310 
00311   LALDestroyRealFFTPlan( &status, &fwdRealPlan );
00312   TestStatus( &status, CODES( 0 ), 1 );
00313   LALDestroyRealFFTPlan( &status, &revRealPlan );
00314   TestStatus( &status, CODES( 0 ), 1 );
00315   LALDestroyComplexFFTPlan( &status, &fwdComplexPlan );
00316   TestStatus( &status, CODES( 0 ), 1 );
00317   LALDestroyComplexFFTPlan( &status, &revComplexPlan );
00318   TestStatus( &status, CODES( 0 ), 1 );
00319 
00320   LALCDestroyVector( &status, &Z.data );
00321   TestStatus( &status, CODES( 0 ), 1 );
00322   LALCDestroyVector( &status, &z.data );
00323   TestStatus( &status, CODES( 0 ), 1 );
00324 
00325   LALCDestroyVector( &status, &X.data );
00326   TestStatus( &status, CODES( 0 ), 1 );
00327   LALSDestroyVector( &status, &x.data );
00328   TestStatus( &status, CODES( 0 ), 1 );
00329 
00330   LALCheckMemoryLeaks();
00331   return 0;
00332 }
00333 
00334 
00335 /*
00336  * TestStatus()
00337  *
00338  * Routine to check that the status code status->statusCode agrees with one of
00339  * the codes specified in the space-delimited string ignored; if not,
00340  * exit to the system with code exitcode.
00341  *
00342  */
00343 static void
00344 TestStatus( LALStatus *status, const char *ignored, int exitcode )
00345 {
00346   char  str[64];
00347   char *tok;
00348 
00349   if ( verbose )
00350   {
00351     REPORTSTATUS( status );
00352   }
00353 
00354   if ( strncpy( str, ignored, sizeof( str ) ) )
00355   {
00356     if ( (tok = strtok( str, " " ) ) )
00357     {
00358       do
00359       {
00360         if ( status->statusCode == atoi( tok ) )
00361         {
00362           return;
00363         }
00364       }
00365       while ( ( tok = strtok( NULL, " " ) ) );
00366     }
00367     else
00368     {
00369       if ( status->statusCode == atoi( tok ) )
00370       {
00371         return;
00372       }
00373     }
00374   }
00375 
00376   fprintf( stderr, "\nExiting to system with code %d\n", exitcode );
00377   exit( exitcode );
00378 }
00379 
00380 
00381 /*
00382  *
00383  * ClearStatus()
00384  *
00385  * Recursively applies DETATCHSTATUSPTR() to status structure to destroy
00386  * linked list of statuses.
00387  *
00388  */
00389 void
00390 ClearStatus( LALStatus *status )
00391 {
00392   if ( status->statusPtr )
00393   {
00394     ClearStatus( status->statusPtr );
00395     DETATCHSTATUSPTR( status );
00396   }
00397 }
00398 
00399 
00400 /*
00401  *
00402  * Usage()
00403  *
00404  * Prints a usage message for program program and exits with code exitcode.
00405  *
00406  */
00407 static void
00408 Usage( const char *program, int exitcode )
00409 {
00410   fprintf( stderr, "Usage: %s [options]\n", program );
00411   fprintf( stderr, "Options:\n" );
00412   fprintf( stderr, "  -h         print this message\n" );
00413   fprintf( stderr, "  -q         quiet: run silently\n" );
00414   fprintf( stderr, "  -v         verbose: print extra information\n" );
00415   fprintf( stderr, "  -d level   set lalDebugLevel to level\n" );
00416   exit( exitcode );
00417 }
00418 
00419 
00420 /*
00421  * ParseOptions()
00422  *
00423  * Parses the argc - 1 option strings in argv[].
00424  *
00425  */
00426 static void
00427 ParseOptions( int argc, char *argv[] )
00428 {
00429   while ( 1 )
00430   {
00431     int c = -1;
00432 
00433     c = getopt( argc, argv, "hqvd:" );
00434     if ( c == -1 )
00435     {
00436       break;
00437     }
00438 
00439     switch ( c )
00440     {
00441       case 'd': /* set debug level */
00442         lalDebugLevel = atoi( optarg );
00443         break;
00444 
00445       case 'v': /* verbose */
00446         ++verbose;
00447         break;
00448 
00449       case 'q': /* quiet: run silently (ignore error messages) */
00450         freopen( "/dev/null", "w", stderr );
00451         freopen( "/dev/null", "w", stdout );
00452         break;
00453 
00454       case 'h':
00455         Usage( argv[0], 0 );
00456         break;
00457 
00458       default:
00459         Usage( argv[0], 1 );
00460     }
00461 
00462   }
00463 
00464   if ( optind < argc )
00465   {
00466     Usage( argv[0], 1 );
00467   }
00468 
00469   return;
00470 }

Generated on Tue Oct 14 02:32:33 2008 for LAL by  doxygen 1.5.2