MsPASS C++ API  2.4.4.dev114+gf4c3cfaca
Defines the C++ API for MsPASS
Loading...
Searching...
No Matches
Public Member Functions | List of all members
mspass::algorithms::Butterworth Class Reference

MsPASS implementation of Butterworth filter as processing object. More...

#include <Butterworth.h>

Public Member Functions

 Butterworth ()
 Default constructor.
 
 Butterworth (const bool zerophase, const bool enable_lo, const bool enable_hi, const double fstoplo, const double astoplo, const double fpasslo, const double apasslo, const double fpasshi, const double apasshi, const double fstophi, const double astophi, const double sample_interval)
 Fully parameterized constructor with args similar to subfilt.
 
 Butterworth (const mspass::utility::Metadata &md)
 
 Butterworth (const bool zerophase, const bool enable_lo, const bool enable_hi, const int npolelo, const double f3dblo, const int npolehi, const double f3dbhi, const double sample_interval)
 Construct by defining corner frequencies and number of npoles.
 
 Butterworth (const Butterworth &parent)
 
Butterworth & operator= (const Butterworth &parent)
 
mspass::seismic::CoreTimeSeries impulse_response (const int n)
 Return the impulse response.
 
void apply (mspass::seismic::CoreTimeSeries &d)
 pply the filter to a CoreTimeSeries object.
 
void apply (mspass::seismic::TimeSeries &d)
 Apply the filter to a CoreTimeSeries object.
 
void apply (std::vector< double > &d)
 Filter a raw vector of data.
 
void apply (mspass::seismic::CoreSeismogram &d)
 Apply the filter to a CoreSeismogram object.
 
void apply (mspass::seismic::Seismogram &d)
 Apply the filter to a CoreTimeSeries object.
 
mspass::algorithms::deconvolution::ComplexArray transfer_function (const int n)
 Return the response of the filter in the frequency domain.
 
void change_dt (const double dtnew)
 set the sample interval assumed for input data.
 
double low_corner () const
 
double high_corner () const
 
int npoles_low () const
 
int npoles_high () const
 
double current_dt () const
 
std::string filter_type () const
 
bool is_zerophase () const
 

Detailed Description

MsPASS implementation of Butterworth filter as processing object.

MsPASS has an existing filter routine that can implement buterworth filters via obspy. This class was created to allow a clean interface to Butterworth filtering from C++ code that needs such an operator. The original use was an experimental deconvolution code, but there will likely be others because simple, efficient filters are a common internal need for potential applications.

This C++ class can be viewed as a wrapper for Seismic Unix functions that implement Butterworth filters. The parent functions were found in the cwp lib and were called bfdesign, bfhighpass, and bflowpass. Those three functions are the central tools used to implement this class. All the rest is really just a wrapper to provide an object oriented api to the su functions.

This class implements a processing object concept. That is, it is intended to be constructed and then used for processing multiple data objects with fixed parameters. For Butterwoth filtering the parameters are relatively simple (mainly two corner frequencies and number of poles defining the filter rolloff). A complexity, however, is that the class was designed to allow automatic handling of multiple sample rate data. That is handled internally by caching the sample interval of the data and automatically adjusting the coefficients when the sample interval changes. Note that feature only works for MsPASS data objects CoreTimeSeries and Seismogram where the sample interval is embedded in the object. The raw interface with a simple vector cannot know that. The method to change the expected sample interval has some sanity checks to reduce, but not eliminate the possibility of mistakes that will create unstable filters.

Constructor & Destructor Documentation

◆ Butterworth() [1/5]

mspass::algorithms::Butterworth::Butterworth ( )

Default constructor.

The default constructor does not define a null. The default generates an antialiasing filter identical to the default in the antialias function in seismic unix. That is it produces a low pass filter with a band edge (pass parameter) at 60% of Nyquist and a stop edge at Nyquist. It then calls the su bfdesign function to compute the number of poles and the 3db frequency of the corner to define this filter. These can be retrieved with getters (see below)

19 {
20 /* This is a translation of a minimum phase antialias filter used in
21 the antialias function in seismic unix. We define it as a default
22 because it does almost nothing - almost because it depends upon
23 form of antialias applied to get to current state. */
24 double fnyq, fpass, apass, fstop, astop;
25 fnyq = 0.5;
26 fpass = 0.6 * fnyq;
27 apass = 0.99;
28 fstop = fnyq;
29 astop = 0.01;
30 this->bfdesign(fpass, apass, fstop, astop, &(this->npoles_hi),
31 &(this->f3db_hi));
32 dt = 1.0;
33 use_lo = false;
34 use_hi = true;
35 f3db_lo = 0.0;
36 npoles_lo = 0;
37 zerophase = false;
38};

◆ Butterworth() [2/5]

mspass::algorithms::Butterworth::Butterworth ( const bool  zerophase,
const bool  enable_lo,
const bool  enable_hi,
const double  fstoplo,
const double  astoplo,
const double  fpasslo,
const double  apasslo,
const double  fpasshi,
const double  apasshi,
const double  fstophi,
const double  astophi,
const double  sample_interval 
)

Fully parameterized constructor with args similar to subfilt.

A butterworth filter can be described two ways: (1) corner frequency and number of poles and (2) by band stop and band frequencies. This constructor is used to define the filter by stop and pass band parameters. Frequencies must satisfy fstoplo<fpasslo and fpasshi<fstophi as the four frequencis define a bandd pass between the fpasslo and fpasshi. The stop frequencies define where the response should near zero. Thus for band pass filters the apasslo and apasshi should be 1 and the stop Amplitudes a small number like 0.01. For a band reject filter set stop amplitudes to 1 and pass amplitudes to small numbers like 0.01. (For a reject filter the pass frequencies act like stop frequencies for a bandbpass filer - this is mostly like the subfilt seismic unix program). The booleans control which terms are enabld. When enable_lo is true the lo components are used an when enable_hi is true the high componens are used.

There is a confusing nomenclature related to "high" and "low". In this implmentation I always take low to mean the low side of the passband and high to be the high side of the passband as described above for the 4 frequency point defiitions. The issue is "lowcut" versus "lowpass". Seismic Unix really mixes this up as their implmenetation (which I used here) refernces bflowpass and bfhighpass but subfilt uses the inverse lowcut and higcut terminology. A geeky implementation detail is I actually changed the names of the functions to eliminate the confusion in the implementation. That matters only if you want to compare what we did here to the original seismic unix code.

Note the iir filter coefficiets are always derived from the poles and Frequencies so this constructor is just an alternate way to define the filter without the abstraction of number of poles.

Parameters
zerophasewhen true use a zerophase filter. When false defines a one pass minimum phase filter.
enable_lois a boolean that when true enables the low band parameters for the filter (i.e. the highpass=low-cut components)
enable_hiis a boolean taht when true enables the parameters defining the upper frequency band edge (i.e. lowpass=high-cut parameters)
fstoplo- stop band frequency for lower band edge
astoplo- amplitude at stop frequency (small number for band pass, 1 for band reject)
fpasslo- pass band frequency for lower band edge
apasslo- amplitude at fpasslo frequency (1 for bandpass, small number for band reject)
fstophi- stop band frequency for upper band edge
astophi- amplitude at stop frequency (small number for band pass, 1 for band reject)
fpasshi- pass band frequency for upper band edge
apasshi- amplitude at fpasshi frequency (1 for bandpass, small number for band reject)
sample_intervalis the expected data sample interval
44 {
45 dt = sample_interval;
46 zerophase = zp;
47 use_lo = lcon;
48 use_hi = hcon;
49 this->bfdesign(fpasslo * dt, apasslo, fstoplo * dt, astoplo,
50 &(this->npoles_lo), &(this->f3db_lo));
51 this->bfdesign(fpasshi * dt, apasshi, fstophi * dt, astophi,
52 &(this->npoles_hi), &(this->f3db_hi));
53};

◆ Butterworth() [3/5]

mspass::algorithms::Butterworth::Butterworth ( const mspass::utility::Metadata &  md)

Construct using tagged valus created from a Metadata container.

This behaves exactly like the fully parameterized contructor except it gets the parameters from metadata. Metadata keys in initial implementation are identical to the argument names defined above. The best guidance for using this constuctor is to look a the comments in the default parameter file.

Construct using tagged valus created from a Metadata container

71 {
72 string base_error("Butterworth pf constructor: ");
73 try {
74 dt = md.get<double>("sample_interval");
75 /* We define these here even if they aren't all used for all options.
76 Better for tiny memory cost than declaration in each block */
77 double fpass, apass, fstop, astop;
78 zerophase = md.get_bool("zerophase");
79 /* These options simplify setup but complicate this constructor. */
80 string ftype, fdmeth;
81 ftype = md.get_string("filter_type");
82 fdmeth = md.get_string("filter_definition_method");
83 if (ftype == "bandpass") {
84 use_lo = true;
85 use_hi = true;
86 if (fdmeth == "corner_pole") {
87 /* Note we allow flow>figh to create strongly peaked filters although
88 we don't scale these any any rational way */
89 npoles_lo = md.get<int>("npoles_low");
90 npoles_hi = md.get<int>("npoles_high");
91 f3db_lo = md.get<double>("corner_low");
92 f3db_hi = md.get<double>("corner_high");
93 /* Stored as nondimensional internally*/
94 f3db_lo *= dt;
95 f3db_hi *= dt;
96 } else {
97 /* note the set routines will test validity of input and throw
98 an error if the points do not define the right sense of pass versus
99 cut*/
100 fpass = md.get<double>("fpass_low");
101 apass = md.get<double>("apass_low");
102 fstop = md.get<double>("fstop_low");
103 astop = md.get<double>("astop_low");
104 this->set_lo(fstop, fpass, astop, apass);
105 fpass = md.get<double>("fpass_high");
106 apass = md.get<double>("apass_high");
107 fstop = md.get<double>("fstop_high");
108 astop = md.get<double>("astop_high");
109 this->set_hi(fstop, fpass, astop, apass);
110 }
111 } else if (ftype == "lowpass") {
112 /* Note the confusing naming hre - lo means lo corner not low pass*/
113 use_lo = false;
114 use_hi = true;
115 /* Explicity initialization useful here */
116 npoles_lo = 0;
117 f3db_lo = 0.0;
118 if (fdmeth == "corner_pole") {
119 npoles_hi = md.get<int>("npoles_high");
120 f3db_hi = md.get<double>("corner_high");
121 f3db_hi *= dt;
122 } else {
123 fpass = md.get<double>("fpass_high");
124 apass = md.get<double>("apass_high");
125 fstop = md.get<double>("fstop_high");
126 astop = md.get<double>("astop_high");
127 /* note this handles inconsistencies and can throw an error */
128 this->set_hi(fstop, fpass, astop, apass);
129 }
130 } else if (ftype == "highpass") {
131 use_lo = true;
132 use_hi = false;
133 /* Explicity initialization useful here */
134 npoles_hi = 0;
135 f3db_hi = 0.0;
136 if (fdmeth == "corner_pole") {
137 npoles_lo = md.get<int>("npoles_low");
138 f3db_lo = md.get<double>("corner_low");
139 f3db_lo *= dt;
140 } else {
141 fpass = md.get<double>("fpass_low");
142 apass = md.get<double>("apass_low");
143 fstop = md.get<double>("fstop_low");
144 astop = md.get<double>("astop_low");
145 /* note this handles inconsistencies and can throw an error */
146 this->set_lo(fstop, fpass, astop, apass);
147 }
148 } else if (ftype == "bandreject") {
149 use_lo = true;
150 use_hi = true;
151 if (fdmeth == "corner_pole") {
152 /* Note we allow flow>figh to create strongly peaked filters although
153 we don't scale these any any rational way */
154 npoles_lo = md.get<int>("npoles_low");
155 npoles_hi = md.get<int>("npoles_high");
156 f3db_lo = md.get<double>("corner_low");
157 f3db_hi = md.get<double>("corner_high");
158 /* Enforce this constraint or we don't have a band reject filtr */
159 if (f3db_lo < f3db_hi) {
160 throw MsPASSError(base_error +
161 "Illegal corner frequencies for band reject "
162 "filter definition" +
163 "For a band reject low corner must be larger "
164 "than high corner (pass becomes cut to reject)",
165 ErrorSeverity::Invalid);
166 }
167 f3db_lo *= dt;
168 f3db_hi *= dt;
169 } else {
170 /* We should test these values for defining band reject but bypass
171 these safeties for now as I don't expect this feature to get much
172 use. */
173 fpass = md.get<double>("fpass_low");
174 apass = md.get<double>("apass_low");
175 fstop = md.get<double>("fstop_low");
176 astop = md.get<double>("astop_low");
177 this->bfdesign(fpass * dt, apass, fstop * dt, astop, &(this->npoles_lo),
178 &(this->f3db_lo));
179 fpass = md.get<double>("fpass_high");
180 apass = md.get<double>("apass_high");
181 fstop = md.get<double>("fstop_high");
182 astop = md.get<double>("astop_high");
183 this->bfdesign(fpass * dt, apass, fstop * dt, astop, &(this->npoles_hi),
184 &(this->f3db_hi));
185 }
186 } else {
187 throw MsPASSError(base_error + "Unsupported filtr_type=" + ftype,
188 ErrorSeverity::Invalid);
189 }
190 } catch (...) {
191 throw;
192 };
193}
bool get_bool(const std::string key) const override
Definition Metadata.cc:392
std::string get_string(const std::string key) const override
Definition Metadata.h:189
T get(const std::string key) const
Definition Metadata.h:477

References mspass::utility::Metadata::get(), mspass::utility::Metadata::get_bool(), and mspass::utility::Metadata::get_string().

◆ Butterworth() [4/5]

mspass::algorithms::Butterworth::Butterworth ( const bool  zerophase,
const bool  enable_lo,
const bool  enable_hi,
const int  npolelo,
const double  f3dblo,
const int  npolehi,
const double  f3dbhi,
const double  sample_interval 
)

Construct by defining corner frequencies and number of npoles.

Butterworth filters can also be defind by a corner frequency and number of poles. In fact, only the nondimensional form of these parameters are stored as private attributes to define the filter.

Parameters
zerophasewhen true use a zerophase filter. When false defines a one pass minimum phase filter.
enable_lois a boolean that when true enables the low band parameters for the filter (i.e. the highpass=low-cut components)
enable_hiis a boolean taht when true enables the parameters defining the upper frequency band edge (i.e. lowpass=high-cut parameters)
npolelois the number of poles for the low frequency corner (highpass)
f3dblois the corner frequency for the low frequency corner (highpass)
npolehiis the number of poles for the high frequency corner (lowpass)
f3dbhiis the corner frequency for the high frequency corner (lowpass)
sample_intervalis the expected data sample interval
57 {
58 this->dt = sample_interval;
59 this->zerophase = zero;
60 this->use_lo = locut;
61 this->use_hi = hicut;
62 this->f3db_hi = f3dbhi;
63 this->f3db_lo = f3dblo;
64 this->npoles_lo = npolelo;
65 this->npoles_hi = npolehi;
66 /* Convert the frequencies to nondimensional form */
67 this->f3db_lo *= dt;
68 this->f3db_hi *= dt;
69}

◆ Butterworth() [5/5]

mspass::algorithms::Butterworth::Butterworth ( const Butterworth &  parent)

Standard copy conststructor.

194 {
195 use_lo = parent.use_lo;
196 use_hi = parent.use_hi;
197 zerophase = parent.zerophase;
198 f3db_lo = parent.f3db_lo;
199 f3db_hi = parent.f3db_hi;
200 npoles_lo = parent.npoles_lo;
201 npoles_hi = parent.npoles_hi;
202 dt = parent.dt;
203}

Member Function Documentation

◆ apply() [1/5]

void mspass::algorithms::Butterworth::apply ( mspass::seismic::CoreSeismogram &  d)

Apply the filter to a CoreSeismogram object.

This method alters the data vector inside d in place and changes no other parts of the data. Automatic switching of data sample rate is used on the operator. That is, if the sample rate of the data is different than the operator sample rate the internal operator coefficients will be adjusted to the new sample rate. The operator sample rate will also be changed to the sample rate of d whenever the sample rate changes from the previous call.

This method has a safety to prevent irrational sample rate changes. The IRR filter used to compute a Butterworth filter becomes unstable if the low pass filter component (high corner) approach Nyquist or worse exceed Nyquist. This method will throw a MsPASSError exception if the sample rate of d is too low for the filter high corner. (current 90% of Nyquist). When this error is throw the data will be unaltered and the internal sample rate will be left in the previous state.

Parameters
dinput data to be filtered - altered in place.
Exceptions
throwsa MsPASSError if the hi corner is inconsistent with the sample rate of d
320 {
321 /* we could just handle a MsPASSError to take care of exceptions
322 thrown by apply if the sample rate is illegal, but this is more adaptable. */
323 try {
324 if (d.npts() == 0)
325 return;
326 double d_dt = d.dt();
327 if ((this->dt != d_dt) && use_hi &&
328 (this->f3db_hi * d_dt / this->dt > FHighFloor)) {
329 stringstream ss;
330 ss << "Butterworth::apply: automatic dt change error" << endl
331 << "Current operator dt=" << this->dt << " data dt=" << d_dt << endl
332 << "Change would produce a corner too close to Nyquist"
333 << " and create an unstable filter" << endl
334 << "Use a different filter operator for data with this sample rate"
335 << endl;
336 throw MsPASSError(ss.str(), ErrorSeverity::Invalid);
337 }
338 if (this->dt != d_dt)
339 this->change_dt(d_dt);
340 /* We copy each component to this buffer, filter, and then copy
341 back. Not as efficient as if we used a strike parameter in the filter
342 functions, but I did not want to rewrite those functions. */
343 vector<double> comp;
344 int npts = d.npts();
345 comp.reserve(npts);
346 /* This initializes the buffer to allow us a simpler loop from 0 to 2
347 using the blas function dcopy to handle the skip for a fortran style
348 array used for storing the 3c data in u*/
349 for (auto i = 0; i < npts; ++i)
350 comp.push_back(0.0);
351 for (auto k = 0; k < 3; ++k) {
352 dcopy(npts, d.u.get_address(k, 0), 3, &(comp[0]), 1);
353 this->apply(comp);
354 dcopy(npts, &(comp[0]), 1, d.u.get_address(k, 0), 3);
355 }
356 } catch (...) {
357 throw;
358 };
359}
void change_dt(const double dtnew)
set the sample interval assumed for input data.
Definition Butterworth.h:293
void apply(mspass::seismic::CoreTimeSeries &d)
pply the filter to a CoreTimeSeries object.
Definition Butterworth.cc:232
size_t npts() const
Definition BasicTimeSeries.h:173
double dt() const
Definition BasicTimeSeries.h:153
mspass::utility::dmatrix u
Definition CoreSeismogram.h:52
double * get_address(size_t r, size_t c) const
Get a pointer to the location of a matrix component.
Definition dmatrix.cc:72

References apply(), change_dt(), mspass::seismic::BasicTimeSeries::dt(), mspass::utility::dmatrix::get_address(), mspass::seismic::BasicTimeSeries::npts(), and mspass::seismic::CoreSeismogram::u.

◆ apply() [2/5]

void mspass::algorithms::Butterworth::apply ( mspass::seismic::CoreTimeSeries &  d)

pply the filter to a CoreTimeSeries object.

This method alters the data vector inside d in place and changes no other parts of the data. Automatic switching of data sample rate is used on the operator. That is, if the sample rate of the data is different than the operator sample rate the internal operator coefficients will be adjusted to the new sample rate. The operator sample rate will also be changed to the sample rate of d whenever the sample rate changes from the previous call.

This method has a safety to prevent irrational sample rate changes. The IRR filter used to compute a Butterworth filter becomes unstable if the low pass filter component (high corner) approach Nyquist or worse exceed Nyquist. This method will throw a MsPASSError exception if the sample rate of d is too low for the filter high corner. (current 90% of Nyquist). When this error is throw the data will be unaltered and the internal sample rate will be left in the previous state.

Parameters
dinput data to be filtered - altered in place.
Exceptions
throwsa MsPASSError if the hi corner is inconsistent with the sample rate of d
232 {
233 if (d.npts() == 0)
234 return;
235 double d_dt = d.dt();
236 if (this->dt != d_dt) {
237 /* Here we throw an exception if a requested sample rate is
238 illegal */
239 double fhtest = this->f3db_hi * d_dt / this->dt;
240 if (use_hi && (fhtest > FHighFloor)) {
241 stringstream ss;
242 ss << "Butterworth::apply: automatic dt change error" << endl
243 << "Current operator dt=" << this->dt << " data dt=" << d_dt << endl
244 << "Change would produce a corner too close to Nyquist"
245 << " and create an unstable filter" << endl
246 << "Use a different filter operator for data with this sample rate"
247 << endl;
248 throw MsPASSError(ss.str(), ErrorSeverity::Invalid);
249 }
250 this->change_dt(d_dt);
251 }
252 this->apply(d.s);
253}
std::vector< double > s
Definition CoreTimeSeries.h:27

References apply(), change_dt(), mspass::seismic::BasicTimeSeries::dt(), mspass::seismic::BasicTimeSeries::npts(), and mspass::seismic::CoreTimeSeries::s.

◆ apply() [3/5]

void mspass::algorithms::Butterworth::apply ( mspass::seismic::Seismogram &  d)

Apply the filter to a CoreTimeSeries object.

This method alters the data vector inside d in place and changes no other parts of the data. Automatic switching of data sample rate is used on the operator. That is, if the sample rate of the data is different than the operator sample rate the internal operator coefficients will be adjusted to the new sample rate. The operator sample rate will also be changed to the sample rate of d whenever the sample rate changes from the previous call.

This method has a safety to prevent irrational sample rate changes. The IRR filter used to compute a Butterworth filter becomes unstable if the low pass filter component (high corner) approach Nyquist or worse exceed Nyquist. This method will automatically disable the high corner (lowpass) component of the filter if the corner approaches or exceed Nyquist. When that happens the internal sample rate is restored to the previous value and a complaint message is posted to elog of d.

Parameters
dinput data to be filtered - altered in place.
Exceptions
none,butcallers should consider checking for errors posted to elog
363 {
364 if (d.npts() == 0)
365 return;
366 double d_dt = d.dt();
367 if (this->dt != d_dt) {
368 /* Here we throw an exception if a requested sample rate is
369 illegal */
370 double fhtest = this->f3db_hi * d_dt / this->dt;
371 if (use_hi && (fhtest > FHighFloor)) {
372 Butterworth adjusted(*this);
373 adjusted.use_hi = false;
374 adjusted.change_dt(d_dt);
375 adjusted.apply(d);
376 stringstream ss;
377 ss << "Auto adjust for sample rate change error" << endl
378 << "Upper corner of filter=" << this->high_corner()
379 << " is near or above Nyquist frequency for requested sample "
380 << "interval=" << d_dt << endl
381 << "Disabling upper corner (lowpass) and applying filter anyway"
382 << endl;
383 d.elog.log_error(string("Butterworth::apply"), ss.str(),
384 ErrorSeverity::Complaint);
385 return;
386 } else {
387 this->change_dt(d_dt);
388 }
389 }
390 vector<double> comp;
391 int npts = d.npts();
392 comp.reserve(npts);
393 /* This initializes the buffer to allow us a simpler loop from 0 to 2
394 using the blas function dcopy to handle the skip for a fortran style
395 array used for storing the 3c data in u*/
396 for (auto i = 0; i < npts; ++i)
397 comp.push_back(0.0);
398 for (auto k = 0; k < 3; ++k) {
399 dcopy(npts, d.u.get_address(k, 0), 3, &(comp[0]), 1);
400 this->apply(comp);
401 dcopy(npts, &(comp[0]), 1, d.u.get_address(k, 0), 3);
402 }
403}
Butterworth()
Default constructor.
Definition Butterworth.cc:19
double high_corner() const
Definition Butterworth.h:301
int log_error(const mspass::utility::MsPASSError &merr)
Definition ErrorLogger.cc:72
ErrorLogger elog
Definition ProcessingHistory.h:246

References apply(), change_dt(), mspass::seismic::BasicTimeSeries::dt(), mspass::utility::ProcessingHistory::elog, mspass::utility::dmatrix::get_address(), high_corner(), mspass::utility::ErrorLogger::log_error(), mspass::seismic::BasicTimeSeries::npts(), and mspass::seismic::CoreSeismogram::u.

◆ apply() [4/5]

void mspass::algorithms::Butterworth::apply ( mspass::seismic::TimeSeries &  d)

Apply the filter to a CoreTimeSeries object.

This method alters the data vector inside d in place and changes no other parts of the data. Automatic switching of data sample rate is used on the operator. That is, if the sample rate of the data is different than the operator sample rate the internal operator coefficients will be adjusted to the new sample rate. The operator sample rate will also be changed to the sample rate of d whenever the sample rate changes from the previous call.

This method has a safety to prevent irrational sample rate changes. The IRR filter used to compute a Butterworth filter becomes unstable if the low pass filter component (high corner) approach Nyquist or worse exceed Nyquist. This method will automatically disable the high corner (lowpass) component of the filter if the corner approaches or exceed Nyquist. When that happens the internal sample rate is restored to the previous value and a complaint message is posted to elog of d.

Parameters
dinput data to be filtered - altered in place.
Exceptions
none,butcallers should consider checking for errors posted to elog
256 {
257 if (d.npts() == 0)
258 return;
259 double d_dt = d.dt();
260 if (this->dt != d_dt) {
261 /* Here we throw an exception if a requested sample rate is
262 illegal */
263 double fhtest = this->f3db_hi * d_dt / this->dt;
264 if (use_hi && (fhtest > FHighFloor)) {
265 Butterworth adjusted(*this);
266 adjusted.use_hi = false;
267 adjusted.change_dt(d_dt);
268 adjusted.apply(d.s);
269 stringstream ss;
270 ss << "Auto adjust for sample rate change error" << endl
271 << "Upper corner of filter=" << this->high_corner()
272 << " is near or above Nyquist frequency for requested sample "
273 << "interval=" << d_dt << endl
274 << "Disabling upper corner (lowpass) and applying filter anyway"
275 << endl;
276 d.elog.log_error(string("Butterworth::apply"), ss.str(),
277 ErrorSeverity::Complaint);
278 return;
279 } else {
280 this->change_dt(d_dt);
281 }
282 }
283 this->apply(d.s);
284}

References apply(), change_dt(), mspass::seismic::BasicTimeSeries::dt(), mspass::utility::ProcessingHistory::elog, high_corner(), mspass::utility::ErrorLogger::log_error(), mspass::seismic::BasicTimeSeries::npts(), and mspass::seismic::CoreTimeSeries::s.

◆ apply() [5/5]

void mspass::algorithms::Butterworth::apply ( std::vector< double > &  d)

Filter a raw vector of data.

Use this method to apply the filter to a raw vector of data. The C++ interface uses an std::vector container, but the python api in MsPASS allows this to be a double numpy array or any iterable version of a vector container (meaning storage as a contiguous block of memory). If this method is used it is assumed the sample interval defined for the operator is the same as the for the input data.

Parameters
dis the data to be filtered (note the data are altered in place)
299 {
300 if (d.empty())
301 return;
302 if (use_lo) {
303 this->bflowcut(npoles_lo, f3db_lo, d.size(), &(d[0]), &(d[0]));
304 if (zerophase) {
305 reverse_vector(d.size(), &(d[0]));
306 this->bflowcut(npoles_lo, f3db_lo, d.size(), &(d[0]), &(d[0]));
307 reverse_vector(d.size(), &(d[0]));
308 }
309 }
310 if (use_hi) {
311 this->bfhighcut(npoles_hi, f3db_hi, d.size(), &(d[0]), &(d[0]));
312 if (zerophase) {
313 reverse_vector(d.size(), &(d[0]));
314 this->bfhighcut(npoles_hi, f3db_hi, d.size(), &(d[0]), &(d[0]));
315 reverse_vector(d.size(), &(d[0]));
316 }
317 }
318}

◆ change_dt()

void mspass::algorithms::Butterworth::change_dt ( const double  dtnew)
inline

set the sample interval assumed for input data.

This function can be used when running with raw data vectors if the sample interval of the data series is different from that called on construction or set previously. This is a nontrivial change because the filter coefficients depend upon sample interval. In particular, for this implementation npoles and the 3db frequency points stored internally are altered when this function is called. If the frequency intervals change the expectation is the user will create a new instance of this object.

Warning: this routine does not implement the safeties built into TimeSeries and Seismogram apply methods. It will silently change the upper corner to an unstable position if called inappropriately.

Parameters
dtnewis the new sample interval to set for the operator.
293 {
294 this->f3db_lo *= (dtnew / (this->dt));
295 this->f3db_hi *= (dtnew / (this->dt));
296 this->dt = dtnew;
297 };

◆ current_dt()

double mspass::algorithms::Butterworth::current_dt ( ) const
inline

Return the current operator sample interval.

309{ return dt; };

◆ filter_type()

std::string mspass::algorithms::Butterworth::filter_type ( ) const
inline

Return a string defining the type of operator this filter defines. Currently can be one of the following: bandpass, lowpass, or highpass. It is possible to construct a band reject filter with the right constructor, but the implementation of this method will not detect that condition. A band reject filter will be incorrectly tagged bandpass. The algorithm just looks to see which of the band edges are defined (the hi and lo concepts described above) and guesses the filter type. If both are off it returns "Undefined".

319 {
320 if (use_lo) {
321 if (use_hi)
322 return std::string("bandpass");
323 else
324 return std::string("highpass");
325 } else {
326 if (use_hi)
327 return std::string("lowpass");
328 else
329 return std::string("Undefined");
330 }
331 };

◆ high_corner()

double mspass::algorithms::Butterworth::high_corner ( ) const
inline

Return the high frequency 3db corner (in Hz).

301{ return f3db_hi / dt; };

◆ impulse_response()

CoreTimeSeries mspass::algorithms::Butterworth::impulse_response ( const int  n)

Return the impulse response.

The response of a linear filter like the butterworth filter can always be described by either the time domain impulse response or its fourier transform commonly called the tranfer function. This function returns the impulse response centered in a time window with a specified number of samples using the current sample interval cached in the object. Note the return has dt and the impulse is at the center of the data window (n/2) with t0 set so the functions zero is correct if using the implict time scale (time method) of a time series object.

Parameters
nis the number of samples to generate to characterize the impulse response. The function is always returned centered on the vector of length n and t0 of the TimeSeries is set to make that impulse point be time 0.
217 {
218 CoreTimeSeries result(n);
219 /* We use a feature that the above constructor initiallizes the buffer
220 to zeros so just a spike at n/2. */
221 result.s[n / 2] = 1.0;
222 result.set_t0(((double)(-n / 2)) * (this->dt));
223 result.set_dt(this->dt);
224 result.set_tref(TimeReferenceType::Relative);
225 result.set_live();
226 this->apply(result.s);
227 result.s = normalize<double>(result.s);
228 return result;
229}

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

◆ is_zerophase()

bool mspass::algorithms::Butterworth::is_zerophase ( ) const
inline

Return true if the filter is defined as a zero phase filter. Returns false if it is minimum phase.

334{ return zerophase; };

◆ low_corner()

double mspass::algorithms::Butterworth::low_corner ( ) const
inline

Return the low frequency 3db corner (in Hz).

299{ return f3db_lo / dt; };

◆ npoles_high()

int mspass::algorithms::Butterworth::npoles_high ( ) const
inline

Return the number of poles defining the lowpass (highcut) element of the filter.

307{ return npoles_hi; };

◆ npoles_low()

int mspass::algorithms::Butterworth::npoles_low ( ) const
inline

Return the number of poles defining the highpass (lowcut) element of the filter.

304{ return npoles_lo; };

◆ operator=()

Butterworth & mspass::algorithms::Butterworth::operator= ( const Butterworth &  parent)

Standard assignment operator.

204 {
205 if (this != &parent) {
206 use_lo = parent.use_lo;
207 use_hi = parent.use_hi;
208 zerophase = parent.zerophase;
209 f3db_lo = parent.f3db_lo;
210 f3db_hi = parent.f3db_hi;
211 npoles_lo = parent.npoles_lo;
212 npoles_hi = parent.npoles_hi;
213 dt = parent.dt;
214 }
215 return *this;
216}

◆ transfer_function()

ComplexArray mspass::algorithms::Butterworth::transfer_function ( const int  n)

Return the response of the filter in the frequency domain.

The impulse response of any linear system can always be characterized by either the time domain response to spike signal or the alternative frequency domain version of the same function commonly called the transfer function. This method returns the transfer funtion as a mspass::algorithms::deconvolution::ComplexArray container. Use methods in that object to get amplitude and phase response functions.

Parameters
nis the number of points that should be used to characterize the transfer function. Note because we are dealing with strictly real valued signals the array returned will be folded at the Nyquist frequency in the standard way of all FFT implementations (current implementation uses the fft in the gnu scientific library that definitely does that).
404 {
405 CoreTimeSeries imp = this->impulse_response(nfft);
406 /* the impulse response function uses a time shift and sets t0 to the
407 required position. A disconnect with any fft is that will introduce an
408 undesirable phase shift for many algorithms. We remove it here using our
409 circular shift function */
410 int ishift = imp.sample_number(0.0);
411 imp.s = circular_shift(imp.s, ishift);
412 gsl_fft_complex_wavetable *wavetable = gsl_fft_complex_wavetable_alloc(nfft);
413 gsl_fft_complex_workspace *workspace = gsl_fft_complex_workspace_alloc(nfft);
414 ComplexArray work(nfft, imp.s);
415 gsl_fft_complex_forward(work.ptr(), 1, nfft, wavetable, workspace);
416 gsl_fft_complex_wavetable_free(wavetable);
417 gsl_fft_complex_workspace_free(workspace);
418 return work;
419}
mspass::seismic::CoreTimeSeries impulse_response(const int n)
Return the impulse response.
Definition Butterworth.cc:217

References impulse_response(), mspass::algorithms::deconvolution::ComplexArray::ptr(), mspass::seismic::CoreTimeSeries::s, and mspass::seismic::BasicTimeSeries::sample_number().


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