/*************************************************************************\ * Copyright (c) 2002 The University of Chicago, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * This file is distributed subject to a Software License Agreement found * in the file LICENSE that is included with this distribution. \*************************************************************************/ /* program: sddsfft * purpose: SDDS-format fft program * * Michael Borland, 1994 * based on mpl-format fft program $Log: sddsfft.c,v $ Revision 1.36 2010/06/11 17:10:06 borland Added more window types. Revision 1.35 2008/09/15 14:42:00 shang updated usage message, and added warning messages for inverse option Revision 1.34 2008/09/10 19:07:45 shang added inverse option, and added folded and unfolded suboptions to complexInput and fullOutput options. Revision 1.33 2006/12/14 22:21:58 soliday Updated a bunch of programs because SDDS_SaveLayout is now called by SDDS_WriteLayout and it is no longer required to be called directly. Also the AutoCheckMode is turned off by default now so I removed calls to SDDS_SetAutoCheckMode that would attempt to turn it off. It is now up to the programmer to turn it on in new programs until debugging is completed and then remove the call to SDDS_SetAutoCheckMode. Revision 1.32 2005/10/10 19:13:15 borland Added optional correction factors for windowed data. Revision 1.31 2003/10/20 16:17:25 borland Fixed error in phase computation. Was using atan2(x, y) when I should have used atan2(y, x). Revision 1.30 2003/09/02 19:16:04 soliday Cleaned up code for Linux. Revision 1.29 2003/03/27 22:56:13 soliday Fixed output message that should not be set to stderr Revision 1.28 2002/08/14 17:12:46 soliday Added Open License Revision 1.27 2002/01/22 15:40:21 borland Previous changes resulted in changed behavior for -padwithzeroes option. It now behaves as before it the exponent value is not given. Updated the usage message. Revision 1.26 2002/01/20 17:49:45 borland The pad option now accepts an integer specifying extra padding beyond the minimum necessary (as a power of 2). Revision 1.25 2001/10/25 21:59:09 borland makeFrequencyUnits() and greatestProductOfSmallPrimes() are not in SDDSutil.c Revision 1.24 2001/05/08 19:33:01 emery variable length was not defined for padding. Revision 1.23 2001/05/07 16:14:45 emery Fixed sign error for time shifting term. Revision 1.22 2001/05/03 21:29:19 soliday Split usage message because of limits on WIN32. Revision 1.21 2001/04/06 20:06:36 borland Added ability to perform FFTs of complex input. Revision 1.20 2001/04/04 18:16:46 borland Fixed problem with truncation. Was still truncating to power of two in data processing but writing out truncation for power of primes. Revision 1.19 2001/01/10 19:35:38 soliday Standardized usage message. Revision 1.18 2000/11/27 14:58:33 borland Fixed memory leak. Revision 1.17 2000/11/21 17:17:36 soliday Added missing SDDS_Terminate procedures. Revision 1.16 2000/04/13 18:03:11 soliday Removed invalid prototypes. Revision 1.15 2000/04/13 17:10:34 soliday Added missing include statment. Revision 1.14 1999/11/23 16:46:11 borland Updated the usage message. Revision 1.13 1999/10/29 20:05:52 borland The -truncate option now truncates to a product of small primes between 2 and 19. Revision 1.12 1999/09/14 18:31:27 soliday dp_pad_with_zeroes and realFFT2 are no longer defined locally Revision 1.11 1999/07/14 14:15:43 borland Changed the names for the integrated PSD output. Was IntegSqrtPSD..., but should have been SqrtIntegPSD... Revision 1.10 1999/05/25 19:10:20 soliday Removed compiler warning on linux. Revision 1.9 1999/01/07 17:00:47 borland Added option for reverse integral to psdOutput. Revision 1.8 1999/01/06 19:54:44 borland Fixed the version number in the usage message. Revision 1.7 1998/12/16 21:26:02 borland Brought up to date with new version of SDDS_TransferAllParameters. Now correctly transfers through parameters, but overwrites them if it needs to do so. Revision 1.6 1998/11/13 22:39:51 borland Now copies through parameters from the input to the output. Revision 1.5 1998/10/08 18:21:03 borland Added qualifiers to -psdOutput option: plain, integrated. plain is just the PSD as before. integrated gives Integ{Sqrt{PSD}}. Revision 1.4 1998/06/03 01:35:32 borland Added -nowarning option. * Revision 1.3 1995/09/06 14:56:28 saunders * First test release of SDDS1.5 * */ #include "mdb.h" #include "SDDS.h" #include "scan.h" #include "fftpackC.h" #include "SDDSutils.h" #include #define SET_WINDOW 0 #define SET_NORMALIZE 1 #define SET_PADWITHZEROES 2 #define SET_TRUNCATE 3 #define SET_SUPPRESSAVERAGE 4 #define SET_SAMPLEINTERVAL 5 #define SET_COLUMNS 6 #define SET_FULLOUTPUT 7 #define SET_PIPE 8 #define SET_PSDOUTPUT 9 #define SET_EXCLUDE 10 #define SET_NOWARNINGS 11 #define SET_COMPLEXINPUT 12 #define SET_INVERSE 13 #define N_OPTIONS 14 char *option[N_OPTIONS] = { "window", "normalize", "padwithzeroes", "truncate", "suppressaverage", "sampleinterval", "columns", "fulloutput", "pipe", "psdoutput", "exclude", "nowarnings", "complexinput", "inverse", }; #define FL_TRUNCATE 0x0008 #define FL_PADWITHZEROES 0x0010 #define FL_NORMALIZE 0x0020 #define FL_SUPPRESSAVERAGE 0x0040 #define FL_FULLOUTPUT 0x0080 #define FL_MAKEFREQDATA 0x0100 #define FL_PSDOUTPUT 0x0200 #define FL_PSDINTEGOUTPUT 0x0400 #define FL_PSDRINTEGOUTPUT 0x0800 #define FL_FULLOUTPUT_FOLDED 0x1000 #define FL_FULLOUTPUT_UNFOLDED 0x2000 #define FL_COMPLEXINPUT_FOLDED 0x4000 #define FL_COMPLEXINPUT_UNFOLDED 0x8000 #define WINDOW_HANNING 0 #define WINDOW_WELCH 1 #define WINDOW_PARZEN 2 #define WINDOW_HAMMING 3 #define WINDOW_FLATTOP 4 #define WINDOW_GAUSSIAN 5 #define N_WINDOW_TYPES 6 char *window_type[N_WINDOW_TYPES] = { "hanning", "welch", "parzen", "hamming", "flattop", "gaussian", } ; static char *USAGE1="sddsfft [] []\n\ [-pipe=[input][,output]]\n\ [-columns=[,[,...]]] \n\ [-complexInput[=unfolded|folded]] [-exclude=[,...]]\n\ [-window[={hanning|welch|parzen|hamming|flattop|gaussian}[,correct]]] \n\ [-sampleInterval=] [-normalize] [-fullOutput[=unfolded|folded]]\n\ [-psdOutput[=plain][,{integrated|rintegrated}]] [-inverse]\n\ [-padwithzeroes[=exponent] | -truncate] [-suppressaverage] [-noWarnings]\n\n\ -pipe The standard SDDS Toolkit pipe option.\n\ -columns Provides the name of the independent variable \n\ and the data to Fourier analyze. \n\ entries may contain wildcards.\n\ -complexInput Specifies that the names of the input columns are\n\ of the form Real and Imag, giving\n\ the real and imaginary part of a function to be analyzed.\n\ In this case, the entries in the -columns\n\ option give the rootname, not the full quantity name.\n\ It has options folded and unfolded, unfolded means the input frequency \n\ space input is unfolded and it must have negative frequency.\n\ default is \"folded\", If no option is given, and if the input file\n\ has \"SpectrumFolded\" parameter, then it will be defined by this parameter.\n\ -inverse produce inverse fourier transform. when it is given, the output is\n\ always unfolded spectrum. so -fullOutput=folded will be changed to -fullOutput=unfoled.\n\ -exclude Specifies a list of wild-card patterns to use in excluding\n\ quantities from analysis.\n"; static char *USAGE2="-window Requests windowing of data prior to analysis. The default\n\ window is Hanning. If the \"correct\" qualifier is given, the signal\n\ is also multiplied by a correction factor to ensure that the integrated\n\ PSD is unchanged by the window.\n\ -sampleInterval Requests sampling of the input data points with the given interval.\n\ -normalize Specifies normalization of the output to a peak magnitude of 1.\n\ -fullOutput Requests output of the real and imaginary parts of the FFT.\n\ it also has folded and unfolded options, while the unfolded option \n\ outputs the unfolded freqeuncy-space (full FFT), but the folded option \n\ outputs the folded frequency-space (half FFT). default is folded. \n\ -psdOutput Requests output of the Power Spectral Density. By default, the\n\ \"plain\" PSD output is included. Giving the integrated or\n\ rintegrated qualifier substitutes the integrated or reverse-\n\ integrated PSD. Giving the \"plain\" qualifier in addition\n\ gives both.\n\ -padWithZeroes Requests padding of the data with zeroes if the number of data \n\ points is not a product of small prime numbers. May substantially\n\ reducing run time. If exponent is given, the padding takes place\n\ of the original number of points. The number of data points used\n\ is the nearest power of 2 to the original number of points, times\n\ 2^(exponent).\n\ -truncate Requests truncation of the data if the number of data points is\n\ not a product of small prime numbers. May substantially reduce run\n\ time.\n\ -suppressAverage Specifies that the average value of the data should be removed\n\ prior to taking the FFT.\n\ -noWarnings Suppresses warning messages.\n\n\ Program by Michael Borland. (This is version 10, January 2002.)\n"; long greatestProductOfSmallPrimes(long rows); long process_data(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, double *tdata, long rows, long rowsToUse, char *depenQuantity, char *depenQuantity2, unsigned long flags, long windowType, long sampleInterval, long correctWindowEffects, long inverse); long create_fft_frequency_column(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, char *timeName, char *freqUnits, long inverse); long create_fft_columns(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, char *origName, char *indepName, char *freqUnits, long full_output, unsigned long psd_output, long complexInput, long inverse); long create_fft_parameters(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, char *indepName, char *freqUnits); char *makeFrequencyUnits(SDDS_DATASET *SDDSin, char *indepName); long expandComplexColumnPairNames(SDDS_DATASET *SDDSin, char **name, char ***realName, char ***imagName, long names, char **excludeName, long excludeNames, long typeMode, long typeValue); int main(int argc, char **argv) { int iArg; char *freqUnits; char *indepQuantity, **depenQuantity, **exclude, **realQuan, **imagQuan; long depenQuantities, excludes; char *input, *output; long sampleInterval, i, rows, readCode, rowsToUse, noWarnings, complexInput, inverse, spectrumFoldParExist=0, spectrumFolded=0, page=0; unsigned long flags, pipeFlags, complexInputFlags=0, fullOutputFlags=0; long windowType = -1; SCANNED_ARG *scanned; SDDS_DATASET SDDSin, SDDSout; double *tdata; long padFactor, correctWindowEffects=0; SDDS_RegisterProgramName(argv[0]); argc = scanargs(&scanned, argc, argv); if (argc<3 || argc>(3+N_OPTIONS)) { fprintf(stderr, "%s%s", USAGE1, USAGE2); exit(1); /* bomb(NULL, USAGE);*/ } output = input = NULL; flags = pipeFlags = excludes = complexInput = inverse = 0; sampleInterval = 1; indepQuantity = NULL; depenQuantity = exclude = NULL; depenQuantities = 0; noWarnings = 0; padFactor = 0; for (iArg=1; iArg2) { if (strncmp(scanned[iArg].list[2], "correct", strlen(scanned[iArg].list[2]))==0) correctWindowEffects = 1; else SDDS_Bomb("invalid -window syntax"); } } else windowType = 0; break; case SET_PADWITHZEROES: flags |= FL_PADWITHZEROES; if (scanned[iArg].n_items!=1) { if (scanned[iArg].n_items!=2 || sscanf(scanned[iArg].list[1], "%ld", &padFactor)!=1 || padFactor<1) SDDS_Bomb("invalid -padwithzeroes syntax"); } break; case SET_TRUNCATE: flags |= FL_TRUNCATE; break; case SET_SUPPRESSAVERAGE: flags |= FL_SUPPRESSAVERAGE; break; case SET_SAMPLEINTERVAL: if (scanned[iArg].n_items!=2 || sscanf(scanned[iArg].list[1], "%ld", &sampleInterval)!=1 || sampleInterval<=0) SDDS_Bomb("invalid -sampleinterval syntax"); break; case SET_COLUMNS: if (indepQuantity) SDDS_Bomb("only one -columns option may be given"); if (scanned[iArg].n_items<2) SDDS_Bomb("invalid -columns syntax"); indepQuantity = scanned[iArg].list[1]; if (scanned[iArg].n_items>=2) { depenQuantity = tmalloc(sizeof(*depenQuantity)*(depenQuantities=scanned[iArg].n_items-2)); for (i=0; i0) { page ++; if ((rows = SDDS_CountRowsOfInterest(&SDDSin))<0) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); if (page==1 && spectrumFoldParExist) { if (!SDDS_GetParameterAsLong(&SDDSin, "SpectrumFolded", &spectrumFolded)) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); if (spectrumFolded) flags |= FL_COMPLEXINPUT_FOLDED; else flags |= FL_COMPLEXINPUT_UNFOLDED; } if (rows) { long primeRows, pow2Rows; rowsToUse = rows; primeRows = greatestProductOfSmallPrimes(rows); if (rows!=primeRows || padFactor) { if (flags&FL_PADWITHZEROES) { pow2Rows = ipow(2., ((long)(log((double)rows)/log(2.0F))) + (padFactor?padFactor:1.0) ); if ((primeRows = greatestProductOfSmallPrimes(pow2Rows))>rows) rowsToUse = primeRows; else rowsToUse = pow2Rows; fprintf(stdout, "Using %ld rows\n", rowsToUse); } else if (flags&FL_TRUNCATE) rowsToUse = greatestProductOfSmallPrimes(rows); else if (largest_prime_factor(rows)>100 && !noWarnings) fputs("Warning: number of points has large prime factors.\nThis could take a very long time.\nConsider using the -truncate option.\n", stderr); } if (!SDDS_StartPage(&SDDSout, 2*rowsToUse+2) || !SDDS_CopyParameters(&SDDSout, &SDDSin)) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); if (!(tdata = SDDS_GetColumnInDoubles(&SDDSin, indepQuantity))) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); for (i=0; irowsToUse */ if (flags&FL_SUPPRESSAVERAGE) { compute_average(&r, data, rows); for (i=0; ifabs(max)) max1 = fabs(min); else max1 = fabs(max); find_min_max(&min, &max, imagData, rows); if (fabs(min)>max1) max1 = fabs(min); if (fabs(max)>max1) max1 = fabs(max); if (fabs(imagData[rows-1])/max1<1.0e-15) { fftrows = 2 * (rows-1); for (i=1; i=0; i--) psdInteg[i] = psdInteg[i+1] + (psd[i+1]+psd[i])*df/2.; for (i=0; ifactor) factor = magData[i]; if (factor!= -DBL_MAX) for (i=0; ilongest) longest = strlen(name[i]); } longest += 10; if (!(realPattern = SDDS_Malloc(sizeof(*realPattern)*longest)) || !(imagPattern = SDDS_Malloc(sizeof(*imagPattern)*longest))) SDDS_Bomb("memory allocation failure"); for (i=0; i