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

References mspass::utility::Metadata::get_double(), mspass::utility::Metadata::get_int(), mspass::utility::Metadata::get_string(), mspass::utility::MsPASSError::log_error(), and mspass::algorithms::Butterworth::transfer_function().

◆ ShapingWavelet() [3/6]

mspass::algorithms::deconvolution::ShapingWavelet::ShapingWavelet ( mspass::seismic::CoreTimeSeries  d,
int  nfft = 0 
)
203 {
204 const string base_error("ShapingWavelet TimeSeries constructor: ");
205 wavelet_name = string("data");
206 /* Silently handle this default condition that allows calling the
207 * constructor without the nfft argument */
208 if (nfft <= 0)
209 nfft = d.npts();
210 dt = d.dt();
211 df = 1.0 / (dt * ((double)nfft));
212 /* This is prone to an off by one error */
213 double t0;
214 if (nfft % 2)
215 t0 = -(double)(nfft / 2) + 1;
216 else
217 t0 = -(double)(nfft / 2);
218 t0 *= dt;
219 /* A basic sanity check on d */
220 if (d.time_is_UTC())
221 throw MsPASSError(
222 base_error +
223 "Shaping wavelet must be defined in relative time centered on 0",
224 ErrorSeverity::Invalid);
225 if ((d.endtime() < t0) || (d.t0() > (-t0)))
226 throw MsPASSError(base_error + "Input wavelet time span is illegal\n" +
227 "Wavelet must be centered on 0 reference time",
228 ErrorSeverity::Invalid);
229 /* Create a work vector an initialize it to zeros to make insertion
230 * algorithm easier */
231 vector<double> dwork;
232 dwork.reserve(nfft);
233 int i;
234 for (i = 0; i < nfft; ++i)
235 dwork.push_back(0.0);
236 /* We loop over
237 * we skip through d vector until we insert */
238 for (i = 0; i < d.npts(); ++i) {
239 double t;
240 t = t0 + dt * ((double)i);
241 int iw = d.sample_number(t);
242 if (t > d.endtime())
243 break;
244 if ((iw >= 0) && (iw < nfft))
245 dwork[i] = d.s[iw];
246 }
247 gsl_fft_complex_wavetable *wavetable;
248 gsl_fft_complex_workspace *workspace;
249 wavetable = gsl_fft_complex_wavetable_alloc(nfft);
250 workspace = gsl_fft_complex_workspace_alloc(nfft);
251 w = ComplexArray(nfft, &(dwork[0]));
252 gsl_fft_complex_forward(w.ptr(), 1, nfft, wavetable, workspace);
253 gsl_fft_complex_wavetable_free(wavetable);
254 gsl_fft_complex_workspace_free(workspace);
255}
size_t npts() const
Definition BasicTimeSeries.h:171
double t0() const
Definition BasicTimeSeries.h:174
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

◆ 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.

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

◆ 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
nplolehiis the number of poles for the upper corner filter
f3dbhiis the 3db point for the high corner of the passband.
191 : wavelet_name("butterworth") {
192 nfft = n;
193 dt = dtin;
194 df = 1.0 / (dt * static_cast<double>(n));
195 Butterworth bwf(true, true, true, npolelo, f3dblo, npolehi, f3dbhi, dtin);
196 w = bwf.transfer_function(nfft);
197}

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

◆ ShapingWavelet() [6/6]

mspass::algorithms::deconvolution::ShapingWavelet::ShapingWavelet ( const ShapingWavelet parent)
198 : w(parent.w) {
199 dt = parent.dt;
200 df = parent.df;
201 wavelet_name = parent.wavelet_name;
202}

Member Function Documentation

◆ freq_bin_size()

double mspass::algorithms::deconvolution::ShapingWavelet::freq_bin_size ( )
inline
79{ 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.

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

References mspass::seismic::CoreTimeSeries::s, mspass::seismic::CoreTimeSeries::set_dt(), mspass::seismic::BasicTimeSeries::set_live(), mspass::seismic::CoreTimeSeries::set_npts(), mspass::seismic::CoreTimeSeries::set_t0(), and mspass::seismic::BasicTimeSeries::set_tref().

◆ operator=()

ShapingWavelet & mspass::algorithms::deconvolution::ShapingWavelet::operator= ( const ShapingWavelet parent)
256 {
257 if (this != &parent) {
258 w = parent.w;
259 dt = parent.dt;
260 df = parent.df;
261 wavelet_name = parent.wavelet_name;
262 }
263 return *this;
264}

◆ sample_interval()

double mspass::algorithms::deconvolution::ShapingWavelet::sample_interval ( )
inline
80{ return dt; };

◆ size()

int mspass::algorithms::deconvolution::ShapingWavelet::size ( ) const
inline
82{ return w.size(); };

◆ type()

std::string mspass::algorithms::deconvolution::ShapingWavelet::type ( )
inline
81{ 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.

75{ return &w; };

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