version  0.0.1
Defines the C++ API for MsPASS
Loading...
Searching...
No Matches
Public Member Functions | List of all members
mspass::algorithms::deconvolution::MTPowerSpectrumEngine Class Reference

Multittaper power spectral estimator. More...

#include <MTPowerSpectrumEngine.h>

Public Member Functions

 MTPowerSpectrumEngine ()
 
 MTPowerSpectrumEngine (const int winsize, const double tbp, const int ntapers, const int nfftin=-1, const double dtin=1.0)
 construct with full definition.
 
 MTPowerSpectrumEngine (const MTPowerSpectrumEngine &parent)
 
 ~MTPowerSpectrumEngine ()
 
MTPowerSpectrumEngineoperator= (const MTPowerSpectrumEngine &parent)
 
mspass::seismic::PowerSpectrum apply (const mspass::seismic::TimeSeries &d)
 
std::vector< double > apply (const std::vector< double > &d)
 Low level processing of vector of data.
 
double df () const
 
std::vector< double > frequencies ()
 
int taper_length () const
 
double time_bandwidth_product () const
 
int number_tapers () const
 
int fftsize () const
 
double dt () const
 
double set_df (double dt)
 Putter equivalent of df.
 
int nf ()
 

Detailed Description

Multittaper power spectral estimator.

The multitaper method uses averages of spectra windowed by Slepian functions. This class can be used to compute power spectra. For efficiency the design has constructors that build the Slepian functions and cache them in a private area. We use this model because computing spectra on a large data set in parallel will usually be done with a fixed time window. The expected use is that normally the engine is created once and passed as an argument to functions using it in a map operator.

This class uses the apply model for processing. It accepts raw vector or TimeSeries data. The former assumes the sample interval is 1 while the second scales the spectrum to have units of 1/Hz.

Constructor & Destructor Documentation

◆ MTPowerSpectrumEngine() [1/3]

mspass::algorithms::deconvolution::MTPowerSpectrumEngine::MTPowerSpectrumEngine ( )

Default constructor. Do not use as it produces a null object that is no functional.

17 {
18 taperlen = 0;
19 ntapers = 0;
20 nfft = 0;
21 tbp = 0.0;
22 deltaf = 1.0;
23 operator_dt = 1.0;
24 wavetable = NULL;
25 workspace = NULL;
26}

◆ MTPowerSpectrumEngine() [2/3]

mspass::algorithms::deconvolution::MTPowerSpectrumEngine::MTPowerSpectrumEngine ( const int  winsize,
const double  tbp,
const int  ntapers,
const int  nfftin = -1,
const double  dtin = 1.0 
)

construct with full definition.

This should be the normal constructor used to create this object. It creates and caches the Slepian tapers that are used on calls the apply method.

Parameters
winsizeis the length of time windows in samples the operator will be designed to compute.
tbpis the time bandwidth product to use for the operator.
ntapersis the number of tapers to actually use for the operator. Note the maximum ntapers is always int(tbp*2). If ntapers is more than 2*tbp a mesage will be posted to cerr and ntapers set to tbp*2.
nfftinis the size of the fft workspace to use for computation. When less than the winsize (the default forces this) set to 2*winsize+1.
dtinsets the operator sample interval stored in the object and used to compute frequency bin size from fft length.
30 {
31 taperlen = winsize;
32 tbp = tbpin;
33 ntapers = ntpin;
34 if (nfftin < winsize) {
35 nfft = nextPowerOf2(winsize);
36 if (nfft == winsize)
37 nfft = 2 * winsize;
38 } else
39 nfft = nfftin;
40 operator_dt = dtin;
41 this->set_df(dtin);
42 int nseq = static_cast<int>(2.0 * tbp);
43 if (ntapers > nseq) {
44 cerr << "MTPowerSpectrumEngine (WARNING): requested number of tapers="
45 << ntpin << endl
46 << "is inconsistent with requested time time bandwidth product ="
47 << tbp << endl
48 << "Automatically reset number tapers to max allowed=" << nseq << endl;
49 ntapers = nseq;
50 }
51 int seql(0);
52 int sequ = ntapers - 1;
53 double *work = new double[ntapers * taperlen];
54 dpss_calc(taperlen, tbp, seql, sequ, work);
55 tapers = dmatrix(ntapers, taperlen);
56 int i, ii, j;
57 for (i = 0, ii = 0; i < ntapers; ++i) {
58 for (j = 0; j < taperlen; ++j) {
59 tapers(i, j) = work[ii];
60 ++ii;
61 }
62 }
63 delete[] work;
64 /* To be consistent with Prieto we use this algorithm to convert to
65 what he calls the "positive standard". That means we assure the
66 center point is positive.
67 */
68 for (i = 0; i < ntapers; ++i) {
69 int lh; // matches Prieto algorithm name - see multitaper module
70 if (taperlen % 2)
71 lh = static_cast<int>((taperlen + 1) / 2);
72 else
73 lh = static_cast<int>(taperlen / 2);
74 if (tapers(i, lh) < 0.0) {
75 for (j = 0; j < taperlen; ++j)
76 tapers(i, j) = -tapers(i, j);
77 }
78 }
79 wavetable = gsl_fft_complex_wavetable_alloc(nfft);
80 workspace = gsl_fft_complex_workspace_alloc(nfft);
81}
double set_df(double dt)
Putter equivalent of df.
Definition MTPowerSpectrumEngine.h:126

References set_df().

◆ MTPowerSpectrumEngine() [3/3]

mspass::algorithms::deconvolution::MTPowerSpectrumEngine::MTPowerSpectrumEngine ( const MTPowerSpectrumEngine parent)

Standard copy constructor

84 : tapers(parent.tapers) {
85 taperlen = parent.taperlen;
86 ntapers = parent.ntapers;
87 nfft = parent.nfft;
88 tbp = parent.tbp;
89 operator_dt = parent.operator_dt;
90 deltaf = parent.deltaf;
91 wavetable = gsl_fft_complex_wavetable_alloc(nfft);
92 workspace = gsl_fft_complex_workspace_alloc(nfft);
93}

◆ ~MTPowerSpectrumEngine()

mspass::algorithms::deconvolution::MTPowerSpectrumEngine::~MTPowerSpectrumEngine ( )

Destructor. Not trivial as it has to delete the fft workspace and cached tapers.

95 {
96 if (wavetable != NULL)
97 gsl_fft_complex_wavetable_free(wavetable);
98 if (workspace != NULL)
99 gsl_fft_complex_workspace_free(workspace);
100}

Member Function Documentation

◆ apply() [1/2]

PowerSpectrum mspass::algorithms::deconvolution::MTPowerSpectrumEngine::apply ( const mspass::seismic::TimeSeries d)

\process a TimeSeries.

This is one of two methods for applying the multiaper algorithm to data. This one uses dt and data length to set the Rayleigh bin size (df). If the input data vector length is not the same as the operator length an elog complaint is posted to parent. Short data are processed but should be considered suspect unless the sizes differ by only a tiny fraction (e.g. and off by one error from rounding). Long data will be truncated on the right (i.e. sample 0 will be the start of the window used). The data return will be scaled to psd in units if 1/Hz.

Parameters
parentis the data to process
Returns
vector containing estimated power spwecrum
116 {
117 try {
118 int k;
119 /* Used to test for operator sample interval against data sample interval.
120 We don't use a epsilon comparison as slippery clock data sometime shave
121 sample rates small percentage difference from nominal.*/
122 const double DT_FRACTION_TOLERANCE(0.001);
123 const string algorithm("MTPowerSpectrumEngine");
124 /* We need to define this here to allow posting problems to elog.*/
125 PowerSpectrum result;
126 int dsize = d.npts();
127 vector<double> work;
128 work.reserve(this->nfft);
129 double dtfrac = fabs(d.dt() - this->operator_dt) / this->operator_dt;
130 if (dtfrac > DT_FRACTION_TOLERANCE) {
131 stringstream ss;
132 ss << "Date sample interval=" << d.dt()
133 << " does not match operator sample interval=" << this->operator_dt
134 << endl
135 << "Cannot proceed. Returning a null result";
136 result.elog.log_error("MTPowerSpectrumEngine::apply", ss.str(),
137 ErrorSeverity::Invalid);
138 result.kill();
139 return result;
140 }
141
142 if (dsize < taperlen) {
143 stringstream ss;
144 ss << "Received data window of length=" << d.npts() << " samples" << endl
145 << "Operator length=" << taperlen << endl
146 << "Results may be unreliable" << endl;
147 result.elog.log_error(algorithm, string(ss.str()),
148 ErrorSeverity::Suspect);
149 for (k = 0; k < taperlen; ++k)
150 work.push_back(0.0);
151 for (k = 0; k < dsize; ++k)
152 work[k] = d.s[k];
153 } else {
154 if (dsize > taperlen) {
155 stringstream ss;
156 ss << "Received data window of length=" << d.npts() << " samples"
157 << endl
158 << "Operator length=" << taperlen << endl
159 << "Results may be unreliable because data will be truncated to "
160 "taper length"
161 << endl;
162 result.elog.log_error(algorithm, ss.str(), ErrorSeverity::Suspect);
163 }
164 for (k = 0; k < taperlen; ++k)
165 work.push_back(d.s[k]);
166 }
167 /* intentionally omit try catch here because the above logic assures Sizes
168 must match here. This overloaded method will throw an exception in that
169 case. Note in this implementation the result returned by apply is scaled to
170 assumed properly scaled to power spectrum and normalized for multitapers.*/
171 vector<double> spec(this->apply(work));
172
173 result = PowerSpectrum(dynamic_cast<const Metadata &>(d), spec, deltaf,
174 string("Multitaper"), 0.0, d.dt(), d.npts());
175 /* We post these to metadata for the generic PowerSpectrum object. */
176 result.put<double>("time_bandwidth_product", tbp);
177 result.put<long>("number_tapers", ntapers);
178 return result;
179 } catch (...) {
180 throw;
181 };
182}
mspass::seismic::PowerSpectrum apply(const mspass::seismic::TimeSeries &d)
Definition MTPowerSpectrumEngine.cc:116
size_t npts() const
Definition BasicTimeSeries.h:171
double dt() const
Definition BasicTimeSeries.h:153
std::vector< double > s
Definition CoreTimeSeries.h:27

References apply(), mspass::seismic::BasicTimeSeries::dt(), mspass::seismic::PowerSpectrum::elog, mspass::seismic::BasicSpectrum::kill(), mspass::utility::ErrorLogger::log_error(), mspass::seismic::BasicTimeSeries::npts(), and mspass::seismic::CoreTimeSeries::s.

◆ apply() [2/2]

std::vector< double > mspass::algorithms::deconvolution::MTPowerSpectrumEngine::apply ( const std::vector< double > &  d)

Low level processing of vector of data.

This is lower level function that processes a raw vector of data. Since it does not know the sample interval it cannot compute the rayleigh bin size so if callers need that feature they must do that (simple) calculation themselves. Unlike the TimeSeries method this one will throw an exception if the input data size does not match the operator size. It returns power spectral density assuming a sample rate of 1. i.e. it scales to correct for the gsl fft scaling by of the forward transform by N.

Parameters
dis the vector of data to process. d.size() must this->taperlen() value.
Returns
vector containing estimated power spectrum (usual convention with 0 containing 0 frequency value)
Exceptions
throwa MsPASSError if the size of d does not match operator length

◆ df()

double mspass::algorithms::deconvolution::MTPowerSpectrumEngine::df ( ) const
inline

Return the frquency bin size defined for this operator.

92{ return deltaf; };

◆ dt()

double mspass::algorithms::deconvolution::MTPowerSpectrumEngine::dt ( ) const
inline

Retrieve the internally cached required data sample interval.

106{ return operator_dt; };

◆ fftsize()

int mspass::algorithms::deconvolution::MTPowerSpectrumEngine::fftsize ( ) const
inline

Return size of fft used by this operator - usually not the same as taper length.

104{ return nfft; };

◆ frequencies()

vector< double > mspass::algorithms::deconvolution::MTPowerSpectrumEngine::frequencies ( )

Return and std::vector of all frequencies for spectral estimates this operator computes.

266 {
267 vector<double> f;
268 /* If taperlen is odd this still works according to gsl documentation.*/
269 for (int i = 0; i < this->nf(); ++i) {
270 /* Here we assume i=0 frequency is 0 */
271 f.push_back(deltaf * ((double)i));
272 }
273 return f;
274}
int nf()
Definition MTPowerSpectrumEngine.h:135

References nf().

◆ nf()

int mspass::algorithms::deconvolution::MTPowerSpectrumEngine::nf ( )
inline

Return tne number of frequency bins in estimates the operator will compute.

135 {
136 /* this simple formula depends upon integer truncation when used with
137 nfft as an odd number. For reference, this is what prieto uses in
138 the python multitaper package:
139 if (nfft%2 == 0):
140 nf = int(nfft/2 + 1)
141 else:
142 nf = int((nfft+1)/2)
143 they will yield the same result but this is simpler and faster
144 */
145 return (this->nfft) / 2 + 1;
146 };

◆ number_tapers()

int mspass::algorithms::deconvolution::MTPowerSpectrumEngine::number_tapers ( ) const
inline

Return number of tapers used by this engine.

101{ return ntapers; };

◆ operator=()

MTPowerSpectrumEngine & mspass::algorithms::deconvolution::MTPowerSpectrumEngine::operator= ( const MTPowerSpectrumEngine parent)

Standard assignment operator.

102 {
103 if (&parent != this) {
104 taperlen = parent.taperlen;
105 ntapers = parent.ntapers;
106 nfft = parent.nfft;
107 tbp = parent.tbp;
108 operator_dt = parent.operator_dt;
109 deltaf = parent.deltaf;
110 tapers = parent.tapers;
111 wavetable = gsl_fft_complex_wavetable_alloc(nfft);
112 workspace = gsl_fft_complex_workspace_alloc(nfft);
113 }
114 return *this;
115}

◆ set_df()

double mspass::algorithms::deconvolution::MTPowerSpectrumEngine::set_df ( double  dt)
inline

Putter equivalent of df.

The computation of the Rayleigh bin size is complicated a bit by the folding properties of fft algorithms that have to handle odd and even length inputs differently. This algorithm uses the internally set nfft value to set the frequency bin size for even or odd nfft and the input sample interval. NOTE POSSIBLE CONFUSION that input is time sample interval NOT the actual frquency bin size. The reason is that the odd/even issue makes df dependent on if the fft size is even or odd. We include this method as a convenience as that is an implementation detail for the fft algorithm.

Note also this method sets not just df but the internally stored sample interval (symbol operator_dt in the source code.)

Parameters
dtis the data sample interval (time domain)
Returns
computed df
126 {
127 this->operator_dt = dt;
128 int this_nf = this->nf();
129 double fny = 1.0 / (2.0 * dt);
130 this->deltaf = fny / static_cast<double>(this_nf - 1);
131 return deltaf;
132 };
double dt() const
Definition MTPowerSpectrumEngine.h:106

References dt(), and nf().

◆ taper_length()

int mspass::algorithms::deconvolution::MTPowerSpectrumEngine::taper_length ( ) const
inline

Retrieve the taper length.

97{ return taperlen; };

◆ time_bandwidth_product()

double mspass::algorithms::deconvolution::MTPowerSpectrumEngine::time_bandwidth_product ( ) const
inline

Retrieve time-bandwidth product.

99{ return tbp; };

The documentation for this class was generated from the following files: