55 CLO_INDEPENDENTCOLUMN,
65char *option[N_OPTIONS] = {
79#define USAGE "Usage: sddsconvolve <signal-file> <response-file> <output>\n\
80 -signalColumns=<indepColumn>,<dataName>\n\
81 -responseColumns=<indepColumn>,<dataName> [-reuse]\n\
82 -outputColumns=<indepColumn>,<dataName> [-majorOrder=row|column]\n\
83 [{-deconvolve [{-noiseFraction=<value> | -wienerFilter=<value>}] | -correlate}]\n\n\
85 Performs discrete Fourier convolution, deconvolution, or correlation between signal and response files.\n\
86 Assumes uniform spacing of points in both input files and that both files contain the same number of data points.\n\
88Mathematical Operations:\n\
89 - Convolution: O = S * R\n\
90 - Deconvolution: O = S / R\n\
91 - Correlation: O = S * Conj(R)\n\
94 -signalColumns=<indepColumn>,<dataName> Specify the independent column and data name for the signal file.\n\
95 -responseColumns=<indepColumn>,<dataName> Specify the independent column and data name for the response file.\n\
96 -outputColumns=<indepColumn>,<dataName> Specify the independent column and data name for the output file.\n\
97 -reuse Reuse the first page of the response file for each page of the signal file.\n\
98 -majorOrder=row|column Set data ordering in the output file.\n\
99 -deconvolve Perform deconvolution instead of convolution.\n\
100 -noiseFraction=<value> Specify noise fraction to prevent divide-by-zero.\n\
101 -wienerFilter=<value> Apply a Wiener filter with the specified fraction.\n\
102 -correlate Perform correlation instead of convolution.\n\
103 -pipe Use standard input/output in place of file arguments.\n\
105Program Information:\n\
106 Michael Borland (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n"
108void complex_multiply(
double *r0,
double *i0,
double r1,
double i1,
double r2,
double i2);
109void complex_divide(
double *r0,
double *i0,
double r1,
double i1,
double r2,
double i2,
double threshold);
110void wrap_around_order(
double *response1,
double *t,
double *response, int64_t nres, int64_t nsig);
112#define MODE_CONVOLVE 1
113#define MODE_DECONVOLVE 2
114#define MODE_CORRELATE 3
116int main(
int argc,
char **argv) {
119 SCANNED_ARG *scanned;
120 char *input1, *input2, *output;
122 double *fft_sig, *fft_res, noise, mag2, threshold, range;
123 double *signal1, *signal2, *indep1, *indep2;
124 double WienerFraction, *WienerFilter = NULL;
125 unsigned long pipeFlags, majorOrderFlag;
126 char *input1Column[2], *input2Column[2], *outputColumn[2];
127 char description[1024];
128 long tmpfile_used, code1, code2;
129 int64_t i, rows1, rows2, nfreq;
130 int32_t parameters = 0;
131 char **parameterName = NULL;
132 short columnMajorOrder = -1, reuse = 0;
135 argc =
scanargs(&scanned, argc, argv);
136 if (argc < 4 || argc > (4 + N_OPTIONS))
139 input1 = input2 = output = NULL;
140 mode = MODE_CONVOLVE;
142 input1Column[0] = input1Column[1] = NULL;
143 input2Column[0] = input2Column[1] = NULL;
144 outputColumn[0] = outputColumn[1] = NULL;
148 for (i_arg = 1; i_arg < argc; i_arg++) {
149 if (scanned[i_arg].arg_type == OPTION) {
151 switch (
match_string(scanned[i_arg].list[0], option, N_OPTIONS, 0)) {
152 case CLO_MAJOR_ORDER:
154 scanned[i_arg].n_items--;
155 if (scanned[i_arg].n_items > 0 &&
156 (!
scanItemList(&majorOrderFlag, scanned[i_arg].list + 1, &scanned[i_arg].n_items, 0,
157 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
158 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
159 SDDS_Bomb(
"Invalid -majorOrder syntax or values.");
160 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
161 columnMajorOrder = 1;
162 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
163 columnMajorOrder = 0;
166 mode = MODE_DECONVOLVE;
169 mode = MODE_CORRELATE;
172 if (!
processPipeOption(scanned[i_arg].list + 1, scanned[i_arg].n_items - 1, &pipeFlags))
175 case CLO_NOISE_FRACTION:
176 if (scanned[i_arg].n_items != 2 || sscanf(scanned[i_arg].list[1],
"%lf", &noise) != 1 || noise <= 0)
177 SDDS_Bomb(
"Invalid -noisefraction syntax or value.");
179 case CLO_WIENER_FILTER:
180 if (scanned[i_arg].n_items != 2 || sscanf(scanned[i_arg].list[1],
"%lf", &WienerFraction) != 1 ||
181 WienerFraction <= 0 || WienerFraction >= 1)
182 SDDS_Bomb(
"Invalid -wienerfilter syntax or value.");
185 case CLO_SIGNALCOLUMN:
186 if (scanned[i_arg].n_items != 3 ||
187 !strlen(input1Column[0] = scanned[i_arg].list[1]) ||
188 !strlen(input1Column[1] = scanned[i_arg].list[2]))
189 SDDS_Bomb(
"Invalid -signalColumns syntax.");
191 case CLO_RESPONSECOLUMN:
192 if (scanned[i_arg].n_items != 3 ||
193 !strlen(input2Column[0] = scanned[i_arg].list[1]) ||
194 !strlen(input2Column[1] = scanned[i_arg].list[2]))
195 SDDS_Bomb(
"Invalid -responseColumns syntax.");
197 case CLO_OUTPUTCOLUMN:
198 if (scanned[i_arg].n_items != 3 ||
199 !strlen(outputColumn[0] = scanned[i_arg].list[1]) ||
200 !strlen(outputColumn[1] = scanned[i_arg].list[2]))
201 SDDS_Bomb(
"Invalid -outputColumns syntax.");
212 input1 = scanned[i_arg].list[0];
214 input2 = scanned[i_arg].list[0];
216 output = scanned[i_arg].list[0];
218 SDDS_Bomb(
"Too many filenames provided.");
222 if (pipeFlags & USE_STDIN && input1) {
224 SDDS_Bomb(
"Too many filenames provided.");
229 if (!input1Column[0] || !input1Column[1] || !strlen(input1Column[0]) || !strlen(input1Column[1]))
230 SDDS_Bomb(
"SignalColumns not provided.");
231 if (!input2Column[0] || !input2Column[1] || !strlen(input2Column[0]) || !strlen(input2Column[1]))
232 SDDS_Bomb(
"ResponseColumns not provided.");
233 if (!outputColumn[0] || !outputColumn[1] || !strlen(outputColumn[0]) || !strlen(outputColumn[1]))
234 SDDS_Bomb(
"OutputColumns not provided.");
236 processFilenames(
"sddsconvolve", &input1, &output, pipeFlags, 1, &tmpfile_used);
238 SDDS_Bomb(
"Second input file not specified.");
247 sprintf(description,
"Convolution of signal '%s' with response '%s'", input1Column[1], input2Column[1]);
249 case MODE_DECONVOLVE:
250 sprintf(description,
"Deconvolution of signal '%s' with response '%s'", input1Column[1], input2Column[1]);
253 sprintf(description,
"Correlation of signal '%s' with response '%s'", input1Column[1], input2Column[1]);
264 if (columnMajorOrder != -1)
265 SDDSout.layout.data_mode.column_major = columnMajorOrder;
267 SDDSout.layout.data_mode.column_major = SDDS1.layout.data_mode.column_major;
270 for (i = 0; i < parameters; i++)
282 if ((rows1 = SDDS_RowCount(&SDDS1)) <= 0) {
283 fprintf(stderr,
"Warning (sddsconvolve): Skipping page due to no signal rows.\n");
289 fprintf(stderr,
"Error (sddsconvolve): Couldn't read data from response file.\n");
292 if ((rows2 = SDDS_RowCount(&SDDS2)) < 0) {
293 fprintf(stderr,
"Error (sddsconvolve): Response file has zero rows on first page.\n");
300 rows2 = SDDS_RowCount(&SDDS2);
303 SDDS_Bomb(
"Different numbers of points for signal and response.");
313 if (!(fft_sig =
SDDS_Calloc(
sizeof(*fft_sig), (2 * rows1 + 2))) ||
314 !(fft_res =
SDDS_Calloc(
sizeof(*fft_res), (2 * rows1 + 2)))) {
321 wrap_around_order(fft_res, indep2, signal2, rows2, rows1);
322 for (i = 0; i < rows1; i++)
323 fft_sig[i] = signal1[i];
326 realFFT2(fft_sig, fft_sig, 2 * rows1, 0);
327 realFFT2(fft_res, fft_res, 2 * rows1, 0);
329 range = 2 * rows1 * (indep1[rows1 - 1] - indep1[0]) / (rows1 - 1);
331 if (mode == MODE_CONVOLVE || mode == MODE_CORRELATE) {
332 if (mode == MODE_CORRELATE)
334 for (i = 0; i < nfreq; i++)
335 fft_res[2 * i + 1] = -fft_res[2 * i + 1];
338 for (i = 0; i < nfreq; i++) {
340 fft_sig[2 * i], fft_sig[2 * i + 1],
341 fft_res[2 * i], fft_res[2 * i + 1]);
345 realFFT2(fft_sig, fft_sig, 2 * rows1, INVERSE_FFT);
348 for (i = 0; i < rows1; i++)
360 }
else if (mode == MODE_DECONVOLVE) {
363 for (i = threshold = 0; i < nfreq; i++) {
364 if ((mag2 = sqr(fft_res[2 * i]) + sqr(fft_res[2 * i + 1])) > threshold)
368 threshold = threshold * noise;
372 double *S = NULL, *N = NULL, wThreshold;
373 if (!(WienerFilter = malloc(
sizeof(*WienerFilter) * nfreq)) ||
374 !(S = malloc(
sizeof(*S) * nfreq)) ||
375 !(N = malloc(
sizeof(*N) * nfreq))) {
378 wThreshold = maxMag2 * sqr(WienerFraction);
379 for (i = 0; i < nfreq; i++) {
380 S[i] = sqrt(sqr(fft_res[2 * i]) + sqr(fft_res[2 * i + 1]));
381 if (sqr(S[i]) < wThreshold) {
385 S[i] = S[i] - sqrt(wThreshold);
386 N[i] = sqrt(wThreshold);
389 for (i = 0; i < nfreq; i++)
390 WienerFilter[i] = sqr(S[i]) / (sqr(S[i]) + sqr(N[i]) + threshold);
396 for (i = 0; i < nfreq; i++) {
398 fft_sig[2 * i], fft_sig[2 * i + 1],
399 fft_res[2 * i], fft_res[2 * i + 1],
404 for (i = 0; i < nfreq; i++) {
405 fft_sig[2 * i] *= WienerFilter[i];
406 fft_sig[2 * i + 1] *= WienerFilter[i];
412 realFFT2(fft_sig, fft_sig, 2 * rows1, INVERSE_FFT);
415 for (i = 0; i < rows1; i++)
416 fft_sig[i] = fft_sig[i] / range;
428 SDDS_Bomb(
"Unexpected processing mode encountered.");
440 signal1 = indep1 = signal2 = indep2 = NULL;
457void wrap_around_order(
double *response1,
double *t,
double *response, int64_t nres, int64_t nsig) {
461 for (iz = 0; iz < nres; iz++)
465 bomb(
"Response function is acausal.", NULL);
468 for (i = iz; i < nres; i++)
469 response1[i - iz] = response[i];
470 for (i = 0; i < iz; i++)
471 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.