98char *option[N_OPTIONS] = {
116#define FL_TRUNCATE 0x0001
117#define FL_PADWITHZEROES 0x0002
118#define FL_NORMALIZE 0x0004
119#define FL_SUPPRESSAVERAGE 0x0008
120#define FL_FULLOUTPUT 0x0010
121#define FL_MAKEFREQDATA 0x0020
122#define FL_PSDOUTPUT 0x0040
123#define FL_PSDINTEGOUTPUT 0x0080
124#define FL_PSDRINTEGOUTPUT 0x0100
125#define FL_FULLOUTPUT_FOLDED 0x0200
126#define FL_FULLOUTPUT_UNFOLDED 0x0400
127#define FL_COMPLEXINPUT_FOLDED 0x0800
128#define FL_COMPLEXINPUT_UNFOLDED 0x1000
129#define FL_UNWRAP_PHASE 0x2000
131#define WINDOW_HANNING 0
132#define WINDOW_WELCH 1
133#define WINDOW_PARZEN 2
134#define WINDOW_HAMMING 3
135#define WINDOW_FLATTOP 4
136#define WINDOW_GAUSSIAN 5
138#define N_WINDOW_TYPES 7
139char *window_type[N_WINDOW_TYPES] = {
140 "hanning",
"welch",
"parzen",
"hamming",
"flattop",
"gaussian",
"none"};
145 " sddsfft [<inputfile>] [<outputfile>]\n"
146 " [-pipe=[input][,output]]\n"
147 " [-columns=<indep-variable>[,<depen-quantity>[,...]]]\n"
148 " [-complexInput[=unfolded|folded]]\n"
149 " [-exclude=<depen-quantity>[,...]]\n"
150 " [-window[={hanning|welch|parzen|hamming|flattop|gaussian|none}[,correct]]]\n"
151 " [-sampleInterval=<number>]\n"
153 " [-fullOutput[=unfolded|folded],unwrapLimit=<value>]\n"
154 " [-psdOutput[=plain][,{integrated|rintegrated[=<cutoff>]}]]\n"
156 " [-padwithzeroes[=exponent] | -truncate]\n"
157 " [-suppressaverage]\n"
159 " [-majorOrder=row|column]\n\n";
164 " Utilize the standard SDDS Toolkit pipe option for input and/or output.\n\n"
166 " Specify the independent variable and dependent quantities to Fourier analyze.\n"
167 " <depen-quantity> entries may include wildcards.\n\n"
169 " Indicate that input columns are complex, with names prefixed by Real and Imag.\n"
171 " folded (default): Input frequency space is folded.\n"
172 " unfolded : Input frequency space is unfolded and must include negative frequencies.\n"
173 " If omitted, the program checks the SpectrumFolded parameter in the input file.\n\n"
175 " Provide a list of wildcard patterns to exclude specific quantities from analysis.\n\n"
177 " Apply a windowing function to the data before analysis.\n"
178 " Available types:\n"
179 " hanning, welch, parzen, hamming, flattop, gaussian, none\n"
180 " Adding ',correct' applies a correction factor to preserve the integrated PSD.\n"
181 " Default: hanning.\n\n"
183 " Sample the input data points at the specified interval.\n\n"
185 " Normalize the output to have a peak magnitude of 1.\n\n"
187 " Output the real and imaginary parts of the FFT.\n"
189 " folded (default): Outputs the half FFT spectrum.\n"
190 " unfolded : Outputs the full FFT spectrum.\n"
191 " Adding ',unwrapLimit=<value>' computes and outputs the unwrapped phase where the relative magnitude exceeds the limit.\n\n"
193 " Output the Power Spectral Density (PSD).\n"
195 " plain : Outputs the standard PSD.\n"
196 " integrated : Outputs the integrated PSD.\n"
197 " rintegrated=<cutoff> : Outputs the reverse-integrated PSD with an optional cutoff frequency.\n"
198 " Multiple options can be combined using commas.\n\n"
200 " Perform an inverse Fourier transform. The output will always be an unfolded spectrum.\n"
201 " If combined with -fullOutput=folded, it overrides to -fullOutput=unfolded.\n\n"
203 " Pad data with zeroes to optimize FFT performance.\n"
204 " Optionally specify an exponent to determine the padding size as 2^(original points * exponent).\n"
206 " Truncate data to the nearest product of small prime numbers to reduce runtime.\n"
207 " Note: Only one of -padwithzeroes or -truncate can be used.\n\n"
208 " -suppressaverage\n"
209 " Remove the average value from the data before performing the FFT.\n\n"
211 " Suppress all warning messages.\n\n"
213 " Specify the output file's data order:\n"
214 " row : Row-major order.\n"
215 " column : Column-major order.\n\n"
216 "Program by Michael Borland. (" __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
")\n";
222int64_t greatestProductOfSmallPrimes(int64_t rows);
224 char *depenQuantity,
char *depenQuantity2,
unsigned long flags,
long windowType,
225 int64_t sampleInterval,
long correctWindowEffects,
long inverse,
double rintegCutOffFreq,
double unwrapLimit);
226long create_fft_frequency_column(
SDDS_DATASET *SDDSout,
SDDS_DATASET *SDDSin,
char *timeName,
char *freqUnits,
long inverse);
229 char *freqUnits,
long full_output,
unsigned long psd_output,
long complexInput,
long inverse,
long unwrap_phase);
231char *makeFrequencyUnits(
SDDS_DATASET *SDDSin,
char *indepName);
232long expandComplexColumnPairNames(
SDDS_DATASET *SDDSin,
char **name,
char ***realName,
char ***imagName,
233 long names,
char **excludeName,
long excludeNames,
long typeMode,
long typeValue);
235int main(
int argc,
char **argv) {
238 char *indepQuantity, **depenQuantity, **exclude, **realQuan = NULL, **imagQuan = NULL;
239 long depenQuantities, excludes;
240 char *input, *output;
241 long i, readCode, noWarnings, complexInput, inverse, spectrumFoldParExist = 0;
242 int64_t rows, rowsToUse, sampleInterval;
243 int32_t spectrumFolded = 0, page = 0;
244 unsigned long flags, pipeFlags, complexInputFlags = 0, fullOutputFlags = 0, majorOrderFlag;
245 long windowType = -1;
246 SCANNED_ARG *scanned;
248 double *tdata, rintegCutOffFreq, unwrapLimit = 0;
249 long padFactor, correctWindowEffects = 0;
250 short columnMajorOrder = -1;
253 argc =
scanargs(&scanned, argc, argv);
254 if (argc < 3 || argc > (3 + N_OPTIONS)) {
255 fprintf(stderr,
"%s%s", USAGE1, USAGE2);
259 rintegCutOffFreq = 0;
260 output = input = NULL;
261 flags = pipeFlags = excludes = complexInput = inverse = 0;
263 indepQuantity = NULL;
264 depenQuantity = exclude = NULL;
268 for (iArg = 1; iArg < argc; iArg++) {
269 if (scanned[iArg].arg_type == OPTION) {
271 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
273 flags |= FL_NORMALIZE;
276 if (scanned[iArg].n_items != 1) {
277 if ((i =
match_string(scanned[iArg].list[1], window_type, N_WINDOW_TYPES, 0)) < 0)
280 if (scanned[iArg].n_items > 2) {
281 if (strncmp(scanned[iArg].list[2],
"correct", strlen(scanned[iArg].list[2])) == 0)
282 correctWindowEffects = 1;
289 case SET_PADWITHZEROES:
290 flags |= FL_PADWITHZEROES;
291 if (scanned[iArg].n_items != 1) {
292 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1],
"%ld", &padFactor) != 1 || padFactor < 1)
293 SDDS_Bomb(
"invalid -padwithzeroes syntax");
297 flags |= FL_TRUNCATE;
299 case SET_SUPPRESSAVERAGE:
300 flags |= FL_SUPPRESSAVERAGE;
302 case SET_SAMPLEINTERVAL:
303 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1],
"%" SCNd64, &sampleInterval) != 1 || sampleInterval <= 0)
304 SDDS_Bomb(
"invalid -sampleinterval syntax");
308 SDDS_Bomb(
"only one -columns option may be given");
309 if (scanned[iArg].n_items < 2)
311 indepQuantity = scanned[iArg].list[1];
312 if (scanned[iArg].n_items >= 2) {
313 depenQuantity =
tmalloc(
sizeof(*depenQuantity) * (depenQuantities = scanned[iArg].n_items - 2));
314 for (i = 0; i < depenQuantities; i++)
315 depenQuantity[i] = scanned[iArg].list[i + 2];
319 flags |= FL_FULLOUTPUT;
320 if (scanned[iArg].n_items >= 2) {
321 scanned[iArg].n_items--;
322 if (!
scanItemList(&fullOutputFlags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
"folded", -1, NULL, 0, FL_FULLOUTPUT_FOLDED,
"unfolded", -1, NULL, 0, FL_FULLOUTPUT_UNFOLDED,
"unwrapLimit",
SDDS_DOUBLE, &unwrapLimit, 0, FL_UNWRAP_PHASE, NULL))
324 scanned[iArg].n_items++;
325 if (fullOutputFlags & FL_FULLOUTPUT_UNFOLDED)
326 flags |= FL_FULLOUTPUT_UNFOLDED;
328 flags |= FL_FULLOUTPUT_FOLDED;
329 if (fullOutputFlags & FL_UNWRAP_PHASE)
330 flags |= FL_UNWRAP_PHASE;
334 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
338 if (scanned[iArg].n_items -= 1) {
339 unsigned long tmpFlags;
340 if (strchr(scanned[iArg].list[1],
'=') <= 0) {
341 if (!
scanItemList(&tmpFlags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
"integrated", -1, NULL, 0, FL_PSDINTEGOUTPUT,
"rintegrated", -1, NULL, 0, FL_PSDRINTEGOUTPUT,
"plain", -1, NULL, 0, FL_PSDOUTPUT, NULL))
344 if (!
scanItemList(&tmpFlags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
"integrated", -1, NULL, 0, FL_PSDINTEGOUTPUT,
"rintegrated",
SDDS_DOUBLE, &rintegCutOffFreq, 0, FL_PSDRINTEGOUTPUT,
"plain", -1, NULL, 0, FL_PSDOUTPUT, NULL))
349 flags |= FL_PSDOUTPUT;
350 if (flags & FL_PSDINTEGOUTPUT && flags & FL_PSDRINTEGOUTPUT)
351 SDDS_Bomb(
"invalid -psdOutput syntax: give only one of integrated or rintegrated");
354 if (scanned[iArg].n_items < 2)
356 moveToStringArray(&exclude, &excludes, scanned[iArg].list + 1, scanned[iArg].n_items - 1);
361 case SET_COMPLEXINPUT:
363 if (scanned[iArg].n_items == 2) {
364 scanned[iArg].n_items--;
365 if (!
scanItemList(&complexInputFlags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
"folded", -1, NULL, 0, FL_COMPLEXINPUT_FOLDED,
"unfolded", -1, NULL, 0, FL_COMPLEXINPUT_UNFOLDED, NULL))
366 SDDS_Bomb(
"Invalid -complexInput syntax");
367 scanned[iArg].n_items++;
373 case SET_MAJOR_ORDER:
375 scanned[iArg].n_items--;
376 if (scanned[iArg].n_items > 0 && (!
scanItemList(&majorOrderFlag, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
"row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
"column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
377 SDDS_Bomb(
"invalid -majorOrder syntax/values");
378 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
379 columnMajorOrder = 1;
380 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
381 columnMajorOrder = 0;
384 fprintf(stderr,
"error: unknown/ambiguous option: %s\n", scanned[iArg].list[0]);
390 input = scanned[iArg].list[0];
392 output = scanned[iArg].list[0];
398 if (!noWarnings && inverse)
399 fprintf(stderr,
"Warning: the inverse option is ignored since it only works with -complexInput.\n");
402 if (!noWarnings && inverse && flags & FL_FULLOUTPUT_FOLDED)
403 fprintf(stderr,
"Warning: the -inverse -fullOutput=folded will be changed to -inverse -fullOutput=unfolded.\n");
408 SDDS_Bomb(
"Supply the independent quantity name with the -columns option.");
410 if (flags & FL_TRUNCATE && flags & FL_PADWITHZEROES)
411 SDDS_Bomb(
"Specify only one of -padwithzeroes and -truncate.");
419 excludes = appendToStringArray(&exclude, excludes, indepQuantity);
420 if (!depenQuantities)
421 depenQuantities = appendToStringArray(&depenQuantity, depenQuantities,
"*");
424 if ((depenQuantities = expandColumnPairNames(&SDDSin, &depenQuantity, NULL, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
426 SDDS_Bomb(
"No quantities selected to FFT.");
429 if ((depenQuantities = expandComplexColumnPairNames(&SDDSin, depenQuantity, &realQuan, &imagQuan, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
431 SDDS_Bomb(
"No quantities selected to FFT.");
436 fprintf(stderr,
"%ld dependent quantities:\n", depenQuantities);
437 for (i = 0; i < depenQuantities; i++)
438 fprintf(stderr,
" %s\n", depenQuantity[i]);
441 if (!(freqUnits = makeFrequencyUnits(&SDDSin, indepQuantity)) ||
443 !create_fft_frequency_column(&SDDSout, &SDDSin, indepQuantity, freqUnits, inverse) ||
447 if (columnMajorOrder != -1)
448 SDDSout.layout.data_mode.column_major = columnMajorOrder;
450 SDDSout.layout.data_mode.column_major = SDDSin.layout.data_mode.column_major;
455 if (!complexInputFlags) {
457 spectrumFoldParExist = 1;
458 }
else if (complexInputFlags & FL_COMPLEXINPUT_UNFOLDED)
459 flags |= FL_COMPLEXINPUT_UNFOLDED;
461 flags |= FL_COMPLEXINPUT_FOLDED;
463 for (i = 0; i < depenQuantities; i++) {
465 create_fft_columns(&SDDSout, &SDDSin, depenQuantity[i], indepQuantity, freqUnits,
466 flags & FL_FULLOUTPUT,
467 flags & (FL_PSDOUTPUT + FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT),
468 0, inverse, flags & FL_UNWRAP_PHASE);
470 create_fft_columns(&SDDSout, &SDDSin, realQuan[i], indepQuantity, freqUnits,
471 flags & FL_FULLOUTPUT,
472 flags & (FL_PSDOUTPUT + FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT),
473 1, inverse, flags & FL_UNWRAP_PHASE);
484 if (page == 1 && spectrumFoldParExist) {
488 flags |= FL_COMPLEXINPUT_FOLDED;
490 flags |= FL_COMPLEXINPUT_UNFOLDED;
493 int64_t primeRows, pow2Rows;
495 primeRows = greatestProductOfSmallPrimes(rows);
496 if (rows != primeRows || padFactor) {
497 if (flags & FL_PADWITHZEROES) {
498 pow2Rows =
ipow(2., ((int64_t)(log((
double)rows) / log(2.0F))) + (padFactor ? padFactor : 1.0));
499 if ((primeRows = greatestProductOfSmallPrimes(pow2Rows)) > rows)
500 rowsToUse = primeRows;
502 rowsToUse = pow2Rows;
503 }
else if (flags & FL_TRUNCATE)
504 rowsToUse = greatestProductOfSmallPrimes(rows);
506 fputs(
"Warning: number of points has large prime factors.\nThis could take a very long time.\nConsider using the -truncate option.\n", stderr);
512 for (i = 0; i < depenQuantities; i++)
513 if (!process_data(&SDDSout, &SDDSin, tdata, rows, rowsToUse,
514 complexInput ? realQuan[i] : depenQuantity[i],
515 complexInput ? imagQuan[i] : NULL,
516 flags | (i == 0 ? FL_MAKEFREQDATA : 0),
517 windowType, sampleInterval, correctWindowEffects, inverse,
518 rintegCutOffFreq, unwrapLimit)) {
543static long psdOffset, argOffset, realOffset, imagOffset, fftOffset = -1, psdIntOffset, psdIntPowerOffset, unwrappedArgOffset = -1;
546 int64_t rowsToUse,
char *depenQuantity,
char *imagQuantity,
unsigned long flags,
long windowType,
547 int64_t sampleInterval,
long correctWindowEffects,
long inverse,
double rintegCutOffFreq,
double unwrapLimit) {
548 long offset, index, unfold = 0;
549 int64_t n_freq, i, fftrows = 0;
550 double r, r1, r2, length, factor, df, min, max, delta;
551 double *real, *imag, *magData, *arg = NULL, *real_imag, *data, *psd = NULL, *psdInteg = NULL, *psdIntegPower = NULL, *unwrapArg = NULL, phase_correction = 0;
552 double dtf_real, dtf_imag, t0;
554 double *fdata, *imagData = NULL;
555 double *tDataStore = NULL;
556 double windowCorrectionFactor = 0;
562 if (flags & FL_SUPPRESSAVERAGE) {
564 for (i = 0; i < rows; i++)
568 for (i = 0; i < rows; i++)
572 if (rows < rowsToUse) {
574 tDataStore =
tmalloc(
sizeof(*tDataStore) * rowsToUse);
575 memcpy((
char *)tDataStore, (
char *)tdata, rows *
sizeof(*tdata));
576 if (!(data =
SDDS_Realloc(data,
sizeof(*data) * rowsToUse)))
578 if (imagData && !(imagData =
SDDS_Realloc(imagData,
sizeof(*imagData) * rowsToUse)))
579 length = ((double)rows) * (tdata[rows - 1] - tdata[0]) / ((double)rows - 1.0);
581 length = tdata[rows - 1] - tdata[0];
582 for (i = rows; i < rowsToUse; i++) {
583 tDataStore[i] = tDataStore[i - 1] + length / ((double)rows - 1);
587 for (i = rows; i < rowsToUse; i++)
592 windowCorrectionFactor = 0;
593 switch (windowType) {
595 r = PIx2 / (rows - 1);
596 for (i = 0; i < rows; i++) {
597 factor = (1 - cos(i * r)) / 2;
599 windowCorrectionFactor += sqr(factor);
601 imagData[i] *= factor;
605 r = PIx2 / (rows - 1);
606 for (i = 0; i < rows; i++) {
607 factor = 0.54 - 0.46 * cos(i * r);
609 windowCorrectionFactor += sqr(factor);
611 imagData[i] *= factor;
614 for (i = 0; i < rows; i++)
615 imagData[i] *= (1 - cos(i * r)) / 2;
618 r1 = (rows - 1) / 2.0;
619 r2 = sqr((rows + 1) / 2.0);
620 for (i = 0; i < rows; i++) {
621 factor = 1 - sqr(i - r1) / r2;
623 windowCorrectionFactor += sqr(factor);
625 imagData[i] *= factor;
629 r = (rows - 1) / 2.0;
630 for (i = 0; i < rows; i++) {
631 factor = 1 - FABS((i - r) / r);
633 windowCorrectionFactor += sqr(factor);
635 imagData[i] *= factor;
639 for (i = 0; i < rows; i++) {
640 r = i * PIx2 / (rows - 1);
641 factor = 1 - 1.93 * cos(r) + 1.29 * cos(2 * r) - 0.388 * cos(3 * r) + 0.032 * cos(4 * r);
643 windowCorrectionFactor += sqr(factor);
645 imagData[i] *= factor;
648 case WINDOW_GAUSSIAN:
649 for (i = 0; i < rows; i++) {
650 r = sqr((i - (rows - 1) / 2.) / (0.4 * (rows - 1) / 2.)) / 2;
653 windowCorrectionFactor += sqr(factor);
655 imagData[i] *= factor;
660 windowCorrectionFactor = 1;
664 if (correctWindowEffects) {
666 windowCorrectionFactor = 1 / sqrt(windowCorrectionFactor / rows);
667 for (i = 0; i < rows; i++)
668 data[i] *= windowCorrectionFactor;
670 imagData[i] *= windowCorrectionFactor;
672 if (imagData && flags & FL_COMPLEXINPUT_FOLDED) {
673 double min, max, max1;
675 imagData =
SDDS_Realloc(imagData,
sizeof(*data) * rows * 2);
677 if (fabs(min) > fabs(max))
682 if (fabs(min) > max1)
684 if (fabs(max) > max1)
686 if (fabs(imagData[rows - 1]) / max1 < 1.0e-15) {
687 fftrows = 2 * (rows - 1);
688 for (i = 1; i < rows - 1; i++) {
689 data[i] = data[i] / 2.0;
690 imagData[i] = imagData[i] / 2.0;
692 for (i = 1; i < rows - 1; i++) {
693 data[rows - 1 + i] = data[rows - 1 - i];
694 imagData[rows - 1 + i] = -imagData[rows - 1 - i];
696 length = (tdata[rows - 1] - tdata[0]) * 2.0;
698 fftrows = 2 * (rows - 1) + 1;
699 for (i = 1; i < rows; i++) {
700 data[i] = data[i] / 2.0;
701 imagData[i] = imagData[i] / 2.0;
703 for (i = 0; i < rows - 1; i++) {
704 data[rows + i] = data[rows - 1 - i];
705 imagData[rows + i] = -imagData[rows - 1 - i];
707 length = ((double)fftrows) * (tdata[rows - 1] - tdata[0]) / ((double)fftrows - 1.0) * 2;
711 length = ((double)rows) * (tdata[rows - 1] - tdata[0]) / ((double)rows - 1.0);
715 real_imag =
tmalloc(
sizeof(
double) * (2 * fftrows + 2));
716 for (i = 0; i < fftrows; i++) {
717 real_imag[2 * i] = data[i];
719 real_imag[2 * i + 1] = imagData[i];
721 real_imag[2 * i + 1] = 0;
724 complexFFT(real_imag, fftrows, 0);
725 if (flags & FL_FULLOUTPUT_UNFOLDED) {
728 }
else if (flags & FL_FULLOUTPUT_FOLDED)
729 n_freq = fftrows / 2 + 1;
731 n_freq = fftrows / 2 + 1;
733 n_freq = fftrows + 1;
735 complexFFT(real_imag, fftrows, INVERSE_FFT);
743 df = factor = 1.0 / length;
746 real =
tmalloc(
sizeof(
double) * n_freq);
747 imag =
tmalloc(
sizeof(
double) * n_freq);
748 fdata =
tmalloc(
sizeof(
double) * n_freq);
749 magData =
tmalloc(
sizeof(
double) * n_freq);
750 if (flags & FL_PSDOUTPUT || flags & (FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT)) {
751 psd =
tmalloc(
sizeof(*psd) * n_freq);
752 if (flags & (FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT)) {
753 psdInteg =
tmalloc(
sizeof(*psdInteg) * n_freq);
754 psdIntegPower =
tmalloc(
sizeof(*psdIntegPower) * n_freq);
758 for (i = 0; i < n_freq; i++) {
760 dtf_real = cos(-2 * PI * fdata[i] * t0);
761 dtf_imag = sin(-2 * PI * fdata[i] * t0);
763 psd[i] = (sqr(real_imag[2 * i]) + sqr(real_imag[2 * i + 1])) / df;
764 if (!imagData && i != 0 && !(i == (n_freq - 1) && rows % 2 == 0)) {
770 real_imag[2 * i] *= 2;
771 real_imag[2 * i + 1] *= 2;
776 real[i] = real_imag[2 * i] * dtf_real - real_imag[2 * i + 1] * dtf_imag;
777 imag[i] = real_imag[2 * i + 1] * dtf_real + real_imag[2 * i] * dtf_imag;
778 magData[i] = sqrt(sqr(real[i]) + sqr(imag[i]));
782 if (flags & FL_PSDINTEGOUTPUT) {
783 psdIntegPower[0] = 0;
784 for (i = 1; i < n_freq; i++)
785 psdIntegPower[i] = psdIntegPower[i - 1] + (psd[i - 1] + psd[i]) * df / 2.;
786 for (i = 0; i < n_freq; i++)
787 psdInteg[i] = sqrt(psdIntegPower[i]);
789 psdIntegPower[n_freq - 1] = 0;
790 for (i = n_freq - 2; i >= 0; i--) {
791 if (rintegCutOffFreq == 0 || fdata[i] <= rintegCutOffFreq)
792 psdIntegPower[i] = psdIntegPower[i + 1] + (psd[i + 1] + psd[i]) * df / 2.;
794 for (i = 0; i < n_freq; i++)
795 psdInteg[i] = sqrt(psdIntegPower[i]);
799 if (flags & FL_FULLOUTPUT) {
800 arg =
tmalloc(
sizeof(*arg) * n_freq);
801 for (i = 0; i < n_freq; i++) {
802 if (real[i] || imag[i])
803 arg[i] = 180.0 / PI * atan2(imag[i], real[i]);
808 if (flags & FL_UNWRAP_PHASE) {
810 unwrapArg =
tmalloc(
sizeof(*unwrapArg) * n_freq);
811 phase_correction = 0;
812 for (i = 0; i < n_freq; i++) {
813 if (i && magData[i] / max > unwrapLimit) {
814 delta = arg[i] - arg[i - 1];
816 phase_correction += 360.0;
817 else if (delta > 180.0)
818 phase_correction -= 360.0;
820 unwrapArg[i] = arg[i] + phase_correction;
824 if (flags & FL_NORMALIZE) {
826 for (i = 0; i < n_freq; i++)
827 if (magData[i] > factor)
829 if (factor != -DBL_MAX)
830 for (i = 0; i < n_freq; i++) {
833 magData[i] /= factor;
837 sprintf(s,
"FFT%s", depenQuantity + (imagData ? 4 : 0));
839 if (strncmp(depenQuantity,
"FFT", 3) == 0)
840 sprintf(s,
"%s", depenQuantity + 3);
841 else if (strncmp(depenQuantity,
"RealFFT", 7) == 0)
842 sprintf(s,
"%s", depenQuantity + 7);
844 sprintf(s,
"%s", depenQuantity);
850 if (flags & FL_SUPPRESSAVERAGE) {
856 if ((flags & FL_MAKEFREQDATA &&
857 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, fdata + offset, n_freq, 0)) ||
858 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, magData + offset, n_freq, index + fftOffset) ||
859 (flags & FL_FULLOUTPUT &&
860 (!
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, real + offset, n_freq, index + realOffset) ||
861 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, imag + offset, n_freq, index + imagOffset) ||
862 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, arg + offset, n_freq, index + argOffset))) ||
863 (flags & FL_PSDOUTPUT &&
864 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, psd + offset, n_freq, index + psdOffset)) ||
865 (flags & (FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT) && (!
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, psdInteg + offset, n_freq, index + psdIntOffset) ||
866 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, psdIntegPower + offset, n_freq, index + psdIntPowerOffset))) ||
867 (flags & FL_UNWRAP_PHASE && !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, unwrapArg + offset, n_freq, index + unwrappedArgOffset)))
869 if (sampleInterval > 0) {
870 int32_t *sample_row_flag;
871 sample_row_flag = calloc(
sizeof(*sample_row_flag), n_freq);
872 for (i = 0; i < n_freq; i += sampleInterval)
873 sample_row_flag[i] = 1;
878 free(sample_row_flag);
880 if (!
SDDS_SetParameters(SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE,
"fftFrequencies", n_freq,
"fftFrequencySpacing", df, NULL))
882 if (flags & FL_FULLOUTPUT && !
SDDS_SetParameters(SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE,
"SpectrumFolded", flags & FL_FULLOUTPUT_UNFOLDED ? 0 : 1, NULL))
907long create_fft_frequency_column(
SDDS_DATASET *SDDSout,
SDDS_DATASET *SDDSin,
char *timeName,
char *freqUnits,
long inverse) {
908 char s[SDDS_MAXLINE];
917 sprintf(s,
"Frequency for %s", timeSymbol);
926 sprintf(s,
"inverse for %s", timeSymbol);
939long 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 unwrap_phase) {
940 char s[SDDS_MAXLINE];
941 char *origUnits, *origSymbol;
942 char *description, *name, *symbol, *units;
952 sprintf(s,
"FFT%s", origName + offset);
954 if (strncmp(origName,
"FFT", 3) == 0)
956 else if (strncmp(origName,
"RealFFT", 7) == 0)
960 sprintf(s,
"%s", origName + offset);
965 sprintf(s,
"FFT %s", origSymbol);
968 sprintf(s,
"Amplitude of FFT of %s", origSymbol);
980 if (psd_output & FL_PSDOUTPUT) {
983 sprintf(s,
"(%s)$a2$n/(%s)", origUnits, freqUnits);
985 sprintf(s,
"(%s)$a2$n", origUnits);
990 sprintf(s,
"PSD%s", origName + offset);
995 sprintf(s,
"PSD %s", origSymbol);
998 sprintf(s,
"PSD of %s", origSymbol);
1003 psdOffset = index1 - index0;
1011 if (psd_output & (FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT)) {
1017 sprintf(s,
"SqrtIntegPSD%s", origName + offset);
1022 sprintf(s,
"Sqrt Integ PSD %s", origSymbol);
1025 sprintf(s,
"Sqrt Integ PSD of %s", origSymbol);
1030 psdIntOffset = index1 - index0;
1032 sprintf(s,
"IntegPSD%s", origName + offset);
1037 sprintf(s,
"Integ PSD %s", origSymbol);
1040 sprintf(s,
"Integ PSD of %s", origSymbol);
1044 sprintf(s,
"%sPower", origUnits);
1051 psdIntPowerOffset = index1 - index0;
1061 sprintf(s,
"RealFFT%s", origName + offset);
1063 sprintf(s,
"Real%s", origName + offset);
1069 sprintf(s,
"Re[FFT %s]", origSymbol);
1071 sprintf(s,
"Re[%s]", origSymbol);
1075 sprintf(s,
"Real part of FFT of %s", origSymbol);
1077 sprintf(s,
"Real part of %s", origSymbol);
1082 realOffset = index1 - index0;
1088 sprintf(s,
"ImagFFT%s", origName + offset);
1090 sprintf(s,
"Imag%s", origName + offset);
1096 sprintf(s,
"Im[FFT %s]", origSymbol);
1098 sprintf(s,
"Im[%s]", origSymbol);
1102 sprintf(s,
"Imaginary part of FFT of %s", origSymbol);
1104 sprintf(s,
"Imaginary part of %s", origSymbol);
1109 imagOffset = index1 - index0;
1115 sprintf(s,
"ArgFFT%s", origName + offset);
1117 sprintf(s,
"Arg%s", origName + offset);
1123 sprintf(s,
"Arg[FFT %s]", origSymbol);
1125 sprintf(s,
"Arg[%s]", origSymbol);
1129 sprintf(s,
"Phase of FFT of %s", origSymbol);
1131 sprintf(s,
"Phase of %s", origSymbol);
1136 argOffset = index1 - index0;
1142 sprintf(s,
"UnwrapArgFFT%s", origName + offset);
1144 sprintf(s,
"UnwrapArg%s", origName + offset);
1150 sprintf(s,
"UnwrapArg[FFT %s]", origSymbol);
1152 sprintf(s,
"UnwrapArg[%s]", origSymbol);
1156 sprintf(s,
"Unwrapped Phase of FFT of %s", origSymbol);
1158 sprintf(s,
"Unwrapped Phase of %s", origSymbol);
1163 unwrappedArgOffset = index1 - index0;
1173void moveToStringArrayComplex(
char ***targetReal,
char ***targetImag,
long *targets,
char **sourceReal,
char **sourceImag,
long sources);
1175long expandComplexColumnPairNames(
SDDS_DATASET *SDDSin,
char **name,
char ***realName,
char ***imagName,
long names,
char **excludeName,
long excludeNames,
long typeMode,
long typeValue) {
1176 long i, j, k, realNames, imagNames, names2;
1177 char **realName1, **imagName1, **realName2, **imagName2;
1178 char *realPattern, *imagPattern = NULL;
1181 if (!names || !name)
1183 realName1 = imagName1 = realName2 = imagName2 = NULL;
1184 realNames = imagNames = names2 = 0;
1185 for (i = 0; i < names; i++) {
1186 if (strlen(name[i]) > longest)
1187 longest = strlen(name[i]);
1190 if (!(realPattern =
SDDS_Malloc(
sizeof(*realPattern) * longest)) || !(imagPattern =
SDDS_Malloc(
sizeof(*imagPattern) * longest)))
1193 for (i = 0; i < names; i++) {
1194 for (j = 0; j < 2; j++) {
1196 sprintf(realPattern,
"Real%s", name[i]);
1197 sprintf(imagPattern,
"Imag%s", name[i]);
1199 sprintf(realPattern,
"%sReal", name[i]);
1200 sprintf(imagPattern,
"%sImag", name[i]);
1204 case FIND_NUMERIC_TYPE:
1205 case FIND_INTEGER_TYPE:
1206 case FIND_FLOATING_TYPE:
1207 realNames =
SDDS_MatchColumns(SDDSin, &realName1, SDDS_MATCH_STRING, typeMode, realPattern, SDDS_0_PREVIOUS | SDDS_OR);
1208 imagNames =
SDDS_MatchColumns(SDDSin, &imagName1, SDDS_MATCH_STRING, typeMode, imagPattern, SDDS_0_PREVIOUS | SDDS_OR);
1210 case FIND_SPECIFIED_TYPE:
1212 SDDS_Bomb(
"invalid type value in expandColumnPairNames");
1213 realNames =
SDDS_MatchColumns(SDDSin, &realName1, SDDS_MATCH_STRING, typeMode, typeValue, realPattern, SDDS_0_PREVIOUS | SDDS_OR);
1214 imagNames =
SDDS_MatchColumns(SDDSin, &imagName1, SDDS_MATCH_STRING, typeMode, typeValue, imagPattern, SDDS_0_PREVIOUS | SDDS_OR);
1217 SDDS_Bomb(
"invalid typeMode in expandColumnPairNames");
1223 if (realNames == -1 || imagNames == -1) {
1225 SDDS_Bomb(
"unable to perform column name match in expandColumnPairNames");
1227 if (realNames != imagNames)
1228 SDDS_Bomb(
"found different number of real and imaginary columns");
1230 for (j = 0; j < excludeNames; j++)
1231 for (k = 0; k < realNames; k++)
1232 if (
wild_match(realName1[k], excludeName[j])) {
1235 imagName1[k] = realName1[k] = NULL;
1238 moveToStringArrayComplex(&realName2, &imagName2, &names2, realName1, imagName1, realNames);
1247 *realName = realName2;
1248 *imagName = imagName2;
1252void moveToStringArrayComplex(
char ***targetReal,
char ***targetImag,
long *targets,
char **sourceReal,
char **sourceImag,
long sources) {
1256 if (!(*targetReal =
SDDS_Realloc(*targetReal,
sizeof(**targetReal) * (*targets + sources))) ||
1257 !(*targetImag =
SDDS_Realloc(*targetImag,
sizeof(**targetImag) * (*targets + sources))))
1259 for (i = 0; i < sources; i++) {
1260 if (sourceReal[i] == NULL || sourceImag[i] == NULL)
1262 for (j = 0; j < *targets; j++)
1263 if (strcmp(sourceReal[i], (*targetReal)[j]) == 0)
1265 if (j == *targets) {
1266 (*targetReal)[j] = sourceReal[i];
1267 (*targetImag)[j] = sourceImag[i];
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_SetParameters(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
int32_t SDDS_SetColumn(SDDS_DATASET *SDDS_dataset, int32_t mode, void *data, int64_t rows,...)
Sets the values for one data column in the current data table of an SDDS dataset.
int32_t SDDS_GetColumnInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Retrieves information about a specified column in the SDDS dataset.
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
int32_t SDDS_DefineColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length)
Defines a data column within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_DefineParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, char *fixed_value)
Defines a data parameter with a fixed string value.
int32_t SDDS_TransferAllParameterDefinitions(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, uint32_t mode)
Transfers all parameter definitions from a source dataset to a target dataset.
int32_t SDDS_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named column in the SDDS dataset.
int32_t SDDS_CheckColumn(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a column exists in the SDDS dataset with the specified name, units, and type.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
void * SDDS_Malloc(size_t size)
Allocates memory of a specified size.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
int32_t SDDS_NumberOfErrors()
Retrieves the number of errors recorded by SDDS library routines.
int32_t SDDS_StringIsBlank(char *s)
Checks if a string is blank (contains only whitespace characters).
int32_t SDDS_MatchColumns(SDDS_DATASET *SDDS_dataset, char ***nameReturn, int32_t matchMode, int32_t typeMode,...)
Matches and retrieves column names from an SDDS dataset based on specified criteria.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
int32_t SDDS_CheckParameter(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a parameter exists in the SDDS dataset with the specified name, units, and type.
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
#define SDDS_VALID_TYPE(type)
Validates whether the given type identifier is within the defined range of SDDS types.
#define SDDS_STRING
Identifier for the string data type.
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
#define SDDS_ANY_NUMERIC_TYPE
Special identifier used by SDDS_Check*() routines to accept any numeric type.
#define SDDS_DOUBLE
Identifier for the double data type.
Utility functions for SDDS dataset manipulation and string array operations.
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
int64_t largest_prime_factor(int64_t number)
Find the largest prime factor of a number.
int find_min_max(double *min, double *max, double *list, int64_t n)
Finds the minimum and maximum values in a list of doubles.
double ipow(const double x, const int64_t p)
Compute x raised to the power p (x^p).
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
long processPipeOption(char **item, long items, unsigned long *flags)
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items and assigns values based on provided keywords and types.
int wild_match(char *string, char *template)
Determine whether one string is a wildcard match for another.