Waveform filter programs
cross.cc
Go to the documentation of this file.
1 
40 #define CROSS_VERSION \
41  "CROSS V1.3 cross correlation and convolution"
42 
43 #include <fstream>
44 #include <iostream>
45 #include <list>
46 #include <string>
47 #include <tfxx/commandline.h>
48 #include <tfxx/xcmdline.h>
49 #include <tfxx/error.h>
50 #include <tfxx/misc.h>
51 #include <tfxx/rangelist.h>
52 #include <tfxx/rangestring.h>
53 #include <tsioxx/sfftimeseries.h>
54 #include <tsioxx/inputoperators.h>
55 #include <tsioxx/outputoperators.h>
56 #include <tsxx/correlate.h>
57 #include <tsxx/convolve.h>
58 #include <datrwxx/writeany.h>
59 #include <datrwxx/readany.h>
60 #include <aff/seriesoperators.h>
61 #include <aff/subarray.h>
62 #include <aff/iterator.h>
63 #include <fourier/fftwaff.h>
64 
65 using std::cout;
66 using std::cerr;
67 using std::endl;
68 
69 typedef aff::Series<double> Tseries;
70 typedef ts::sff::SFFTimeSeries<Tseries> Tts;
72 
73 struct Options {
75  std::string inputformat, outputformat;
76 }; // struct Options
77 
78 /* ====================================================================== */
79 
89  public:
91  typedef fourier::fft::DRFFTWAFF Tfft;
95  typedef Tfft::Tspectrum Tspectrum;
97  typedef ts::TDtimeseries Ttimeseries;
99  typedef Ttimeseries::Tconsttimeseries Tconsttimeseries;
101  FourierProcessor(const bool& debug=false):
102  Mspecavail(false), Minsize(0), Mdt(0), Mdebug(debug) { }
105  const bool& debug=false):
106  Mspecavail(false), Minsize(0), Mdt(0), Mdebug(debug)
107  { this->setseries(s); }
111  FourierProcessor(const Tconsttimeseries& s, const unsigned int& n):
112  Mspecavail(false), Minsize(0), Mdt(0)
113  {
114  this->setseries(s);
115  this->padseries(n);
116  }
118  Tspectrum::Tcoc operator()(const unsigned int& n);
120  Tspectrum::Tcoc operator()(const Tconsttimeseries& s,
121  const unsigned int& n);
123  void setseries(const Tconsttimeseries& s);
124  private:
126  void padseries(const unsigned int& n);
127  private:
139  unsigned int Minsize;
141  double Mdt;
143  bool Mdebug;
144 }; // class FourierProcessor
145 
146 /* ---------------------------------------------------------------------- */
147 
148 FourierProcessor::Tspectrum::Tcoc
150  const unsigned int& n)
151 {
152  TFXX_debug(this->Mdebug,
153  "FourierProcessor::operator()(const Tconsttimeseries& s,\n"
154  " const unsigned int& n)",
155  TFXX_value(s.size()) << " " << TFXX_value(n));
156  this->setseries(s);
157  return(this->operator()(n));
158 } // FourierProcessor::Tspectrum::Tcoc
159  // FourierProcessor::operator()(const Tconsttimeseries& s,
160  // const unsigned int& n)
161 
162 /* ---------------------------------------------------------------------- */
163 
164 FourierProcessor::Tspectrum::Tcoc
165  FourierProcessor::operator()(const unsigned int& n)
166 {
167  TFXX_debug(this->Mdebug,
168  "FourierProcessor::operator()(const unsigned int& n)",
169  TFXX_value(n));
170  TFXX_assert(Minsize>0, "no input time series available");
171  this->padseries(n);
172  TFXX_assert(Mspecavail, "no Fourier coefficents available");
173  return(Mspectrum);
174 } // FourierProcessor::Tspectrum::Tcoc
175  // FourierProcessor::operator()(const unsigned int& n)
176 
177 /* ---------------------------------------------------------------------- */
178 
180 {
181  TFXX_debug(this->Mdebug,
182  "FourierProcessor::setseries(const Tconsttimeseries& s)",
183  TFXX_value(s.size()));
184  Minsize=s.size();
185  if (Minsize>Mseries.size())
186  {
187  Mseries=Tseries(s.size());
188  }
189  Mseries=0.;
190  Mseries.copyin(s);
191  Mdt=s.header.dt;
192  TFXX_debug(this->Mdebug,
193  "FourierProcessor::setseries(const Tconsttimeseries& s)",
194  TFXX_value(s.header.dt));
196  Mspecavail=false;
197 } // void FourierProcessor::setseries(const Tconsttimeseries& s)
198 
199 /* ---------------------------------------------------------------------- */
200 
201 // pad series
202 // expects samples to be previously set through setseries
203 void FourierProcessor::padseries(const unsigned int& n)
204 {
205  TFXX_debug(this->Mdebug,
206  "FourierProcessor::padseries(const Tconsttimeseries& n)",
207  TFXX_value(n));
208  TFXX_assert(Minsize<=n,
209  "desired series size would truncate original series");
210  bool refft=((Mpadded.size() != n) || (!Mspecavail));
211  if (n>Mseries.size())
212  {
213  Mseries=Tseries(n);
214  Mseries=0.;
215  Mseries.copyin(Mpadded);
216  refft=true;
217  }
218  if (refft)
219  {
220  Mpadded=aff::subarray(Mseries)(Mseries.f(),Mseries.f()+n-1);
221  Mspectrum=MFFT(Mpadded, this->Mdt);
222  Mspecavail=true;
223  }
224 } // void FourierProcessor::padseries(const unsigned int& n)
225 
226 /* ---------------------------------------------------------------------- */
227 
229  specconv(const FourierProcessor::Tspectrum::Tcoc & sref,
230  const FourierProcessor::Tspectrum::Tcoc & ssig)
231 {
232  TFXX_assert(sref.size() == ssig.size(),
233  "inconsistent sets of coefficients");
234  FourierProcessor::Tspectrum result(sref.size());
236  aff::Browser<FourierProcessor::Tspectrum::Tcoc> BR(sref);
237  aff::Browser<FourierProcessor::Tspectrum::Tcoc> BD(ssig);
238  aff::Iterator<FourierProcessor::Tspectrum> IR(result);
239  while (BR.valid() && BD.valid() && IR.valid())
240  {
241  (*IR) = ((*BR) * (*BD));
242  ++IR;
243  ++BR;
244  ++BD;
245  }
246  return(result);
247 } // FourierProcessor::Tspectrum
248  // specconv(const FourierProcessor::Tspectrum::Tcoc & sref,
249  // const FourierProcessor::Tspectrum::Tcoc & ssig)
250 
251 /* ---------------------------------------------------------------------- */
252 
254  speccorr(const FourierProcessor::Tspectrum::Tcoc & sref,
255  const FourierProcessor::Tspectrum::Tcoc & ssig)
256 {
257  TFXX_assert(sref.size() == ssig.size(),
258  "inconsistent sets of coefficients");
259  // imaginary unit time pi (shift factor)
260  const std::complex<double> expfac(0.,M_PI);
261  FourierProcessor::Tspectrum result(sref.size());
263  aff::Browser<FourierProcessor::Tspectrum::Tcoc> BR(sref);
264  aff::Browser<FourierProcessor::Tspectrum::Tcoc> BD(ssig);
265  aff::Iterator<FourierProcessor::Tspectrum> IR(result);
266  int l=0;
267  while (BR.valid() && BD.valid() && IR.valid())
268  {
269  // cross correlation in the Fourier domain and simultaneous time shift to
270  // place origin of time scale in center of corresponding time series
271  *IR = conj(*BR) * (*BD) * std::exp(double(l)*expfac);
272  ++IR;
273  ++BR;
274  ++BD;
275  ++l;
276  }
277  return(result);
278 } // FourierProcessor::Tspectrum
279  // speccorr(const FourierProcessor::Tspectrum::Tcoc & sref,
280  // const FourierProcessor::Tspectrum::Tcoc & ssig)
281 
282 /* ====================================================================== */
283 
284 int main(int iargc, char* argv[])
285 {
286 
287  // define usage information
288  char usage_text[]=
289  {
290  CROSS_VERSION "\n"
291  "usage: cross [-v] [-o] [-D] [-convolve] [--itype t] [--otype f]\n"
292  " [-fourier]\n"
293  " file [f:F] [t:T] [file [f:F] [t:T] [...]] outfile\n"
294  " or: cross --help|-h" "\n"
295  " or: cross --xhelp" "\n"
296  };
297 
298  // define full help text
299  char help_text[]=
300  {
301  "-v be verbose" "\n"
302  "-D debug mode" "\n"
303  "-o overwrite existing output file" "\n"
304  "-convolve apply convolution rather than correlation\n"
305  "-fourier operate in the Fourier domain\n"
306  "-itype t file format for input files\n"
307  "-otype t file format for output files\n"
308  "\n"
309  "file ... input file(s)" "\n"
310  " t:T select traces T, where T may be any range\n"
311  " specification like '3-4' or '5,6,7-12,20'\n"
312  " f:F specifies an input file format differing from\n"
313  " the format selected by \"--itype\"\n"
314  "outfile output file" "\n"
315  "\n"
316  "--xhelp print details on supported I/O formats\n"
317  "\n"
318  "The first trace read will be taken as a reference. All other\n"
319  "traces will be cross-correlated with the reference or convolved\n"
320  "with the reference. Convolution and cross-correlation are understood\n"
321  "as an approximation to the corresponding integral form. Consequently\n"
322  "the sampling interval of time series must be identical and the\n"
323  "result of the discrete operation will be scaled with the sampling\n"
324  "interval." "\n"
325  "\n"
326  "Data time will be handled as follows:\n"
327  "\n"
328  "Convolution\n"
329  " The reference series is understood as the impulse response of a\n"
330  " filter which s to be applied to the other input series. If a\n"
331  " source date is given in the file of the reference trace, this will\n"
332  " be taken as the origin of time, allowing for acausal impulse\n"
333  " response. If it is missing, the first sample of the reference (filter\n"
334  " impulse response) is understood to be at lag=0s. The date of the\n"
335  " first sample of the output trace is set to account for possible\n"
336  " acausal parts of the filter response. Source definition is taken\n"
337  " only from the first of the input files and is passed unaltered to\n"
338  " the output.\n"
339  "\n"
340  "Cross-correlation\n"
341  " Each input trace is cross-correlated with the reference trace.\n"
342  " When calculating the lag time, absolute time of the first sample\n"
343  " of each of the traces is taken into account. Absolute time of the\n"
344  " output is set with respect to the source time. The source time is\n"
345  " taken from the file header of the reference trace. If a source time\n"
346  " is missing there, it will be set to a default value.\n"
347  "\n"
348  "If option -convolve is selected, all traces will be convolved with\n"
349  "the reference trace.\n"
350  "\n"
351  };
352 
353  // define commandline options
354  using namespace tfxx::cmdline;
355  static Declare options[]=
356  {
357  // 0: print help
358  {"help",arg_no,"-"},
359  // 1: verbose mode
360  {"v",arg_no,"-"},
361  // 2: overwrite mode
362  {"o",arg_no,"-"},
363  // 3: debug mode
364  {"D",arg_no,"-"},
365  // 4: convolve rather than correlate
366  {"convolve",arg_no,"-"},
367  // 5: detailed information on I/O formats
368  {"xhelp",arg_no,"-"},
369  // 6: convolve rather than correlate
370  {"itype",arg_yes,"sff"},
371  // 7: convolve rather than correlate
372  {"otype",arg_yes,"sff"},
373  // 8: convolve rather than correlate
374  {"fourier",arg_no,"-"},
375  {NULL}
376  };
377 
378  /*----------------------------------------------------------------------*/
379  /* define file specific options
380  */
381 
382  static const char formatkey[]="f";
383  static const char tracekey[]="t";
384 
385  // define commandline argument modifier keys
386  static const char* cmdlinekeys[]
387  ={formatkey, tracekey, 0};
388 
389  /*----------------------------------------------------------------------*/
390 
391  // no arguments? print usage...
392  if (iargc<2)
393  {
394  cerr << usage_text << endl;
395  exit(0);
396  }
397 
398  // collect options from commandline
399  Commandline cmdline(iargc, argv, options);
400 
401  // help requested? print full help text...
402  if (cmdline.optset(0) || cmdline.optset(5))
403  {
404  cerr << usage_text << endl;
405  cerr << help_text << endl;
406  cerr << endl;
407  datrw::supported_data_types(cerr);
408  cerr << endl;
409  if (cmdline.optset(5))
410  {
411  cerr << endl;
412  datrw::online_help(cerr);
413  }
414  exit(0);
415  }
416 
417  /* ---------------------------------------------------------------------- */
418  // evaluate command line parameters
419  Options opt;
420  opt.verbose=cmdline.optset(1);
421  opt.overwrite=cmdline.optset(2);
422  opt.debug=cmdline.optset(3);
423  opt.convolve=cmdline.optset(4);
424  opt.inputformat=cmdline.string_arg(6);
425  opt.outputformat=cmdline.string_arg(7);
426  opt.fourier=cmdline.optset(8);
427 
428  if (opt.verbose) { cout << CROSS_VERSION << endl; }
429 
430  TFXX_assert(cmdline.extra(), "missing input file!");
431  tfxx::cmdline::Tparsed arguments=parse_cmdline(cmdline, cmdlinekeys);
432  TFXX_assert(arguments.size()>1, "missing output file!");
433  // extract output file name and remove from list
434  std::string outfile=arguments.back().name;
435  arguments.pop_back();
436 
437  if ((arguments.size()>1) && opt.verbose)
438  {
439  cout
440  << "NOTICE: file specific information (SRCE line and file FREE)" << endl
441  << " will be taken from first file only!" << endl;
442  }
443 
444  /* ---------------------------------------------------------------------- */
445  // create Fourier workspace
446  FourierProcessor FFTreference(opt.debug), FFTdata(opt.debug);
447  // create FFT processor for transformation to time domain
449 
450  /* ---------------------------------------------------------------------- */
451  // open output file
452  // ----------------
453  if (opt.verbose) { cout << "open output file " << outfile << endl; }
454  // check if output file exists and open
455  if (!opt.overwrite) { datrw::abort_if_exists(outfile); }
456  std::ios_base::openmode oopenmode
457  =datrw::oanystream::openmode(opt.outputformat);
458  std::ofstream ofs(outfile.c_str(), oopenmode);
459  TFXX_debug(opt.debug, "main()", "open os");
460  datrw::oanystream os(ofs, opt.outputformat, opt.debug);
461  TFXX_debug(opt.debug, "main()", "os is open");
462 
463  /*
464  * the first trace to be read has to be stored as the reference trace
465  */
466  Tts reference;
467  bool referenceread=false;
468 
469  // file header information for reference trace
470  ts::sff::FileHeader referencefileheader;
471 
472  // cycle through list of file names found on command line
473  tfxx::cmdline::Tparsed::const_iterator infile=arguments.begin();
474  while (infile!=arguments.end())
475  {
476  if (opt.verbose) { cout << "open " << std::string(infile->name) << endl; }
477  std::string inputformat=opt.inputformat;
478  if (infile->haskey(formatkey))
479  {
480  inputformat=infile->value(formatkey);
481  }
482  std::ios_base::openmode iopenmode
483  =datrw::ianystream::openmode(inputformat);
484  std::ifstream ifs(infile->name.c_str(), iopenmode);
485  datrw::ianystream is(ifs, inputformat);
486 
487  // handle file header
488  // ------------------
489  ts::sff::FileHeader fileheader;
490  is >> fileheader;
491 
492  // cycle through traces of input file
493  // ----------------------------------
494  // setup trace selection
495  typedef tfxx::RangeList<int> Trangelist;
496  bool doselect=infile->haskey(tracekey);
497  Trangelist traceranges=
498  tfxx::string::rangelist<Trangelist::Tvalue>(infile->value(tracekey));
499 
500  int iftrace=0;
501  while (is.good())
502  {
503  ++iftrace;
504  if (doselect && (!traceranges.contains(iftrace)))
505  {
506  if (opt.verbose)
507  { std::cout << " skip trace #" << iftrace << std::endl; }
508  is.skipseries();
509  }
510  else
511  {
512  if (opt.verbose) { std::cout << "process trace #" << iftrace << ": "; }
513  if (!referenceread)
514  {
515  // handle file header of reference
516  // -------------------------------
517  // set a SRCE definition if not present in input and mode is
518  // cross-correlation
519  sff::FREE freeblock(fileheader.free());
520  freeblock.append(CROSS_VERSION);
521  // SRCE date is a reference time for cross-correlograms
522  if (!opt.convolve)
523  {
524  if (!fileheader.hassrce())
525  {
526  sff::SRCE srce;
527  srce.date=libtime::TAbsoluteTime(2000);
528  fileheader.srce(srce);
529  freeblock.append("added SRCE definition to file header");
530  }
531  }
532  fileheader.free(freeblock);
533  os << fileheader;
534  referencefileheader=fileheader;
535 
536  // read actual reference time series
537  // ---------------------------------
538  if (opt.verbose)
539  { std::cout << "read reference trace" << std::endl; }
540  is >> reference;
541  referenceread=true;
542  if (opt.verbose) { cout << reference.header.wid2().line() << endl; }
543  if (opt.fourier)
544  {
545  TFXX_debug(opt.debug,
546  "main()", "prepare FFTreference "
547  << TFXX_value(reference.header.wid2().dt));
548  Tts::Tdttimeseries dtreference(reference);
549  TFXX_debug(opt.debug,
550  "main()", TFXX_value(dtreference.header.dt));
551  FFTreference.setseries(dtreference);
552  }
553  }
554  else
555  {
556  if (opt.verbose) { cout << "read trace" << endl; }
557  Tts data;
558  is >> data;
559  if (opt.verbose) { cout << data.header.wid2().line() << endl; }
560  TFXX_assert((data.header.wid2().dt == reference.header.wid2().dt),
561  "sampling intervals do not match!");
562  Tts result(data);
563  sff::WID2 wid2line(data.header.wid2());
564  if (opt.fourier)
565  {
566  TFXX_debug(opt.debug,
567  "main()", "prepare FFTdata");
568  Tts::Tdttimeseries dtdata(data);
569  FFTdata.setseries(dtdata);
570  }
571  if (opt.convolve)
572  {
573  if (opt.fourier)
574  {
575  TFXX_debug(opt.debug,
576  "main()", "start convolution in the Fourier domain");
577  unsigned int n=data.size()+reference.size();
578  TFXX_debug(opt.debug,
579  "main()", "padded size: " << TFXX_value(n));
580  FourierProcessor::Tspectrum::Tcoc sdata=FFTdata(n);
581  FourierProcessor::Tspectrum::Tcoc sreference=FFTreference(n);
582  TFXX_debug(opt.debug,
583  "main()", "call specconv "
584  << TFXX_value(sreference.size()) << ", "
585  << TFXX_value(sdata.size()));
587  sresult=specconv(sreference, sdata);
588  TFXX_debug(opt.debug,
589  "main()", "returned: " << TFXX_value(sresult.size()));
590  result=FFT(sresult, reference.header.wid2().dt);
591  }
592  else
593  {
594  result=ts::convolve(reference,data);
595  result *= wid2line.dt;
596  } // else, if (opt.fourier)
597  wid2line.auxid="conv";
598  // set time of first sample
599  // ------------------------
600  if (referencefileheader.hasfree())
601  {
602  // offset of impulse response
603  libtime::TRelativeTime t0(reference.header.wid2().date
604  -referencefileheader.srce().date);
605  if (reference.header.wid2().date
606  <referencefileheader.srce().date)
607  {
608  wid2line.date -= t0;
609  }
610  else
611  {
612  wid2line.date += t0;
613  }
614  }
615  } else {
616  if (opt.fourier)
617  {
618  unsigned int n=data.size()+reference.size();
619  FourierProcessor::Tspectrum::Tcoc sdata=FFTdata(n);
620  FourierProcessor::Tspectrum::Tcoc sreference=FFTreference(n);
622  sresult=speccorr(sreference, sdata);
623  result=FFT(sresult, reference.header.wid2().dt);
624  }
625  else
626  {
627  result=ts::correlate(reference,data);
628  result *= wid2line.dt;
629  } // else, if (opt.fourier)
630  wid2line.auxid="corr";
631  /*
632  * Time delay of current signal with respect to first sample of
633  * reference signal to be understood as a signed value:
634  *
635  * tor = signal.date-ref.date
636  *
637  * Duration of reference signal: Tr
638  * Duration of current signal: Ts
639  *
640  * Duration of cross-correlogram: Tr+Ts
641  *
642  * lag time of first sample:
643  *
644  * tl1=tor-(Tr+Ts)/2
645  */
646  libtime::TRelativeTime
647  Tr(libtime::double2time(reference.header.wid2().dt
648  *(reference.header.wid2().nsamples-1)));
649  libtime::TRelativeTime
650  Ts(libtime::double2time(data.header.wid2().dt
651  *(data.header.wid2().nsamples-1)));
652  libtime::TRelativeTime tor(data.header.wid2().date
653  -reference.header.wid2().date);
654  libtime::TAbsoluteTime
655  torigin=referencefileheader.srce().date-((Tr+Ts)/2);
656  if (data.header.wid2().date
657  >=reference.header.wid2().date)
658  {
659  torigin += tor;
660  }
661  else
662  {
663  torigin -= tor;
664  }
665  wid2line.date=torigin;
666  }
667  result.header.wid2(wid2line);
668  /*
669  result.header.wid2().date=fileheader.srce.date
670  +(result.series.first()
671  *libtime::double2time(result.header.wid2().dt))
672  +(data.header.wid2().date-reference.header.wid2().date);
673  */
674  if (opt.verbose) { cout << result.header.wid2().line() << endl; }
675  os << result;
676  } // else; if (!referenceread)
677  } // else; if (doselect && (!traceranges.contains(itrace)))
678  }
679  ++infile;
680  }
681 }
682 
683 /* ----- END OF cross.cc ----- */
bool convolve
Definition: cross.cc:74
Ttimeseries::Tconsttimeseries Tconsttimeseries
full time series with sampling interval
Definition: cross.cc:99
void setseries(const Tconsttimeseries &s)
set new input series
Definition: cross.cc:179
Tseries Mpadded
series addressing part of workspace
Definition: cross.cc:133
bool fourier
Definition: cross.cc:74
Tfft::Tspectrum Tspectrum
type of Fourier coefficient data
Definition: cross.cc:95
fourier::fft::DRFFTWAFF Tfft
type of FFT processor
Definition: cross.cc:91
std::string inputformat
Definition: cross.cc:75
static const char * cmdlinekeys[]
Definition: fidasexx.cc:131
FourierProcessor::Tspectrum specconv(const FourierProcessor::Tspectrum::Tcoc &sref, const FourierProcessor::Tspectrum::Tcoc &ssig)
Definition: cross.cc:229
Tts::Tdttimeseries Tdttimeseries
Definition: cross.cc:71
double Tvalue
Definition: fidasexx.cc:136
Tspectrum Mspectrum
resulting Fourier coefficients
Definition: cross.cc:135
unsigned int Minsize
size of original input series
Definition: cross.cc:139
bool Mdebug
debug flag
Definition: cross.cc:143
#define CROSS_VERSION
Definition: cross.cc:40
static const char formatkey[]
Definition: fidasexx.cc:128
bool overwrite
Definition: autocorr.cc:61
ts::TDtimeseries Ttimeseries
full time series with sampling interval
Definition: cross.cc:97
std::string outputformat
Definition: cross.cc:75
FourierProcessor(const Tconsttimeseries &s, const bool &debug=false)
create object by passing a time series
Definition: cross.cc:104
ts::TDsfftimeseries Tts
Definition: autocorr.cc:58
FourierProcessor(const bool &debug=false)
create object
Definition: cross.cc:101
Tspectrum::Tcoc operator()(const unsigned int &n)
return Fourier coefficients for padded time series with n samples
Definition: cross.cc:165
bool debug
Definition: autocorr.cc:61
Tfft::Tseries Tseries
type of time series data
Definition: cross.cc:93
double Mdt
sampling interval
Definition: cross.cc:141
bool verbose
Definition: autocorr.cc:61
FourierProcessor(const Tconsttimeseries &s, const unsigned int &n)
Definition: cross.cc:111
Tseries Mseries
workspace for input series must have at least desired size
Definition: cross.cc:131
int main(int iargc, char *argv[])
Definition: cross.cc:284
const char *const tracekey
key to select traces
Definition: deconv.cc:68
void padseries(const unsigned int &n)
pad input series and calculate Fourier coefficients
Definition: cross.cc:203
Tfft MFFT
FFT processor.
Definition: cross.cc:129
aff::Series< double > Tseries
Definition: cross.cc:69
ts::sff::SFFTimeSeries< Tseries > Tts
Definition: cross.cc:70
bool Mspecavail
indicate available Fourier coefficients
Definition: cross.cc:137
FourierProcessor::Tspectrum speccorr(const FourierProcessor::Tspectrum::Tcoc &sref, const FourierProcessor::Tspectrum::Tcoc &ssig)
Definition: cross.cc:254