MsPASS C++ API  2.4.3.dev1+g61b06b96
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)
 
void swap (ShapingWavelet &other) noexcept
 
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
24: nfft(0), dt(-1), df(-1) {};

◆ 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".
24 {
25 const string base_error("ShapingWavelet object constructor: ");
26 try {
27 /* We use this to allow a nfft to be set in md. A bit error prone
28 * we add a special error handler. */
29 if (nfftin > 0)
30 this->nfft = nfftin;
31 else {
32 try {
33 nfft = GetIntRequired(md, "operator_nfft");
34 } catch (MetadataGetError &mderr) {
35 throw MsPASSError(base_error +
36 "Called constructor with nfft=0 but parameter "
37 "with key=operator_nfft is not in parameter file",
38 ErrorSeverity::Invalid);
39 }
40 }
41 if (nfft <= 0)
42 throw MsPASSError(base_error + "FFT length must be positive",
43 ErrorSeverity::Invalid);
44 /* these are workspaces used by gnu's fft algorithm. Other parts
45 * of this library cache them for efficiency, but this one we
46 * compute ever time the object is created and then discard it. */
47 auto resources = detail::AllocateGSLFFTResources(nfft, base_error);
48 string wavelettype = md.get_string("shaping_wavelet_type");
49 wavelet_name = wavelettype;
50 dt = GetDoubleRequired(md, "shaping_wavelet_dt");
51 if (wavelettype == "gaussian") {
52 float fpeak = GetDoubleRequired(md, "shaping_wavelet_frequency");
53 // construct wavelet and fft
54 unique_ptr<double[]> r(gaussian(fpeak, (float)dt, nfft));
55 if (!r)
56 throw bad_alloc();
57 w = ComplexArray(nfft, r.get());
58 gsl_fft_complex_forward(w.ptr(), 1, nfft, resources.wavetable.get(),
59 resources.workspace.get());
60 }
61 /* Note for CNR3CDecon the initial values on construction for
62 ricker or butterworth are irrelevant and wasted effort. We keep
63 them in this class because these forms are needed by the family of
64 scalar deconvolution algorithms */
65 else if (wavelettype == "ricker") {
66 float fpeak =
67 static_cast<float>(GetDoubleRequired(md, "shaping_wavelet_frequency"));
68 // construct wavelet and fft
69 unique_ptr<double[]> r(rickerwavelet(fpeak, (float)dt, nfft));
70 if (!r)
71 throw bad_alloc();
72 // DEBUG
73 // cerr << "Ricker shaping wavelet"<<endl;
74 // for(int k=0;k<nfft;++k) cerr << r[k]<<endl;
75 w = ComplexArray(nfft, r.get());
76 gsl_fft_complex_forward(w.ptr(), 1, nfft, resources.wavetable.get(),
77 resources.workspace.get());
78 } else if (wavelettype == "butterworth") {
79 double f3db_lo, f3db_hi;
80 f3db_lo = GetDoubleRequired(md, "f3db_lo");
81 f3db_hi = GetDoubleRequired(md, "f3db_hi");
82 int npoles_lo, npoles_hi;
83 npoles_lo = GetIntRequired(md, "npoles_lo");
84 npoles_hi = GetIntRequired(md, "npoles_hi");
85 Butterworth bwf(true, true, true, npoles_lo, f3db_lo, npoles_hi, f3db_hi,
86 this->dt);
87 w = bwf.transfer_function(this->nfft);
88 }
89 /* This option requires a package to compute zero phase wavelets of
90 some specified type and bandwidth. Previous used antelope filters which
91 colides with open source goal of mspass. Another implementation of
92 TimeInvariantFilter and this could be restored.
93 */
94 /*
95 else if(wavelettype=="filter_response")
96 {
97 string filterparam=md.get_string("filter");
98 TimeInvariantFilter filt(filterparam);
99 TimeSeries dtmp(nfft);
100 dtmp.ns=nfft;
101 dtmp.dt=dt;
102 dtmp.live=true;
103 dtmp.t0=(-dt*static_cast<double>(nfft/2));
104 dtmp.tref=relative;
105 int i;
106 i=dtmp.sample_number(0.0);
107 dtmp.s[i]=1.0; // Delta function at 0
108 filt.zerophase(dtmp);
109 // We need to shift the filter response now back to
110 // zero to avoid time shifts in output
111 dtmp.s=circular_shift(dtmp.s,nfft/2);
112 w=ComplexArray(dtmp.s.size(), &(dtmp.s[0]));
113 gsl_fft_complex_forward(w.ptr(), 1, nfft, wavetable, workspace);
114 }
115 */
116 else if ((wavelettype == "slepian") || (wavelettype == "Slepian")) {
117 double tbp = GetDoubleRequired(md, "time_bandwidth_product");
118 double target_pulse_width =
119 GetDoubleRequired(md, "target_pulse_width");
120 /* Sanity check on pulse width */
121 if (target_pulse_width > (nfft / 4) || (target_pulse_width < tbp)) {
122 stringstream ss;
123 ss << "ShapingWavelet Metadata constructor: bad input parameters for "
124 "Slepian shaping wavelet"
125 << endl
126 << "Specified target_pulse_width of " << target_pulse_width
127 << " samples" << endl
128 << "FFT buffer size=" << nfft
129 << " and time bandwidth product=" << tbp << endl
130 << "Pulse width should be small fraction of buffer size but ge than "
131 "tbp"
132 << endl;
133 throw MsPASSError(ss.str(), ErrorSeverity::Invalid);
134 }
135 double c = tbp / target_pulse_width;
136 int nwsize = round(c * (static_cast<double>(nfft)));
137 unique_ptr<double[]> wtmp(slepian0(tbp, nwsize));
138 if (!wtmp)
139 throw bad_alloc();
140 vector<double> work(nfft, 0.0);
141 dcopy(nwsize, wtmp.get(), 1, &(work[0]), 1);
142 w = ComplexArray(nfft, work);
143 gsl_fft_complex_forward(w.ptr(), 1, nfft, resources.wavetable.get(),
144 resources.workspace.get());
145 } else if (wavelettype == "none") {
146 /* The shaping wavelet is stored in the frequency domain. The identity
147 * filter is therefore one at every frequency bin, not a time-domain
148 * delta stored without an FFT. */
149 w = ComplexArray(nfft, 1.0);
150 } else {
151 throw MsPASSError(
152 base_error + "illegal value for shaping_wavelet_type=" + wavelettype,
153 ErrorSeverity::Invalid);
154 }
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}
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.
205 {
206 const string base_error("ShapingWavelet TimeSeries constructor: ");
207 wavelet_name = string("data");
208 /* Silently handle this default condition that allows calling the
209 * constructor without the nfft argument */
210 if (nfft <= 0)
211 nfft = d.npts();
212 if (nfft <= 0)
213 throw MsPASSError(base_error + "FFT length must be positive",
214 ErrorSeverity::Invalid);
215 this->nfft = nfft;
216 dt = d.dt();
217 df = 1.0 / (dt * ((double)nfft));
218 /* This is prone to an off by one error */
219 double t0;
220 if (nfft % 2)
221 t0 = -(double)(nfft / 2) + 1;
222 else
223 t0 = -(double)(nfft / 2);
224 t0 *= dt;
225 /* A basic sanity check on d */
226 if (d.time_is_UTC())
227 throw MsPASSError(
228 base_error +
229 "Shaping wavelet must be defined in relative time centered on 0",
230 ErrorSeverity::Invalid);
231 if ((d.endtime() < t0) || (d.t0() > (-t0)))
232 throw MsPASSError(base_error + "Input wavelet time span is illegal\n" +
233 "Wavelet must be centered on 0 reference time",
234 ErrorSeverity::Invalid);
235 /* Create a work vector an initialize it to zeros to make insertion
236 * algorithm easier */
237 vector<double> dwork;
238 dwork.reserve(nfft);
239 int i;
240 for (i = 0; i < nfft; ++i)
241 dwork.push_back(0.0);
242 /* We loop over
243 * we skip through d vector until we insert */
244 for (i = 0; i < d.npts(); ++i) {
245 double t;
246 t = t0 + dt * ((double)i);
247 int iw = d.sample_number(t);
248 if (t > d.endtime())
249 break;
250 if ((iw >= 0) && (iw < nfft))
251 dwork[i] = d.s[iw];
252 }
253 auto resources = detail::AllocateGSLFFTResources(nfft, base_error);
254 w = ComplexArray(nfft, &(dwork[0]));
255 gsl_fft_complex_forward(w.ptr(), 1, nfft, resources.wavetable.get(),
256 resources.workspace.get());
257}
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.

172 : wavelet_name("ricker") {
173 const string caller("ShapingWavelet Ricker constructor");
174 if (n <= 0)
175 throw MsPASSError(caller + ": FFT length must be positive",
176 ErrorSeverity::Invalid);
177 nfft = n;
178 dt = dtin;
179 df = 1.0 / (dt * static_cast<double>(n));
180 unique_ptr<double[]> r(rickerwavelet((float)fpeak, (float)dt, nfft));
181 if (!r)
182 throw bad_alloc();
183 w = ComplexArray(nfft, r.get());
184 auto resources = detail::AllocateGSLFFTResources(nfft, caller);
185 gsl_fft_complex_forward(w.ptr(), 1, nfft, resources.wavetable.get(),
186 resources.workspace.get());
187}

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.
191 : wavelet_name("butterworth") {
192 if (n <= 0)
193 throw MsPASSError(
194 "ShapingWavelet Butterworth constructor: FFT length must be positive",
195 ErrorSeverity::Invalid);
196 nfft = n;
197 dt = dtin;
198 df = 1.0 / (dt * static_cast<double>(n));
199 Butterworth bwf(true, true, true, npolelo, f3dblo, npolehi, f3dbhi, dtin);
200 w = bwf.transfer_function(nfft);
201}

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

◆ ShapingWavelet() [6/6]

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

Copy constructor.

203 : nfft(parent.nfft), w(parent.w), dt(parent.dt), df(parent.df),
204 wavelet_name(parent.wavelet_name) {}

Member Function Documentation

◆ freq_bin_size()

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

Return the frequency bin size.

90{ 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.

268 {
269 try {
270 int nfft = w.size();
271 const string caller("ShapingWavelet::impulse_response");
272 if (nfft <= 0)
273 throw MsPASSError(caller + ": shaping wavelet is empty",
274 ErrorSeverity::Invalid);
275 auto resources = detail::AllocateGSLFFTResources(nfft, caller);
276 /* We need to copy the current shaping wavelet or the inverse fft
277 * will make it invalid */
278 ComplexArray iwf(w);
279 gsl_fft_complex_inverse(iwf.ptr(), 1, nfft, resources.wavetable.get(),
280 resources.workspace.get());
281 CoreTimeSeries result(nfft);
282
283 result.set_tref(TimeReferenceType::Relative);
284 result.set_npts(nfft);
285 result.set_dt(dt);
286 result.set_t0(dt * (-(double)nfft / 2));
287 result.set_live();
288 /* Unfold the fft output */
289 int k, shift;
290 shift = nfft / 2;
291 // Need this because constructor fills initially with nfft zeros and
292 // we use this approach to unfold the fft output
293 result.s.clear();
294 for (k = 0; k < nfft; ++k)
295 result.s.push_back(iwf[k].real());
296 result.s = circular_shift(result.s, shift);
297 result.s = normalize<double>(result.s);
298 return result;
299 } catch (...) {
300 throw;
301 };
302}
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.

258 {
259 if (this != &parent) {
260 nfft = parent.nfft;
261 w = parent.w;
262 dt = parent.dt;
263 df = parent.df;
264 wavelet_name = parent.wavelet_name;
265 }
266 return *this;
267}

◆ sample_interval()

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

Return the sample interval.

92{ return dt; };

◆ size()

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

Return the number of complex frequency samples.

96{ return w.size(); };

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

◆ swap()

void mspass::algorithms::deconvolution::ShapingWavelet::swap ( ShapingWavelet other)
inlinenoexcept

Exchange complete shaping state without allocation.

76 {
77 std::swap(nfft, other.nfft);
78 w.swap(other.w);
79 std::swap(dt, other.dt);
80 std::swap(df, other.df);
81 wavelet_name.swap(other.wavelet_name);
82 }
void swap(ComplexArray &other) noexcept
Definition ComplexArray.h:88

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

◆ type()

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

Return the shaping wavelet type name.

94{ 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.

85{ return &w; };

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