SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
sddsfdfilter.c
Go to the documentation of this file.
1/**
2 * @file sddsfdfilter.c
3 * @brief SDDS-format frequency-domain filter program.
4 *
5 * @details
6 * This program applies various frequency-domain filters to SDDS-formatted data files. It supports multiple filtering
7 * options, including high-pass, low-pass, notch, bandpass, threshold, and file-based filters. Users can specify
8 * input and output files or use pipes for data processing.
9 *
10 * @section Usage
11 * ```
12 * sddsfdfilter [<inputfile>] [<outputfile>]
13 * [-pipe=[input][,output]]
14 * [-columns=<indep-variable>[,<depen-quantity>[,...]]]
15 * [-exclude=<depen-quantity>[,...]]
16 * [-clipFrequencies=[high=<number>][,low=<number>]]
17 * [-threshold=level=<value>[,fractional][,start=<freq>][,end=<freq>]]
18 * [-highpass=start=<freq>,end=<freq>]
19 * [-lowpass=start=<freq>,end=<freq>]
20 * [-notch=center=<center>,flatWidth=<value>,fullWidth=<value>]
21 * [-bandpass=center=<center>,flatWidth=<value>,fullWidth=<value>]
22 * [-filterFile=filename=<filename>,frequency=<columnName>{,real=<cName>,imaginary=<cName>|magnitude=<cName>}]
23 * [-cascade]
24 * [-newColumns]
25 * [-differenceColumns]
26 * [-majorOrder=row|column]
27 * ```
28 *
29 * @section Options
30 * | Required | Description |
31 * |--------------------|----------------------------------------------------------------------------|
32 * | `-columns` | Specifies columns to filter. |
33 *
34 * | Optional | Description |
35 * |-----------------------------------------|----------------------------------------------------------------------------|
36 * | `-pipe` | Specifies input and/or output via pipes. |
37 * | `-exclude` | Specifies columns to exclude from filtering. |
38 * | `-clipFrequencies` | Clips frequencies outside the specified range. |
39 * | `-threshold` | Filters based on a threshold with optional range. |
40 * | `-highpass` | Applies a high-pass filter with a specified frequency range. |
41 * | `-lowpass` | Applies a low-pass filter with a specified frequency range. |
42 * | `-notch` | Applies a notch filter with specified characteristics. |
43 * | `-bandpass` | Applies a band-pass filter with specified characteristics. |
44 * | `-filterFile` | Specifies a filter based on external file data. |
45 * | `-cascade` | Specifies cascaded filter stages. |
46 * | `-newColumns` | Creates new columns for filtered data. |
47 * | `-differenceColumns` | Creates columns for differences between original and filtered data. |
48 * | `-majorOrder` | Specifies major order as either `row` or `column`. |
49 *
50 * @subsection Incompatibilities
51 * - `-cascade` must not precede filter definitions.
52 * - Only one of the following may be specified for `-filterFile`:
53 * - `magnitude=<columnName>`
54 * - Both `real=<columnName>` and `imaginary=<columnName>`
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, R. Soliday, Xuesong Jiao, L. Emery, H. Shang
66 */
67
68#include "mdb.h"
69#include "SDDS.h"
70#include "scan.h"
71#include "fftpackC.h"
72#include "SDDSutils.h"
73#include <ctype.h>
74
75/* Enumeration for option types */
76enum option_type {
77 SET_PIPE,
78 SET_CASCADE,
79 SET_CLIPFREQ,
80 SET_COLUMNS,
81 SET_THRESHOLD,
82 SET_HIGHPASS,
83 SET_LOWPASS,
84 SET_NOTCH,
85 SET_BANDPASS,
86 SET_FILTERFILE,
87 SET_NEWCOLUMNS,
88 SET_DIFFERENCECOLUMNS,
89 SET_EXCLUDE,
90 SET_MAJOR_ORDER,
91 N_OPTIONS
92};
93
94char *option[N_OPTIONS] = {
95 "pipe",
96 "cascade",
97 "clip",
98 "columns",
99 "threshold",
100 "highpass",
101 "lowpass",
102 "notch",
103 "bandpass",
104 "filterfile",
105 "newcolumns",
106 "differencecolumns",
107 "exclude",
108 "majorOrder",
109};
110
111/* Improved and formatted usage message */
112static char *USAGE =
113 "sddsfdfilter [<inputfile>] [<outputfile>]\n"
114 " [-pipe=[input][,output]]\n"
115 " [-columns=<indep-variable>[,<depen-quantity>[,...]]]\n"
116 " [-exclude=<depen-quantity>[,...]]\n"
117 " [-clipFrequencies=[high=<number>][,low=<number>]]\n"
118 " [-threshold=level=<value>[,fractional][,start=<freq>][,end=<freq>]]\n"
119 " [-highpass=start=<freq>,end=<freq>]\n"
120 " [-lowpass=start=<freq>,end=<freq>]\n"
121 " [-notch=center=<center>,flatWidth=<value>,fullWidth=<value>]\n"
122 " [-bandpass=center=<center>,flatWidth=<value>,fullWidth=<value>]\n"
123 " [-filterFile=filename=<filename>,frequency=<columnName>{,real=<cName>,imaginary=<cName>|magnitude=<cName>}]\n"
124 " [-cascade]\n"
125 " [-newColumns]\n"
126 " [-differenceColumns]\n"
127 " [-majorOrder=row|column]\n\n"
128 "Program by Michael Borland. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
129
130#define FILT_START_GIVEN 0x00000001U
131#define FILT_END_GIVEN 0x00000002U
132#define FILT_THRES_GIVEN 0x00000004U
133#define FILT_CENTER_GIVEN 0x00000008U
134#define FILT_FULLWIDTH_GIVEN 0x00000010U
135#define FILT_FREQNAME_GIVEN 0x00000020U
136#define FILT_REALNAME_GIVEN 0x00000040U
137#define FILT_IMAGNAME_GIVEN 0x00000080U
138#define FILT_MAGNAME_GIVEN 0x00000100U
139#define FILT_FRACTHRES_GIVEN 0x00000200U
140#define FILT_LEVEL_GIVEN 0x00000400U
141#define FILT_FILENAME_GIVEN 0x00000800U
142#define FILT_HIGH_GIVEN 0x00001000U
143#define FILT_LOW_GIVEN 0x00002000U
144#define FILT_FLATWIDTH_GIVEN 0x00004000U
145
146typedef struct {
147 double level, start, end;
148 unsigned long flags;
150
151typedef struct {
152 double start, end;
153 unsigned long flags;
155
156typedef struct {
157 double center, fullwidth, flatwidth;
158 unsigned long flags;
160
161typedef struct {
162 char *file, *freqName, *realName, *imagName, *magName;
163 double *freqData, *realData, *imagData, *magData;
164 long points;
165 unsigned long flags;
167
168typedef struct {
169 int32_t high, low;
170 unsigned long flags;
172
173typedef struct {
174 void *filter;
175 long filterType;
176} FILTER;
177
178typedef struct {
179 FILTER *filter;
180 long filters;
182
183#define FL_NEWCOLUMNS 0x00001UL
184#define FL_DIFCOLUMNS 0x00002UL
185
186long applyFilters(double *outputData, double *inputData, double *timeData, int64_t rows, FILTER_STAGE *filterStage, long filterStages);
187long applyFilterStage(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, FILTER_STAGE *filterStage);
188void addClipFilterOutput(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, CLIP_FILTER *filter);
189void addThresholdFilterOutput(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, THRESHOLD_FILTER *filter);
190void addHighPassFilterOutput(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, HILO_FILTER *filter);
191void addLowPassFilterOutput(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, HILO_FILTER *filter);
192void addNotchFilterOutput(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, NHBP_FILTER *filter);
193void addBandPassFilterOutput(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, NHBP_FILTER *filter);
194void addFileFilterOutput(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, FILE_FILTER *filter);
195int64_t computeIndex(double value, double dfrequency, int64_t frequencies);
196void addFilter(FILTER_STAGE *filterStage, long optionCode, SCANNED_ARG *scanned);
197
198int main(int argc, char **argv) {
199 int iArg;
200 char **outputColumn, **difColumn;
201 char *indepColumn, **depenColumn, **exclude;
202 long depenColumns, excludes;
203 char *input, *output;
204 long i, readCode, optionCode;
205 int64_t rows;
206 unsigned long flags, pipeFlags, majorOrderFlag;
207 SCANNED_ARG *scanned;
208 SDDS_DATASET SDDSin, SDDSout;
209 double *timeData, *inputData, *outputData;
210 FILTER_STAGE *filterStage;
211 long filterStages, totalFilters;
212 short columnMajorOrder = -1;
213
215 argc = scanargs(&scanned, argc, argv);
216 if (argc < 3 || argc > (3 + N_OPTIONS))
217 bomb(NULL, USAGE);
218
219 output = input = NULL;
220 flags = pipeFlags = 0;
221 indepColumn = NULL;
222 depenColumn = exclude = NULL;
223 depenColumns = excludes = 0;
224 if (!(filterStage = (FILTER_STAGE *)calloc(1, sizeof(*filterStage))))
225 SDDS_Bomb("allocation failure");
226
227 filterStage->filter = NULL;
228 filterStage->filters = 0;
229 filterStages = 1;
230 totalFilters = 0;
231
232 for (iArg = 1; iArg < argc; iArg++) {
233 if (scanned[iArg].arg_type == OPTION) {
234 /* Process options here */
235 switch (optionCode = match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
236 case SET_MAJOR_ORDER:
237 majorOrderFlag = 0;
238 scanned[iArg].n_items--;
239 if (scanned[iArg].n_items > 0 && (!scanItemList(&majorOrderFlag, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
240 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
241 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
242 SDDS_Bomb("invalid -majorOrder syntax/values");
243 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
244 columnMajorOrder = 1;
245 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
246 columnMajorOrder = 0;
247 break;
248 case SET_PIPE:
249 if (!processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
250 SDDS_Bomb("invalid -pipe syntax");
251 break;
252 case SET_COLUMNS:
253 if (indepColumn)
254 SDDS_Bomb("only one -columns option may be given");
255 if (scanned[iArg].n_items < 2)
256 SDDS_Bomb("invalid -columns syntax");
257 indepColumn = scanned[iArg].list[1];
258 if (scanned[iArg].n_items >= 2) {
259 depenColumn = tmalloc(sizeof(*depenColumn) * (depenColumns = scanned[iArg].n_items - 2));
260 for (i = 0; i < depenColumns; i++)
261 depenColumn[i] = scanned[iArg].list[i + 2];
262 }
263 break;
264 case SET_THRESHOLD:
265 case SET_HIGHPASS:
266 case SET_LOWPASS:
267 case SET_NOTCH:
268 case SET_BANDPASS:
269 case SET_FILTERFILE:
270 case SET_CLIPFREQ:
271 addFilter(filterStage + filterStages - 1, optionCode, scanned + iArg);
272 totalFilters++;
273 break;
274 case SET_CASCADE:
275 if (filterStages == 0)
276 SDDS_Bomb("-cascade option precedes all filter definitions");
277 if (!(filterStage = SDDS_Realloc(filterStage, (filterStages + 1) * sizeof(*filterStage))))
278 SDDS_Bomb("allocation failure");
279 filterStage[filterStages].filter = NULL;
280 filterStage[filterStages].filters = 0;
281 filterStages++;
282 break;
283 case SET_NEWCOLUMNS:
284 flags |= FL_NEWCOLUMNS;
285 break;
286 case SET_DIFFERENCECOLUMNS:
287 flags |= FL_DIFCOLUMNS;
288 break;
289 case SET_EXCLUDE:
290 if (scanned[iArg].n_items < 2)
291 SDDS_Bomb("invalid -exclude syntax");
292 moveToStringArray(&exclude, &excludes, scanned[iArg].list + 1, scanned[iArg].n_items - 1);
293 break;
294 default:
295 fprintf(stderr, "error: unknown/ambiguous option: %s (%s)\n", scanned[iArg].list[0], argv[0]);
296 exit(EXIT_FAILURE);
297 break;
298 }
299 } else {
300 if (!input)
301 input = scanned[iArg].list[0];
302 else if (!output)
303 output = scanned[iArg].list[0];
304 else
305 SDDS_Bomb("too many filenames seen");
306 }
307 }
308
309 processFilenames("sddsfdfilter", &input, &output, pipeFlags, 0, NULL);
310
311 if (!totalFilters)
312 fputs("warning: no filters specified (sddsfdfilter)\n", stderr);
313
314 if (!indepColumn)
315 SDDS_Bomb("supply the independent column name with the -columns option");
316
317 if (!SDDS_InitializeInput(&SDDSin, input))
318 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
319
320 if (SDDS_CheckColumn(&SDDSin, indepColumn, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OKAY)
321 exit(EXIT_FAILURE);
322
323 excludes = appendToStringArray(&exclude, excludes, indepColumn);
324 if (!depenColumns)
325 depenColumns = appendToStringArray(&depenColumn, depenColumns, "*");
326
327 if ((depenColumns = expandColumnPairNames(&SDDSin, &depenColumn, NULL, depenColumns, exclude, excludes, FIND_NUMERIC_TYPE, 0)) <= 0) {
328 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
329 SDDS_Bomb("No quantities selected to filter");
330 }
331
332 if (!SDDS_InitializeCopy(&SDDSout, &SDDSin, output, "w"))
333 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
334
335 if (columnMajorOrder != -1)
336 SDDSout.layout.data_mode.column_major = columnMajorOrder;
337 else
338 SDDSout.layout.data_mode.column_major = SDDSin.layout.data_mode.column_major;
339
340 if (flags & FL_NEWCOLUMNS) {
341 outputColumn = tmalloc(sizeof(*outputColumn) * depenColumns);
342 for (i = 0; i < depenColumns; i++) {
343 outputColumn[i] = tmalloc(sizeof(**outputColumn) * (strlen(depenColumn[i]) + 1 + strlen("Filtered")));
344 sprintf(outputColumn[i], "%sFiltered", depenColumn[i]);
345 if (!SDDS_TransferColumnDefinition(&SDDSout, &SDDSin, depenColumn[i], outputColumn[i]))
346 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
347 }
348 } else
349 outputColumn = depenColumn;
350
351 difColumn = NULL;
352 if (flags & FL_DIFCOLUMNS) {
353 difColumn = tmalloc(sizeof(*difColumn) * depenColumns);
354 for (i = 0; i < depenColumns; i++) {
355 difColumn[i] = tmalloc(sizeof(**difColumn) * (strlen(depenColumn[i]) + 1 + strlen("Difference")));
356 sprintf(difColumn[i], "%sDifference", depenColumn[i]);
357 if (!SDDS_TransferColumnDefinition(&SDDSout, &SDDSin, depenColumn[i], difColumn[i]))
358 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
359 }
360 }
361
362 if (!SDDS_WriteLayout(&SDDSout))
363 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
364
365 outputData = NULL;
366 while ((readCode = SDDS_ReadPage(&SDDSin)) > 0) {
367 if (!SDDS_CopyPage(&SDDSout, &SDDSin))
368 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
369 if ((rows = SDDS_CountRowsOfInterest(&SDDSin)) < 0)
370 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
371
372 if (rows) {
373 if (!(timeData = SDDS_GetColumnInDoubles(&SDDSin, indepColumn)))
374 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
375 if (!(outputData = SDDS_Realloc(outputData, sizeof(*outputData) * rows)))
376 SDDS_Bomb("allocation failure");
377 for (i = 0; i < depenColumns; i++) {
378 if (!(inputData = SDDS_GetColumnInDoubles(&SDDSin, depenColumn[i])))
379 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
380 if (!applyFilters(outputData, inputData, timeData, rows, filterStage, filterStages))
381 exit(EXIT_FAILURE);
382 if (!SDDS_SetColumnFromDoubles(&SDDSout, SDDS_BY_NAME, outputData, rows, outputColumn[i]))
383 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
384 if (flags & FL_DIFCOLUMNS) {
385 int64_t j;
386 for (j = 0; j < rows; j++)
387 outputData[j] = inputData[j] - outputData[j];
388 if (!SDDS_SetColumnFromDoubles(&SDDSout, SDDS_BY_NAME, outputData, rows, difColumn[i]))
389 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
390 }
391 free(inputData);
392 }
393 free(timeData);
394 }
395 if (!SDDS_WritePage(&SDDSout))
396 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
397 }
398
399 free(outputData);
400 for (i = 0; i < depenColumns; i++) {
401 free(depenColumn[i]);
402 if (flags & FL_NEWCOLUMNS)
403 free(outputColumn[i]);
404 if (flags & FL_DIFCOLUMNS)
405 free(difColumn[i]);
406 }
407 for (i = 0; i < excludes; i++)
408 free(exclude[i]);
409
410 free(indepColumn);
411 if (flags & FL_NEWCOLUMNS)
412 free(outputColumn);
413 free(depenColumn);
414 if (flags & FL_DIFCOLUMNS)
415 free(difColumn);
416 free(exclude);
417 for (i = 0; i < filterStages; i++) {
418 long j;
419 for (j = 0; j < filterStage[i].filters; j++) {
420 switch (filterStage[i].filter[j].filterType) {
421 case SET_FILTERFILE:
422 free(((FILE_FILTER *)(filterStage[i].filter[j].filter))->freqData);
423 free(((FILE_FILTER *)(filterStage[i].filter[j].filter))->magData);
424 free(((FILE_FILTER *)(filterStage[i].filter[j].filter))->imagData);
425 free(((FILE_FILTER *)(filterStage[i].filter[j].filter))->realData);
426 break;
427 default:
428 break;
429 }
430 }
431 }
432
433 if (!SDDS_Terminate(&SDDSout) || !SDDS_Terminate(&SDDSin))
434 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
435
436 return EXIT_SUCCESS;
437}
438
439long applyFilters(double *outputData, double *inputData, double *timeData, int64_t rows, FILTER_STAGE *filterStage, long filterStages) {
440 long stage;
441 int64_t frequencies, row;
442 double *realimagInput, *realimagOutput;
443 double length, dfrequency, factor;
444 realimagOutput = NULL;
445 if (!(realimagInput = (double *)malloc(sizeof(*realimagInput) * (rows + 2))) ||
446 !(realimagOutput = (double *)malloc(sizeof(*realimagOutput) * (rows + 2))))
447 SDDS_Bomb("allocation failure");
448
449 /* Input data is real and has "rows" rows */
450 /* Result is interleaved real and imaginary */
451 realFFT2(realimagInput, inputData, rows, 0);
452 frequencies = rows / 2 + 1;
453
454 /* Length is the assumed length of the periodic signal,
455 which is one interval longer than the actual data entered */
456 length = ((double)rows) * (timeData[rows - 1] - timeData[0]) / ((double)rows - 1.0);
457 dfrequency = factor = 1.0 / length;
458
459 for (stage = 0; stage < filterStages; stage++) {
460 if (!applyFilterStage(realimagOutput, realimagInput, frequencies, dfrequency, filterStage + stage))
461 return 0;
462 SWAP_PTR(realimagOutput, realimagInput);
463 }
464
465 /* Input is still interleaved real and imaginary. The flag
466 INVERSE_FFT ensures that the array is interpreted correctly. */
467 /* Output is interleaved real and imaginary */
468#if DEBUG
469 for (row = 0; row < rows; row++) {
470 fprintf(stdout, "Real: %f, Imag: %f\n", realimagInput[2 * row], realimagInput[2 * row + 1]);
471 }
472#endif
473 realFFT2(realimagOutput, realimagInput, rows, INVERSE_FFT);
474
475 for (row = 0; row < rows; row++)
476 outputData[row] = realimagOutput[row];
477
478 free(realimagOutput);
479 free(realimagInput);
480
481 return 1;
482}
483
484long applyFilterStage(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, FILTER_STAGE *filterStage) {
485 int64_t i, ifilter;
486
487 for (i = 0; i < 2 * frequencies; i++)
488 outputRI[i] = 0;
489
490 for (ifilter = 0; ifilter < filterStage->filters; ifilter++) {
491 switch (filterStage->filter[ifilter].filterType) {
492 case SET_CLIPFREQ:
493 addClipFilterOutput(outputRI, inputRI, frequencies, dfrequency, filterStage->filter[ifilter].filter);
494 break;
495 case SET_THRESHOLD:
496 addThresholdFilterOutput(outputRI, inputRI, frequencies, dfrequency, filterStage->filter[ifilter].filter);
497 break;
498 case SET_HIGHPASS:
499 addHighPassFilterOutput(outputRI, inputRI, frequencies, dfrequency, filterStage->filter[ifilter].filter);
500 break;
501 case SET_LOWPASS:
502 addLowPassFilterOutput(outputRI, inputRI, frequencies, dfrequency, filterStage->filter[ifilter].filter);
503 break;
504 case SET_NOTCH:
505 addNotchFilterOutput(outputRI, inputRI, frequencies, dfrequency, filterStage->filter[ifilter].filter);
506 break;
507 case SET_BANDPASS:
508 addBandPassFilterOutput(outputRI, inputRI, frequencies, dfrequency, filterStage->filter[ifilter].filter);
509 break;
510 case SET_FILTERFILE:
511 addFileFilterOutput(outputRI, inputRI, frequencies, dfrequency, filterStage->filter[ifilter].filter);
512 break;
513 default:
514 SDDS_Bomb("unknown filter type in applyFilterStage--this shouldn't happen");
515 break;
516 }
517 }
518 return 1;
519}
520
521void addClipFilterOutput(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, CLIP_FILTER *filter) {
522 int64_t i1, i2;
523
524 i1 = 0;
525 i2 = frequencies - 1;
526 if (filter->flags & FILT_HIGH_GIVEN)
527 if ((i2 = frequencies - filter->high) < 0)
528 i2 = 0;
529 if (filter->flags & FILT_LOW_GIVEN)
530 if ((i1 = filter->low) >= frequencies)
531 i1 = frequencies - 1;
532 for (; i1 <= i2; i1++) {
533 outputRI[2 * i1] += inputRI[2 * i1];
534 outputRI[2 * i1 + 1] += inputRI[2 * i1 + 1];
535 }
536}
537
538void addThresholdFilterOutput(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, THRESHOLD_FILTER *filter) {
539 int64_t i, i1, i2;
540 double level2, level2q, level2o;
541 double max2, mag2;
542
543 i1 = 0;
544 if (filter->flags & FILT_START_GIVEN)
545 i1 = computeIndex(filter->start, dfrequency, frequencies);
546 i2 = frequencies - 1;
547 if (filter->flags & FILT_END_GIVEN)
548 i2 = computeIndex(filter->end, dfrequency, frequencies);
549
550 if (filter->flags & FILT_FRACTHRES_GIVEN) {
551 max2 = -DBL_MAX;
552 for (i = i1; i <= i2; i++)
553 if ((mag2 = inputRI[2 * i] * inputRI[2 * i] + inputRI[2 * i + 1] * inputRI[2 * i + 1]) > max2)
554 max2 = mag2;
555 level2o = max2 * sqr(filter->level);
556 } else
557 level2o = sqr(filter->level);
558 level2q = level2o / 4;
559
560 for (i = i1; i <= i2; i++) {
561 level2 = level2q; /* only half the amplitude is in positive frequencies */
562 if (i == 0 || i == frequencies - 1)
563 level2 = level2o;
564 if ((inputRI[2 * i] * inputRI[2 * i] + inputRI[2 * i + 1] * inputRI[2 * i + 1]) >= level2) {
565 outputRI[2 * i] += inputRI[2 * i];
566 outputRI[2 * i + 1] += inputRI[2 * i + 1];
567 }
568 }
569}
570
571void addHighPassFilterOutput(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, HILO_FILTER *filter) {
572 int64_t i, i1, i2;
573 double fraction, dfraction;
574
575 i1 = computeIndex(filter->start, dfrequency, frequencies);
576 i2 = computeIndex(filter->end, dfrequency, frequencies);
577
578 dfraction = i1 == i2 ? 0 : 1.0 / (i2 - i1);
579 fraction = 0;
580 for (i = i1; i <= i2; i++) {
581 outputRI[2 * i] += inputRI[2 * i] * fraction;
582 outputRI[2 * i + 1] += inputRI[2 * i + 1] * fraction;
583 if ((fraction += dfraction) > 1)
584 fraction = 1;
585 }
586 for (; i < frequencies; i++) {
587 outputRI[2 * i] += inputRI[2 * i];
588 outputRI[2 * i + 1] += inputRI[2 * i + 1];
589 }
590}
591
592void addLowPassFilterOutput(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, HILO_FILTER *filter) {
593 int64_t i, i1, i2;
594 double fraction, dfraction;
595
596 i1 = computeIndex(filter->start, dfrequency, frequencies);
597 i2 = computeIndex(filter->end, dfrequency, frequencies);
598
599 dfraction = i1 == i2 ? 0 : 1.0 / (i2 - i1);
600 fraction = 1;
601 for (i = i1; i <= i2; i++) {
602 outputRI[2 * i] += inputRI[2 * i] * fraction;
603 outputRI[2 * i + 1] += inputRI[2 * i + 1] * fraction;
604 if ((fraction -= dfraction) < 0)
605 fraction = 0;
606 }
607 for (i = 0; i < i1; i++) {
608 outputRI[2 * i] += inputRI[2 * i];
609 outputRI[2 * i + 1] += inputRI[2 * i + 1];
610 }
611}
612
613void addNotchFilterOutput(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, NHBP_FILTER *filter) {
614 int64_t i1, i2, i;
615 double fraction, dfraction;
616
617 i1 = computeIndex(filter->center - filter->fullwidth / 2, dfrequency, frequencies);
618 i2 = computeIndex(filter->center - filter->flatwidth / 2, dfrequency, frequencies);
619 for (i = 0; i < i1; i++) {
620 outputRI[2 * i] += inputRI[2 * i];
621 outputRI[2 * i + 1] += inputRI[2 * i + 1];
622 }
623 dfraction = i1 == i2 ? 0 : 1.0 / (i2 - i1);
624 fraction = 1;
625 for (i = i1; i <= i2; i++) {
626 outputRI[2 * i] += inputRI[2 * i] * fraction;
627 outputRI[2 * i + 1] += inputRI[2 * i + 1] * fraction;
628 if ((fraction -= dfraction) < 0)
629 fraction = 0;
630 }
631
632 i1 = computeIndex(filter->center + filter->flatwidth / 2, dfrequency, frequencies);
633 i2 = computeIndex(filter->center + filter->fullwidth / 2, dfrequency, frequencies);
634 for (i = i2; i < frequencies; i++) {
635 outputRI[2 * i] += inputRI[2 * i];
636 outputRI[2 * i + 1] += inputRI[2 * i + 1];
637 }
638 dfraction = i1 == i2 ? 0 : 1.0 / (i2 - i1);
639 fraction = 0;
640 for (i = i1; i <= i2; i++) {
641 outputRI[2 * i] += inputRI[2 * i] * fraction;
642 outputRI[2 * i + 1] += inputRI[2 * i + 1] * fraction;
643 if ((fraction += dfraction) > 1)
644 fraction = 1;
645 }
646}
647
648void addBandPassFilterOutput(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, NHBP_FILTER *filter) {
649 int64_t i1, i2, i;
650 double fraction, dfraction;
651
652 i1 = computeIndex(filter->center - filter->fullwidth / 2, dfrequency, frequencies);
653 i2 = computeIndex(filter->center - filter->flatwidth / 2, dfrequency, frequencies);
654 dfraction = i1 == i2 ? 0 : 1.0 / (i2 - i1);
655 fraction = 0;
656 for (i = i1; i <= i2; i++) {
657 outputRI[2 * i] += inputRI[2 * i] * fraction;
658 outputRI[2 * i + 1] += inputRI[2 * i + 1] * fraction;
659 if ((fraction += dfraction) > 1)
660 fraction = 1;
661 }
662
663 i1 = computeIndex(filter->center + filter->flatwidth / 2, dfrequency, frequencies);
664 i2 = computeIndex(filter->center + filter->fullwidth / 2, dfrequency, frequencies);
665 dfraction = i1 == i2 ? 0 : 1.0 / (i2 - i1);
666 fraction = 1;
667 for (i = i1; i <= i2; i++) {
668 outputRI[2 * i] += inputRI[2 * i] * fraction;
669 outputRI[2 * i + 1] += inputRI[2 * i + 1] * fraction;
670 if ((fraction -= dfraction) < 0)
671 fraction = 0;
672 }
673
674 i1 = computeIndex(filter->center - filter->flatwidth / 2, dfrequency, frequencies);
675 i2 = computeIndex(filter->center + filter->flatwidth / 2, dfrequency, frequencies);
676 for (i = i1; i <= i2; i++) {
677 outputRI[2 * i] += inputRI[2 * i];
678 outputRI[2 * i + 1] += inputRI[2 * i + 1];
679 }
680}
681
682void addFileFilterOutput(double *outputRI, double *inputRI, int64_t frequencies, double dfrequency, FILE_FILTER *filter) {
683 long code;
684 int64_t i;
685 double factor, ifactor, rfactor, rdata, idata, f;
686
687 if (!filter->freqData) {
688 SDDS_DATASET SDDSin;
689 long readCode = 0;
690
691 if (!SDDS_InitializeInput(&SDDSin, filter->file) || (readCode = SDDS_ReadPage(&SDDSin)) == 0)
692 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
693 if (readCode < 0) {
694 fprintf(stderr, "error: unable to read filter file %s (sddsfdfilter)\n", filter->file);
695 exit(EXIT_FAILURE);
696 }
697 if ((filter->points = SDDS_CountRowsOfInterest(&SDDSin)) <= 0) {
698 fprintf(stderr, "error: file %s has no data on first page (sddsfdfilter)\n", filter->file);
699 exit(EXIT_FAILURE);
700 }
701 if (!(filter->freqData = SDDS_GetColumnInDoubles(&SDDSin, filter->freqName)) ||
702 (filter->magName && !(filter->magData = SDDS_GetColumnInDoubles(&SDDSin, filter->magName))) ||
703 (filter->imagName && !(filter->imagData = SDDS_GetColumnInDoubles(&SDDSin, filter->imagName))) ||
704 (filter->realName && !(filter->realData = SDDS_GetColumnInDoubles(&SDDSin, filter->realName))) ||
705 !SDDS_Terminate(&SDDSin))
706 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
707 for (i = 1; i < filter->points; i++)
708 if (filter->freqData[i - 1] >= filter->freqData[i]) {
709 fprintf(stderr, "error: frequency data not monotonically increasing for %s (sddsfdfilter)\n", filter->file);
710 exit(EXIT_FAILURE);
711 }
712 }
713 for (i = 0; i < frequencies; i++) {
714 f = i * dfrequency;
715 if (filter->freqData[0] > f || filter->freqData[filter->points - 1] < f)
716 continue;
717 if (filter->magName) {
718 factor = interp(filter->magData, filter->freqData, filter->points, f, 0, 1, &code);
719 outputRI[2 * i] += factor * inputRI[2 * i];
720 outputRI[2 * i + 1] += factor * inputRI[2 * i + 1];
721 } else {
722 rfactor = interp(filter->realData, filter->freqData, filter->points, f, 0, 1, &code);
723 ifactor = interp(filter->imagData, filter->freqData, filter->points, f, 0, 1, &code);
724 rdata = inputRI[2 * i];
725 idata = inputRI[2 * i + 1];
726 outputRI[2 * i] += rdata * rfactor - idata * ifactor;
727 outputRI[2 * i + 1] += rdata * ifactor + idata * rfactor;
728 }
729 }
730}
731
732int64_t computeIndex(double value, double dfrequency, int64_t frequencies) {
733 int64_t i1;
734
735 i1 = value / dfrequency + 0.5;
736 if (i1 < 0)
737 i1 = 0;
738 if (i1 > frequencies - 1)
739 i1 = frequencies - 1;
740 return i1;
741}
742
743void addFilter(FILTER_STAGE *filterStage, long optionCode, SCANNED_ARG *scanned) {
744 THRESHOLD_FILTER *thresholdFilter;
745 HILO_FILTER *hiloFilter;
746 NHBP_FILTER *nhbpFilter;
747 FILE_FILTER *fileFilter;
748 CLIP_FILTER *clipFilter;
749 FILTER *filter;
750 long items, filters;
751 char **item;
752
753 if (!(filterStage->filter = SDDS_Realloc(filterStage->filter, sizeof(*filterStage->filter) * (filterStage->filters + 1))))
754 SDDS_Bomb("allocation failure adding filter slot");
755 filter = filterStage->filter;
756 filters = filterStage->filters;
757 filterStage->filters++;
758
759 items = scanned->n_items - 1;
760 item = scanned->list + 1;
761 switch (filter[filters].filterType = optionCode) {
762 case SET_THRESHOLD:
763 if (!(thresholdFilter = filter[filters].filter = calloc(1, sizeof(THRESHOLD_FILTER))))
764 SDDS_Bomb("allocation failure allocating threshold filter");
765 if (items < 1)
766 SDDS_Bomb("invalid -threshold syntax");
767 if (!scanItemList(&thresholdFilter->flags, item, &items, 0,
768 "level", SDDS_DOUBLE, &thresholdFilter->level, 1, FILT_LEVEL_GIVEN,
769 "fractional", -1, NULL, 0, FILT_FRACTHRES_GIVEN,
770 "start", SDDS_DOUBLE, &thresholdFilter->start, 1, FILT_START_GIVEN,
771 "end", SDDS_DOUBLE, &thresholdFilter->end, 1, FILT_END_GIVEN, NULL))
772 SDDS_Bomb("invalid -threshold syntax/values");
773 if (!(thresholdFilter->flags & FILT_LEVEL_GIVEN))
774 SDDS_Bomb("supply level=<value> qualifier for -threshold");
775 if ((thresholdFilter->flags & FILT_START_GIVEN && thresholdFilter->flags & FILT_END_GIVEN) && thresholdFilter->start > thresholdFilter->end)
776 SDDS_Bomb("start > end for -threshold filter");
777 break;
778 case SET_HIGHPASS:
779 case SET_LOWPASS:
780 if (!(hiloFilter = filter[filters].filter = calloc(1, sizeof(HILO_FILTER))))
781 SDDS_Bomb("allocation failure allocating low-pass or high-pass filter");
782 if (!scanItemList(&hiloFilter->flags, item, &items, 0,
783 "start", SDDS_DOUBLE, &hiloFilter->start, 1, FILT_START_GIVEN,
784 "end", SDDS_DOUBLE, &hiloFilter->end, 1, FILT_END_GIVEN, NULL))
785 SDDS_Bomb("invalid -highpass or -lowpass syntax");
786 if (!(hiloFilter->flags & FILT_START_GIVEN) || !(hiloFilter->flags & FILT_END_GIVEN))
787 SDDS_Bomb("supply start=<value> and end=<value> qualifiers with -highpass and -lowpass");
788 break;
789 case SET_NOTCH:
790 case SET_BANDPASS:
791 if (!(nhbpFilter = filter[filters].filter = calloc(1, sizeof(NHBP_FILTER))))
792 SDDS_Bomb("allocation failure allocating notch or bandpass filter");
793 if (!scanItemList(&nhbpFilter->flags, item, &items, 0,
794 "center", SDDS_DOUBLE, &nhbpFilter->center, 1, FILT_CENTER_GIVEN,
795 "fullwidth", SDDS_DOUBLE, &nhbpFilter->fullwidth, 1, FILT_FULLWIDTH_GIVEN,
796 "flatwidth", SDDS_DOUBLE, &nhbpFilter->flatwidth, 1, FILT_FLATWIDTH_GIVEN, NULL))
797 SDDS_Bomb("invalid -notch or -bandpass syntax");
798 if (!(nhbpFilter->flags & FILT_CENTER_GIVEN) || !(nhbpFilter->flags & FILT_FLATWIDTH_GIVEN))
799 SDDS_Bomb("supply center=<value> and flatWidth=<value> qualifiers with -notch and -bandpass");
800 if (!(nhbpFilter->flags & FILT_FULLWIDTH_GIVEN))
801 nhbpFilter->fullwidth = nhbpFilter->flatwidth;
802 if (nhbpFilter->fullwidth < nhbpFilter->flatwidth)
803 SDDS_Bomb("full width may not be less than flat width for notch/bandpass filter");
804 break;
805 case SET_FILTERFILE:
806 if (!(fileFilter = filter[filters].filter = calloc(1, sizeof(FILE_FILTER))))
807 SDDS_Bomb("allocation failure allocating file filter");
808 if (!scanItemList(&fileFilter->flags, item, &items, 0,
809 "filename", SDDS_STRING, &fileFilter->file, 1, FILT_FILENAME_GIVEN,
810 "frequency", SDDS_STRING, &fileFilter->freqName, 1, FILT_FREQNAME_GIVEN,
811 "real", SDDS_STRING, &fileFilter->realName, 1, FILT_REALNAME_GIVEN,
812 "imaginary", SDDS_STRING, &fileFilter->imagName, 1, FILT_IMAGNAME_GIVEN,
813 "magnitude", SDDS_STRING, &fileFilter->magName, 1, FILT_MAGNAME_GIVEN, NULL))
814 SDDS_Bomb("invalid -filterFile syntax");
815 if (!(fileFilter->flags & FILT_FILENAME_GIVEN))
816 SDDS_Bomb("supply filename=<string> with -filterFile");
817 if (!(fileFilter->flags & FILT_FREQNAME_GIVEN))
818 SDDS_Bomb("supply frequency=<columnName> with -filterFile");
819 if (!(fileFilter->flags & FILT_MAGNAME_GIVEN) && !(fileFilter->flags & FILT_REALNAME_GIVEN && fileFilter->flags & FILT_IMAGNAME_GIVEN))
820 SDDS_Bomb("supply either magnitude=<columnName>, or real=<columnName> and imag=<columnName>, with -filterFile");
821 if (fileFilter->flags & FILT_MAGNAME_GIVEN && (fileFilter->flags & FILT_REALNAME_GIVEN || fileFilter->flags & FILT_IMAGNAME_GIVEN))
822 SDDS_Bomb("magnitude=<columnName> is incompatible with real=<columnName> and imag=<columnName> for -filterFile");
823 fileFilter->freqData = NULL; /* Indicates no data present */
824 break;
825 case SET_CLIPFREQ:
826 if (!(clipFilter = filter[filters].filter = calloc(1, sizeof(CLIP_FILTER))))
827 SDDS_Bomb("allocation failure allocating clip filter");
828 if (!scanItemList(&clipFilter->flags, item, &items, 0,
829 "high", SDDS_LONG, &clipFilter->high, 1, FILT_HIGH_GIVEN,
830 "low", SDDS_LONG, &clipFilter->low, 1, FILT_LOW_GIVEN, NULL))
831 SDDS_Bomb("invalid -clipFrequencies syntax");
832 if (!(clipFilter->flags & FILT_HIGH_GIVEN) && !(clipFilter->flags & FILT_LOW_GIVEN))
833 SDDS_Bomb("supply at least one of high=<number> or low=<number> with -clipFrequencies");
834 break;
835 default:
836 SDDS_Bomb("invalid filter code---this shouldn't happen");
837 break;
838 }
839}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_InitializeCopy(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, char *filename, char *filemode)
Definition SDDS_copy.c:40
int32_t SDDS_CopyPage(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:578
int32_t SDDS_SetColumnFromDoubles(SDDS_DATASET *SDDS_dataset, int32_t mode, double *data, int64_t rows,...)
Sets the values for a single data column using double-precision floating-point numbers.
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_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_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_TransferColumnDefinition(SDDS_DATASET *target, SDDS_DATASET *source, char *name, char *newName)
Transfers a column definition from a source dataset to a target 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_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:677
#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
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
double interp(double *f, double *x, long n, double xo, long warnings, long order, long *returnCode)
Performs simple linear interpolation of data.
Definition interp.c:34
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)
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.