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");
313 fprintf(stderr,
"Error (sddsconvolve): Couldn't read data from response file.\n");
316 if ((rows2 = SDDS_RowCount(&SDDS2)) < 0) {
317 fprintf(stderr,
"Error (sddsconvolve): Response file has zero rows on first page.\n");
324 rows2 = SDDS_RowCount(&SDDS2);
327 SDDS_Bomb(
"Different numbers of points for signal and response.");
337 if (!(fft_sig =
SDDS_Calloc(
sizeof(*fft_sig), (2 * rows1 + 2))) ||
338 !(fft_res =
SDDS_Calloc(
sizeof(*fft_res), (2 * rows1 + 2)))) {
345 wrap_around_order(fft_res, indep2, signal2, rows2, rows1);
346 for (i = 0; i < rows1; i++)
347 fft_sig[i] = signal1[i];
350 realFFT2(fft_sig, fft_sig, 2 * rows1, 0);
351 realFFT2(fft_res, fft_res, 2 * rows1, 0);
353 range = 2 * rows1 * (indep1[rows1 - 1] - indep1[0]) / (rows1 - 1);
355 if (mode == MODE_CONVOLVE || mode == MODE_CORRELATE) {
356 if (mode == MODE_CORRELATE)
358 for (i = 0; i < nfreq; i++)
359 fft_res[2 * i + 1] = -fft_res[2 * i + 1];
362 for (i = 0; i < nfreq; i++) {
364 fft_sig[2 * i], fft_sig[2 * i + 1],
365 fft_res[2 * i], fft_res[2 * i + 1]);
369 realFFT2(fft_sig, fft_sig, 2 * rows1, INVERSE_FFT);
372 for (i = 0; i < rows1; i++)
384 }
else if (mode == MODE_DECONVOLVE) {
387 for (i = threshold = 0; i < nfreq; i++) {
388 if ((mag2 = sqr(fft_res[2 * i]) + sqr(fft_res[2 * i + 1])) > threshold)
392 threshold = threshold * noise;
396 double *S = NULL, *N = NULL, wThreshold;
397 if (!(WienerFilter = malloc(
sizeof(*WienerFilter) * nfreq)) ||
398 !(S = malloc(
sizeof(*S) * nfreq)) ||
399 !(N = malloc(
sizeof(*N) * nfreq))) {
402 wThreshold = maxMag2 * sqr(WienerFraction);
403 for (i = 0; i < nfreq; i++) {
404 S[i] = sqrt(sqr(fft_res[2 * i]) + sqr(fft_res[2 * i + 1]));
405 if (sqr(S[i]) < wThreshold) {
409 S[i] = S[i] - sqrt(wThreshold);
410 N[i] = sqrt(wThreshold);
413 for (i = 0; i < nfreq; i++)
414 WienerFilter[i] = sqr(S[i]) / (sqr(S[i]) + sqr(N[i]) + threshold);
420 for (i = 0; i < nfreq; i++) {
422 fft_sig[2 * i], fft_sig[2 * i + 1],
423 fft_res[2 * i], fft_res[2 * i + 1],
428 for (i = 0; i < nfreq; i++) {
429 fft_sig[2 * i] *= WienerFilter[i];
430 fft_sig[2 * i + 1] *= WienerFilter[i];
436 realFFT2(fft_sig, fft_sig, 2 * rows1, INVERSE_FFT);
439 for (i = 0; i < rows1; i++)
440 fft_sig[i] = fft_sig[i] / range;
452 SDDS_Bomb(
"Unexpected processing mode encountered.");
464 signal1 = indep1 = signal2 = indep2 = NULL;
481void wrap_around_order(
double *response1,
double *t,
double *response, int64_t nres, int64_t nsig) {
485 for (iz = 0; iz < nres; iz++)
489 bomb(
"Response function is acausal.", NULL);
492 for (i = iz; i < nres; i++)
493 response1[i - iz] = response[i];
494 for (i = 0; i < iz; i++)
495 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.