77 CLO_INDEPENDENTCOLUMN,
87char *option[N_OPTIONS] = {
101#define USAGE "sddsconvolve <signal-file> <response-file> <output>\n\
102 [-pipe=[input][,output]]\n\
103 -signalColumns=<indepColumn>,<dataName>\n\
104 -responseColumns=<indepColumn>,<dataName>\n\
105 -outputColumns=<indepColumn>,<dataName>\n\
106 [-reuse] [-majorOrder=row|column]\n\
107 [{-deconvolve [{-noiseFraction=<value> | -wienerFilter=<value>}] | -correlate}]\n\n\
109 Performs discrete Fourier convolution, deconvolution, or correlation between signal and response files.\n\
110 Assumes uniform spacing of points in both input files and that both files contain the same number of data points.\n\
112Mathematical Operations:\n\
113 - Convolution: O = S * R\n\
114 - Deconvolution: O = S / R\n\
115 - Correlation: O = S * Conj(R)\n\
118 -signalColumns=<indepColumn>,<dataName> Specify the independent column and data name for the signal file.\n\
119 -responseColumns=<indepColumn>,<dataName> Specify the independent column and data name for the response file.\n\
120 -outputColumns=<indepColumn>,<dataName> Specify the independent column and data name for the output file.\n\
121 -reuse Reuse the first page of the response file for each page of the signal file.\n\
122 -majorOrder=row|column Set data ordering in the output file.\n\
123 -deconvolve Perform deconvolution instead of convolution.\n\
124 -noiseFraction=<value> Specify noise fraction to prevent divide-by-zero.\n\
125 -wienerFilter=<value> Apply a Wiener filter with the specified fraction.\n\
126 -correlate Perform correlation instead of convolution.\n\
127 -pipe=[input][,output] Use standard input/output in place of the signal file and output file.\n\
129Program Information:\n\
130 Michael Borland (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n"
132void complex_multiply(
double *r0,
double *i0,
double r1,
double i1,
double r2,
double i2);
133void complex_divide(
double *r0,
double *i0,
double r1,
double i1,
double r2,
double i2,
double threshold);
134void wrap_around_order(
double *response1,
double *t,
double *response, int64_t nres, int64_t nsig);
136#define MODE_CONVOLVE 1
137#define MODE_DECONVOLVE 2
138#define MODE_CORRELATE 3
140int main(
int argc,
char **argv) {
143 SCANNED_ARG *scanned;
144 char *input1, *input2, *output;
146 double *fft_sig, *fft_res, noise, mag2, threshold, range;
147 double *signal1, *signal2, *indep1, *indep2;
148 double WienerFraction, *WienerFilter = NULL;
149 unsigned long pipeFlags, majorOrderFlag;
150 char *input1Column[2], *input2Column[2], *outputColumn[2];
151 char description[1024];
152 long tmpfile_used, code1, code2;
153 int64_t i, rows1, rows2, nfreq;
154 int32_t parameters = 0;
155 char **parameterName = NULL;
156 short columnMajorOrder = -1, reuse = 0;
159 argc =
scanargs(&scanned, argc, argv);
160 if (argc < 4 || argc > (4 + N_OPTIONS))
163 input1 = input2 = output = NULL;
164 mode = MODE_CONVOLVE;
166 input1Column[0] = input1Column[1] = NULL;
167 input2Column[0] = input2Column[1] = NULL;
168 outputColumn[0] = outputColumn[1] = NULL;
172 for (i_arg = 1; i_arg < argc; i_arg++) {
173 if (scanned[i_arg].arg_type == OPTION) {
175 switch (
match_string(scanned[i_arg].list[0], option, N_OPTIONS, 0)) {
176 case CLO_MAJOR_ORDER:
178 scanned[i_arg].n_items--;
179 if (scanned[i_arg].n_items > 0 &&
180 (!
scanItemList(&majorOrderFlag, scanned[i_arg].list + 1, &scanned[i_arg].n_items, 0,
181 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
182 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
183 SDDS_Bomb(
"Invalid -majorOrder syntax or values.");
184 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
185 columnMajorOrder = 1;
186 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
187 columnMajorOrder = 0;
190 mode = MODE_DECONVOLVE;
193 mode = MODE_CORRELATE;
196 if (!
processPipeOption(scanned[i_arg].list + 1, scanned[i_arg].n_items - 1, &pipeFlags))
199 case CLO_NOISE_FRACTION:
200 if (scanned[i_arg].n_items != 2 || sscanf(scanned[i_arg].list[1],
"%lf", &noise) != 1 || noise <= 0)
201 SDDS_Bomb(
"Invalid -noisefraction syntax or value.");
203 case CLO_WIENER_FILTER:
204 if (scanned[i_arg].n_items != 2 || sscanf(scanned[i_arg].list[1],
"%lf", &WienerFraction) != 1 ||
205 WienerFraction <= 0 || WienerFraction >= 1)
206 SDDS_Bomb(
"Invalid -wienerfilter syntax or value.");
209 case CLO_SIGNALCOLUMN:
210 if (scanned[i_arg].n_items != 3 ||
211 !strlen(input1Column[0] = scanned[i_arg].list[1]) ||
212 !strlen(input1Column[1] = scanned[i_arg].list[2]))
213 SDDS_Bomb(
"Invalid -signalColumns syntax.");
215 case CLO_RESPONSECOLUMN:
216 if (scanned[i_arg].n_items != 3 ||
217 !strlen(input2Column[0] = scanned[i_arg].list[1]) ||
218 !strlen(input2Column[1] = scanned[i_arg].list[2]))
219 SDDS_Bomb(
"Invalid -responseColumns syntax.");
221 case CLO_OUTPUTCOLUMN:
222 if (scanned[i_arg].n_items != 3 ||
223 !strlen(outputColumn[0] = scanned[i_arg].list[1]) ||
224 !strlen(outputColumn[1] = scanned[i_arg].list[2]))
225 SDDS_Bomb(
"Invalid -outputColumns syntax.");
236 input1 = scanned[i_arg].list[0];
238 input2 = scanned[i_arg].list[0];
240 output = scanned[i_arg].list[0];
242 SDDS_Bomb(
"Too many filenames provided.");
246 if (pipeFlags & USE_STDIN && input1) {
248 SDDS_Bomb(
"Too many filenames provided.");
253 if (!input1Column[0] || !input1Column[1] || !strlen(input1Column[0]) || !strlen(input1Column[1]))
254 SDDS_Bomb(
"SignalColumns not provided.");
255 if (!input2Column[0] || !input2Column[1] || !strlen(input2Column[0]) || !strlen(input2Column[1]))
256 SDDS_Bomb(
"ResponseColumns not provided.");
257 if (!outputColumn[0] || !outputColumn[1] || !strlen(outputColumn[0]) || !strlen(outputColumn[1]))
258 SDDS_Bomb(
"OutputColumns not provided.");
260 processFilenames(
"sddsconvolve", &input1, &output, pipeFlags, 1, &tmpfile_used);
262 SDDS_Bomb(
"Second input file not specified.");
271 sprintf(description,
"Convolution of signal '%s' with response '%s'", input1Column[1], input2Column[1]);
273 case MODE_DECONVOLVE:
274 sprintf(description,
"Deconvolution of signal '%s' with response '%s'", input1Column[1], input2Column[1]);
277 sprintf(description,
"Correlation of signal '%s' with response '%s'", input1Column[1], input2Column[1]);
288 if (columnMajorOrder != -1)
289 SDDSout.layout.data_mode.column_major = columnMajorOrder;
291 SDDSout.layout.data_mode.column_major = SDDS1.layout.data_mode.column_major;
294 for (i = 0; i < parameters; i++)
306 if ((rows1 = SDDS_RowCount(&SDDS1)) <= 0) {
307 fprintf(stderr,
"Warning (sddsconvolve): Skipping page due to no signal rows.\n");
311 SDDS_Bomb(
"sddsconvolve requires at least two rows on each nonempty signal page");
315 fprintf(stderr,
"Error (sddsconvolve): Couldn't read data from response file.\n");
318 if ((rows2 = SDDS_RowCount(&SDDS2)) < 0) {
319 fprintf(stderr,
"Error (sddsconvolve): Response file has zero rows on first page.\n");
326 rows2 = SDDS_RowCount(&SDDS2);
329 SDDS_Bomb(
"Different numbers of points for signal and response.");
339 if (!(fft_sig =
SDDS_Calloc(
sizeof(*fft_sig), (2 * rows1 + 2))) ||
340 !(fft_res =
SDDS_Calloc(
sizeof(*fft_res), (2 * rows1 + 2)))) {
347 wrap_around_order(fft_res, indep2, signal2, rows2, rows1);
348 for (i = 0; i < rows1; i++)
349 fft_sig[i] = signal1[i];
352 realFFT2(fft_sig, fft_sig, 2 * rows1, 0);
353 realFFT2(fft_res, fft_res, 2 * rows1, 0);
355 range = 2 * rows1 * (indep1[rows1 - 1] - indep1[0]) / (rows1 - 1);
357 if (mode == MODE_CONVOLVE || mode == MODE_CORRELATE) {
358 if (mode == MODE_CORRELATE)
360 for (i = 0; i < nfreq; i++)
361 fft_res[2 * i + 1] = -fft_res[2 * i + 1];
364 for (i = 0; i < nfreq; i++) {
366 fft_sig[2 * i], fft_sig[2 * i + 1],
367 fft_res[2 * i], fft_res[2 * i + 1]);
371 realFFT2(fft_sig, fft_sig, 2 * rows1, INVERSE_FFT);
374 for (i = 0; i < rows1; i++)
386 }
else if (mode == MODE_DECONVOLVE) {
389 for (i = threshold = 0; i < nfreq; i++) {
390 if ((mag2 = sqr(fft_res[2 * i]) + sqr(fft_res[2 * i + 1])) > threshold)
394 threshold = threshold * noise;
398 double *S = NULL, *N = NULL, wThreshold;
399 if (!(WienerFilter = malloc(
sizeof(*WienerFilter) * nfreq)) ||
400 !(S = malloc(
sizeof(*S) * nfreq)) ||
401 !(N = malloc(
sizeof(*N) * nfreq))) {
404 wThreshold = maxMag2 * sqr(WienerFraction);
405 for (i = 0; i < nfreq; i++) {
406 S[i] = sqrt(sqr(fft_res[2 * i]) + sqr(fft_res[2 * i + 1]));
407 if (sqr(S[i]) < wThreshold) {
411 S[i] = S[i] - sqrt(wThreshold);
412 N[i] = sqrt(wThreshold);
415 for (i = 0; i < nfreq; i++)
416 WienerFilter[i] = sqr(S[i]) / (sqr(S[i]) + sqr(N[i]) + threshold);
422 for (i = 0; i < nfreq; i++) {
424 fft_sig[2 * i], fft_sig[2 * i + 1],
425 fft_res[2 * i], fft_res[2 * i + 1],
430 for (i = 0; i < nfreq; i++) {
431 fft_sig[2 * i] *= WienerFilter[i];
432 fft_sig[2 * i + 1] *= WienerFilter[i];
438 realFFT2(fft_sig, fft_sig, 2 * rows1, INVERSE_FFT);
441 for (i = 0; i < rows1; i++)
442 fft_sig[i] = fft_sig[i] / range;
454 SDDS_Bomb(
"Unexpected processing mode encountered.");
466 signal1 = indep1 = signal2 = indep2 = NULL;
483void wrap_around_order(
double *response1,
double *t,
double *response, int64_t nres, int64_t nsig) {
487 for (iz = 0; iz < nres; iz++)
491 bomb(
"Response function is acausal.", NULL);
494 for (i = iz; i < nres; i++)
495 response1[i - iz] = response[i];
496 for (i = 0; i < iz; i++)
497 response1[2 * nsig - (iz - i)] = response[i];
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_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_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_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_TransferParameterDefinition(SDDS_DATASET *target, SDDS_DATASET *source, char *name, char *newName)
Transfers a parameter definition from a source dataset to a target dataset.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
char ** SDDS_GetParameterNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all parameters in the SDDS dataset.
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.
void * SDDS_Calloc(size_t nelem, size_t elem_size)
Allocates zero-initialized memory for an array of elements.
#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.
void fill_double_array(double *array, long n, double value)
Fills a double array with the specified value.
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 replaceFileAndBackUp(char *file, char *replacement)
Replaces a file with a replacement file and creates a backup of the original.
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.
void complex_divide(double *r0, double *i0, double r1, double i1, double r2, double i2, double threshold)
Divides two complex numbers.
void complex_multiply(double *r0, double *i0, double r1, double i1, double r2, double i2)
Multiplies two complex numbers.