/*************************************************************************\ * Copyright (c) 2002 The University of Chicago, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * This file is distributed subject to a Software License Agreement found * in the file LICENSE that is included with this distribution. \*************************************************************************/ /* program: sddsconvolve.c * purpose: do convolution, deconvolution, and correlation * * Michael Borland, 1991, 1993, 1998 */ #include "mdb.h" #include "SDDS.h" #include "scan.h" #include "fftpackC.h" #define CLO_DECONVOLVE 0 #define CLO_PIPE 1 #define CLO_NOISE_FRACTION 2 #define CLO_CORRELATE 3 #define CLO_INDEPENDENTCOLUMN 4 #define CLO_SIGNALCOLUMN 5 #define CLO_RESPONSECOLUMN 6 #define CLO_OUTPUTCOLUMN 7 #define CLO_WIENER_FILTER 8 #define N_OPTIONS 9 char *option[N_OPTIONS] = { "deconvolve", "pipe", "noisefraction", "correlate", "independentcolumn", "signalcolumn", "responsecolumn", "outputcolumn", "wienerfilter", } ; #define USAGE "sddsconvolve \n\ -signalColumns=,\n\ -responseColumns=,\n\ -outputColumns=,\n\ [{-deconvolve [{-noiseFraction=value | -wienerFilter=value}] | -correlate}]\n\n\ Performs discrete Fourier convolution/deconvolution/correlation. Assumes that spacing of \n\ points is the same in both input files and that both files have the same number of data\n\ points.\n\ In terms of Fourier transforms of the signal (S), response (R), and output (O), the program\n\ computes:\n\ O = S*R for convolution\n\ O = S/R for deconvolution\n\ O = S*Conj(R) for correlation\n\n\ If deconvolution is used, one may specify a noise fraction to avoid divide-by-zero problems,\n\ or else use a Wiener filter, specifying the fraction of the maximum magnitude below\n\ which everything is considered to be noise.\n\ The standard -pipe option may be used in place of and/or .\n\ Program by Michael Borland. (This is version 2, April 2003.)\n" void complex_multiply(double *r0, double *i0, double r1, double i1, double r2, double i2); void complex_divide(double *r0, double *i0, double r1, double i1, double r2, double i2, double threshold); void wrap_around_order(double *response1, double *t, double *response, long nres, long nsig); #define MODE_CONVOLVE 1 #define MODE_DECONVOLVE 2 #define MODE_CORRELATE 3 int main(int argc, char **argv) { SDDS_DATASET SDDS1, SDDS2, SDDSout; int i_arg; SCANNED_ARG *scanned; char *input1, *input2, *output; long i, mode, nfreq, doWiener; double *fft_sig, *fft_res, noise, mag2, threshold, range; double *signal1, *signal2, *indep1, *indep2; double WienerFraction, *WienerFilter=NULL; unsigned long pipeFlags; char *input1Column[2], *input2Column[2], *outputColumn[2]; char description[1024]; long tmpfile_used, code1, code2, rows1, rows2, parameters=0; char **parameterName=NULL; SDDS_RegisterProgramName(argv[0]); argc = scanargs(&scanned, argc, argv); if (argc<4 || argc>(4+N_OPTIONS)) bomb(NULL, USAGE); input1 = input2 = output = NULL; mode = MODE_CONVOLVE; noise = 1e-14; input1Column[0] = input1Column[1] = NULL; input2Column[0] = input2Column[1] = NULL; outputColumn[0] = outputColumn[1] = NULL; pipeFlags = 0; doWiener = 0; for (i_arg=1; i_arg=1) SDDS_Bomb("invalid -WienerFraction syntax or value"); doWiener = 1; break; case CLO_SIGNALCOLUMN: if (scanned[i_arg].n_items!=3 || !strlen(input1Column[0]=scanned[i_arg].list[1]) || !strlen(input1Column[1]=scanned[i_arg].list[2])) SDDS_Bomb("invalid -signalColumn syntax"); break; case CLO_RESPONSECOLUMN: if (scanned[i_arg].n_items!=3 || !strlen(input2Column[0]=scanned[i_arg].list[1]) || !strlen(input2Column[1]=scanned[i_arg].list[2])) SDDS_Bomb("invalid -responseColumn syntax"); break; case CLO_OUTPUTCOLUMN: if (scanned[i_arg].n_items!=3 || !strlen(outputColumn[0]=scanned[i_arg].list[1]) || !strlen(outputColumn[1]=scanned[i_arg].list[2])) SDDS_Bomb("invalid -outputColumn syntax"); break; default: SDDS_Bomb("unknown option given"); break; } } else { if (!input1) input1 = scanned[i_arg].list[0]; else if (!input2) input2 = scanned[i_arg].list[0]; else if (!output) output = scanned[i_arg].list[0]; else SDDS_Bomb("too many filenames"); } } if (pipeFlags&USE_STDIN && input1) { if (output) SDDS_Bomb("too many filenames"); output = input2; input2 = input1; input1 = NULL; } if (!input1Column[0] || !input1Column[1] || !strlen(input1Column[0]) || !strlen(input1Column[1])) SDDS_Bomb("singalColumn not provided."); if (!input2Column[0] || !input2Column[1] || !strlen(input2Column[0]) || !strlen(input2Column[1])) SDDS_Bomb("responseColumn not provided."); if (!outputColumn[0] || !outputColumn[1] || !strlen(outputColumn[0]) || !strlen(outputColumn[1])) SDDS_Bomb("outputColumn not provided."); processFilenames("sddsconvolve", &input1, &output, pipeFlags, 1, &tmpfile_used); if (!input2) SDDS_Bomb("second input file not specified"); if (!SDDS_InitializeInput(&SDDS1, input1) || !SDDS_InitializeInput(&SDDS2, input2)) { SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors); exit(1); } switch (mode) { case MODE_CONVOLVE: sprintf(description, "convolution of signal %s with response %s", input1Column[1], input2Column[1]); break; case MODE_DECONVOLVE: sprintf(description, "deconvolution of signal %s with response %s", input1Column[1], input2Column[1]); break; case MODE_CORRELATE: sprintf(description, "correlation of signal %s with signal %s", input1Column[1], input2Column[1]); break; } parameterName = SDDS_GetParameterNames(&SDDS1, ¶meters); if (!SDDS_InitializeOutput(&SDDSout, SDDS_BINARY, 1, NULL, NULL, output) || !SDDS_TransferColumnDefinition(&SDDSout, &SDDS1, input1Column[0], outputColumn[0]) || 0>SDDS_DefineColumn(&SDDSout, outputColumn[1], NULL, NULL, description, NULL, SDDS_DOUBLE, 0)) { SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors); exit(1); } if (parameters) { for (i=0; i0 && (code2=SDDS_ReadPage(&SDDS2))>0) { if ((rows1=SDDS_RowCount(&SDDS1))<=0 || (rows2=SDDS_RowCount(&SDDS2))<0) { fprintf(stderr, "Warning (sddconvolve): skipping page due to no signal or response rows\n"); continue; } if (rows1!=rows2) SDDS_Bomb("different numbers of points for signal and response"); if (!(signal1=SDDS_GetColumnInDoubles(&SDDS1, input1Column[1])) || !(indep1=SDDS_GetColumnInDoubles(&SDDS1, input1Column[0])) || !(signal2=SDDS_GetColumnInDoubles(&SDDS2, input2Column[1])) || !(indep2=SDDS_GetColumnInDoubles(&SDDS2, input2Column[0]))) { SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors); exit(1); } if (!(fft_sig = SDDS_Calloc(sizeof(*fft_sig), (2*rows1+2))) || !(fft_res = SDDS_Calloc(sizeof(*fft_res), (2*rows1+2)))) { SDDS_SetError("memory allocation failure"); SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors); exit(1); } /* return array fft_res with size 2*rows1 + 2 */ wrap_around_order(fft_res, indep2, signal2, rows2, rows1); for (i=0; ithreshold) threshold = mag2; } maxMag2 = threshold; threshold = threshold*noise; if (doWiener) { /* compute and apply Wiener filter */ /* The filter is just * the signal itself if signal=0) break; if (iz==nres) bomb("response function is acausal", NULL); fill_double_array(response1, 2*nsig+2, 0.0L); for (i=iz; i