194 {
195 SCANNED_ARG *s_arg;
197 char *inputfile, *outputfile, *xcolName, **ycolName, **ycolMatch;
198 long columnsupplied, totalFilterCount, totalStages, tmpfileUsed;
199 int64_t npoints;
200 int32_t yColumns, ycolMatches;
201 long i, j, i_arg, filterNum, stageNum, currentFilter, currentStage, filterType, error;
202 unsigned long pipeFlags, majorOrderFlag;
203 char outColName[256], outColDesc[256];
204 double *xcol, *ycol;
205 short columnMajorOrder = -1;
206
211
213 argc =
scanargs(&s_arg, argc, argv);
214 if (argc < 2)
216
217
218 tmpfileUsed = 0;
219 pipeFlags = 0;
220 verbose = 0;
221 columnsupplied = 0;
222 inputfile = outputfile = xcolName = NULL;
223 ycolName = ycolMatch = NULL;
224 yColumns = ycolMatches = 0;
225
226
227 totalFilterCount = 0;
228 filterNum = 0;
229 stageNum = 0;
230
231
232 stage = (
STAGE *)malloc(
sizeof(*stage));
233 stage[0].filter = (void *)malloc(sizeof(*stage[0].filter));
234 stage[0].type = (long *)malloc(sizeof(*stage[0].type));
235
236 for (i_arg = 1; i_arg < argc; i_arg++) {
237 if (s_arg[i_arg].arg_type == OPTION) {
239 switch (
match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
240 case CLO_MAJOR_ORDER:
241 majorOrderFlag = 0;
242 s_arg[i_arg].n_items--;
243 if (s_arg[i_arg].n_items > 0 && (!
scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
"row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
"column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
244 SDDS_Bomb(
"invalid -majorOrder syntax/values");
245 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
246 columnMajorOrder = 1;
247 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
248 columnMajorOrder = 0;
249 break;
250 case CLO_LOWPASS:
251 if (s_arg[i_arg].n_items < 2)
253 LHptr = (
LOWHIGH *)malloc(
sizeof(*LHptr));
254 if (!
get_double(&(LHptr->gain), s_arg[i_arg].list[1]))
255 SDDS_Bomb(
"Invalid -lowpass value provided.");
256 if (s_arg[i_arg].n_items > 2 && !
get_double(&(LHptr->cutoff), s_arg[i_arg].list[2]))
257 SDDS_Bomb(
"Invalid -lowpass value provided.");
258 stage[stageNum].filter[filterNum] = LHptr;
259 stage[stageNum].type[filterNum] = CLO_LOWPASS;
260 stage[stageNum].numFilters = ++filterNum;
261 totalFilterCount++;
262
263 stage[stageNum].filter = (void *)realloc(stage[stageNum].filter, sizeof(*stage[stageNum].filter) * (filterNum + 1));
264 stage[stageNum].type = (long *)realloc(stage[stageNum].type, sizeof(*stage[stageNum].type) * (filterNum + 1));
265 break;
266 case CLO_HIGHPASS:
267 if (s_arg[i_arg].n_items < 2)
269 LHptr = (
LOWHIGH *)malloc(
sizeof(*LHptr));
270 if (!
get_double(&(LHptr->gain), s_arg[i_arg].list[1]))
271 SDDS_Bomb(
"Invalid -highpass value provided.");
272 if (s_arg[i_arg].n_items > 2 && !
get_double(&(LHptr->cutoff), s_arg[i_arg].list[2]))
273 SDDS_Bomb(
"Invalid -highpass value provided.");
274 stage[stageNum].filter[filterNum] = LHptr;
275 stage[stageNum].type[filterNum] = CLO_HIGHPASS;
276 stage[stageNum].numFilters = ++filterNum;
277 totalFilterCount++;
278
279 stage[stageNum].filter = (void *)realloc(stage[stageNum].filter, sizeof(*stage[stageNum].filter) * (filterNum + 1));
280 stage[stageNum].type = (long *)realloc(stage[stageNum].type, sizeof(*stage[stageNum].type) * (filterNum + 1));
281 break;
282 case CLO_PROPORTIONAL:
283 if (s_arg[i_arg].n_items != 2)
284 SDDS_Bomb(
"Invalid -proportional option.");
285 Gptr = (
GAIN *)malloc(
sizeof(*Gptr));
286 if (!
get_double(&(Gptr->gain), s_arg[i_arg].list[1]))
287 SDDS_Bomb(
"Invalid -proportional value provided.");
288 stage[stageNum].filter[filterNum] = Gptr;
289 stage[stageNum].type[filterNum] = CLO_PROPORTIONAL;
290 stage[stageNum].numFilters = ++filterNum;
291 totalFilterCount++;
292
293 stage[stageNum].filter = (void *)realloc(stage[stageNum].filter, sizeof(*stage[stageNum].filter) * (filterNum + 1));
294 stage[stageNum].type = (long *)realloc(stage[stageNum].type, sizeof(*stage[stageNum].type) * (filterNum + 1));
295 break;
296 case CLO_ANALOGFILTER:
297 if (s_arg[i_arg].n_items < 2)
298 SDDS_Bomb(
"Invalid -analogfilter option.");
299 ADptr = (
ANADIG *)malloc(
sizeof(*ADptr));
300 ADptr->ACcoeff = ADptr->BDcoeff = NULL;
301 if (strcasecmp(s_arg[i_arg].list[1], "C") == 0 || strcasecmp(s_arg[i_arg].list[1], "D") == 0) {
302 processFilterParams(s_arg[i_arg].list, s_arg[i_arg].n_items, "C", "D", ADptr);
303 } else {
304 if (s_arg[i_arg].n_items != 4)
305 SDDS_Bomb(
"Invalid -analogfilter option for providing coefficient file and coefficient column names.");
306 processFilterParamsFromFile(s_arg[i_arg].list[1], s_arg[i_arg].list[2], s_arg[i_arg].list[3], ADptr);
307 }
308 stage[stageNum].filter[filterNum] = ADptr;
309 stage[stageNum].type[filterNum] = CLO_ANALOGFILTER;
310 stage[stageNum].numFilters = ++filterNum;
311 totalFilterCount++;
312
313 stage[stageNum].filter = (void *)realloc(stage[stageNum].filter, sizeof(*stage[stageNum].filter) * (filterNum + 1));
314 stage[stageNum].type = (long *)realloc(stage[stageNum].type, sizeof(*stage[stageNum].type) * (filterNum + 1));
315 break;
316 case CLO_DIGITALFILTER:
317 if (s_arg[i_arg].n_items < 2)
318 SDDS_Bomb(
"Invalid -digitalfilter option.");
319 ADptr = (
ANADIG *)malloc(
sizeof(*ADptr));
320 ADptr->ACcoeff = ADptr->BDcoeff = NULL;
321 if (strcasecmp(s_arg[i_arg].list[1], "A") == 0 || strcasecmp(s_arg[i_arg].list[1], "B") == 0) {
322 processFilterParams(s_arg[i_arg].list, s_arg[i_arg].n_items, "A", "B", ADptr);
323 } else {
324 if (s_arg[i_arg].n_items != 4)
325 SDDS_Bomb(
"Invalid -digitalfilter option for providing coefficient file and coefficient column names.");
326 processFilterParamsFromFile(s_arg[i_arg].list[1], s_arg[i_arg].list[2], s_arg[i_arg].list[3], ADptr);
327 }
328 stage[stageNum].filter[filterNum] = ADptr;
329 stage[stageNum].type[filterNum] = CLO_DIGITALFILTER;
330 stage[stageNum].numFilters = ++filterNum;
331 totalFilterCount++;
332
333 stage[stageNum].filter = (void *)realloc(stage[stageNum].filter, sizeof(*stage[stageNum].filter) * (filterNum + 1));
334 stage[stageNum].type = (long *)realloc(stage[stageNum].type, sizeof(*stage[stageNum].type) * (filterNum + 1));
335 break;
336 case CLO_CASCADE:
337 stageNum++;
338
339 stage = (
STAGE *)realloc(stage,
sizeof(*stage) * (stageNum + 1));
340 stage[stageNum].filter = (void *)malloc(sizeof(*stage[stageNum].filter));
341 stage[stageNum].type = (long *)malloc(sizeof(*stage[stageNum].type));
342 filterNum = 0;
343 stage[stageNum].numFilters = filterNum;
344 break;
345 case CLO_COLUMN:
346 if (s_arg[i_arg].n_items < 3)
348 xcolName = s_arg[i_arg].list[1];
349 ycolMatches = s_arg[i_arg].n_items - 2;
350 ycolMatch = malloc(sizeof(*ycolMatch) * ycolMatches);
351 for (i = 2; i < s_arg[i_arg].n_items; i++)
352 ycolMatch[i - 2] = s_arg[i_arg].list[i];
353 columnsupplied = 1;
354 break;
355 case CLO_PIPE:
356 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
358 break;
359 case CLO_VERBOSE:
360 verbose = 1;
361 break;
362 default:
363 fprintf(stderr, "Error (%s): unknown switch: %s\n", argv[0], s_arg[i_arg].list[0]);
364 exit(EXIT_FAILURE);
365 break;
366 }
367 } else {
368 if (inputfile == NULL)
369 inputfile = s_arg[i_arg].list[0];
370 else if (outputfile == NULL)
371 outputfile = s_arg[i_arg].list[0];
372 else
374 }
375 }
376
377 processFilenames(
"sddsdigfilter", &inputfile, &outputfile, pipeFlags, 1, &tmpfileUsed);
378
379 if (totalFilterCount == 0 || columnsupplied == 0) {
380 fprintf(stderr, "no filter or no columns supplied.\n");
381 exit(EXIT_FAILURE);
382 }
383 totalStages = stageNum + 1;
386 if (
SDDS_CheckColumn(&SDDS_input, xcolName, NULL, 0, stderr) != SDDS_CHECK_OKAY) {
387 fprintf(stderr, "xColumn %s does not exist.\n", xcolName);
388 exit(EXIT_FAILURE);
389 }
390 ycolName =
getMatchingSDDSNames(&SDDS_input, ycolMatch, ycolMatches, &yColumns, SDDS_MATCH_COLUMN);
391 for (i = 0; i < yColumns; i++) {
392 if (
SDDS_CheckColumn(&SDDS_input, ycolName[i], NULL, 0, stderr) != SDDS_CHECK_OKAY) {
393 fprintf(stderr, "yColumn %s does not exist.\n", ycolName[i]);
394 exit(EXIT_FAILURE);
395 }
396 }
399 if (columnMajorOrder != -1)
400 SDDS_output.layout.data_mode.column_major = columnMajorOrder;
401 else
402 SDDS_output.layout.data_mode.column_major = SDDS_input.layout.data_mode.column_major;
403 for (i = 0; i < yColumns; i++) {
404 sprintf(outColName, "DigFiltered%s", ycolName[i]);
405 sprintf(outColDesc, "Digital Filtered %s", ycolName[i]);
408 }
411
417 if (npoints) {
418
421 for (i = 0; i < yColumns; i++) {
422 sprintf(outColName, "DigFiltered%s", ycolName[i]);
425
426 for (currentStage = 0; currentStage < totalStages; currentStage++) {
427 if (verbose == 1) {
428 fprintf(stdout, "STAGE %ld\n", currentStage);
429 }
430
431 stage[currentStage].time = xcol;
432
433 if (currentStage == 0) {
434 stage[currentStage].input = ycol;
435 } else {
436 stage[currentStage].input = stage[currentStage - 1].output;
437 }
438
439 stage[currentStage].output = (double *)calloc(npoints, sizeof(*stage[currentStage].output));
440
441 for (currentFilter = 0; currentFilter < stage[currentStage].numFilters; currentFilter++) {
442 if (verbose == 1) {
443 fprintf(stdout, "filter %ld\n", currentFilter);
444 }
445
446 filterType = stage[currentStage].type[currentFilter];
447 error = (*filter_funct[filterType])(&(stage[currentStage]), currentFilter, npoints);
448 if (error != 0) {
449 fprintf(stderr, "nyquist violation.\n");
450 exit(EXIT_FAILURE);
451 }
452
453 }
454
455 }
456
457
460
461 free(ycol);
462 for (currentStage = 0; currentStage < totalStages; currentStage++)
463 free(stage[currentStage].output);
464 }
465 free(xcol);
466 }
469 }
472 for (i = 0; i < totalStages; i++) {
473 for (j = 0; j < stage[i].numFilters; j++) {
474 switch (stage[i].type[j]) {
475 case CLO_ANALOGFILTER:
476 case CLO_DIGITALFILTER:
477 free(((
ANADIG *)(stage[i].filter[j]))->ACcoeff);
478 free(((
ANADIG *)(stage[i].filter[j]))->BDcoeff);
479 free((
ANADIG *)(stage[i].filter[j]));
480 break;
481 case CLO_PROPORTIONAL:
482 free((
GAIN *)(stage[i].filter[j]));
483 break;
484 case CLO_HIGHPASS:
485 case CLO_LOWPASS:
486 free((
LOWHIGH *)(stage[i].filter[j]));
487 break;
488 }
489 }
490 free(stage[i].filter);
491 free(stage[i].type);
492 }
493 free(stage);
495 free(ycolName);
496 free(ycolMatch);
498 return (EXIT_SUCCESS);
499
500}
int32_t SDDS_InitializeCopy(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, char *filename, char *filemode)
int32_t SDDS_CopyPage(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
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.
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_FreeStringArray(char **string, int64_t strings)
Frees an array of strings by deallocating each individual string.
char ** getMatchingSDDSNames(SDDS_DATASET *dataset, char **matchName, int32_t matches, int32_t *names, short type)
Retrieves an array of matching SDDS entity names based on specified criteria.
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_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
#define SDDS_DOUBLE
Identifier for the double data type.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
int get_double(double *dptr, char *s)
Parses a double value from the given string.
char * delete_chars(char *s, char *t)
Removes all occurrences of characters found in string t from string s.
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)
void free_scanargs(SCANNED_ARG **scanned, int argc)
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.