SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
sddsfft.c
Go to the documentation of this file.
1/**
2 * @file sddsfft.c
3 * @brief Performs FFT (Fast Fourier Transform) on SDDS-formatted data files.
4 *
5 * @details
6 * This program processes SDDS data files, performing Fast Fourier Transforms (FFT) with extensive
7 * options for data manipulation, including normalization, windowing, PSD computation, and inverse
8 * transformations. It supports both complex and real input data and allows flexible output formats
9 * based on user-defined parameters.
10 *
11 * @section Usage
12 * ```
13 * sddsfft [<inputfile>] [<outputfile>]
14 * [-pipe=[input][,output]]
15 * [-columns=<indep-variable>[,<depen-quantity>[,...]]]
16 * [-complexInput[=unfolded|folded]]
17 * [-exclude=<depen-quantity>[,...]]
18 * [-window[={hanning|welch|parzen|hamming|flattop|gaussian|none}[,correct]]]
19 * [-sampleInterval=<number>]
20 * [-normalize]
21 * [-fullOutput[=unfolded|folded],unwrapLimit=<value>]
22 * [-psdOutput[=plain][,{integrated|rintegrated[=<cutoff>]}]]
23 * [-inverse]
24 * [-padwithzeroes[=exponent] | -truncate]
25 * [-suppressaverage]
26 * [-noWarnings]
27 * [-majorOrder=row|column]
28 * ```
29 *
30 * @section Options
31 * | Required | Description |
32 * |--------------------|----------------------------------------------------------------------------|
33 * | `-columns` | Specify the independent variable and dependent quantities for FFT analysis. |
34 *
35 * | Optional | Description |
36 * |---------------------------------------|-----------------------------------------------------------------------------|
37 * | `-pipe` | Utilize the standard SDDS Toolkit pipe option for input and/or output. |
38 * | `-complexInput` | Specify complex input column handling. |
39 * | `-exclude` | List of wildcard patterns to exclude specific quantities from analysis. |
40 * | `-window` | Apply a windowing function before analysis. |
41 * | `-sampleInterval` | Define the interval for sampling input data points. |
42 * | `-normalize` | Normalize output to have a peak magnitude of 1. |
43 * | `-fullOutput` | Output the real and imaginary parts of the FFT. |
44 * | `-psdOutput` | Output Power Spectral Density (PSD) in various formats. |
45 * | `-inverse` | Perform an inverse Fourier transform. |
46 * | `-padwithzeroes` | Pad data with zeroes for FFT optimization. |
47 * | `-truncate` | Truncate data to nearest product of small primes for efficiency. |
48 * | `-suppressaverage` | Remove average value from data before FFT. |
49 * | `-noWarnings` | Suppress warning messages. |
50 * | `-majorOrder` | Specify row or column major order for output. |
51 *
52 * @subsection Incompatibilities
53 * - `-truncate` is incompatible with:
54 * - `-padwithzeroes`
55 *
56 * @copyright
57 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
58 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
59 *
60 * @license
61 * This file is distributed under the terms of the Software License Agreement
62 * found in the file LICENSE included with this distribution.
63 *
64 * @authors
65 * - M. Borland
66 * - C. Saunders
67 * - R. Soliday
68 * - L. Emery
69 */
70
71#include "mdb.h"
72#include "SDDS.h"
73#include "scan.h"
74#include "fftpackC.h"
75#include "SDDSutils.h"
76#include <ctype.h>
77
78/* Enumeration for option types */
79enum option_type {
80 SET_WINDOW,
81 SET_NORMALIZE,
82 SET_PADWITHZEROES,
83 SET_TRUNCATE,
84 SET_SUPPRESSAVERAGE,
85 SET_SAMPLEINTERVAL,
86 SET_COLUMNS,
87 SET_FULLOUTPUT,
88 SET_PIPE,
89 SET_PSDOUTPUT,
90 SET_EXCLUDE,
91 SET_NOWARNINGS,
92 SET_COMPLEXINPUT,
93 SET_INVERSE,
94 SET_MAJOR_ORDER,
95 N_OPTIONS
96};
97
98char *option[N_OPTIONS] = {
99 "window",
100 "normalize",
101 "padwithzeroes",
102 "truncate",
103 "suppressaverage",
104 "sampleinterval",
105 "columns",
106 "fulloutput",
107 "pipe",
108 "psdoutput",
109 "exclude",
110 "nowarnings",
111 "complexinput",
112 "inverse",
113 "majorOrder",
114};
115
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
130
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
137#define WINDOW_NONE 6
138#define N_WINDOW_TYPES 7
139char *window_type[N_WINDOW_TYPES] = {
140 "hanning", "welch", "parzen", "hamming", "flattop", "gaussian", "none"};
141
142/* Improved and more readable usage message */
143static char *USAGE1 =
144 "Usage:\n"
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"
152 " [-normalize]\n"
153 " [-fullOutput[=unfolded|folded],unwrapLimit=<value>]\n"
154 " [-psdOutput[=plain][,{integrated|rintegrated[=<cutoff>]}]]\n"
155 " [-inverse]\n"
156 " [-padwithzeroes[=exponent] | -truncate]\n"
157 " [-suppressaverage]\n"
158 " [-noWarnings]\n"
159 " [-majorOrder=row|column]\n\n";
160
161static char *USAGE2 =
162 "Options:\n"
163 " -pipe\n"
164 " Utilize the standard SDDS Toolkit pipe option for input and/or output.\n\n"
165 " -columns\n"
166 " Specify the independent variable and dependent quantities to Fourier analyze.\n"
167 " <depen-quantity> entries may include wildcards.\n\n"
168 " -complexInput\n"
169 " Indicate that input columns are complex, with names prefixed by Real and Imag.\n"
170 " Options:\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"
174 " -exclude\n"
175 " Provide a list of wildcard patterns to exclude specific quantities from analysis.\n\n"
176 " -window\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"
182 " -sampleInterval\n"
183 " Sample the input data points at the specified interval.\n\n"
184 " -normalize\n"
185 " Normalize the output to have a peak magnitude of 1.\n\n"
186 " -fullOutput\n"
187 " Output the real and imaginary parts of the FFT.\n"
188 " Options:\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"
192 " -psdOutput\n"
193 " Output the Power Spectral Density (PSD).\n"
194 " Options:\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"
199 " -inverse\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"
202 " -padwithzeroes\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"
205 " -truncate\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"
210 " -noWarnings\n"
211 " Suppress all warning messages.\n\n"
212 " -majorOrder\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";
217
218/* Rest of the code remains unchanged */
219
220/* ... [The rest of your code continues here without changes] ... */
221
222int64_t greatestProductOfSmallPrimes(int64_t rows);
223long process_data(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, double *tdata, int64_t rows, int64_t rowsToUse,
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);
227
228long create_fft_columns(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, char *origName, char *indepName,
229 char *freqUnits, long full_output, unsigned long psd_output, long complexInput, long inverse, long unwrap_phase);
230long create_fft_parameters(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, char *indepName, char *freqUnits);
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);
234
235int main(int argc, char **argv) {
236 int iArg;
237 char *freqUnits;
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;
247 SDDS_DATASET SDDSin, SDDSout;
248 double *tdata, rintegCutOffFreq, unwrapLimit = 0;
249 long padFactor, correctWindowEffects = 0;
250 short columnMajorOrder = -1;
251
253 argc = scanargs(&scanned, argc, argv);
254 if (argc < 3 || argc > (3 + N_OPTIONS)) {
255 fprintf(stderr, "%s%s", USAGE1, USAGE2);
256 exit(EXIT_FAILURE);
257 /* bomb(NULL, USAGE); */
258 }
259 rintegCutOffFreq = 0;
260 output = input = NULL;
261 flags = pipeFlags = excludes = complexInput = inverse = 0;
262 sampleInterval = 1;
263 indepQuantity = NULL;
264 depenQuantity = exclude = NULL;
265 depenQuantities = 0;
266 noWarnings = 0;
267 padFactor = 0;
268 for (iArg = 1; iArg < argc; iArg++) {
269 if (scanned[iArg].arg_type == OPTION) {
270 /* process options here */
271 switch (match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
272 case SET_NORMALIZE:
273 flags |= FL_NORMALIZE;
274 break;
275 case SET_WINDOW:
276 if (scanned[iArg].n_items != 1) {
277 if ((i = match_string(scanned[iArg].list[1], window_type, N_WINDOW_TYPES, 0)) < 0)
278 SDDS_Bomb("unknown window type");
279 windowType = i;
280 if (scanned[iArg].n_items > 2) {
281 if (strncmp(scanned[iArg].list[2], "correct", strlen(scanned[iArg].list[2])) == 0)
282 correctWindowEffects = 1;
283 else
284 SDDS_Bomb("invalid -window syntax");
285 }
286 } else
287 windowType = 0;
288 break;
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");
294 }
295 break;
296 case SET_TRUNCATE:
297 flags |= FL_TRUNCATE;
298 break;
299 case SET_SUPPRESSAVERAGE:
300 flags |= FL_SUPPRESSAVERAGE;
301 break;
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");
305 break;
306 case SET_COLUMNS:
307 if (indepQuantity)
308 SDDS_Bomb("only one -columns option may be given");
309 if (scanned[iArg].n_items < 2)
310 SDDS_Bomb("invalid -columns syntax");
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];
316 }
317 break;
318 case SET_FULLOUTPUT:
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))
323 SDDS_Bomb("Invalid -fullOutput syntax");
324 scanned[iArg].n_items++;
325 if (fullOutputFlags & FL_FULLOUTPUT_UNFOLDED)
326 flags |= FL_FULLOUTPUT_UNFOLDED;
327 else
328 flags |= FL_FULLOUTPUT_FOLDED;
329 if (fullOutputFlags & FL_UNWRAP_PHASE)
330 flags |= FL_UNWRAP_PHASE;
331 }
332 break;
333 case SET_PIPE:
334 if (!processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
335 SDDS_Bomb("invalid -pipe syntax");
336 break;
337 case SET_PSDOUTPUT:
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))
342 SDDS_Bomb("invalid -psdOutput syntax");
343 } else {
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))
345 SDDS_Bomb("invalid -psdOutput syntax");
346 }
347 flags |= tmpFlags;
348 } else
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");
352 break;
353 case SET_EXCLUDE:
354 if (scanned[iArg].n_items < 2)
355 SDDS_Bomb("invalid -exclude syntax");
356 moveToStringArray(&exclude, &excludes, scanned[iArg].list + 1, scanned[iArg].n_items - 1);
357 break;
358 case SET_NOWARNINGS:
359 noWarnings = 1;
360 break;
361 case SET_COMPLEXINPUT:
362 complexInput = 1;
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++;
368 }
369 break;
370 case SET_INVERSE:
371 inverse = 1;
372 break;
373 case SET_MAJOR_ORDER:
374 majorOrderFlag = 0;
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;
382 break;
383 default:
384 fprintf(stderr, "error: unknown/ambiguous option: %s\n", scanned[iArg].list[0]);
385 exit(EXIT_FAILURE);
386 break;
387 }
388 } else {
389 if (!input)
390 input = scanned[iArg].list[0];
391 else if (!output)
392 output = scanned[iArg].list[0];
393 else
394 SDDS_Bomb("too many filenames seen");
395 }
396 }
397 if (!complexInput) {
398 if (!noWarnings && inverse)
399 fprintf(stderr, "Warning: the inverse option is ignored since it only works with -complexInput.\n");
400 inverse = 0;
401 }
402 if (!noWarnings && inverse && flags & FL_FULLOUTPUT_FOLDED)
403 fprintf(stderr, "Warning: the -inverse -fullOutput=folded will be changed to -inverse -fullOutput=unfolded.\n");
404
405 processFilenames("sddsfft", &input, &output, pipeFlags, 0, NULL);
406
407 if (!indepQuantity)
408 SDDS_Bomb("Supply the independent quantity name with the -columns option.");
409
410 if (flags & FL_TRUNCATE && flags & FL_PADWITHZEROES)
411 SDDS_Bomb("Specify only one of -padwithzeroes and -truncate.");
412
413 if (!SDDS_InitializeInput(&SDDSin, input))
414 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
415
416 if (SDDS_CheckColumn(&SDDSin, indepQuantity, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OKAY)
417 exit(EXIT_FAILURE);
418
419 excludes = appendToStringArray(&exclude, excludes, indepQuantity);
420 if (!depenQuantities)
421 depenQuantities = appendToStringArray(&depenQuantity, depenQuantities, "*");
422
423 if (!complexInput) {
424 if ((depenQuantities = expandColumnPairNames(&SDDSin, &depenQuantity, NULL, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
425 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
426 SDDS_Bomb("No quantities selected to FFT.");
427 }
428 } else {
429 if ((depenQuantities = expandComplexColumnPairNames(&SDDSin, depenQuantity, &realQuan, &imagQuan, depenQuantities, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
430 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
431 SDDS_Bomb("No quantities selected to FFT.");
432 }
433 }
434
435#if 0
436 fprintf(stderr, "%ld dependent quantities:\n", depenQuantities);
437 for (i = 0; i < depenQuantities; i++)
438 fprintf(stderr, " %s\n", depenQuantity[i]);
439#endif
440
441 if (!(freqUnits = makeFrequencyUnits(&SDDSin, indepQuantity)) ||
442 !SDDS_InitializeOutput(&SDDSout, SDDS_BINARY, 0, NULL, "sddsfft output", output) ||
443 !create_fft_frequency_column(&SDDSout, &SDDSin, indepQuantity, freqUnits, inverse) ||
444 SDDS_DefineParameter(&SDDSout, "fftFrequencies", NULL, NULL, NULL, NULL, SDDS_LONG, NULL) < 0 ||
445 SDDS_DefineParameter(&SDDSout, "fftFrequencySpacing", "$gD$rf", freqUnits, NULL, NULL, SDDS_DOUBLE, NULL) < 0)
446 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
447 if (columnMajorOrder != -1)
448 SDDSout.layout.data_mode.column_major = columnMajorOrder;
449 else
450 SDDSout.layout.data_mode.column_major = SDDSin.layout.data_mode.column_major;
451
452 if (flags & FL_FULLOUTPUT && SDDS_DefineParameter(&SDDSout, "SpectrumFolded", NULL, NULL, NULL, NULL, SDDS_LONG, NULL) < 0)
453 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
454 if (complexInput) {
455 if (!complexInputFlags) {
456 if (SDDS_CheckParameter(&SDDSin, "SpectrumFolded", NULL, SDDS_LONG, NULL) == SDDS_CHECK_OK)
457 spectrumFoldParExist = 1;
458 } else if (complexInputFlags & FL_COMPLEXINPUT_UNFOLDED)
459 flags |= FL_COMPLEXINPUT_UNFOLDED;
460 else
461 flags |= FL_COMPLEXINPUT_FOLDED;
462 }
463 for (i = 0; i < depenQuantities; i++) {
464 if (!complexInput)
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);
469 else
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);
474 }
475
476 if (!SDDS_TransferAllParameterDefinitions(&SDDSout, &SDDSin, SDDS_TRANSFER_KEEPOLD) ||
477 !SDDS_WriteLayout(&SDDSout))
478 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
479
480 while ((readCode = SDDS_ReadPage(&SDDSin)) > 0) {
481 page++;
482 if ((rows = SDDS_CountRowsOfInterest(&SDDSin)) < 0)
483 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
484 if (page == 1 && spectrumFoldParExist) {
485 if (!SDDS_GetParameterAsLong(&SDDSin, "SpectrumFolded", &spectrumFolded))
486 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
487 if (spectrumFolded)
488 flags |= FL_COMPLEXINPUT_FOLDED;
489 else
490 flags |= FL_COMPLEXINPUT_UNFOLDED;
491 }
492 if (rows) {
493 int64_t primeRows, pow2Rows;
494 rowsToUse = rows;
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;
501 else
502 rowsToUse = pow2Rows;
503 } else if (flags & FL_TRUNCATE)
504 rowsToUse = greatestProductOfSmallPrimes(rows);
505 else if (largest_prime_factor(rows) > 1000 && !noWarnings)
506 fputs("Warning: number of points has large prime factors.\nThis could take a very long time.\nConsider using the -truncate option.\n", stderr);
507 }
508 if (!SDDS_StartPage(&SDDSout, 2 * rowsToUse + 2) || !SDDS_CopyParameters(&SDDSout, &SDDSin))
509 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
510 if (!(tdata = SDDS_GetColumnInDoubles(&SDDSin, indepQuantity)))
511 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
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)) {
519 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
520 exit(EXIT_FAILURE);
521 }
522 free(tdata);
523 } else {
524 if (!SDDS_StartPage(&SDDSout, 0) || !SDDS_CopyParameters(&SDDSout, &SDDSin))
525 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
526 }
527 if (!SDDS_WritePage(&SDDSout))
528 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
529 }
530
531 if (!SDDS_Terminate(&SDDSin)) {
532 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
533 exit(EXIT_FAILURE);
534 }
535 if (!SDDS_Terminate(&SDDSout)) {
536 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
537 exit(EXIT_FAILURE);
538 }
539
540 return EXIT_SUCCESS;
541}
542
543static long psdOffset, argOffset, realOffset, imagOffset, fftOffset = -1, psdIntOffset, psdIntPowerOffset, unwrappedArgOffset = -1;
544
545long process_data(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, double *tdata, int64_t rows,
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;
553 char s[256];
554 double *fdata, *imagData = NULL;
555 double *tDataStore = NULL;
556 double windowCorrectionFactor = 0;
557
558 if (!(data = SDDS_GetColumnInDoubles(SDDSin, depenQuantity)))
559 return 0;
560 if (imagQuantity && !(imagData = SDDS_GetColumnInDoubles(SDDSin, imagQuantity)))
561 return 0;
562 if (flags & FL_SUPPRESSAVERAGE) {
563 compute_average(&r, data, rows);
564 for (i = 0; i < rows; i++)
565 data[i] -= r;
566 if (imagData) {
567 compute_average(&r, imagData, rows);
568 for (i = 0; i < rows; i++)
569 imagData[i] -= r;
570 }
571 }
572 if (rows < rowsToUse) {
573 /* pad with zeroes */
574 tDataStore = tmalloc(sizeof(*tDataStore) * rowsToUse);
575 memcpy((char *)tDataStore, (char *)tdata, rows * sizeof(*tdata));
576 if (!(data = SDDS_Realloc(data, sizeof(*data) * rowsToUse)))
577 SDDS_Bomb("memory allocation failure");
578 if (imagData && !(imagData = SDDS_Realloc(imagData, sizeof(*imagData) * rowsToUse)))
579 length = ((double)rows) * (tdata[rows - 1] - tdata[0]) / ((double)rows - 1.0);
580 else
581 length = tdata[rows - 1] - tdata[0];
582 for (i = rows; i < rowsToUse; i++) {
583 tDataStore[i] = tDataStore[i - 1] + length / ((double)rows - 1);
584 data[i] = 0;
585 }
586 if (imagData)
587 for (i = rows; i < rowsToUse; i++)
588 imagData[i] = 0;
589 tdata = tDataStore;
590 }
591 rows = rowsToUse; /* results in truncation if rows>rowsToUse */
592 windowCorrectionFactor = 0;
593 switch (windowType) {
594 case WINDOW_HANNING:
595 r = PIx2 / (rows - 1);
596 for (i = 0; i < rows; i++) {
597 factor = (1 - cos(i * r)) / 2;
598 data[i] *= factor;
599 windowCorrectionFactor += sqr(factor);
600 if (imagData)
601 imagData[i] *= factor;
602 }
603 break;
604 case WINDOW_HAMMING:
605 r = PIx2 / (rows - 1);
606 for (i = 0; i < rows; i++) {
607 factor = 0.54 - 0.46 * cos(i * r);
608 data[i] *= factor;
609 windowCorrectionFactor += sqr(factor);
610 if (imagData)
611 imagData[i] *= factor;
612 }
613 if (imagData)
614 for (i = 0; i < rows; i++)
615 imagData[i] *= (1 - cos(i * r)) / 2;
616 break;
617 case WINDOW_WELCH:
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;
622 data[i] *= factor;
623 windowCorrectionFactor += sqr(factor);
624 if (imagData)
625 imagData[i] *= factor;
626 }
627 break;
628 case WINDOW_PARZEN:
629 r = (rows - 1) / 2.0;
630 for (i = 0; i < rows; i++) {
631 factor = 1 - FABS((i - r) / r);
632 data[i] *= factor;
633 windowCorrectionFactor += sqr(factor);
634 if (imagData)
635 imagData[i] *= factor;
636 }
637 break;
638 case WINDOW_FLATTOP:
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);
642 data[i] *= factor;
643 windowCorrectionFactor += sqr(factor);
644 if (imagData)
645 imagData[i] *= factor;
646 }
647 break;
648 case WINDOW_GAUSSIAN:
649 for (i = 0; i < rows; i++) {
650 r = sqr((i - (rows - 1) / 2.) / (0.4 * (rows - 1) / 2.)) / 2;
651 factor = exp(-r);
652 data[i] *= factor;
653 windowCorrectionFactor += sqr(factor);
654 if (imagData)
655 imagData[i] *= factor;
656 }
657 break;
658 case WINDOW_NONE:
659 default:
660 windowCorrectionFactor = 1;
661 break;
662 }
663
664 if (correctWindowEffects) {
665 /* Add correction factor to make the integrated PSD come out right. */
666 windowCorrectionFactor = 1 / sqrt(windowCorrectionFactor / rows);
667 for (i = 0; i < rows; i++)
668 data[i] *= windowCorrectionFactor;
669 if (imagData)
670 imagData[i] *= windowCorrectionFactor;
671 }
672 if (imagData && flags & FL_COMPLEXINPUT_FOLDED) {
673 double min, max, max1;
674 data = SDDS_Realloc(data, sizeof(*data) * rows * 2);
675 imagData = SDDS_Realloc(imagData, sizeof(*data) * rows * 2);
676 find_min_max(&min, &max, data, rows);
677 if (fabs(min) > fabs(max))
678 max1 = fabs(min);
679 else
680 max1 = fabs(max);
681 find_min_max(&min, &max, imagData, rows);
682 if (fabs(min) > max1)
683 max1 = fabs(min);
684 if (fabs(max) > max1)
685 max1 = fabs(max);
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;
691 }
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];
695 }
696 length = (tdata[rows - 1] - tdata[0]) * 2.0;
697 } else {
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;
702 }
703 for (i = 0; i < rows - 1; i++) {
704 data[rows + i] = data[rows - 1 - i];
705 imagData[rows + i] = -imagData[rows - 1 - i];
706 }
707 length = ((double)fftrows) * (tdata[rows - 1] - tdata[0]) / ((double)fftrows - 1.0) * 2;
708 }
709 } else {
710 fftrows = rows;
711 length = ((double)rows) * (tdata[rows - 1] - tdata[0]) / ((double)rows - 1.0);
712 }
713 /* compute FFT */
714
715 real_imag = tmalloc(sizeof(double) * (2 * fftrows + 2));
716 for (i = 0; i < fftrows; i++) {
717 real_imag[2 * i] = data[i];
718 if (imagData)
719 real_imag[2 * i + 1] = imagData[i];
720 else
721 real_imag[2 * i + 1] = 0;
722 }
723 if (!inverse) {
724 complexFFT(real_imag, fftrows, 0);
725 if (flags & FL_FULLOUTPUT_UNFOLDED) {
726 n_freq = fftrows;
727 unfold = 1;
728 } else if (flags & FL_FULLOUTPUT_FOLDED)
729 n_freq = fftrows / 2 + 1;
730 else if (!imagData)
731 n_freq = fftrows / 2 + 1;
732 else
733 n_freq = fftrows + 1;
734 } else {
735 complexFFT(real_imag, fftrows, INVERSE_FFT);
736 n_freq = fftrows;
737 }
738 /* calculate factor for converting k to f or omega */
739 /* length is assumed the length of period, not the total length of the data file */
740
741 /* length = ((double)rows)*(tdata[rows-1]-tdata[0])/((double)rows-1.0); */
742 t0 = tdata[0];
743 df = factor = 1.0 / length;
744
745 /* convert into amplitudes and frequencies, adding phase factor for t[0]!=0 */
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);
755 }
756 }
757
758 for (i = 0; i < n_freq; i++) {
759 fdata[i] = i * df;
760 dtf_real = cos(-2 * PI * fdata[i] * t0);
761 dtf_imag = sin(-2 * PI * fdata[i] * t0);
762 if (psd)
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)) {
765 /* This is not the DC or Nyquist term, so
766 multiply by 2 to account for amplitude in
767 negative frequencies
768 */
769 if (!unfold) {
770 real_imag[2 * i] *= 2;
771 real_imag[2 * i + 1] *= 2;
772 }
773 if (psd)
774 psd[i] *= 2; /* 2 really is what I want--not 4 */
775 }
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]));
779 }
780
781 if (psdInteg) {
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]);
788 } else {
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.;
793 }
794 for (i = 0; i < n_freq; i++)
795 psdInteg[i] = sqrt(psdIntegPower[i]);
796 }
797 }
798
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]);
804 else
805 arg[i] = 0;
806 }
807 }
808 if (flags & FL_UNWRAP_PHASE) {
809 find_min_max(&min, &max, magData, n_freq);
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];
815 if (delta < -180.0)
816 phase_correction += 360.0;
817 else if (delta > 180.0)
818 phase_correction -= 360.0;
819 }
820 unwrapArg[i] = arg[i] + phase_correction;
821 }
822 }
823
824 if (flags & FL_NORMALIZE) {
825 factor = -DBL_MAX;
826 for (i = 0; i < n_freq; i++)
827 if (magData[i] > factor)
828 factor = magData[i];
829 if (factor != -DBL_MAX)
830 for (i = 0; i < n_freq; i++) {
831 real[i] /= factor;
832 imag[i] /= factor;
833 magData[i] /= factor;
834 }
835 }
836 if (!inverse)
837 sprintf(s, "FFT%s", depenQuantity + (imagData ? 4 : 0));
838 else {
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);
843 else
844 sprintf(s, "%s", depenQuantity);
845 }
846
847 if ((index = SDDS_GetColumnIndex(SDDSout, s)) < 0)
848 return 0;
849
850 if (flags & FL_SUPPRESSAVERAGE) {
851 n_freq -= 1;
852 offset = 1;
853 } else
854 offset = 0;
855
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)))
868 return 0;
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;
874 if (!SDDS_AssertRowFlags(SDDSout, SDDS_FLAG_ARRAY, sample_row_flag, n_freq)) {
875 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
876 return 0;
877 }
878 free(sample_row_flag);
879 }
880 if (!SDDS_SetParameters(SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, "fftFrequencies", n_freq, "fftFrequencySpacing", df, NULL))
881 return 0;
882 if (flags & FL_FULLOUTPUT && !SDDS_SetParameters(SDDSout, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, "SpectrumFolded", flags & FL_FULLOUTPUT_UNFOLDED ? 0 : 1, NULL))
883 return 0;
884 free(data);
885 free(magData);
886 if (imagData)
887 free(imagData);
888 if (tDataStore)
889 free(tDataStore);
890 if (arg)
891 free(arg);
892 free(real_imag);
893 free(real);
894 free(imag);
895 free(fdata);
896 if (psd)
897 free(psd);
898 if (psdInteg)
899 free(psdInteg);
900 if (psdIntegPower)
901 free(psdIntegPower);
902 if (unwrapArg)
903 free(unwrapArg);
904 return 1;
905}
906
907long create_fft_frequency_column(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, char *timeName, char *freqUnits, long inverse) {
908 char s[SDDS_MAXLINE];
909 char *timeSymbol;
910 char *description;
911
912 if (SDDS_GetColumnInformation(SDDSin, "symbol", &timeSymbol, SDDS_GET_BY_NAME, timeName) != SDDS_STRING)
913 return 0;
914 if (!timeSymbol || SDDS_StringIsBlank(timeSymbol))
915 SDDS_CopyString(&timeSymbol, timeName);
916
917 sprintf(s, "Frequency for %s", timeSymbol);
918 SDDS_CopyString(&description, s);
919 if (!inverse) {
920 if (SDDS_DefineColumn(SDDSout, "f", NULL, freqUnits, description, NULL, SDDS_DOUBLE, 0) < 0) {
921 free(timeSymbol);
922 free(description);
923 return 0;
924 }
925 } else {
926 sprintf(s, "inverse for %s", timeSymbol);
927 SDDS_CopyString(&description, s);
928 if (SDDS_DefineColumn(SDDSout, "t", NULL, freqUnits, description, NULL, SDDS_DOUBLE, 0) < 0) {
929 free(timeSymbol);
930 free(description);
931 return 0;
932 }
933 }
934 free(timeSymbol);
935 free(description);
936 return 1;
937}
938
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;
943 long index0, index1;
944 long offset = 0;
945
946 if (complexInput)
947 offset = 4;
948 if (SDDS_GetColumnInformation(SDDSin, "units", &origUnits, SDDS_GET_BY_NAME, origName) != SDDS_STRING ||
949 SDDS_GetColumnInformation(SDDSin, "symbol", &origSymbol, SDDS_GET_BY_NAME, origName) != SDDS_STRING)
950 return 0;
951 if (!inverse)
952 sprintf(s, "FFT%s", origName + offset);
953 else {
954 if (strncmp(origName, "FFT", 3) == 0)
955 offset = 3;
956 else if (strncmp(origName, "RealFFT", 7) == 0)
957 offset = 7;
958 else
959 offset = 0;
960 sprintf(s, "%s", origName + offset);
961 }
962 SDDS_CopyString(&name, s);
963 if (!origSymbol)
964 SDDS_CopyString(&origSymbol, origName + offset);
965 sprintf(s, "FFT %s", origSymbol);
966 SDDS_CopyString(&symbol, s);
967
968 sprintf(s, "Amplitude of FFT of %s", origSymbol);
969 SDDS_CopyString(&description, s);
970
971 if (SDDS_NumberOfErrors() || (index0 = SDDS_DefineColumn(SDDSout, name, symbol, origUnits, description, NULL, SDDS_DOUBLE, 0)) < 0)
972 return 0;
973 free(name);
974 free(symbol);
975 free(description);
976
977 if (fftOffset == -1)
978 fftOffset = 0;
979
980 if (psd_output & FL_PSDOUTPUT) {
981 if (origUnits && !SDDS_StringIsBlank(origUnits)) {
982 if (freqUnits && !SDDS_StringIsBlank(freqUnits)) {
983 sprintf(s, "(%s)$a2$n/(%s)", origUnits, freqUnits);
984 } else
985 sprintf(s, "(%s)$a2$n", origUnits);
986 SDDS_CopyString(&units, s);
987 } else
988 units = NULL;
989
990 sprintf(s, "PSD%s", origName + offset);
991 SDDS_CopyString(&name, s);
992
993 if (!origSymbol)
994 SDDS_CopyString(&origSymbol, origName + offset);
995 sprintf(s, "PSD %s", origSymbol);
996 SDDS_CopyString(&symbol, s);
997
998 sprintf(s, "PSD of %s", origSymbol);
999 SDDS_CopyString(&description, s);
1000
1001 if (SDDS_NumberOfErrors() || (index1 = SDDS_DefineColumn(SDDSout, name, symbol, units, description, NULL, SDDS_DOUBLE, 0)) < 0)
1002 return 0;
1003 psdOffset = index1 - index0;
1004 free(name);
1005 if (units)
1006 free(units);
1007 free(symbol);
1008 free(description);
1009 }
1010
1011 if (psd_output & (FL_PSDINTEGOUTPUT + FL_PSDRINTEGOUTPUT)) {
1012 if (origUnits && !SDDS_StringIsBlank(origUnits)) {
1013 SDDS_CopyString(&units, origUnits);
1014 } else
1015 units = NULL;
1016
1017 sprintf(s, "SqrtIntegPSD%s", origName + offset);
1018 SDDS_CopyString(&name, s);
1019
1020 if (!origSymbol)
1021 SDDS_CopyString(&origSymbol, origName + offset);
1022 sprintf(s, "Sqrt Integ PSD %s", origSymbol);
1023 SDDS_CopyString(&symbol, s);
1024
1025 sprintf(s, "Sqrt Integ PSD of %s", origSymbol);
1026 SDDS_CopyString(&description, s);
1027
1028 if (SDDS_NumberOfErrors() || (index1 = SDDS_DefineColumn(SDDSout, name, symbol, units, description, NULL, SDDS_DOUBLE, 0)) < 0)
1029 return 0;
1030 psdIntOffset = index1 - index0;
1031
1032 sprintf(s, "IntegPSD%s", origName + offset);
1033 SDDS_CopyString(&name, s);
1034
1035 if (!origSymbol)
1036 SDDS_CopyString(&origSymbol, origName + offset);
1037 sprintf(s, "Integ PSD %s", origSymbol);
1038 SDDS_CopyString(&symbol, s);
1039
1040 sprintf(s, "Integ PSD of %s", origSymbol);
1041 SDDS_CopyString(&description, s);
1042
1043 if (origUnits && !SDDS_StringIsBlank(origUnits)) {
1044 sprintf(s, "%sPower", origUnits);
1045 SDDS_CopyString(&units, origUnits);
1046 } else
1047 units = NULL;
1048
1049 if (SDDS_NumberOfErrors() || (index1 = SDDS_DefineColumn(SDDSout, name, symbol, units, description, NULL, SDDS_DOUBLE, 0)) < 0)
1050 return 0;
1051 psdIntPowerOffset = index1 - index0;
1052 free(name);
1053 if (units)
1054 free(units);
1055 free(symbol);
1056 free(description);
1057 }
1058
1059 if (full_output) {
1060 if (!inverse)
1061 sprintf(s, "RealFFT%s", origName + offset);
1062 else
1063 sprintf(s, "Real%s", origName + offset);
1064 SDDS_CopyString(&name, s);
1065
1066 if (!origSymbol)
1067 SDDS_CopyString(&origSymbol, origName + offset);
1068 if (!inverse)
1069 sprintf(s, "Re[FFT %s]", origSymbol);
1070 else
1071 sprintf(s, "Re[%s]", origSymbol);
1072 SDDS_CopyString(&symbol, s);
1073
1074 if (!inverse)
1075 sprintf(s, "Real part of FFT of %s", origSymbol);
1076 else
1077 sprintf(s, "Real part of %s", origSymbol);
1078 SDDS_CopyString(&description, s);
1079
1080 if (SDDS_NumberOfErrors() || (index1 = SDDS_DefineColumn(SDDSout, name, symbol, origUnits, description, NULL, SDDS_DOUBLE, 0)) < 0)
1081 return 0;
1082 realOffset = index1 - index0;
1083 free(name);
1084 free(symbol);
1085 free(description);
1086
1087 if (!inverse)
1088 sprintf(s, "ImagFFT%s", origName + offset);
1089 else
1090 sprintf(s, "Imag%s", origName + offset);
1091 SDDS_CopyString(&name, s);
1092
1093 if (!origSymbol)
1094 SDDS_CopyString(&origSymbol, origName + offset);
1095 if (!inverse)
1096 sprintf(s, "Im[FFT %s]", origSymbol);
1097 else
1098 sprintf(s, "Im[%s]", origSymbol);
1099 SDDS_CopyString(&symbol, s);
1100
1101 if (!inverse)
1102 sprintf(s, "Imaginary part of FFT of %s", origSymbol);
1103 else
1104 sprintf(s, "Imaginary part of %s", origSymbol);
1105 SDDS_CopyString(&description, s);
1106
1107 if (SDDS_NumberOfErrors() || (index1 = SDDS_DefineColumn(SDDSout, name, symbol, origUnits, description, NULL, SDDS_DOUBLE, 0)) < 0)
1108 return 0;
1109 imagOffset = index1 - index0;
1110 free(name);
1111 free(symbol);
1112 free(description);
1113
1114 if (!inverse)
1115 sprintf(s, "ArgFFT%s", origName + offset);
1116 else
1117 sprintf(s, "Arg%s", origName + offset);
1118 SDDS_CopyString(&name, s);
1119
1120 if (!origSymbol)
1121 SDDS_CopyString(&origSymbol, origName + offset);
1122 if (!inverse)
1123 sprintf(s, "Arg[FFT %s]", origSymbol);
1124 else
1125 sprintf(s, "Arg[%s]", origSymbol);
1126 SDDS_CopyString(&symbol, s);
1127
1128 if (!inverse)
1129 sprintf(s, "Phase of FFT of %s", origSymbol);
1130 else
1131 sprintf(s, "Phase of %s", origSymbol);
1132 SDDS_CopyString(&description, s);
1133
1134 if (SDDS_NumberOfErrors() || (index1 = SDDS_DefineColumn(SDDSout, name, symbol, "degrees", description, NULL, SDDS_DOUBLE, 0)) < 0)
1135 return 0;
1136 argOffset = index1 - index0;
1137 free(name);
1138 free(symbol);
1139 free(description);
1140 if (unwrap_phase) {
1141 if (!inverse)
1142 sprintf(s, "UnwrapArgFFT%s", origName + offset);
1143 else
1144 sprintf(s, "UnwrapArg%s", origName + offset);
1145 SDDS_CopyString(&name, s);
1146
1147 if (!origSymbol)
1148 SDDS_CopyString(&origSymbol, origName + offset);
1149 if (!inverse)
1150 sprintf(s, "UnwrapArg[FFT %s]", origSymbol);
1151 else
1152 sprintf(s, "UnwrapArg[%s]", origSymbol);
1153 SDDS_CopyString(&symbol, s);
1154
1155 if (!inverse)
1156 sprintf(s, "Unwrapped Phase of FFT of %s", origSymbol);
1157 else
1158 sprintf(s, "Unwrapped Phase of %s", origSymbol);
1159 SDDS_CopyString(&description, s);
1160
1161 if (SDDS_NumberOfErrors() || (index1 = SDDS_DefineColumn(SDDSout, name, symbol, "degrees", description, NULL, SDDS_DOUBLE, 0)) < 0)
1162 return 0;
1163 unwrappedArgOffset = index1 - index0;
1164 free(name);
1165 free(symbol);
1166 free(description);
1167 }
1168 }
1169
1170 return 1;
1171}
1172
1173void moveToStringArrayComplex(char ***targetReal, char ***targetImag, long *targets, char **sourceReal, char **sourceImag, long sources);
1174
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;
1179 long longest=0;
1180
1181 if (!names || !name)
1182 return 0;
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]);
1188 }
1189 longest += 10;
1190 if (!(realPattern = SDDS_Malloc(sizeof(*realPattern) * longest)) || !(imagPattern = SDDS_Malloc(sizeof(*imagPattern) * longest)))
1191 SDDS_Bomb("memory allocation failure");
1192
1193 for (i = 0; i < names; i++) {
1194 for (j = 0; j < 2; j++) {
1195 if (j == 0) {
1196 sprintf(realPattern, "Real%s", name[i]);
1197 sprintf(imagPattern, "Imag%s", name[i]);
1198 } else {
1199 sprintf(realPattern, "%sReal", name[i]);
1200 sprintf(imagPattern, "%sImag", name[i]);
1201 }
1202 switch (typeMode) {
1203 case FIND_ANY_TYPE:
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);
1209 break;
1210 case FIND_SPECIFIED_TYPE:
1211 if (!SDDS_VALID_TYPE(typeValue))
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);
1215 break;
1216 default:
1217 SDDS_Bomb("invalid typeMode in expandColumnPairNames");
1218 exit(EXIT_FAILURE);
1219 break;
1220 }
1221 if (realNames == 0)
1222 continue;
1223 if (realNames == -1 || imagNames == -1) {
1224 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
1225 SDDS_Bomb("unable to perform column name match in expandColumnPairNames");
1226 }
1227 if (realNames != imagNames)
1228 SDDS_Bomb("found different number of real and imaginary columns");
1229 if (excludeNames) {
1230 for (j = 0; j < excludeNames; j++)
1231 for (k = 0; k < realNames; k++)
1232 if (wild_match(realName1[k], excludeName[j])) {
1233 free(realName1[k]);
1234 free(imagName1[k]);
1235 imagName1[k] = realName1[k] = NULL;
1236 }
1237 }
1238 moveToStringArrayComplex(&realName2, &imagName2, &names2, realName1, imagName1, realNames);
1239 free(realName1);
1240 free(imagName1);
1241 }
1242 }
1243 free(realPattern);
1244 free(imagPattern);
1245 if (names2 == 0)
1246 return 0;
1247 *realName = realName2;
1248 *imagName = imagName2;
1249 return names2;
1250}
1251
1252void moveToStringArrayComplex(char ***targetReal, char ***targetImag, long *targets, char **sourceReal, char **sourceImag, long sources) {
1253 long i, j;
1254 if (!sources)
1255 return;
1256 if (!(*targetReal = SDDS_Realloc(*targetReal, sizeof(**targetReal) * (*targets + sources))) ||
1257 !(*targetImag = SDDS_Realloc(*targetImag, sizeof(**targetImag) * (*targets + sources))))
1258 SDDS_Bomb("memory allocation failure");
1259 for (i = 0; i < sources; i++) {
1260 if (sourceReal[i] == NULL || sourceImag[i] == NULL)
1261 continue;
1262 for (j = 0; j < *targets; j++)
1263 if (strcmp(sourceReal[i], (*targetReal)[j]) == 0)
1264 break;
1265 if (j == *targets) {
1266 (*targetReal)[j] = sourceReal[i];
1267 (*targetImag)[j] = sourceImag[i];
1268 *targets += 1;
1269 }
1270 }
1271}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:286
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_AssertRowFlags(SDDS_DATASET *SDDS_dataset, uint32_t mode,...)
Sets acceptance flags for rows based on specified criteria.
int32_t * SDDS_GetParameterAsLong(SDDS_DATASET *SDDS_dataset, char *parameter_name, int32_t *memory)
Retrieves the value of a specified parameter as a 32-bit integer from the current data table of a dat...
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
double * SDDS_GetColumnInDoubles(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of doubles, considering only rows mark...
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.
Definition SDDS_info.c:41
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:49
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_ReadPage(SDDS_DATASET *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.
Definition SDDS_utils.c:432
void * SDDS_Malloc(size_t size)
Allocates memory of a specified size.
Definition SDDS_utils.c:639
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
int32_t SDDS_NumberOfErrors()
Retrieves the number of errors recorded by SDDS library routines.
Definition SDDS_utils.c:304
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.
Definition SDDS_utils.c:342
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.
Definition SDDS_utils.c:856
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:677
#define SDDS_VALID_TYPE(type)
Validates whether the given type identifier is within the defined range of SDDS types.
Definition SDDStypes.h:149
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_ANY_NUMERIC_TYPE
Special identifier used by SDDS_Check*() routines to accept any numeric type.
Definition SDDStypes.h:157
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
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.
Definition array.c:59
int64_t largest_prime_factor(int64_t number)
Find the largest prime factor of a number.
Definition factorize.c:83
int find_min_max(double *min, double *max, double *list, int64_t n)
Finds the minimum and maximum values in a list of doubles.
Definition findMinMax.c:33
double ipow(const double x, const int64_t p)
Compute x raised to the power p (x^p).
Definition ipow.c:33
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.
long compute_average(double *value, double *data, int64_t n)
Computes the average of an array of doubles.
Definition median.c:144
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:356
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:390
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.
Definition wild_match.c:49