140 {
142 int i_arg;
143 SCANNED_ARG *scanned;
144 char *input1, *input2, *output;
145 long mode, doWiener;
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;
157
159 argc =
scanargs(&scanned, argc, argv);
160 if (argc < 4 || argc > (4 + N_OPTIONS))
162
163 input1 = input2 = output = NULL;
164 mode = MODE_CONVOLVE;
165 noise = 1e-14;
166 input1Column[0] = input1Column[1] = NULL;
167 input2Column[0] = input2Column[1] = NULL;
168 outputColumn[0] = outputColumn[1] = NULL;
169 pipeFlags = 0;
170 doWiener = 0;
171
172 for (i_arg = 1; i_arg < argc; i_arg++) {
173 if (scanned[i_arg].arg_type == OPTION) {
174
175 switch (
match_string(scanned[i_arg].list[0], option, N_OPTIONS, 0)) {
176 case CLO_MAJOR_ORDER:
177 majorOrderFlag = 0;
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;
188 break;
189 case CLO_DECONVOLVE:
190 mode = MODE_DECONVOLVE;
191 break;
192 case CLO_CORRELATE:
193 mode = MODE_CORRELATE;
194 break;
195 case CLO_PIPE:
196 if (!
processPipeOption(scanned[i_arg].list + 1, scanned[i_arg].n_items - 1, &pipeFlags))
198 break;
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.");
202 break;
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.");
207 doWiener = 1;
208 break;
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.");
214 break;
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.");
220 break;
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.");
226 break;
227 case CLO_REUSE:
228 reuse = 1;
229 break;
230 default:
232 break;
233 }
234 } else {
235 if (!input1)
236 input1 = scanned[i_arg].list[0];
237 else if (!input2)
238 input2 = scanned[i_arg].list[0];
239 else if (!output)
240 output = scanned[i_arg].list[0];
241 else
242 SDDS_Bomb(
"Too many filenames provided.");
243 }
244 }
245
246 if (pipeFlags & USE_STDIN && input1) {
247 if (output)
248 SDDS_Bomb(
"Too many filenames provided.");
249 output = input2;
250 input2 = input1;
251 input1 = NULL;
252 }
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.");
259
260 processFilenames(
"sddsconvolve", &input1, &output, pipeFlags, 1, &tmpfile_used);
261 if (!input2)
262 SDDS_Bomb(
"Second input file not specified.");
263
266 exit(EXIT_FAILURE);
267 }
268
269 switch (mode) {
270 case MODE_CONVOLVE:
271 sprintf(description, "Convolution of signal '%s' with response '%s'", input1Column[1], input2Column[1]);
272 break;
273 case MODE_DECONVOLVE:
274 sprintf(description, "Deconvolution of signal '%s' with response '%s'", input1Column[1], input2Column[1]);
275 break;
276 case MODE_CORRELATE:
277 sprintf(description, "Correlation of signal '%s' with response '%s'", input1Column[1], input2Column[1]);
278 break;
279 }
280
286 exit(EXIT_FAILURE);
287 }
288 if (columnMajorOrder != -1)
289 SDDSout.layout.data_mode.column_major = columnMajorOrder;
290 else
291 SDDSout.layout.data_mode.column_major = SDDS1.layout.data_mode.column_major;
292
293 if (parameters) {
294 for (i = 0; i < parameters; i++)
297 }
298
301 exit(EXIT_FAILURE);
302 }
303
304 code2 = -1;
306 if ((rows1 = SDDS_RowCount(&SDDS1)) <= 0) {
307 fprintf(stderr, "Warning (sddsconvolve): Skipping page due to no signal rows.\n");
308 continue;
309 }
310 if (reuse) {
311 if (code2 == -1) {
313 fprintf(stderr, "Error (sddsconvolve): Couldn't read data from response file.\n");
314 exit(EXIT_FAILURE);
315 }
316 if ((rows2 = SDDS_RowCount(&SDDS2)) < 0) {
317 fprintf(stderr, "Error (sddsconvolve): Response file has zero rows on first page.\n");
318 exit(EXIT_FAILURE);
319 }
320 }
321 } else {
323 break;
324 rows2 = SDDS_RowCount(&SDDS2);
325 }
326 if (rows1 != rows2)
327 SDDS_Bomb(
"Different numbers of points for signal and response.");
328
334 exit(EXIT_FAILURE);
335 }
336
337 if (!(fft_sig =
SDDS_Calloc(
sizeof(*fft_sig), (2 * rows1 + 2))) ||
338 !(fft_res =
SDDS_Calloc(
sizeof(*fft_res), (2 * rows1 + 2)))) {
341 exit(EXIT_FAILURE);
342 }
343
344
345 wrap_around_order(fft_res, indep2, signal2, rows2, rows1);
346 for (i = 0; i < rows1; i++)
347 fft_sig[i] = signal1[i];
348
349
350 realFFT2(fft_sig, fft_sig, 2 * rows1, 0);
351 realFFT2(fft_res, fft_res, 2 * rows1, 0);
352 nfreq = rows1 + 1;
353 range = 2 * rows1 * (indep1[rows1 - 1] - indep1[0]) / (rows1 - 1);
354
355 if (mode == MODE_CONVOLVE || mode == MODE_CORRELATE) {
356 if (mode == MODE_CORRELATE)
357
358 for (i = 0; i < nfreq; i++)
359 fft_res[2 * i + 1] = -fft_res[2 * i + 1];
360
361
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]);
366 }
367
368
369 realFFT2(fft_sig, fft_sig, 2 * rows1, INVERSE_FFT);
370
371
372 for (i = 0; i < rows1; i++)
373 fft_sig[i] *= range;
374
375
382 exit(EXIT_FAILURE);
383 }
384 } else if (mode == MODE_DECONVOLVE) {
385 double maxMag2;
386
387 for (i = threshold = 0; i < nfreq; i++) {
388 if ((mag2 = sqr(fft_res[2 * i]) + sqr(fft_res[2 * i + 1])) > threshold)
389 threshold = mag2;
390 }
391 maxMag2 = threshold;
392 threshold = threshold * noise;
393
394 if (doWiener) {
395
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))) {
401 }
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) {
406 N[i] = S[i];
407 S[i] = 0;
408 } else {
409 S[i] = S[i] - sqrt(wThreshold);
410 N[i] = sqrt(wThreshold);
411 }
412 }
413 for (i = 0; i < nfreq; i++)
414 WienerFilter[i] = sqr(S[i]) / (sqr(S[i]) + sqr(N[i]) + threshold);
415 free(N);
416 free(S);
417 }
418
419
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],
424 threshold);
425 }
426
427 if (doWiener) {
428 for (i = 0; i < nfreq; i++) {
429 fft_sig[2 * i] *= WienerFilter[i];
430 fft_sig[2 * i + 1] *= WienerFilter[i];
431 }
432 free(WienerFilter);
433 }
434
435
436 realFFT2(fft_sig, fft_sig, 2 * rows1, INVERSE_FFT);
437
438
439 for (i = 0; i < rows1; i++)
440 fft_sig[i] = fft_sig[i] / range;
441
442
449 exit(EXIT_FAILURE);
450 }
451 } else {
452 SDDS_Bomb(
"Unexpected processing mode encountered.");
453 }
454
455
456 free(fft_sig);
457 fft_sig = NULL;
458 free(fft_res);
459 fft_res = NULL;
460 free(signal1);
461 free(indep1);
462 free(signal2);
463 free(indep2);
464 signal1 = indep1 = signal2 = indep2 = NULL;
465 }
466
469 exit(EXIT_FAILURE);
470 }
471
473 exit(EXIT_FAILURE);
474
475 free(parameterName);
477
478 return EXIT_SUCCESS;
479}
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.
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.