66char *option[N_OPTIONS] = {
84#define FL_TRUNCATE 0x0001
85#define FL_PADWITHZEROES 0x0002
86#define FL_NORMALIZE 0x0004
87#define FL_SUPPRESSAVERAGE 0x0008
88#define FL_FULLOUTPUT 0x0010
89#define FL_MAKEFREQDATA 0x0020
90#define FL_PSDOUTPUT 0x0040
91#define FL_PSDINTEGOUTPUT 0x0080
92#define FL_PSDRINTEGOUTPUT 0x0100
93#define FL_FULLOUTPUT_FOLDED 0x0200
94#define FL_FULLOUTPUT_UNFOLDED 0x0400
95#define FL_COMPLEXINPUT_FOLDED 0x0800
96#define FL_COMPLEXINPUT_UNFOLDED 0x1000
97#define FL_UNWRAP_PHASE 0x2000
99#define WINDOW_HANNING 0
100#define WINDOW_WELCH 1
101#define WINDOW_PARZEN 2
102#define WINDOW_HAMMING 3
103#define WINDOW_FLATTOP 4
104#define WINDOW_GAUSSIAN 5
106#define N_WINDOW_TYPES 7
107char *window_type[N_WINDOW_TYPES] = {
108 "hanning",
"welch",
"parzen",
"hamming",
"flattop",
"gaussian",
"none"};
113 " sddsfft [<inputfile>] [<outputfile>]\n"
114 " [-pipe=[input][,output]]\n"
115 " [-columns=<indep-variable>[,<depen-quantity>[,...]]]\n"
116 " [-complexInput[=unfolded|folded]]\n"
117 " [-exclude=<depen-quantity>[,...]]\n"
118 " [-window[={hanning|welch|parzen|hamming|flattop|gaussian|none}[,correct]]]\n"
119 " [-sampleInterval=<number>]\n"
121 " [-fullOutput[=unfolded|folded],unwrapLimit=<value>]\n"
122 " [-psdOutput[=plain][,{integrated|rintegrated[=<cutoff>]}]]\n"
124 " [-padwithzeroes[=exponent] | -truncate]\n"
125 " [-suppressaverage]\n"
127 " [-majorOrder=row|column]\n\n";
132 " Utilize the standard SDDS Toolkit pipe option for input and/or output.\n\n"
134 " Specify the independent variable and dependent quantities to Fourier analyze.\n"
135 " <depen-quantity> entries may include wildcards.\n\n"
137 " Indicate that input columns are complex, with names prefixed by Real and Imag.\n"
139 " folded (default): Input frequency space is folded.\n"
140 " unfolded : Input frequency space is unfolded and must include negative frequencies.\n"
141 " If omitted, the program checks the SpectrumFolded parameter in the input file.\n\n"
143 " Provide a list of wildcard patterns to exclude specific quantities from analysis.\n\n"
145 " Apply a windowing function to the data before analysis.\n"
146 " Available types:\n"
147 " hanning, welch, parzen, hamming, flattop, gaussian, none\n"
148 " Adding ',correct' applies a correction factor to preserve the integrated PSD.\n"
149 " Default: hanning.\n\n"
151 " Sample the input data points at the specified interval.\n\n"
153 " Normalize the output to have a peak magnitude of 1.\n\n"
155 " Output the real and imaginary parts of the FFT.\n"
157 " folded (default): Outputs the half FFT spectrum.\n"
158 " unfolded : Outputs the full FFT spectrum.\n"
159 " Adding ',unwrapLimit=<value>' computes and outputs the unwrapped phase where the relative magnitude exceeds the limit.\n\n"
161 " Output the Power Spectral Density (PSD).\n"
163 " plain : Outputs the standard PSD.\n"
164 " integrated : Outputs the integrated PSD.\n"
165 " rintegrated=<cutoff> : Outputs the reverse-integrated PSD with an optional cutoff frequency.\n"
166 " Multiple options can be combined using commas.\n\n"
168 " Perform an inverse Fourier transform. The output will always be an unfolded spectrum.\n"
169 " If combined with -fullOutput=folded, it overrides to -fullOutput=unfolded.\n\n"
171 " Pad data with zeroes to optimize FFT performance.\n"
172 " Optionally specify an exponent to determine the padding size as 2^(original points * exponent).\n"
174 " Truncate data to the nearest product of small prime numbers to reduce runtime.\n"
175 " Note: Only one of -padwithzeroes or -truncate can be used.\n\n"
176 " -suppressaverage\n"
177 " Remove the average value from the data before performing the FFT.\n\n"
179 " Suppress all warning messages.\n\n"
181 " Specify the output file's data order:\n"
182 " row : Row-major order.\n"
183 " column : Column-major order.\n\n"
184 "Program by Michael Borland. (" __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
")\n";
190int64_t greatestProductOfSmallPrimes(int64_t rows);
192 char *depenQuantity,
char *depenQuantity2,
unsigned long flags,
long windowType,
193 int64_t sampleInterval,
long correctWindowEffects,
long inverse,
double rintegCutOffFreq,
double unwrapLimit);
194long create_fft_frequency_column(
SDDS_DATASET *SDDSout,
SDDS_DATASET *SDDSin,
char *timeName,
char *freqUnits,
long inverse);
197 char *freqUnits,
long full_output,
unsigned long psd_output,
long complexInput,
long inverse,
long unwrap_phase);
199char *makeFrequencyUnits(
SDDS_DATASET *SDDSin,
char *indepName);
200long expandComplexColumnPairNames(
SDDS_DATASET *SDDSin,
char **name,
char ***realName,
char ***imagName,
201 long names,
char **excludeName,
long excludeNames,
long typeMode,
long typeValue);
203int main(
int argc,
char **argv) {
206 char *indepQuantity, **depenQuantity, **exclude, **realQuan = NULL, **imagQuan = NULL;
207 long depenQuantities, excludes;
208 char *input, *output;
209 long i, readCode, noWarnings, complexInput, inverse, spectrumFoldParExist = 0;
210 int64_t rows, rowsToUse, sampleInterval;
211 int32_t spectrumFolded = 0, page = 0;
212 unsigned long flags, pipeFlags, complexInputFlags = 0, fullOutputFlags = 0, majorOrderFlag;
213 long windowType = -1;
214 SCANNED_ARG *scanned;
216 double *tdata, rintegCutOffFreq, unwrapLimit = 0;
217 long padFactor, correctWindowEffects = 0;
218 short columnMajorOrder = -1;
221 argc =
scanargs(&scanned, argc, argv);
222 if (argc < 3 || argc > (3 + N_OPTIONS)) {
223 fprintf(stderr,
"%s%s", USAGE1, USAGE2);
227 rintegCutOffFreq = 0;
228 output = input = NULL;
229 flags = pipeFlags = excludes = complexInput = inverse = 0;
231 indepQuantity = NULL;
232 depenQuantity = exclude = NULL;
236 for (iArg = 1; iArg < argc; iArg++) {
237 if (scanned[iArg].arg_type == OPTION) {
239 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
241 flags |= FL_NORMALIZE;
244 if (scanned[iArg].n_items != 1) {
245 if ((i =
match_string(scanned[iArg].list[1], window_type, N_WINDOW_TYPES, 0)) < 0)
248 if (scanned[iArg].n_items > 2) {
249 if (strncmp(scanned[iArg].list[2],
"correct", strlen(scanned[iArg].list[2])) == 0)
250 correctWindowEffects = 1;
257 case SET_PADWITHZEROES:
258 flags |= FL_PADWITHZEROES;
259 if (scanned[iArg].n_items != 1) {
260 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1],
"%ld", &padFactor) != 1 || padFactor < 1)
261 SDDS_Bomb(
"invalid -padwithzeroes syntax");
265 flags |= FL_TRUNCATE;
267 case SET_SUPPRESSAVERAGE:
268 flags |= FL_SUPPRESSAVERAGE;
270 case SET_SAMPLEINTERVAL:
271 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1],
"%" SCNd64, &sampleInterval) != 1 || sampleInterval <= 0)
272 SDDS_Bomb(
"invalid -sampleinterval syntax");
276 SDDS_Bomb(
"only one -columns option may be given");
277 if (scanned[iArg].n_items < 2)
279 indepQuantity = scanned[iArg].list[1];
280 if (scanned[iArg].n_items >= 2) {
281 depenQuantity =
tmalloc(
sizeof(*depenQuantity) * (depenQuantities = scanned[iArg].n_items - 2));
282 for (i = 0; i < depenQuantities; i++)
283 depenQuantity[i] = scanned[iArg].list[i + 2];
287 flags |= FL_FULLOUTPUT;
288 if (scanned[iArg].n_items >= 2) {
289 scanned[iArg].n_items--;
290 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))
292 scanned[iArg].n_items++;
293 if (fullOutputFlags & FL_FULLOUTPUT_UNFOLDED)
294 flags |= FL_FULLOUTPUT_UNFOLDED;
296 flags |= FL_FULLOUTPUT_FOLDED;
297 if (fullOutputFlags & FL_UNWRAP_PHASE)
298 flags |= FL_UNWRAP_PHASE;
302 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
306 if (scanned[iArg].n_items -= 1) {
307 unsigned long tmpFlags;
308 if (strchr(scanned[iArg].list[1],
'=') <= 0) {
309 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))
312 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))
317 flags |= FL_PSDOUTPUT;
318 if (flags & FL_PSDINTEGOUTPUT && flags & FL_PSDRINTEGOUTPUT)
319 SDDS_Bomb(
"invalid -psdOutput syntax: give only one of integrated or rintegrated");
322 if (scanned[iArg].n_items < 2)
324 moveToStringArray(&exclude, &excludes, scanned[iArg].list + 1, scanned[iArg].n_items - 1);
329 case SET_COMPLEXINPUT:
331 if (scanned[iArg].n_items == 2) {
332 scanned[iArg].n_items--;
333 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))
334 SDDS_Bomb(
"Invalid -complexInput syntax");
335 scanned[iArg].n_items++;
341 case SET_MAJOR_ORDER:
343 scanned[iArg].n_items--;
344 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)))
345 SDDS_Bomb(
"invalid -majorOrder syntax/values");
346 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
347 columnMajorOrder = 1;
348 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
349 columnMajorOrder = 0;
352 fprintf(stderr,
"error: unknown/ambiguous option: %s\n", scanned[iArg].list[0]);
358 input = scanned[iArg].list[0];
360 output = scanned[iArg].list[0];
366 if (!noWarnings && inverse)
367 fprintf(stderr,
"Warning: the inverse option is ignored since it only works with -complexInput.\n");
370 if (!noWarnings && inverse && flags & FL_FULLOUTPUT_FOLDED)
371 fprintf(stderr,
"Warning: the -inverse -fullOutput=folded will be changed to -inverse -fullOutput=unfolded.\n");
376 SDDS_Bomb(
"Supply the independent quantity name with the -columns option.");
378 if (flags & FL_TRUNCATE && flags & FL_PADWITHZEROES)
379 SDDS_Bomb(
"Specify only one of -padwithzeroes and -truncate.");
387 excludes = appendToStringArray(&exclude, excludes, indepQuantity);
388 if (!depenQuantities)
389 depenQuantities = appendToStringArray(&depenQuantity, depenQuantities,
"*");
392 if ((depenQuantities = expandColumnPairNames(&SDDSin, &depenQuantity, NULL, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
394 SDDS_Bomb(
"No quantities selected to FFT.");
397 if ((depenQuantities = expandComplexColumnPairNames(&SDDSin, depenQuantity, &realQuan, &imagQuan, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
399 SDDS_Bomb(
"No quantities selected to FFT.");
404 fprintf(stderr,
"%ld dependent quantities:\n", depenQuantities);
405 for (i = 0; i < depenQuantities; i++)
406 fprintf(stderr,
" %s\n", depenQuantity[i]);
409 if (!(freqUnits = makeFrequencyUnits(&SDDSin, indepQuantity)) ||
411 !create_fft_frequency_column(&SDDSout, &SDDSin, indepQuantity, freqUnits, inverse) ||
415 if (columnMajorOrder != -1)
416 SDDSout.layout.data_mode.column_major = columnMajorOrder;
418 SDDSout.layout.data_mode.column_major = SDDSin.layout.data_mode.column_major;
423 if (!complexInputFlags) {
425 spectrumFoldParExist = 1;
426 }
else if (complexInputFlags & FL_COMPLEXINPUT_UNFOLDED)
427 flags |= FL_COMPLEXINPUT_UNFOLDED;
429 flags |= FL_COMPLEXINPUT_FOLDED;
431 for (i = 0; i < depenQuantities; i++) {
433 create_fft_columns(&SDDSout, &SDDSin, depenQuantity[i], indepQuantity, freqUnits,
434 flags & FL_FULLOUTPUT,
435 flags & (FL_PSDOUTPUT + FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT),
436 0, inverse, flags & FL_UNWRAP_PHASE);
438 create_fft_columns(&SDDSout, &SDDSin, realQuan[i], indepQuantity, freqUnits,
439 flags & FL_FULLOUTPUT,
440 flags & (FL_PSDOUTPUT + FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT),
441 1, inverse, flags & FL_UNWRAP_PHASE);
452 if (page == 1 && spectrumFoldParExist) {
456 flags |= FL_COMPLEXINPUT_FOLDED;
458 flags |= FL_COMPLEXINPUT_UNFOLDED;
461 int64_t primeRows, pow2Rows;
463 primeRows = greatestProductOfSmallPrimes(rows);
464 if (rows != primeRows || padFactor) {
465 if (flags & FL_PADWITHZEROES) {
466 pow2Rows =
ipow(2., ((int64_t)(log((
double)rows) / log(2.0F))) + (padFactor ? padFactor : 1.0));
467 if ((primeRows = greatestProductOfSmallPrimes(pow2Rows)) > rows)
468 rowsToUse = primeRows;
470 rowsToUse = pow2Rows;
471 }
else if (flags & FL_TRUNCATE)
472 rowsToUse = greatestProductOfSmallPrimes(rows);
474 fputs(
"Warning: number of points has large prime factors.\nThis could take a very long time.\nConsider using the -truncate option.\n", stderr);
480 for (i = 0; i < depenQuantities; i++)
481 if (!process_data(&SDDSout, &SDDSin, tdata, rows, rowsToUse,
482 complexInput ? realQuan[i] : depenQuantity[i],
483 complexInput ? imagQuan[i] : NULL,
484 flags | (i == 0 ? FL_MAKEFREQDATA : 0),
485 windowType, sampleInterval, correctWindowEffects, inverse,
486 rintegCutOffFreq, unwrapLimit)) {
511static long psdOffset, argOffset, realOffset, imagOffset, fftOffset = -1, psdIntOffset, psdIntPowerOffset, unwrappedArgOffset = -1;
514 int64_t rowsToUse,
char *depenQuantity,
char *imagQuantity,
unsigned long flags,
long windowType,
515 int64_t sampleInterval,
long correctWindowEffects,
long inverse,
double rintegCutOffFreq,
double unwrapLimit) {
516 long offset, index, unfold = 0;
517 int64_t n_freq, i, fftrows = 0;
518 double r, r1, r2, length, factor, df, min, max, delta;
519 double *real, *imag, *magData, *arg = NULL, *real_imag, *data, *psd = NULL, *psdInteg = NULL, *psdIntegPower = NULL, *unwrapArg = NULL, phase_correction = 0;
520 double dtf_real, dtf_imag, t0;
522 double *fdata, *imagData = NULL;
523 double *tDataStore = NULL;
524 double windowCorrectionFactor = 0;
530 if (flags & FL_SUPPRESSAVERAGE) {
532 for (i = 0; i < rows; i++)
536 for (i = 0; i < rows; i++)
540 if (rows < rowsToUse) {
542 tDataStore =
tmalloc(
sizeof(*tDataStore) * rowsToUse);
543 memcpy((
char *)tDataStore, (
char *)tdata, rows *
sizeof(*tdata));
544 if (!(data =
SDDS_Realloc(data,
sizeof(*data) * rowsToUse)))
546 if (imagData && !(imagData =
SDDS_Realloc(imagData,
sizeof(*imagData) * rowsToUse)))
547 length = ((double)rows) * (tdata[rows - 1] - tdata[0]) / ((double)rows - 1.0);
549 length = tdata[rows - 1] - tdata[0];
550 for (i = rows; i < rowsToUse; i++) {
551 tDataStore[i] = tDataStore[i - 1] + length / ((double)rows - 1);
555 for (i = rows; i < rowsToUse; i++)
560 windowCorrectionFactor = 0;
561 switch (windowType) {
563 r = PIx2 / (rows - 1);
564 for (i = 0; i < rows; i++) {
565 factor = (1 - cos(i * r)) / 2;
567 windowCorrectionFactor += sqr(factor);
569 imagData[i] *= factor;
573 r = PIx2 / (rows - 1);
574 for (i = 0; i < rows; i++) {
575 factor = 0.54 - 0.46 * cos(i * r);
577 windowCorrectionFactor += sqr(factor);
579 imagData[i] *= factor;
582 for (i = 0; i < rows; i++)
583 imagData[i] *= (1 - cos(i * r)) / 2;
586 r1 = (rows - 1) / 2.0;
587 r2 = sqr((rows + 1) / 2.0);
588 for (i = 0; i < rows; i++) {
589 factor = 1 - sqr(i - r1) / r2;
591 windowCorrectionFactor += sqr(factor);
593 imagData[i] *= factor;
597 r = (rows - 1) / 2.0;
598 for (i = 0; i < rows; i++) {
599 factor = 1 - FABS((i - r) / r);
601 windowCorrectionFactor += sqr(factor);
603 imagData[i] *= factor;
607 for (i = 0; i < rows; i++) {
608 r = i * PIx2 / (rows - 1);
609 factor = 1 - 1.93 * cos(r) + 1.29 * cos(2 * r) - 0.388 * cos(3 * r) + 0.032 * cos(4 * r);
611 windowCorrectionFactor += sqr(factor);
613 imagData[i] *= factor;
616 case WINDOW_GAUSSIAN:
617 for (i = 0; i < rows; i++) {
618 r = sqr((i - (rows - 1) / 2.) / (0.4 * (rows - 1) / 2.)) / 2;
621 windowCorrectionFactor += sqr(factor);
623 imagData[i] *= factor;
628 windowCorrectionFactor = 1;
632 if (correctWindowEffects) {
634 windowCorrectionFactor = 1 / sqrt(windowCorrectionFactor / rows);
635 for (i = 0; i < rows; i++)
636 data[i] *= windowCorrectionFactor;
638 imagData[i] *= windowCorrectionFactor;
640 if (imagData && flags & FL_COMPLEXINPUT_FOLDED) {
641 double min, max, max1;
643 imagData =
SDDS_Realloc(imagData,
sizeof(*data) * rows * 2);
645 if (fabs(min) > fabs(max))
650 if (fabs(min) > max1)
652 if (fabs(max) > max1)
654 if (fabs(imagData[rows - 1]) / max1 < 1.0e-15) {
655 fftrows = 2 * (rows - 1);
656 for (i = 1; i < rows - 1; i++) {
657 data[i] = data[i] / 2.0;
658 imagData[i] = imagData[i] / 2.0;
660 for (i = 1; i < rows - 1; i++) {
661 data[rows - 1 + i] = data[rows - 1 - i];
662 imagData[rows - 1 + i] = -imagData[rows - 1 - i];
664 length = (tdata[rows - 1] - tdata[0]) * 2.0;
666 fftrows = 2 * (rows - 1) + 1;
667 for (i = 1; i < rows; i++) {
668 data[i] = data[i] / 2.0;
669 imagData[i] = imagData[i] / 2.0;
671 for (i = 0; i < rows - 1; i++) {
672 data[rows + i] = data[rows - 1 - i];
673 imagData[rows + i] = -imagData[rows - 1 - i];
675 length = ((double)fftrows) * (tdata[rows - 1] - tdata[0]) / ((double)fftrows - 1.0) * 2;
679 length = ((double)rows) * (tdata[rows - 1] - tdata[0]) / ((double)rows - 1.0);
683 real_imag =
tmalloc(
sizeof(
double) * (2 * fftrows + 2));
684 for (i = 0; i < fftrows; i++) {
685 real_imag[2 * i] = data[i];
687 real_imag[2 * i + 1] = imagData[i];
689 real_imag[2 * i + 1] = 0;
692 complexFFT(real_imag, fftrows, 0);
693 if (flags & FL_FULLOUTPUT_UNFOLDED) {
696 }
else if (flags & FL_FULLOUTPUT_FOLDED)
697 n_freq = fftrows / 2 + 1;
699 n_freq = fftrows / 2 + 1;
701 n_freq = fftrows + 1;
703 complexFFT(real_imag, fftrows, INVERSE_FFT);
711 df = factor = 1.0 / length;
714 real =
tmalloc(
sizeof(
double) * n_freq);
715 imag =
tmalloc(
sizeof(
double) * n_freq);
716 fdata =
tmalloc(
sizeof(
double) * n_freq);
717 magData =
tmalloc(
sizeof(
double) * n_freq);
718 if (flags & FL_PSDOUTPUT || flags & (FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT)) {
719 psd =
tmalloc(
sizeof(*psd) * n_freq);
720 if (flags & (FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT)) {
721 psdInteg =
tmalloc(
sizeof(*psdInteg) * n_freq);
722 psdIntegPower =
tmalloc(
sizeof(*psdIntegPower) * n_freq);
726 for (i = 0; i < n_freq; i++) {
728 dtf_real = cos(-2 * PI * fdata[i] * t0);
729 dtf_imag = sin(-2 * PI * fdata[i] * t0);
731 psd[i] = (sqr(real_imag[2 * i]) + sqr(real_imag[2 * i + 1])) / df;
732 if (!imagData && i != 0 && !(i == (n_freq - 1) && rows % 2 == 0)) {
738 real_imag[2 * i] *= 2;
739 real_imag[2 * i + 1] *= 2;
744 real[i] = real_imag[2 * i] * dtf_real - real_imag[2 * i + 1] * dtf_imag;
745 imag[i] = real_imag[2 * i + 1] * dtf_real + real_imag[2 * i] * dtf_imag;
746 magData[i] = sqrt(sqr(real[i]) + sqr(imag[i]));
750 if (flags & FL_PSDINTEGOUTPUT) {
751 psdIntegPower[0] = 0;
752 for (i = 1; i < n_freq; i++)
753 psdIntegPower[i] = psdIntegPower[i - 1] + (psd[i - 1] + psd[i]) * df / 2.;
754 for (i = 0; i < n_freq; i++)
755 psdInteg[i] = sqrt(psdIntegPower[i]);
757 psdIntegPower[n_freq - 1] = 0;
758 for (i = n_freq - 2; i >= 0; i--) {
759 if (rintegCutOffFreq == 0 || fdata[i] <= rintegCutOffFreq)
760 psdIntegPower[i] = psdIntegPower[i + 1] + (psd[i + 1] + psd[i]) * df / 2.;
762 for (i = 0; i < n_freq; i++)
763 psdInteg[i] = sqrt(psdIntegPower[i]);
767 if (flags & FL_FULLOUTPUT) {
768 arg =
tmalloc(
sizeof(*arg) * n_freq);
769 for (i = 0; i < n_freq; i++) {
770 if (real[i] || imag[i])
771 arg[i] = 180.0 / PI * atan2(imag[i], real[i]);
776 if (flags & FL_UNWRAP_PHASE) {
778 unwrapArg =
tmalloc(
sizeof(*unwrapArg) * n_freq);
779 phase_correction = 0;
780 for (i = 0; i < n_freq; i++) {
781 if (i && magData[i] / max > unwrapLimit) {
782 delta = arg[i] - arg[i - 1];
784 phase_correction += 360.0;
785 else if (delta > 180.0)
786 phase_correction -= 360.0;
788 unwrapArg[i] = arg[i] + phase_correction;
792 if (flags & FL_NORMALIZE) {
794 for (i = 0; i < n_freq; i++)
795 if (magData[i] > factor)
797 if (factor != -DBL_MAX)
798 for (i = 0; i < n_freq; i++) {
801 magData[i] /= factor;
805 sprintf(s,
"FFT%s", depenQuantity + (imagData ? 4 : 0));
807 if (strncmp(depenQuantity,
"FFT", 3) == 0)
808 sprintf(s,
"%s", depenQuantity + 3);
809 else if (strncmp(depenQuantity,
"RealFFT", 7) == 0)
810 sprintf(s,
"%s", depenQuantity + 7);
812 sprintf(s,
"%s", depenQuantity);
818 if (flags & FL_SUPPRESSAVERAGE) {
824 if ((flags & FL_MAKEFREQDATA &&
825 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, fdata + offset, n_freq, 0)) ||
826 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, magData + offset, n_freq, index + fftOffset) ||
827 (flags & FL_FULLOUTPUT &&
828 (!
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, real + offset, n_freq, index + realOffset) ||
829 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, imag + offset, n_freq, index + imagOffset) ||
830 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, arg + offset, n_freq, index + argOffset))) ||
831 (flags & FL_PSDOUTPUT &&
832 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, psd + offset, n_freq, index + psdOffset)) ||
833 (flags & (FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT) && (!
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, psdInteg + offset, n_freq, index + psdIntOffset) ||
834 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, psdIntegPower + offset, n_freq, index + psdIntPowerOffset))) ||
835 (flags & FL_UNWRAP_PHASE && !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, unwrapArg + offset, n_freq, index + unwrappedArgOffset)))
837 if (sampleInterval > 0) {
838 int32_t *sample_row_flag;
839 sample_row_flag = calloc(
sizeof(*sample_row_flag), n_freq);
840 for (i = 0; i < n_freq; i += sampleInterval)
841 sample_row_flag[i] = 1;
846 free(sample_row_flag);
848 if (!
SDDS_SetParameters(SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE,
"fftFrequencies", n_freq,
"fftFrequencySpacing", df, NULL))
850 if (flags & FL_FULLOUTPUT && !
SDDS_SetParameters(SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE,
"SpectrumFolded", flags & FL_FULLOUTPUT_UNFOLDED ? 0 : 1, NULL))
875long create_fft_frequency_column(
SDDS_DATASET *SDDSout,
SDDS_DATASET *SDDSin,
char *timeName,
char *freqUnits,
long inverse) {
876 char s[SDDS_MAXLINE];
885 sprintf(s,
"Frequency for %s", timeSymbol);
894 sprintf(s,
"inverse for %s", timeSymbol);
907long 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) {
908 char s[SDDS_MAXLINE];
909 char *origUnits, *origSymbol;
910 char *description, *name, *symbol, *units;
920 sprintf(s,
"FFT%s", origName + offset);
922 if (strncmp(origName,
"FFT", 3) == 0)
924 else if (strncmp(origName,
"RealFFT", 7) == 0)
928 sprintf(s,
"%s", origName + offset);
933 sprintf(s,
"FFT %s", origSymbol);
936 sprintf(s,
"Amplitude of FFT of %s", origSymbol);
948 if (psd_output & FL_PSDOUTPUT) {
951 sprintf(s,
"(%s)$a2$n/(%s)", origUnits, freqUnits);
953 sprintf(s,
"(%s)$a2$n", origUnits);
958 sprintf(s,
"PSD%s", origName + offset);
963 sprintf(s,
"PSD %s", origSymbol);
966 sprintf(s,
"PSD of %s", origSymbol);
971 psdOffset = index1 - index0;
979 if (psd_output & (FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT)) {
985 sprintf(s,
"SqrtIntegPSD%s", origName + offset);
990 sprintf(s,
"Sqrt Integ PSD %s", origSymbol);
993 sprintf(s,
"Sqrt Integ PSD of %s", origSymbol);
998 psdIntOffset = index1 - index0;
1000 sprintf(s,
"IntegPSD%s", origName + offset);
1005 sprintf(s,
"Integ PSD %s", origSymbol);
1008 sprintf(s,
"Integ PSD of %s", origSymbol);
1012 sprintf(s,
"%sPower", origUnits);
1019 psdIntPowerOffset = index1 - index0;
1029 sprintf(s,
"RealFFT%s", origName + offset);
1031 sprintf(s,
"Real%s", origName + offset);
1037 sprintf(s,
"Re[FFT %s]", origSymbol);
1039 sprintf(s,
"Re[%s]", origSymbol);
1043 sprintf(s,
"Real part of FFT of %s", origSymbol);
1045 sprintf(s,
"Real part of %s", origSymbol);
1050 realOffset = index1 - index0;
1056 sprintf(s,
"ImagFFT%s", origName + offset);
1058 sprintf(s,
"Imag%s", origName + offset);
1064 sprintf(s,
"Im[FFT %s]", origSymbol);
1066 sprintf(s,
"Im[%s]", origSymbol);
1070 sprintf(s,
"Imaginary part of FFT of %s", origSymbol);
1072 sprintf(s,
"Imaginary part of %s", origSymbol);
1077 imagOffset = index1 - index0;
1083 sprintf(s,
"ArgFFT%s", origName + offset);
1085 sprintf(s,
"Arg%s", origName + offset);
1091 sprintf(s,
"Arg[FFT %s]", origSymbol);
1093 sprintf(s,
"Arg[%s]", origSymbol);
1097 sprintf(s,
"Phase of FFT of %s", origSymbol);
1099 sprintf(s,
"Phase of %s", origSymbol);
1104 argOffset = index1 - index0;
1110 sprintf(s,
"UnwrapArgFFT%s", origName + offset);
1112 sprintf(s,
"UnwrapArg%s", origName + offset);
1118 sprintf(s,
"UnwrapArg[FFT %s]", origSymbol);
1120 sprintf(s,
"UnwrapArg[%s]", origSymbol);
1124 sprintf(s,
"Unwrapped Phase of FFT of %s", origSymbol);
1126 sprintf(s,
"Unwrapped Phase of %s", origSymbol);
1131 unwrappedArgOffset = index1 - index0;
1141void moveToStringArrayComplex(
char ***targetReal,
char ***targetImag,
long *targets,
char **sourceReal,
char **sourceImag,
long sources);
1143long expandComplexColumnPairNames(
SDDS_DATASET *SDDSin,
char **name,
char ***realName,
char ***imagName,
long names,
char **excludeName,
long excludeNames,
long typeMode,
long typeValue) {
1144 long i, j, k, realNames, imagNames, names2;
1145 char **realName1, **imagName1, **realName2, **imagName2;
1146 char *realPattern, *imagPattern = NULL;
1149 if (!names || !name)
1151 realName1 = imagName1 = realName2 = imagName2 = NULL;
1152 realNames = imagNames = names2 = 0;
1153 for (i = 0; i < names; i++) {
1154 if (strlen(name[i]) > longest)
1155 longest = strlen(name[i]);
1158 if (!(realPattern =
SDDS_Malloc(
sizeof(*realPattern) * longest)) || !(imagPattern =
SDDS_Malloc(
sizeof(*imagPattern) * longest)))
1161 for (i = 0; i < names; i++) {
1162 for (j = 0; j < 2; j++) {
1164 sprintf(realPattern,
"Real%s", name[i]);
1165 sprintf(imagPattern,
"Imag%s", name[i]);
1167 sprintf(realPattern,
"%sReal", name[i]);
1168 sprintf(imagPattern,
"%sImag", name[i]);
1172 case FIND_NUMERIC_TYPE:
1173 case FIND_INTEGER_TYPE:
1174 case FIND_FLOATING_TYPE:
1175 realNames =
SDDS_MatchColumns(SDDSin, &realName1, SDDS_MATCH_STRING, typeMode, realPattern, SDDS_0_PREVIOUS | SDDS_OR);
1176 imagNames =
SDDS_MatchColumns(SDDSin, &imagName1, SDDS_MATCH_STRING, typeMode, imagPattern, SDDS_0_PREVIOUS | SDDS_OR);
1178 case FIND_SPECIFIED_TYPE:
1180 SDDS_Bomb(
"invalid type value in expandColumnPairNames");
1181 realNames =
SDDS_MatchColumns(SDDSin, &realName1, SDDS_MATCH_STRING, typeMode, typeValue, realPattern, SDDS_0_PREVIOUS | SDDS_OR);
1182 imagNames =
SDDS_MatchColumns(SDDSin, &imagName1, SDDS_MATCH_STRING, typeMode, typeValue, imagPattern, SDDS_0_PREVIOUS | SDDS_OR);
1185 SDDS_Bomb(
"invalid typeMode in expandColumnPairNames");
1191 if (realNames == -1 || imagNames == -1) {
1193 SDDS_Bomb(
"unable to perform column name match in expandColumnPairNames");
1195 if (realNames != imagNames)
1196 SDDS_Bomb(
"found different number of real and imaginary columns");
1198 for (j = 0; j < excludeNames; j++)
1199 for (k = 0; k < realNames; k++)
1200 if (
wild_match(realName1[k], excludeName[j])) {
1203 imagName1[k] = realName1[k] = NULL;
1206 moveToStringArrayComplex(&realName2, &imagName2, &names2, realName1, imagName1, realNames);
1215 *realName = realName2;
1216 *imagName = imagName2;
1220void moveToStringArrayComplex(
char ***targetReal,
char ***targetImag,
long *targets,
char **sourceReal,
char **sourceImag,
long sources) {
1224 if (!(*targetReal =
SDDS_Realloc(*targetReal,
sizeof(**targetReal) * (*targets + sources))) ||
1225 !(*targetImag =
SDDS_Realloc(*targetImag,
sizeof(**targetImag) * (*targets + sources))))
1227 for (i = 0; i < sources; i++) {
1228 if (sourceReal[i] == NULL || sourceImag[i] == NULL)
1230 for (j = 0; j < *targets; j++)
1231 if (strcmp(sourceReal[i], (*targetReal)[j]) == 0)
1233 if (j == *targets) {
1234 (*targetReal)[j] = sourceReal[i];
1235 (*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.
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.