MsPASS C++ API  2.4.1.dev4+g92330b7a
Defines the C++ API for MsPASS
Loading...
Searching...
No Matches
Public Member Functions | List of all members
mspass::algorithms::deconvolution::ShapingWavelet Class Reference

Frequency domain shaping wavelet. More...

#include <ShapingWavelet.h>

Public Member Functions

 ShapingWavelet (const mspass::utility::Metadata &md, int npts=0)
 Construct using a limited set of analytic forms for the wavelet.
 
 ShapingWavelet (mspass::seismic::CoreTimeSeries d, int nfft=0)
 Use a wavelet defined by a TimeSeries object.
 
 ShapingWavelet (const double fpeak, const double dtin, const int n)
 
 ShapingWavelet (const int npolelo, const double f3dblo, const int npolehi, const double f3dbhi, const double dtin, const int n)
 
 ShapingWavelet (const ShapingWavelet &parent)
 
ShapingWaveletoperator= (const ShapingWavelet &parent)
 
ComplexArraywavelet ()
 
mspass::seismic::CoreTimeSeries impulse_response ()
 
double freq_bin_size ()
 
double sample_interval ()
 
std::string type ()
 
int size () const
 

Detailed Description

Frequency domain shaping wavelet.

Frequency domain based deconvolution methods all use a shaping wavelet for output to avoid ringing. Frequency domain deconvolution methods in this Library contain an instance of this object. In all cases it is hidden behind the interface. A complexity, however, is that all frequency domain methods will call the Metadata driven constructor.

This version currently allows three shaping wavelets: Gaussin, Ricker, and Slepian0. The first two are standard. The last is novel and theoretically can produce an actual output with the smalle posible sidebands

Constructor & Destructor Documentation

◆ ShapingWavelet() [1/6]

mspass::algorithms::deconvolution::ShapingWavelet::ShapingWavelet ( )
inline
23 {
24 dt = -1;
25 df = -1;
26 };

◆ ShapingWavelet() [2/6]

mspass::algorithms::deconvolution::ShapingWavelet::ShapingWavelet ( const mspass::utility::Metadata md,
int  npts = 0 
)

Construct using a limited set of analytic forms for the wavelet.

This constructor is used to create a ricker or gaussian shaping wavelet with parameters defined by parameters passed through the Metadata object.

Parameters
md- Metadata object with parameters specifying the wavelet.
nptslength of signal to be generated which is the same as the fft size for real valued signals. If set 0 (the default) the constructor will attempt to get npts from md using the keyword "operator_nfft".
21 {
22 const string base_error("ShapingWavelet object constructor: ");
23 try {
24 /* We use this to allow a nfft to be set in md. A bit error prone
25 * we add a special error handler. */
26 if (nfftin > 0)
27 this->nfft = nfftin;
28 else {
29 try {
30 nfft = GetIntRequired(md, "operator_nfft");
31 } catch (MetadataGetError &mderr) {
32 throw MsPASSError(base_error +
33 "Called constructor with nfft=0 but parameter "
34 "with key=operator_nfft is not in parameter file",
35 ErrorSeverity::Invalid);
36 }
37 }
38 /* these are workspaces used by gnu's fft algorithm. Other parts
39 * of this library cache them for efficiency, but this one we
40 * compute ever time the object is created and then discard it. */
41 gsl_fft_complex_wavetable *wavetable;
42 gsl_fft_complex_workspace *workspace;
43 wavetable = gsl_fft_complex_wavetable_alloc(nfft);
44 workspace = gsl_fft_complex_workspace_alloc(nfft);
45 string wavelettype = md.get_string("shaping_wavelet_type");
46 wavelet_name = wavelettype;
47 dt = GetDoubleRequired(md, "shaping_wavelet_dt");
48 double *r;
49 if (wavelettype == "gaussian") {
50 float fpeak = GetDoubleRequired(md, "shaping_wavelet_frequency");
51 // construct wavelet and fft
52 r = gaussian(fpeak, (float)dt, nfft);
53 w = ComplexArray(nfft, r);
54 gsl_fft_complex_forward(w.ptr(), 1, nfft, wavetable, workspace);
55 delete[] r;
56 }
57 /* Note for CNR3CDecon the initial values on construction for
58 ricker or butterworth are irrelevant and wasted effort. We keep
59 them in this class because these forms are needed by the family of
60 scalar deconvolution algorithms */
61 else if (wavelettype == "ricker") {
62 float fpeak =
63 static_cast<float>(GetDoubleRequired(md, "shaping_wavelet_frequency"));
64 // construct wavelet and fft
65 r = rickerwavelet(fpeak, (float)dt, nfft);
66 // DEBUG
67 // cerr << "Ricker shaping wavelet"<<endl;
68 // for(int k=0;k<nfft;++k) cerr << r[k]<<endl;
69 w = ComplexArray(nfft, r);
70 gsl_fft_complex_forward(w.ptr(), 1, nfft, wavetable, workspace);
71 delete[] r;
72 } else if (wavelettype == "butterworth") {
73 double f3db_lo, f3db_hi;
74 f3db_lo = GetDoubleRequired(md, "f3db_lo");
75 f3db_hi = GetDoubleRequired(md, "f3db_hi");
76 int npoles_lo, npoles_hi;
77 npoles_lo = GetIntRequired(md, "npoles_lo");
78 npoles_hi = GetIntRequired(md, "npoles_hi");
79 Butterworth bwf(true, true, true, npoles_lo, f3db_lo, npoles_hi, f3db_hi,
80 this->dt);
81 w = bwf.transfer_function(this->nfft);
82 }
83 /* This option requires a package to compute zero phase wavelets of
84 some specified type and bandwidth. Previous used antelope filters which
85 colides with open source goal of mspass. Another implementation of
86 TimeInvariantFilter and this could be restored.
87 */
88 /*
89 else if(wavelettype=="filter_response")
90 {
91 string filterparam=md.get_string("filter");
92 TimeInvariantFilter filt(filterparam);
93 TimeSeries dtmp(nfft);
94 dtmp.ns=nfft;
95 dtmp.dt=dt;
96 dtmp.live=true;
97 dtmp.t0=(-dt*static_cast<double>(nfft/2));
98 dtmp.tref=relative;
99 int i;
100 i=dtmp.sample_number(0.0);
101 dtmp.s[i]=1.0; // Delta function at 0
102 filt.zerophase(dtmp);
103 // We need to shift the filter response now back to
104 // zero to avoid time shifts in output
105 dtmp.s=circular_shift(dtmp.s,nfft/2);
106 w=ComplexArray(dtmp.s.size(), &(dtmp.s[0]));
107 gsl_fft_complex_forward(w.ptr(), 1, nfft, wavetable, workspace);
108 }
109 */
110 else if ((wavelettype == "slepian") || (wavelettype == "Slepian")) {
111 double tbp = GetDoubleRequired(md, "time_bandwidth_product");
112 double target_pulse_width =
113 GetDoubleRequired(md, "target_pulse_width");
114 /* Sanity check on pulse width */
115 if (target_pulse_width > (nfft / 4) || (target_pulse_width < tbp)) {
116 stringstream ss;
117 ss << "ShapingWavelet Metadata constructor: bad input parameters for "
118 "Slepian shaping wavelet"
119 << endl
120 << "Specified target_pulse_width of " << target_pulse_width
121 << " samples" << endl
122 << "FFT buffer size=" << nfft
123 << " and time bandwidth product=" << tbp << endl
124 << "Pulse width should be small fraction of buffer size but ge than "
125 "tbp"
126 << endl;
127 throw MsPASSError(ss.str(), ErrorSeverity::Invalid);
128 }
129 double c = tbp / target_pulse_width;
130 int nwsize = round(c * (static_cast<double>(nfft)));
131 double *wtmp = slepian0(tbp, nwsize);
132 vector<double> work(nfft, 0.0);
133 dcopy(nwsize, wtmp, 1, &(work[0]), 1);
134 delete[] wtmp;
135 w = ComplexArray(nfft, work);
136 gsl_fft_complex_forward(w.ptr(), 1, nfft, wavetable, workspace);
137 } else if (wavelettype == "none") {
138 /* The shaping wavelet is stored in the frequency domain. The identity
139 * filter is therefore one at every frequency bin, not a time-domain
140 * delta stored without an FFT. */
141 w = ComplexArray(nfft, 1.0);
142 } else {
143 throw MsPASSError(
144 base_error + "illegal value for shaping_wavelet_type=" + wavelettype,
145 ErrorSeverity::Invalid);
146 }
147 gsl_fft_complex_wavetable_free(wavetable);
148 gsl_fft_complex_workspace_free(workspace);
149 df = 1.0 / (dt * ((double)nfft));
150 } catch (MsPASSError &err) {
151 cerr << base_error
152 << "Something threw an unhandled MsPASSError with this message:"
153 << endl;
154 err.log_error();
155 cerr << "This is a nonfatal bug that needs to be fixed" << endl;
156 throw err;
157 } catch (...) {
158 throw;
159 }
160}
double * ptr()
Definition ComplexArray.cc:111
std::string get_string(const std::string key) const override
Definition Metadata.h:189

References mspass::utility::Metadata::get_string(), mspass::utility::MsPASSError::log_error(), mspass::algorithms::deconvolution::ComplexArray::ptr(), and mspass::algorithms::Butterworth::transfer_function().

◆ ShapingWavelet() [3/6]

mspass::algorithms::deconvolution::ShapingWavelet::ShapingWavelet ( mspass::seismic::CoreTimeSeries  d,
int  nfft = 0 
)

Use a wavelet defined by a TimeSeries object.

This constructor uses the data stored in a TimeSeries object to define the shaping wavelet. Note to assure output is properly time aligned this signal is forced to be symmetric around relative time 0. That is necessary because of the way this, like every fft we are aware of, handles phase. Hence, the user should assure zero time is an appropriate zero reference (e.g. a zero phase filter should the dominant peak at 0 time.) If the input data size is smaller than the buffer size specified the buffer is zero padded.

Parameters
dTimeSeries specifying wavelet. Note dt will be extracted and stored in this object.
nfft- buffer size = fft length for frequency domain representation of the wavelet. If ns of d is less than nfft or the time range defined by d is does not exceed -(nfft/2)*dt to (nfft2)*dt the result will be sero padded before computing the fft. if nfft is 0 the d.ns will set the fft length.
197 {
198 const string base_error("ShapingWavelet TimeSeries constructor: ");
199 wavelet_name = string("data");
200 /* Silently handle this default condition that allows calling the
201 * constructor without the nfft argument */
202 if (nfft <= 0)
203 nfft = d.npts();
204 dt = d.dt();
205 df = 1.0 / (dt * ((double)nfft));
206 /* This is prone to an off by one error */
207 double t0;
208 if (nfft % 2)
209 t0 = -(double)(nfft / 2) + 1;
210 else
211 t0 = -(double)(nfft / 2);
212 t0 *= dt;
213 /* A basic sanity check on d */
214 if (d.time_is_UTC())
215 throw MsPASSError(
216 base_error +
217 "Shaping wavelet must be defined in relative time centered on 0",
218 ErrorSeverity::Invalid);
219 if ((d.endtime() < t0) || (d.t0() > (-t0)))
220 throw MsPASSError(base_error + "Input wavelet time span is illegal\n" +
221 "Wavelet must be centered on 0 reference time",
222 ErrorSeverity::Invalid);
223 /* Create a work vector an initialize it to zeros to make insertion
224 * algorithm easier */
225 vector<double> dwork;
226 dwork.reserve(nfft);
227 int i;
228 for (i = 0; i < nfft; ++i)
229 dwork.push_back(0.0);
230 /* We loop over
231 * we skip through d vector until we insert */
232 for (i = 0; i < d.npts(); ++i) {
233 double t;
234 t = t0 + dt * ((double)i);
235 int iw = d.sample_number(t);
236 if (t > d.endtime())
237 break;
238 if ((iw >= 0) && (iw < nfft))
239 dwork[i] = d.s[iw];
240 }
241 gsl_fft_complex_wavetable *wavetable;
242 gsl_fft_complex_workspace *workspace;
243 wavetable = gsl_fft_complex_wavetable_alloc(nfft);
244 workspace = gsl_fft_complex_workspace_alloc(nfft);
245 w = ComplexArray(nfft, &(dwork[0]));
246 gsl_fft_complex_forward(w.ptr(), 1, nfft, wavetable, workspace);
247 gsl_fft_complex_wavetable_free(wavetable);
248 gsl_fft_complex_workspace_free(workspace);
249}
size_t npts() const
Definition BasicTimeSeries.h:173
double t0() const
Definition BasicTimeSeries.h:176
bool time_is_UTC() const
Definition BasicTimeSeries.h:155
int sample_number(double t) const
Definition BasicTimeSeries.h:72
double dt() const
Definition BasicTimeSeries.h:153
double endtime() const noexcept
Definition BasicTimeSeries.h:77
std::vector< double > s
Definition CoreTimeSeries.h:27

References mspass::seismic::BasicTimeSeries::dt(), mspass::seismic::BasicTimeSeries::endtime(), mspass::seismic::BasicTimeSeries::npts(), mspass::algorithms::deconvolution::ComplexArray::ptr(), mspass::seismic::CoreTimeSeries::s, mspass::seismic::BasicTimeSeries::sample_number(), mspass::seismic::BasicTimeSeries::t0(), and mspass::seismic::BasicTimeSeries::time_is_UTC().

◆ ShapingWavelet() [4/6]

mspass::algorithms::deconvolution::ShapingWavelet::ShapingWavelet ( const double  fpeak,
const double  dtin,
const int  n 
)

Construct a Ricker wavelet shaping filter with peak frequency fpeak.

166 : wavelet_name("ricker") {
167 nfft = n;
168 dt = dtin;
169 df = 1.0 / (dt * static_cast<double>(n));
170 double *r;
171 r = rickerwavelet((float)fpeak, (float)dt, nfft);
172 w = ComplexArray(nfft, r);
173 gsl_fft_complex_wavetable *wavetable;
174 gsl_fft_complex_workspace *workspace;
175 wavetable = gsl_fft_complex_wavetable_alloc(nfft);
176 workspace = gsl_fft_complex_workspace_alloc(nfft);
177 gsl_fft_complex_forward(w.ptr(), 1, nfft, wavetable, workspace);
178 gsl_fft_complex_wavetable_free(wavetable);
179 gsl_fft_complex_workspace_free(workspace);
180 delete[] r;
181}

References mspass::algorithms::deconvolution::ComplexArray::ptr().

◆ ShapingWavelet() [5/6]

mspass::algorithms::deconvolution::ShapingWavelet::ShapingWavelet ( const int  npolelo,
const double  f3dblo,
const int  npolehi,
const double  f3dbhi,
const double  dtin,
const int  n 
)

Construct a zero phase Butterworth filter wavelet.

This is the recommended constructor to use for adjustable bandwidth shaping. It is the default for CNR3CDecon.

Parameters
npolelois the number of poles for the low corner
f3dblois the 3db point for the low corner of the passband
npolehiis the number of poles for the upper corner filter
f3dbhiis the 3db point for the high corner of the passband.
dtinsample interval of the wavelet.
nnumber of samples in the wavelet.
185 : wavelet_name("butterworth") {
186 nfft = n;
187 dt = dtin;
188 df = 1.0 / (dt * static_cast<double>(n));
189 Butterworth bwf(true, true, true, npolelo, f3dblo, npolehi, f3dbhi, dtin);
190 w = bwf.transfer_function(nfft);
191}

References mspass::algorithms::Butterworth::transfer_function().

◆ ShapingWavelet() [6/6]

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

Copy constructor.

192 : w(parent.w) {
193 dt = parent.dt;
194 df = parent.df;
195 wavelet_name = parent.wavelet_name;
196}

Member Function Documentation

◆ freq_bin_size()

double mspass::algorithms::deconvolution::ShapingWavelet::freq_bin_size ( )
inline

Return the frequency bin size.

84{ return df; };

◆ impulse_response()

CoreTimeSeries mspass::algorithms::deconvolution::ShapingWavelet::impulse_response ( )

Return the impulse response of the shaping filter. Expect the result to be symmetric about 0 (i.e. output spans nfft/2 to nfft/2.

259 {
260 try {
261 int nfft = w.size();
262 gsl_fft_complex_wavetable *wavetable;
263 gsl_fft_complex_workspace *workspace;
264 wavetable = gsl_fft_complex_wavetable_alloc(nfft);
265 workspace = gsl_fft_complex_workspace_alloc(nfft);
266 /* We need to copy the current shaping wavelet or the inverse fft
267 * will make it invalid */
268 ComplexArray iwf(w);
269 gsl_fft_complex_inverse(iwf.ptr(), 1, nfft, wavetable, workspace);
270 gsl_fft_complex_wavetable_free(wavetable);
271 gsl_fft_complex_workspace_free(workspace);
272 CoreTimeSeries result(nfft);
273
274 result.set_tref(TimeReferenceType::Relative);
275 result.set_npts(nfft);
276 result.set_dt(dt);
277 result.set_t0(dt * (-(double)nfft / 2));
278 result.set_live();
279 /* Unfold the fft output */
280 int k, shift;
281 shift = nfft / 2;
282 // Need this because constructor fills initially with nfft zeros and
283 // we use this approach to unfold the fft output
284 result.s.clear();
285 for (k = 0; k < nfft; ++k)
286 result.s.push_back(iwf[k].real());
287 result.s = circular_shift(result.s, shift);
288 result.s = normalize<double>(result.s);
289 return result;
290 } catch (...) {
291 throw;
292 };
293}
int size() const
Definition ComplexArray.cc:275

References mspass::algorithms::deconvolution::ComplexArray::ptr(), mspass::seismic::CoreTimeSeries::s, mspass::seismic::CoreTimeSeries::set_dt(), mspass::seismic::BasicTimeSeries::set_live(), mspass::seismic::CoreTimeSeries::set_npts(), mspass::seismic::CoreTimeSeries::set_t0(), mspass::seismic::BasicTimeSeries::set_tref(), and mspass::algorithms::deconvolution::ComplexArray::size().

◆ operator=()

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

Assignment operator.

250 {
251 if (this != &parent) {
252 w = parent.w;
253 dt = parent.dt;
254 df = parent.df;
255 wavelet_name = parent.wavelet_name;
256 }
257 return *this;
258}

◆ sample_interval()

double mspass::algorithms::deconvolution::ShapingWavelet::sample_interval ( )
inline

Return the sample interval.

86{ return dt; };

◆ size()

int mspass::algorithms::deconvolution::ShapingWavelet::size ( ) const
inline

Return the number of complex frequency samples.

90{ return w.size(); };

References mspass::algorithms::deconvolution::ComplexArray::size().

◆ type()

std::string mspass::algorithms::deconvolution::ShapingWavelet::type ( )
inline

Return the shaping wavelet type name.

88{ return wavelet_name; };

◆ wavelet()

ComplexArray * mspass::algorithms::deconvolution::ShapingWavelet::wavelet ( )
inline

Return a pointer to the shaping wavelet this object defines in the frequency domain.

79{ return &w; };

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