version  0.0.1
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)
 
Butterworthoperator= (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(fpass, fstop, 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(fpass, fstop, apass, astop);
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_hi = md.get<int>("npoles_low");
138 f3db_hi = md.get<double>("corner_low");
139 f3db_hi *= 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.h:219
std::string get_string(const std::string key) const override
Definition Metadata.h:202
T get(const std::string key) const
Definition Metadata.h:445

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
319 {
320 /* we could just handle a MsPASSError to take care of exceptions
321 thrown by apply if the sample rate is illegal, but this is more adaptable. */
322 try {
323 double d_dt = d.dt();
324 if (this->dt != d_dt)
325 this->change_dt(d_dt);
326 /* We copy each component to this buffer, filter, and then copy
327 back. Not as efficient as if we used a strike parameter in the filter
328 functions, but I did not want to rewrite those functions. */
329 vector<double> comp;
330 int npts = d.npts();
331 comp.reserve(npts);
332 /* This initializes the buffer to allow us a simpler loop from 0 to 2
333 using the blas function dcopy to handle the skip for a fortran style
334 array used for storing the 3c data in u*/
335 for (auto i = 0; i < npts; ++i)
336 comp.push_back(0.0);
337 for (auto k = 0; k < 3; ++k) {
338 dcopy(npts, d.u.get_address(k, 0), 3, &(comp[0]), 1);
339 this->apply(comp);
340 dcopy(npts, &(comp[0]), 1, d.u.get_address(k, 0), 3);
341 }
342 } catch (...) {
343 throw;
344 };
345}
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:171
double dt() const
Definition BasicTimeSeries.h:153
mspass::utility::dmatrix u
Definition CoreSeismogram.h:52

References apply(), change_dt(), mspass::seismic::BasicTimeSeries::dt(), 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 double d_dt = d.dt();
234 if (this->dt != d_dt) {
235 /* Here we throw an exception if a requested sample rate is
236 illegal */
237 double fhtest = d_dt / (this->dt);
238 if (fhtest > FHighFloor) {
239 stringstream ss;
240 ss << "Butterworth::apply: automatic dt change error" << endl
241 << "Current operator dt=" << this->dt << " data dt=" << d_dt << endl
242 << "Change would produce a corner too close to Nyquist"
243 << " and create an unstable filter" << endl
244 << "Use a different filter operator for data with this sample rate"
245 << endl;
246 throw MsPASSError(ss.str(), ErrorSeverity::Invalid);
247 }
248 this->change_dt(d_dt);
249 }
250 this->apply(d.s);
251}
std::vector< double > s
Definition CoreTimeSeries.h:27

References apply(), change_dt(), mspass::seismic::BasicTimeSeries::dt(), 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
349 {
350
351 double d_dt = d.dt();
352 if (this->dt != d_dt) {
353 /* Here we throw an exception if a requested sample rate is
354 illegal */
355 double fhtest = d_dt / (this->dt);
356 if (use_hi && (fhtest > FHighFloor)) {
357 /*In this case we temporarily disable the upper corner and
358 cache the old dt to restore it before returning. */
359 double olddt = this->dt;
360 double flow_old = this->f3db_lo;
361 use_hi = false;
362 this->apply(d);
363 use_hi = true;
364 this->dt = olddt;
365 this->f3db_lo = flow_old;
366 stringstream ss;
367 ss << "Auto adjust for sample rate change error" << endl
368 << "Upper corner of filter=" << this->high_corner()
369 << " is near or above Nyquist frequency for requested sample "
370 << "interval=" << this->dt << endl
371 << "Disabling upper corner (lowpass) and applying filter anyway"
372 << endl;
373 d.elog.log_error(string("Butterworth::apply"), ss.str(),
374 ErrorSeverity::Complaint);
375 /* With this logic we have separate return here */
376 } else {
377 this->change_dt(d_dt);
378 }
379 }
380 vector<double> comp;
381 int npts = d.npts();
382 comp.reserve(npts);
383 /* This initializes the buffer to allow us a simpler loop from 0 to 2
384 using the blas function dcopy to handle the skip for a fortran style
385 array used for storing the 3c data in u*/
386 for (auto i = 0; i < npts; ++i)
387 comp.push_back(0.0);
388 for (auto k = 0; k < 3; ++k) {
389 dcopy(npts, d.u.get_address(k, 0), 3, &(comp[0]), 1);
390 this->apply(comp);
391 dcopy(npts, &(comp[0]), 1, d.u.get_address(k, 0), 3);
392 }
393}
double high_corner() const
Definition Butterworth.h:301
int log_error(const mspass::utility::MsPASSError &merr)
Definition ErrorLogger.cc:72

References apply(), change_dt(), mspass::seismic::BasicTimeSeries::dt(), 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
254 {
255 double d_dt = d.dt();
256 if (this->dt != d_dt) {
257 /* Here we throw an exception if a requested sample rate is
258 illegal */
259 double fhtest = d_dt / (this->dt);
260 if (use_hi && (fhtest > FHighFloor)) {
261 /*In this case we temporarily disable the upper corner and
262 cache the old dt to restore it before returning. */
263 double olddt = this->dt;
264 double flow_old = this->f3db_lo;
265 use_hi = false;
266 this->apply(d.s);
267 use_hi = true;
268 this->dt = olddt;
269 this->f3db_lo = flow_old;
270 stringstream ss;
271 ss << "Auto adjust for sample rate change error" << endl
272 << "Upper corner of filter=" << this->high_corner()
273 << " is near or above Nyquist frequency for requested sample "
274 << "interval=" << this->dt << endl
275 << "Disabling upper corner (lowpass) and applying filter anyway"
276 << endl;
277 d.elog.log_error(string("Butterworth::apply"), ss.str(),
278 ErrorSeverity::Complaint);
279 /* With this logic we have separate return here */
280 } else {
281 this->change_dt(d_dt);
282 }
283 }
284 this->apply(d.s);
285}

References apply(), change_dt(), mspass::seismic::BasicTimeSeries::dt(), high_corner(), mspass::utility::ErrorLogger::log_error(), 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)

◆ 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).
394 {
395 CoreTimeSeries imp = this->impulse_response(nfft);
396 /* the impulse response function uses a time shift and sets t0 to the
397 required position. A disconnect with any fft is that will introduce an
398 undesirable phase shift for many algorithms. We remove it here using our
399 circular shift function */
400 int ishift = imp.sample_number(0.0);
401 imp.s = circular_shift(imp.s, ishift);
402 gsl_fft_complex_wavetable *wavetable = gsl_fft_complex_wavetable_alloc(nfft);
403 gsl_fft_complex_workspace *workspace = gsl_fft_complex_workspace_alloc(nfft);
404 ComplexArray work(nfft, imp.s);
405 gsl_fft_complex_forward(work.ptr(), 1, nfft, wavetable, workspace);
406 gsl_fft_complex_wavetable_free(wavetable);
407 gsl_fft_complex_workspace_free(workspace);
408 return work;
409}
mspass::seismic::CoreTimeSeries impulse_response(const int n)
Return the impulse response.
Definition Butterworth.cc:217

References impulse_response(), mspass::seismic::CoreTimeSeries::s, and mspass::seismic::BasicTimeSeries::sample_number().


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