72 #define FOUTRA_VERSION \ 73 "FOUTRA V1.10 Fourier transforms" 76 #include <tfxx/commandline.h> 77 #include <aff/series.h> 78 #include <aff/iterator.h> 80 #include <aff/seriesoperators.h> 81 #include <aff/functions/avg.h> 82 #include <aff/functions/rms.h> 83 #include <aff/functions/sqrsum.h> 84 #include <aff/subarray.h> 85 #include <tsxx/tsxx.h> 86 #include <tsxx/tapers.h> 87 #include <tsxx/filter.h> 88 #include <tsxx/wid2timeseries.h> 89 #include <tsioxx/tsioxx.h> 91 #include <tfxx/error.h> 92 #include <tfxx/rangestring.h> 93 #include <tfxx/xcmdline.h> 94 #include <tfxx/misc.h> 95 #include <tfxx/handle.h> 96 #include <tfxx/seitosh.h> 97 #include <datrwxx/readany.h> 98 #include <datrwxx/writeany.h> 99 #include <fourier/fftwaff.h> 131 typedef ts::sff::File<Tseries>
Tfile;
136 typedef fourier::fft::DRFFTWAFF
Tfft;
140 int main(
int iargc,
char* argv[])
150 using namespace tfxx::cmdline;
151 static Declare options[]=
160 {
"type",arg_yes,
"sff"},
164 {
"amplitude",arg_no,
"-"},
166 {
"power",arg_no,
"-"},
168 {
"boxcar",arg_no,
"-"},
170 {
"avg",arg_opt,
"21"},
172 {
"rbw",arg_opt,
"0.167"},
174 {
"demean",arg_opt,
"0"},
176 {
"detrend",arg_opt,
"0"},
178 {
"scalerbw",arg_opt,
"0.167"},
180 {
"ASCII",arg_opt,
"spectrum"},
182 {
"logascii",arg_opt,
"0.167"},
184 {
"avgascii",arg_no,
"-"},
186 {
"divisor",arg_opt,
"100"},
190 {
"harmonic",arg_no,
"-"},
194 {
"nsegments",arg_yes,
"1"},
196 {
"xhelp",arg_no,
"-"},
198 {
"Type",arg_yes,
"sff"},
200 {
"derivative",arg_opt,
"1"},
212 cerr << version_text << endl;
214 cerr << tfxx::seitosh::repository_reference << endl;
219 Commandline cmdline(iargc, argv, options);
222 if (cmdline.optset(0) || cmdline.optset(21))
224 cerr << version_text << endl;
228 datrw::supported_data_types(cerr);
229 if (cmdline.optset(21)) { datrw::online_help(cerr); }
230 cerr << endl << tfxx::seitosh::repository_reference << endl;
238 opt.
debug=cmdline.optset(4);
246 opt.
decades=cmdline.double_arg(9);
247 opt.
demean=cmdline.optset(10);
248 opt.
ndemean=cmdline.int_arg(10);
249 opt.
detrend=cmdline.optset(11);
259 opt.
divisor=cmdline.int_arg(16);
269 TFXX_assert((opt.
divisor > 0),
"illegal value for argument divisor");
270 TFXX_assert((opt.
nsegments > 0),
"illegal value for argument nsegments");
271 TFXX_assert((opt.
padfactor > 0),
"illegal value for argument pad");
277 TFXX_assert(cmdline.extra(),
"missing output file");
278 std::string outfile=cmdline.next();
279 TFXX_assert(cmdline.extra(),
"missing input file");
280 tfxx::cmdline::Tparsed arguments=parse_cmdline(cmdline,
cmdlinekeys);
281 if ((arguments.size()>1) && opt.
verbose)
283 cout <<
"NOTICE: file specific information (SRCE line and file FREE)" <<
285 <<
" will be taken from first file only!" << endl;
294 sff::FREE processfree;
297 std::ostringstream freeline;
298 freeline <<
"Input series is subdivided into " 299 << opt.
nsegments <<
" segments with 50% overlap";
300 processfree.append(freeline.str());
301 processfree.append(
"The analysis is done individually for all segments");
302 processfree.append(
"The result is the average over all segments");
306 std::ostringstream freeline;
307 freeline <<
"The average over ";
316 freeline <<
" samples is removed from all samples";
317 processfree.append(freeline.str());
321 std::ostringstream freeline;
322 freeline <<
"The trend over ";
331 freeline <<
" samples is removed from all samples";
332 processfree.append(freeline.str());
336 processfree.append(
"A boxcar taper (i.e no taper) is applied to the data");
340 processfree.append(
"A Hanning taper is applied to the data");
344 std::ostringstream freeline;
345 freeline <<
"pad with zeroes increasing the total " 346 <<
"number of samples by a factor of " << opt.
padfactor;
347 processfree.append(freeline.str());
351 processfree.append(
"An appropriately scaled FFT (libdrfftw) is applied");
354 processfree.append(
"Calculate values for derivative with respect to");
355 processfree.append(
" time by multiplication of the Fourier coefficients");
356 std::ostringstream freeline;
357 freeline <<
" with the angular frequency to the power of " 359 processfree.append(freeline.str());
364 processfree.append(
"The result are coefficients of the amplitude spectrum");
365 processfree.append(
"Units are: input units / Hz");
369 processfree.append(
"The result are coefficients of the power spectrum");
372 std::ostringstream freeline;
373 freeline <<
"The result is the average power in " 375 processfree.append(freeline.str());
376 processfree.append(
"Units are: input units squared");
380 processfree.append(
"Units are: input units squared / Hz");
384 processfree.append(
"The spectrum is smoothed with a boxcar over");
387 std::ostringstream freeline;
389 processfree.append(freeline.str());
393 std::ostringstream freeline;
394 freeline << opt.
decades <<
" decades";
395 processfree.append(freeline.str());
400 processfree.append(
"The spectrum is not smoothed");
403 processfree.append(
"The ASCII output is smoothed with a boxcar over");
404 std::ostringstream freeline;
405 freeline << opt.
decades <<
" decades";
406 processfree.append(freeline.str());
412 processfree.append(
"The input is understood to contain harmonic signals.");
413 processfree.append(
"The result are signal amplitudes for harmonic peaks.");
414 processfree.append(
"Units are: input units");
418 processfree.append(
"The output is a tapered version of the time series");
422 processfree.append(
"The sampling interval provided in the WID2 line");
423 processfree.append(
"specifies the sampling interval of the spectrum");
424 processfree.append(
"in Hz. The first coefficient is that at 0 Hz.");
429 cout <<
"processing of each trace will take place as follows:" << endl;
430 for(sff::FREE::Tlines::const_iterator I=processfree.lines.begin();
431 I != processfree.lines.end(); ++I)
432 { cout <<
" " << *I << std::endl; }
439 ts::tapers::Hanning taper;
445 if (opt.
verbose) { cout <<
"open output file " << outfile << endl; }
449 std::ifstream file(outfile.c_str(),std::ios_base::in);
450 TFXX_assert((!file.good()),
"ERROR: output file exists!");
452 std::ofstream ofs(outfile.c_str());
464 tfxx::cmdline::Tparsed::const_iterator infile=arguments.begin();
465 while (infile != arguments.end())
468 if (opt.
verbose) { cout <<
"open input file " << infile->name << endl; }
469 std::ifstream ifs(infile->name.c_str());
476 sff::FREE infilefree;
478 filefree.append(
"block read from first input file:");
479 filefree.append(infilefree);
484 sff::SRCE insrceline;
493 typedef tfxx::RangeList<int> Trangelist;
494 bool doselect=infile->haskey(
tracekey);
495 Trangelist traceranges=
496 tfxx::string::rangelist<Trangelist::Tvalue>(infile->value(
tracekey));
501 if ((!doselect) || traceranges.contains(itrace))
503 TFXX_debug(opt.
debug,
"main",
"process trace #" << itrace );
505 { std::cout <<
" process trace #" << itrace << std::endl; }
510 TFXX_debug(opt.
debug,
"main",
" series and WID2 are read");
516 std::cout <<
" rms-value of input time series: " 517 << aff::func::rms(inputseries) << std::endl;
539 int nsegsamples=inputseries.size();
542 nsegsamples=2*inputseries.size()/(opt.
nsegments+1);
550 std::cout <<
" adjust divisor to " << opt.
divisor << std::endl;
551 std::cout <<
" number of input samples: " << wid2.nsamples
553 std::cout <<
" number of segment samples: " << nsegsamples
556 int rest=nsegsamples % opt.
divisor;
557 nsegsamples=nsegsamples-rest;
560 std::cout <<
" number of processing samples: " << nsegsamples
566 int segstride=inputseries.size()/(opt.
nsegments+1);
570 cout <<
" number of input samples: " 571 << inputseries.size() << endl;
572 cout <<
" number of segments: " 574 cout <<
" number of samples in each segment: " 575 << nsegsamples << endl;
576 cout <<
" stride between segments: " 577 << segstride << endl;
578 cout <<
" overlap of proximate segments: " 579 << 100.*(nsegsamples-segstride)/nsegsamples <<
"%" << endl;
583 double T=wid2.dt*nsegsamples;
597 cout <<
" duration T of each segment: " 599 cout <<
" duration Tw of signal window: " 600 << Tw <<
"s" << endl;
601 cout <<
" frequency sampling interval df: " 602 << df <<
"Hz" << endl;
615 int firstindex=inputseries.first()+isegment*segstride;
616 int lastindex=firstindex+nsegsamples-1;
617 TFXX_debug(opt.
debug,
"main",
" segment index range: " 618 << firstindex <<
"-" << lastindex);
619 TFXX_assert((firstindex >= inputseries.first()) &&
620 (firstindex <= inputseries.last()) &&
621 (lastindex >= inputseries.first()) &&
622 (lastindex <= inputseries.last()),
623 "ERROR: index out of range; program design error");
624 Tseries segseries=aff::subarray(inputseries)(firstindex,lastindex);
626 if (opt.
nsegments>1) { series=segseries.copyout(); }
627 series.shift(-series.first());
631 TFXX_debug(opt.
debug,
"main",
" demean");
632 ts::filter::RemoveAverage demean(opt.
ndemean);
638 TFXX_debug(opt.
debug,
"main",
" detrend");
639 ts::filter::RemoveTrend detrend(opt.
ndetrend);
645 TFXX_debug(opt.
debug,
"main",
" apply taper");
656 Tseries subseries(aff::subarray(newseries)(series.f(),series.l()));
657 subseries.copyin(series);
664 TFXX_debug(opt.
debug,
"main",
"call FFT");
665 Tfft::Tspectrum coeff=fft(series, wid2.dt);
666 TFXX_debug(opt.
debug,
"main",
667 "returned from FFT; create output series");
669 TFXX_debug(opt.
debug,
"main",
"create iterators");
670 aff::Iterator<Tseries> S(series);
671 aff::Browser<Tfft::Tspectrum> C(coeff);
676 for (
int i=coeff.f()+1; i<=coeff.l(); ++i)
678 double frequency=df*(i-coeff.f())*2*M_PI;
680 double factor=std::pow(frequency,thepower);
685 TFXX_debug(opt.
debug,
"main",
"calculate square of modulus and copy");
686 while(S.valid() && C.valid())
688 *S = C->real()*C->real()+C->imag()*C->imag();
696 TFXX_debug(opt.
debug,
"main",
"calculate sqrt and scale");
697 aff::Iterator<Tseries> S(series);
712 { fscaling = 2./Tw; }
714 { fscaling = 4./Tw; }
722 double tapscaling=1.;
739 double scalingfactor=2.*tapscaling/Tw;
744 TFXX_debug(opt.
debug,
"main",
745 "scale to average in relative bandwidth");
751 for (
int k=series.f(); k<=series.l(); ++k)
755 series(k) *= scalingfactor*bwfactor*fm;
760 TFXX_debug(opt.
debug,
"main",
"scale");
761 series *= scalingfactor;
767 TFXX_debug(opt.
debug,
"main",
"average over constant bandwidth");
772 for (
int k=p.f(); k<=p.l(); ++k)
776 k1 = k1 < p.f() ? p.f() : k1;
777 k2 = k2 > p.l() ? p.l() : k2;
779 TFXX_assert(k2>k1,
"negative bandwidth for averaging")
780 Tseries sub=aff::subarray(p)(k1,k2);
781 series(k)=aff::func::avg(sub);
794 TFXX_debug(opt.
debug,
"main",
"average over relative bandwidth");
796 TFXX_debug(opt.
debug,
"main",
" create a copy");
798 TFXX_debug(opt.
debug,
"main",
" copy in data");
800 double bwfactor=std::sqrt(std::pow(10.,opt.
decades));
802 TFXX_debug(opt.
debug,
"main",
" cycle over data");
803 for (
int k=p.f(); k<=p.l(); ++k)
807 double f1=fm/bwfactor;
808 double f2=fm*bwfactor;
812 k1 = k1 < p.f() ? p.f() : k1;
813 k2 = k2 > p.l() ? p.l() : k2;
814 TFXX_assert(k2>k1,
"negative bandwidth for averaging")
815 Tseries sub=aff::subarray(p)(k1,k2);
816 series(k)=aff::func::avg(sub);
824 spectrum=series.copyout();
825 TFXX_debug(opt.
debug,
"main",
"copy result");
830 for (
int i=spectrum.f(),
832 i<=spectrum.l(); ++i, ++j)
834 TFXX_assert(j<=series.l(),
835 "ERROR: program design error");
836 spectrum(i) += series(j);
838 TFXX_debug(opt.
debug,
"main",
"added result");
842 TFXX_debug(opt.
debug,
"main",
843 "finished segment #" << isegment);
859 wid2.nsamples=series.size();
862 TFXX_debug(opt.
debug,
"main",
" series and WID are written");
863 if (is.hasinfo()) { sff::INFO info; is >> info; os << info; }
864 if (is.hasfree() ||
true)
869 tracefree.append(
"data read from file " + infile->name);
870 tracefree.append(processfree);
878 TFXX_debug(opt.
debug,
"main",
"write to ASCII file");
880 std::ostringstream outname;
884 outname << otrace <<
".asc";
885 std::string filename(outname.str());
886 std::ofstream aos(filename.c_str());
892 TFXX_debug(opt.
debug,
"main",
893 "prepare data with logarithmic scale");
899 int kmax=int(std::log10(
double(series.l()))/opt.
asciidecades);
900 TFXX_debug(opt.
debug,
"main",
901 " output index range: " << kmin <<
"-" << kmax);
904 double bwfactor=std::sqrt(std::pow(10.,opt.
decades));
905 for (
int k=f.f(); k<=f.l(); ++k)
909 int l=int(0.5+fm/df);
915 double f1=fm/bwfactor;
916 double f2=fm*bwfactor;
919 l1 = l1 < series.f() ? series.f() : l1;
920 l2 = l2 > series.l() ? series.l() : l2;
929 TFXX_assert(l2>=l1,
"negative bandwidth for averaging");
930 Tseries sub=aff::subarray(series)(l1,l2);
931 p(k)=aff::func::avg(sub);
945 for (
int k=f.f(); k<=f.l(); ++k)
950 for (
int k=f.f(); k<=f.l(); ++k)
953 aos.setf(std::ios_base::scientific,std::ios_base::floatfield);
956 aos.setf(std::ios_base::scientific,std::ios_base::floatfield);
962 TFXX_debug(opt.
debug,
"main",
963 "trace #" << itrace <<
" successfully processed");
967 TFXX_debug(opt.
debug,
"main",
"skip trace #" << itrace );
969 { std::cout <<
" skip trace #" << itrace << std::endl; }
fourier::fft::DRFFTWAFF Tfft
char foutra_options_brief_help[]
int main(int iargc, char *argv[])
char foutra_options_help[]
static const char * cmdlinekeys[]
fourier::fft::DRFFTWAFF Tfft
ts::TDsfftimeseries Ttimeseries
aff::Series< Tvalue > Tseries
const char *const tracekey
key to select traces
aff::Series< double > Tseries
ts::sff::File< Tseries > Tfile