101char *option[N_OPTIONS] = {
120#define FL_TRUNCATE 0x0001
121#define FL_PADWITHZEROES 0x0002
122#define FL_NORMALIZE 0x0004
123#define FL_SUPPRESSAVERAGE 0x0008
124#define FL_FULLOUTPUT 0x0010
125#define FL_MAKEFREQDATA 0x0020
126#define FL_PSDOUTPUT 0x0040
127#define FL_PSDINTEGOUTPUT 0x0080
128#define FL_PSDRINTEGOUTPUT 0x0100
129#define FL_FULLOUTPUT_FOLDED 0x0200
130#define FL_FULLOUTPUT_UNFOLDED 0x0400
131#define FL_COMPLEXINPUT_FOLDED 0x0800
132#define FL_COMPLEXINPUT_UNFOLDED 0x1000
133#define FL_UNWRAP_PHASE 0x2000
135#define WINDOW_HANNING 0
136#define WINDOW_WELCH 1
137#define WINDOW_PARZEN 2
138#define WINDOW_HAMMING 3
139#define WINDOW_FLATTOP 4
140#define WINDOW_GAUSSIAN 5
142#define N_WINDOW_TYPES 7
143char *window_type[N_WINDOW_TYPES] = {
144 "hanning",
"welch",
"parzen",
"hamming",
"flattop",
"gaussian",
"none"};
149 " sddsfft [<inputfile>] [<outputfile>]\n"
150 " [-pipe=[input][,output]]\n"
151 " [-columns=<indep-variable>[,<depen-quantity>[,...]]]\n"
152 " [-complexInput[=unfolded|folded]]\n"
153 " [-exclude=<depen-quantity>[,...]]\n"
154 " [-window[={hanning|welch|parzen|hamming|flattop|gaussian|none}[,correct]]]\n"
155 " [-sampleInterval=<number>]\n"
157 " [-fullOutput[=unfolded|folded],unwrapLimit=<value>]\n"
158 " [-psdOutput[=plain][,{integrated|rintegrated[=<cutoff>]}]]\n"
160 " [-padwithzeroes[=exponent] | -truncate]\n"
161 " [-suppressaverage]\n"
163 " [-majorOrder=row|column]\n"
164 " [-threads=<number>]\n\n";
169 " Utilize the standard SDDS Toolkit pipe option for input and/or output.\n\n"
171 " Specify the independent variable and dependent quantities to Fourier analyze.\n"
172 " <depen-quantity> entries may include wildcards.\n\n"
174 " Indicate that input columns are complex, with names prefixed by Real and Imag.\n"
176 " folded (default): Input frequency space is folded.\n"
177 " unfolded : Input frequency space is unfolded and must include negative frequencies.\n"
178 " If omitted, the program checks the SpectrumFolded parameter in the input file.\n\n"
180 " Provide a list of wildcard patterns to exclude specific quantities from analysis.\n\n"
182 " Apply a windowing function to the data before analysis.\n"
183 " Available types:\n"
184 " hanning, welch, parzen, hamming, flattop, gaussian, none\n"
185 " Adding ',correct' applies a correction factor to preserve the integrated PSD.\n"
186 " Default: hanning.\n\n"
188 " Sample the input data points at the specified interval.\n\n"
190 " Normalize the output to have a peak magnitude of 1.\n\n"
192 " Output the real and imaginary parts of the FFT.\n"
194 " folded (default): Outputs the half FFT spectrum.\n"
195 " unfolded : Outputs the full FFT spectrum.\n"
196 " Adding ',unwrapLimit=<value>' computes and outputs the unwrapped phase where the relative magnitude exceeds the limit.\n\n"
198 " Output the Power Spectral Density (PSD).\n"
200 " plain : Outputs the standard PSD.\n"
201 " integrated : Outputs the integrated PSD.\n"
202 " rintegrated=<cutoff> : Outputs the reverse-integrated PSD with an optional cutoff frequency.\n"
203 " Multiple options can be combined using commas.\n\n"
205 " Perform an inverse Fourier transform. The output will always be an unfolded spectrum.\n"
206 " If combined with -fullOutput=folded, it overrides to -fullOutput=unfolded.\n\n"
208 " Pad data with zeroes to optimize FFT performance.\n"
209 " Optionally specify an exponent to determine the padding size as 2^(original points * exponent).\n"
211 " Truncate data to the nearest product of small prime numbers to reduce runtime.\n"
212 " Note: Only one of -padwithzeroes or -truncate can be used.\n\n"
213 " -suppressaverage\n"
214 " Remove the average value from the data before performing the FFT.\n\n"
216 " Suppress all warning messages.\n\n"
218 " Specify the output file's data order:\n"
219 " row : Row-major order.\n"
220 " column : Column-major order.\n\n"
222 " Number of threads for per-column FFT preparation and result calculations.\n\n"
223 "Program by Michael Borland. (" __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
")\n";
229int64_t greatestProductOfSmallPrimes(int64_t rows);
231 char *depenQuantity,
char *depenQuantity2,
unsigned long flags,
long windowType,
232 int64_t sampleInterval,
long correctWindowEffects,
long inverse,
double rintegCutOffFreq,
double unwrapLimit,
234long create_fft_frequency_column(
SDDS_DATASET *SDDSout,
SDDS_DATASET *SDDSin,
char *timeName,
char *freqUnits,
long inverse);
237 char *freqUnits,
long full_output,
unsigned long psd_output,
long complexInput,
long inverse,
long unwrap_phase);
239char *makeFrequencyUnits(
SDDS_DATASET *SDDSin,
char *indepName);
240long expandComplexColumnPairNames(
SDDS_DATASET *SDDSin,
char **name,
char ***realName,
char ***imagName,
241 long names,
char **excludeName,
long excludeNames,
long typeMode,
long typeValue);
243int main(
int argc,
char **argv) {
246 char *indepQuantity, **depenQuantity, **exclude, **realQuan = NULL, **imagQuan = NULL;
247 long depenQuantities, excludes;
248 char *input, *output;
249 long i, readCode, noWarnings, complexInput, inverse, spectrumFoldParExist = 0;
250 int64_t rows, rowsToUse, sampleInterval;
251 int32_t spectrumFolded = 0, page = 0;
252 unsigned long flags, pipeFlags, complexInputFlags = 0, fullOutputFlags = 0, majorOrderFlag;
253 long windowType = -1;
254 SCANNED_ARG *scanned;
256 double *tdata, rintegCutOffFreq, unwrapLimit = 0;
257 long padFactor, correctWindowEffects = 0;
258 short columnMajorOrder = -1;
262 argc =
scanargs(&scanned, argc, argv);
263 if (argc < 3 || argc > (3 + N_OPTIONS)) {
264 fprintf(stderr,
"%s%s", USAGE1, USAGE2);
268 rintegCutOffFreq = 0;
269 output = input = NULL;
270 flags = pipeFlags = excludes = complexInput = inverse = 0;
272 indepQuantity = NULL;
273 depenQuantity = exclude = NULL;
277 for (iArg = 1; iArg < argc; iArg++) {
278 if (scanned[iArg].arg_type == OPTION) {
280 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
282 flags |= FL_NORMALIZE;
285 if (scanned[iArg].n_items != 1) {
286 if ((i =
match_string(scanned[iArg].list[1], window_type, N_WINDOW_TYPES, 0)) < 0)
289 if (scanned[iArg].n_items > 2) {
290 if (strncmp(scanned[iArg].list[2],
"correct", strlen(scanned[iArg].list[2])) == 0)
291 correctWindowEffects = 1;
298 case SET_PADWITHZEROES:
299 flags |= FL_PADWITHZEROES;
300 if (scanned[iArg].n_items != 1) {
301 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1],
"%ld", &padFactor) != 1 || padFactor < 1)
302 SDDS_Bomb(
"invalid -padwithzeroes syntax");
306 flags |= FL_TRUNCATE;
308 case SET_SUPPRESSAVERAGE:
309 flags |= FL_SUPPRESSAVERAGE;
311 case SET_SAMPLEINTERVAL:
312 if (scanned[iArg].n_items != 2 || sscanf(scanned[iArg].list[1],
"%" SCNd64, &sampleInterval) != 1 || sampleInterval <= 0)
313 SDDS_Bomb(
"invalid -sampleinterval syntax");
317 SDDS_Bomb(
"only one -columns option may be given");
318 if (scanned[iArg].n_items < 2)
320 indepQuantity = scanned[iArg].list[1];
321 if (scanned[iArg].n_items >= 2) {
322 depenQuantity =
tmalloc(
sizeof(*depenQuantity) * (depenQuantities = scanned[iArg].n_items - 2));
323 for (i = 0; i < depenQuantities; i++)
324 depenQuantity[i] = scanned[iArg].list[i + 2];
328 flags |= FL_FULLOUTPUT;
329 if (scanned[iArg].n_items >= 2) {
330 scanned[iArg].n_items--;
331 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))
333 scanned[iArg].n_items++;
334 if (fullOutputFlags & FL_FULLOUTPUT_UNFOLDED)
335 flags |= FL_FULLOUTPUT_UNFOLDED;
337 flags |= FL_FULLOUTPUT_FOLDED;
338 if (fullOutputFlags & FL_UNWRAP_PHASE)
339 flags |= FL_UNWRAP_PHASE;
343 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
347 if (scanned[iArg].n_items -= 1) {
348 unsigned long tmpFlags;
349 if (strchr(scanned[iArg].list[1],
'=') <= 0) {
350 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))
353 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))
358 flags |= FL_PSDOUTPUT;
359 if (flags & FL_PSDINTEGOUTPUT && flags & FL_PSDRINTEGOUTPUT)
360 SDDS_Bomb(
"invalid -psdOutput syntax: give only one of integrated or rintegrated");
363 if (scanned[iArg].n_items < 2)
365 moveToStringArray(&exclude, &excludes, scanned[iArg].list + 1, scanned[iArg].n_items - 1);
370 case SET_COMPLEXINPUT:
372 if (scanned[iArg].n_items == 2) {
373 scanned[iArg].n_items--;
374 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))
375 SDDS_Bomb(
"Invalid -complexInput syntax");
376 scanned[iArg].n_items++;
382 case SET_MAJOR_ORDER:
384 scanned[iArg].n_items--;
385 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)))
386 SDDS_Bomb(
"invalid -majorOrder syntax/values");
387 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
388 columnMajorOrder = 1;
389 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
390 columnMajorOrder = 0;
393 if (scanned[iArg].n_items != 2 ||
394 sscanf(scanned[iArg].list[1],
"%d", &threads) != 1 || threads < 1)
398 fprintf(stderr,
"error: unknown/ambiguous option: %s\n", scanned[iArg].list[0]);
404 input = scanned[iArg].list[0];
406 output = scanned[iArg].list[0];
412 if (!noWarnings && inverse)
413 fprintf(stderr,
"Warning: the inverse option is ignored since it only works with -complexInput.\n");
416 if (!noWarnings && inverse && flags & FL_FULLOUTPUT_FOLDED)
417 fprintf(stderr,
"Warning: the -inverse -fullOutput=folded will be changed to -inverse -fullOutput=unfolded.\n");
422 SDDS_Bomb(
"Supply the independent quantity name with the -columns option.");
424 if (flags & FL_TRUNCATE && flags & FL_PADWITHZEROES)
425 SDDS_Bomb(
"Specify only one of -padwithzeroes and -truncate.");
433 excludes = appendToStringArray(&exclude, excludes, indepQuantity);
434 if (!depenQuantities)
435 depenQuantities = appendToStringArray(&depenQuantity, depenQuantities,
"*");
438 if ((depenQuantities = expandColumnPairNames(&SDDSin, &depenQuantity, NULL, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
440 SDDS_Bomb(
"No quantities selected to FFT.");
443 if ((depenQuantities = expandComplexColumnPairNames(&SDDSin, depenQuantity, &realQuan, &imagQuan, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
445 SDDS_Bomb(
"No quantities selected to FFT.");
450 fprintf(stderr,
"%ld dependent quantities:\n", depenQuantities);
451 for (i = 0; i < depenQuantities; i++)
452 fprintf(stderr,
" %s\n", depenQuantity[i]);
455 if (!(freqUnits = makeFrequencyUnits(&SDDSin, indepQuantity)) ||
457 !create_fft_frequency_column(&SDDSout, &SDDSin, indepQuantity, freqUnits, inverse) ||
461 if (columnMajorOrder != -1)
462 SDDSout.layout.data_mode.column_major = columnMajorOrder;
464 SDDSout.layout.data_mode.column_major = SDDSin.layout.data_mode.column_major;
469 if (!complexInputFlags) {
471 spectrumFoldParExist = 1;
472 }
else if (complexInputFlags & FL_COMPLEXINPUT_UNFOLDED)
473 flags |= FL_COMPLEXINPUT_UNFOLDED;
475 flags |= FL_COMPLEXINPUT_FOLDED;
477 for (i = 0; i < depenQuantities; i++) {
479 create_fft_columns(&SDDSout, &SDDSin, depenQuantity[i], indepQuantity, freqUnits,
480 flags & FL_FULLOUTPUT,
481 flags & (FL_PSDOUTPUT + FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT),
482 0, inverse, flags & FL_UNWRAP_PHASE);
484 create_fft_columns(&SDDSout, &SDDSin, realQuan[i], indepQuantity, freqUnits,
485 flags & FL_FULLOUTPUT,
486 flags & (FL_PSDOUTPUT + FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT),
487 1, inverse, flags & FL_UNWRAP_PHASE);
498 if (page == 1 && spectrumFoldParExist) {
502 flags |= FL_COMPLEXINPUT_FOLDED;
504 flags |= FL_COMPLEXINPUT_UNFOLDED;
507 int64_t primeRows, pow2Rows;
509 SDDS_Bomb(
"sddsfft requires at least two rows on each nonempty page");
511 primeRows = greatestProductOfSmallPrimes(rows);
512 if (rows != primeRows || padFactor) {
513 if (flags & FL_PADWITHZEROES) {
514 pow2Rows =
ipow(2., ((int64_t)(log((
double)rows) / log(2.0F))) + (padFactor ? padFactor : 1.0));
515 if ((primeRows = greatestProductOfSmallPrimes(pow2Rows)) > rows)
516 rowsToUse = primeRows;
518 rowsToUse = pow2Rows;
519 }
else if (flags & FL_TRUNCATE)
520 rowsToUse = greatestProductOfSmallPrimes(rows);
522 fputs(
"Warning: number of points has large prime factors.\nThis could take a very long time.\nConsider using the -truncate option.\n", stderr);
528 for (i = 0; i < depenQuantities; i++)
529 if (!process_data(&SDDSout, &SDDSin, tdata, rows, rowsToUse,
530 complexInput ? realQuan[i] : depenQuantity[i],
531 complexInput ? imagQuan[i] : NULL,
532 flags | (i == 0 ? FL_MAKEFREQDATA : 0),
533 windowType, sampleInterval, correctWindowEffects, inverse,
534 rintegCutOffFreq, unwrapLimit, threads)) {
559static long psdOffset, argOffset, realOffset, imagOffset, fftOffset = -1, psdIntOffset, psdIntPowerOffset, unwrappedArgOffset = -1;
562 int64_t rowsToUse,
char *depenQuantity,
char *imagQuantity,
unsigned long flags,
long windowType,
563 int64_t sampleInterval,
long correctWindowEffects,
long inverse,
double rintegCutOffFreq,
double unwrapLimit,
565 long offset, index, unfold = 0;
566 int64_t n_freq, i, fftrows = 0;
567 double r, r1, r2, length, factor, df, min, max, delta;
568 double *real, *imag, *magData, *arg = NULL, *real_imag, *data, *psd = NULL, *psdInteg = NULL, *psdIntegPower = NULL, *unwrapArg = NULL, phase_correction = 0;
571 double *fdata, *imagData = NULL;
572 double *tDataStore = NULL;
573 double windowCorrectionFactor = 0;
579 if (flags & FL_SUPPRESSAVERAGE) {
581#pragma omp parallel for if (threads > 1) num_threads(threads)
582 for (i = 0; i < rows; i++)
586#pragma omp parallel for if (threads > 1) num_threads(threads)
587 for (i = 0; i < rows; i++)
591 if (rows < rowsToUse) {
593 tDataStore =
tmalloc(
sizeof(*tDataStore) * rowsToUse);
594 memcpy((
char *)tDataStore, (
char *)tdata, rows *
sizeof(*tdata));
595 if (!(data =
SDDS_Realloc(data,
sizeof(*data) * rowsToUse)))
597 if (imagData && !(imagData =
SDDS_Realloc(imagData,
sizeof(*imagData) * rowsToUse)))
599 length = tdata[rows - 1] - tdata[0];
600 for (i = rows; i < rowsToUse; i++) {
601 tDataStore[i] = tDataStore[i - 1] + length / ((double)rows - 1);
605 for (i = rows; i < rowsToUse; i++)
610 windowCorrectionFactor = 0;
611 switch (windowType) {
613 r = PIx2 / (rows - 1);
614#pragma omp parallel for private(factor) reduction(+ : windowCorrectionFactor) if (threads > 1) num_threads(threads)
615 for (i = 0; i < rows; i++) {
616 factor = (1 - cos(i * r)) / 2;
618 windowCorrectionFactor += sqr(factor);
620 imagData[i] *= factor;
624 r = PIx2 / (rows - 1);
625#pragma omp parallel for private(factor) reduction(+ : windowCorrectionFactor) if (threads > 1) num_threads(threads)
626 for (i = 0; i < rows; i++) {
627 factor = 0.54 - 0.46 * cos(i * r);
629 windowCorrectionFactor += sqr(factor);
631 imagData[i] *= factor;
634#pragma omp parallel for if (threads > 1) num_threads(threads)
635 for (i = 0; i < rows; i++)
636 imagData[i] *= (1 - cos(i * r)) / 2;
639 r1 = (rows - 1) / 2.0;
640 r2 = sqr((rows + 1) / 2.0);
641#pragma omp parallel for private(factor) reduction(+ : windowCorrectionFactor) if (threads > 1) num_threads(threads)
642 for (i = 0; i < rows; i++) {
643 factor = 1 - sqr(i - r1) / r2;
645 windowCorrectionFactor += sqr(factor);
647 imagData[i] *= factor;
651 r = (rows - 1) / 2.0;
652#pragma omp parallel for private(factor) reduction(+ : windowCorrectionFactor) if (threads > 1) num_threads(threads)
653 for (i = 0; i < rows; i++) {
654 factor = 1 - FABS((i - r) / r);
656 windowCorrectionFactor += sqr(factor);
658 imagData[i] *= factor;
662#pragma omp parallel for private(r, factor) reduction(+ : windowCorrectionFactor) if (threads > 1) num_threads(threads)
663 for (i = 0; i < rows; i++) {
664 r = i * PIx2 / (rows - 1);
665 factor = 1 - 1.93 * cos(r) + 1.29 * cos(2 * r) - 0.388 * cos(3 * r) + 0.032 * cos(4 * r);
667 windowCorrectionFactor += sqr(factor);
669 imagData[i] *= factor;
672 case WINDOW_GAUSSIAN:
673#pragma omp parallel for private(r, factor) reduction(+ : windowCorrectionFactor) if (threads > 1) num_threads(threads)
674 for (i = 0; i < rows; i++) {
675 r = sqr((i - (rows - 1) / 2.) / (0.4 * (rows - 1) / 2.)) / 2;
678 windowCorrectionFactor += sqr(factor);
680 imagData[i] *= factor;
685 windowCorrectionFactor = 1;
689 if (correctWindowEffects) {
691 windowCorrectionFactor = 1 / sqrt(windowCorrectionFactor / rows);
692#pragma omp parallel for if (threads > 1) num_threads(threads)
693 for (i = 0; i < rows; i++)
694 data[i] *= windowCorrectionFactor;
696#pragma omp parallel for if (threads > 1) num_threads(threads)
697 for (i = 0; i < rows; i++)
698 imagData[i] *= windowCorrectionFactor;
701 if (imagData && flags & FL_COMPLEXINPUT_FOLDED) {
702 double min, max, max1;
704 imagData =
SDDS_Realloc(imagData,
sizeof(*data) * rows * 2);
706 if (fabs(min) > fabs(max))
711 if (fabs(min) > max1)
713 if (fabs(max) > max1)
715 if (fabs(imagData[rows - 1]) / max1 < 1.0e-15) {
716 fftrows = 2 * (rows - 1);
717 for (i = 1; i < rows - 1; i++) {
718 data[i] = data[i] / 2.0;
719 imagData[i] = imagData[i] / 2.0;
721 for (i = 1; i < rows - 1; i++) {
722 data[rows - 1 + i] = data[rows - 1 - i];
723 imagData[rows - 1 + i] = -imagData[rows - 1 - i];
725 length = (tdata[rows - 1] - tdata[0]) * 2.0;
727 fftrows = 2 * (rows - 1) + 1;
728 for (i = 1; i < rows; i++) {
729 data[i] = data[i] / 2.0;
730 imagData[i] = imagData[i] / 2.0;
732 for (i = 0; i < rows - 1; i++) {
733 data[rows + i] = data[rows - 1 - i];
734 imagData[rows + i] = -imagData[rows - 1 - i];
736 length = ((double)fftrows) * (tdata[rows - 1] - tdata[0]) / ((double)fftrows - 1.0) * 2;
740 length = ((double)rows) * (tdata[rows - 1] - tdata[0]) / ((double)rows - 1.0);
744 real_imag =
tmalloc(
sizeof(
double) * (2 * fftrows + 2));
745#pragma omp parallel for if (threads > 1) num_threads(threads)
746 for (i = 0; i < fftrows; i++) {
747 real_imag[2 * i] = data[i];
749 real_imag[2 * i + 1] = imagData[i];
751 real_imag[2 * i + 1] = 0;
754 complexFFT(real_imag, fftrows, 0);
755 if (flags & FL_FULLOUTPUT_UNFOLDED) {
758 }
else if (flags & FL_FULLOUTPUT_FOLDED)
759 n_freq = fftrows / 2 + 1;
761 n_freq = fftrows / 2 + 1;
763 n_freq = fftrows + 1;
765 complexFFT(real_imag, fftrows, INVERSE_FFT);
773 df = factor = 1.0 / length;
776 real =
tmalloc(
sizeof(
double) * n_freq);
777 imag =
tmalloc(
sizeof(
double) * n_freq);
778 fdata =
tmalloc(
sizeof(
double) * n_freq);
779 magData =
tmalloc(
sizeof(
double) * n_freq);
780 if (flags & FL_PSDOUTPUT || flags & (FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT)) {
781 psd =
tmalloc(
sizeof(*psd) * n_freq);
782 if (flags & (FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT)) {
783 psdInteg =
tmalloc(
sizeof(*psdInteg) * n_freq);
784 psdIntegPower =
tmalloc(
sizeof(*psdIntegPower) * n_freq);
788#pragma omp parallel for if (threads > 1) num_threads(threads)
789 for (i = 0; i < n_freq; i++) {
790 double dtf_real, dtf_imag;
792 dtf_real = cos(-2 * PI * fdata[i] * t0);
793 dtf_imag = sin(-2 * PI * fdata[i] * t0);
795 psd[i] = (sqr(real_imag[2 * i]) + sqr(real_imag[2 * i + 1])) / df;
796 if (!imagData && i != 0 && !(i == (n_freq - 1) && rows % 2 == 0)) {
802 real_imag[2 * i] *= 2;
803 real_imag[2 * i + 1] *= 2;
808 real[i] = real_imag[2 * i] * dtf_real - real_imag[2 * i + 1] * dtf_imag;
809 imag[i] = real_imag[2 * i + 1] * dtf_real + real_imag[2 * i] * dtf_imag;
810 magData[i] = sqrt(sqr(real[i]) + sqr(imag[i]));
814 if (flags & FL_PSDINTEGOUTPUT) {
815 psdIntegPower[0] = 0;
816 for (i = 1; i < n_freq; i++)
817 psdIntegPower[i] = psdIntegPower[i - 1] + (psd[i - 1] + psd[i]) * df / 2.;
818 for (i = 0; i < n_freq; i++)
819 psdInteg[i] = sqrt(psdIntegPower[i]);
821 psdIntegPower[n_freq - 1] = 0;
822 for (i = n_freq - 2; i >= 0; i--) {
823 if (rintegCutOffFreq == 0 || fdata[i] <= rintegCutOffFreq)
824 psdIntegPower[i] = psdIntegPower[i + 1] + (psd[i + 1] + psd[i]) * df / 2.;
826 for (i = 0; i < n_freq; i++)
827 psdInteg[i] = sqrt(psdIntegPower[i]);
831 if (flags & FL_FULLOUTPUT) {
832 arg =
tmalloc(
sizeof(*arg) * n_freq);
833#pragma omp parallel for if (threads > 1) num_threads(threads)
834 for (i = 0; i < n_freq; i++) {
835 if (real[i] || imag[i])
836 arg[i] = 180.0 / PI * atan2(imag[i], real[i]);
841 if (flags & FL_UNWRAP_PHASE) {
843 unwrapArg =
tmalloc(
sizeof(*unwrapArg) * n_freq);
844 phase_correction = 0;
845 for (i = 0; i < n_freq; i++) {
846 if (i && magData[i] / max > unwrapLimit) {
847 delta = arg[i] - arg[i - 1];
849 phase_correction += 360.0;
850 else if (delta > 180.0)
851 phase_correction -= 360.0;
853 unwrapArg[i] = arg[i] + phase_correction;
857 if (flags & FL_NORMALIZE) {
859 for (i = 0; i < n_freq; i++)
860 if (magData[i] > factor)
862 if (factor != -DBL_MAX)
863 for (i = 0; i < n_freq; i++) {
866 magData[i] /= factor;
870 sprintf(s,
"FFT%s", depenQuantity + (imagData ? 4 : 0));
872 if (strncmp(depenQuantity,
"FFT", 3) == 0)
873 sprintf(s,
"%s", depenQuantity + 3);
874 else if (strncmp(depenQuantity,
"RealFFT", 7) == 0)
875 sprintf(s,
"%s", depenQuantity + 7);
877 sprintf(s,
"%s", depenQuantity);
883 if (flags & FL_SUPPRESSAVERAGE) {
889 if ((flags & FL_MAKEFREQDATA &&
890 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, fdata + offset, n_freq, 0)) ||
891 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, magData + offset, n_freq, index + fftOffset) ||
892 (flags & FL_FULLOUTPUT &&
893 (!
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, real + offset, n_freq, index + realOffset) ||
894 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, imag + offset, n_freq, index + imagOffset) ||
895 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, arg + offset, n_freq, index + argOffset))) ||
896 (flags & FL_PSDOUTPUT &&
897 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, psd + offset, n_freq, index + psdOffset)) ||
898 (flags & (FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT) && (!
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, psdInteg + offset, n_freq, index + psdIntOffset) ||
899 !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, psdIntegPower + offset, n_freq, index + psdIntPowerOffset))) ||
900 (flags & FL_UNWRAP_PHASE && !
SDDS_SetColumn(SDDSout, SDDS_SET_BY_INDEX, unwrapArg + offset, n_freq, index + unwrappedArgOffset)))
902 if (sampleInterval > 0) {
903 int32_t *sample_row_flag;
904 sample_row_flag = calloc(
sizeof(*sample_row_flag), n_freq);
905 for (i = 0; i < n_freq; i += sampleInterval)
906 sample_row_flag[i] = 1;
911 free(sample_row_flag);
913 if (!
SDDS_SetParameters(SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE,
"fftFrequencies", n_freq,
"fftFrequencySpacing", df, NULL))
915 if (flags & FL_FULLOUTPUT && !
SDDS_SetParameters(SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE,
"SpectrumFolded", flags & FL_FULLOUTPUT_UNFOLDED ? 0 : 1, NULL))
940long create_fft_frequency_column(
SDDS_DATASET *SDDSout,
SDDS_DATASET *SDDSin,
char *timeName,
char *freqUnits,
long inverse) {
941 char s[SDDS_MAXLINE];
950 sprintf(s,
"Frequency for %s", timeSymbol);
959 sprintf(s,
"inverse for %s", timeSymbol);
972long 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) {
973 char s[SDDS_MAXLINE];
974 char *origUnits, *origSymbol;
975 char *description, *name, *symbol, *units;
985 sprintf(s,
"FFT%s", origName + offset);
987 if (strncmp(origName,
"FFT", 3) == 0)
989 else if (strncmp(origName,
"RealFFT", 7) == 0)
993 sprintf(s,
"%s", origName + offset);
998 sprintf(s,
"FFT %s", origSymbol);
1001 sprintf(s,
"Amplitude of FFT of %s", origSymbol);
1010 if (fftOffset == -1)
1013 if (psd_output & FL_PSDOUTPUT) {
1016 sprintf(s,
"(%s)$a2$n/(%s)", origUnits, freqUnits);
1018 sprintf(s,
"(%s)$a2$n", origUnits);
1023 sprintf(s,
"PSD%s", origName + offset);
1028 sprintf(s,
"PSD %s", origSymbol);
1031 sprintf(s,
"PSD of %s", origSymbol);
1036 psdOffset = index1 - index0;
1044 if (psd_output & (FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT)) {
1050 sprintf(s,
"SqrtIntegPSD%s", origName + offset);
1055 sprintf(s,
"Sqrt Integ PSD %s", origSymbol);
1058 sprintf(s,
"Sqrt Integ PSD of %s", origSymbol);
1063 psdIntOffset = index1 - index0;
1065 sprintf(s,
"IntegPSD%s", origName + offset);
1070 sprintf(s,
"Integ PSD %s", origSymbol);
1073 sprintf(s,
"Integ PSD of %s", origSymbol);
1077 sprintf(s,
"%sPower", origUnits);
1084 psdIntPowerOffset = index1 - index0;
1094 sprintf(s,
"RealFFT%s", origName + offset);
1096 sprintf(s,
"Real%s", origName + offset);
1102 sprintf(s,
"Re[FFT %s]", origSymbol);
1104 sprintf(s,
"Re[%s]", origSymbol);
1108 sprintf(s,
"Real part of FFT of %s", origSymbol);
1110 sprintf(s,
"Real part of %s", origSymbol);
1115 realOffset = index1 - index0;
1121 sprintf(s,
"ImagFFT%s", origName + offset);
1123 sprintf(s,
"Imag%s", origName + offset);
1129 sprintf(s,
"Im[FFT %s]", origSymbol);
1131 sprintf(s,
"Im[%s]", origSymbol);
1135 sprintf(s,
"Imaginary part of FFT of %s", origSymbol);
1137 sprintf(s,
"Imaginary part of %s", origSymbol);
1142 imagOffset = index1 - index0;
1148 sprintf(s,
"ArgFFT%s", origName + offset);
1150 sprintf(s,
"Arg%s", origName + offset);
1156 sprintf(s,
"Arg[FFT %s]", origSymbol);
1158 sprintf(s,
"Arg[%s]", origSymbol);
1162 sprintf(s,
"Phase of FFT of %s", origSymbol);
1164 sprintf(s,
"Phase of %s", origSymbol);
1169 argOffset = index1 - index0;
1175 sprintf(s,
"UnwrapArgFFT%s", origName + offset);
1177 sprintf(s,
"UnwrapArg%s", origName + offset);
1183 sprintf(s,
"UnwrapArg[FFT %s]", origSymbol);
1185 sprintf(s,
"UnwrapArg[%s]", origSymbol);
1189 sprintf(s,
"Unwrapped Phase of FFT of %s", origSymbol);
1191 sprintf(s,
"Unwrapped Phase of %s", origSymbol);
1196 unwrappedArgOffset = index1 - index0;
1206void moveToStringArrayComplex(
char ***targetReal,
char ***targetImag,
long *targets,
char **sourceReal,
char **sourceImag,
long sources);
1208long expandComplexColumnPairNames(
SDDS_DATASET *SDDSin,
char **name,
char ***realName,
char ***imagName,
long names,
char **excludeName,
long excludeNames,
long typeMode,
long typeValue) {
1209 long i, j, k, realNames, imagNames, names2;
1210 char **realName1, **imagName1, **realName2, **imagName2;
1211 char *realPattern, *imagPattern = NULL;
1214 if (!names || !name)
1216 realName1 = imagName1 = realName2 = imagName2 = NULL;
1217 realNames = imagNames = names2 = 0;
1218 for (i = 0; i < names; i++) {
1219 if (strlen(name[i]) > longest)
1220 longest = strlen(name[i]);
1223 if (!(realPattern =
SDDS_Malloc(
sizeof(*realPattern) * longest)) || !(imagPattern =
SDDS_Malloc(
sizeof(*imagPattern) * longest)))
1226 for (i = 0; i < names; i++) {
1227 for (j = 0; j < 2; j++) {
1229 sprintf(realPattern,
"Real%s", name[i]);
1230 sprintf(imagPattern,
"Imag%s", name[i]);
1232 sprintf(realPattern,
"%sReal", name[i]);
1233 sprintf(imagPattern,
"%sImag", name[i]);
1237 case FIND_NUMERIC_TYPE:
1238 case FIND_INTEGER_TYPE:
1239 case FIND_FLOATING_TYPE:
1240 realNames =
SDDS_MatchColumns(SDDSin, &realName1, SDDS_MATCH_STRING, typeMode, realPattern, SDDS_0_PREVIOUS | SDDS_OR);
1241 imagNames =
SDDS_MatchColumns(SDDSin, &imagName1, SDDS_MATCH_STRING, typeMode, imagPattern, SDDS_0_PREVIOUS | SDDS_OR);
1243 case FIND_SPECIFIED_TYPE:
1245 SDDS_Bomb(
"invalid type value in expandColumnPairNames");
1246 realNames =
SDDS_MatchColumns(SDDSin, &realName1, SDDS_MATCH_STRING, typeMode, typeValue, realPattern, SDDS_0_PREVIOUS | SDDS_OR);
1247 imagNames =
SDDS_MatchColumns(SDDSin, &imagName1, SDDS_MATCH_STRING, typeMode, typeValue, imagPattern, SDDS_0_PREVIOUS | SDDS_OR);
1250 SDDS_Bomb(
"invalid typeMode in expandColumnPairNames");
1256 if (realNames == -1 || imagNames == -1) {
1258 SDDS_Bomb(
"unable to perform column name match in expandColumnPairNames");
1260 if (realNames != imagNames)
1261 SDDS_Bomb(
"found different number of real and imaginary columns");
1263 for (j = 0; j < excludeNames; j++)
1264 for (k = 0; k < realNames; k++)
1265 if (
wild_match(realName1[k], excludeName[j])) {
1268 imagName1[k] = realName1[k] = NULL;
1271 moveToStringArrayComplex(&realName2, &imagName2, &names2, realName1, imagName1, realNames);
1280 *realName = realName2;
1281 *imagName = imagName2;
1285void moveToStringArrayComplex(
char ***targetReal,
char ***targetImag,
long *targets,
char **sourceReal,
char **sourceImag,
long sources) {
1289 if (!(*targetReal =
SDDS_Realloc(*targetReal,
sizeof(**targetReal) * (*targets + sources))) ||
1290 !(*targetImag =
SDDS_Realloc(*targetImag,
sizeof(**targetImag) * (*targets + sources))))
1292 for (i = 0; i < sources; i++) {
1293 if (sourceReal[i] == NULL || sourceImag[i] == NULL)
1295 for (j = 0; j < *targets; j++)
1296 if (strcmp(sourceReal[i], (*targetReal)[j]) == 0)
1298 if (j == *targets) {
1299 (*targetReal)[j] = sourceReal[i];
1300 (*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.