version  0.0.1
Defines the C++ API for MsPASS
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. More...
 
 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. More...
 
 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. More...
 
 Butterworth (const Butterworth &parent)
 
Butterworthoperator= (const Butterworth &parent)
 
mspass::seismic::CoreTimeSeries impulse_response (const int n)
 Return the impulse response. More...
 
void apply (mspass::seismic::CoreTimeSeries &d)
 pply the filter to a CoreTimeSeries object. More...
 
void apply (mspass::seismic::TimeSeries &d)
 Apply the filter to a CoreTimeSeries object. More...
 
void apply (std::vector< double > &d)
 Filter a raw vector of data. More...
 
void apply (mspass::seismic::CoreSeismogram &d)
 Apply the filter to a CoreSeismogram object. More...
 
void apply (mspass::seismic::Seismogram &d)
 Apply the filter to a CoreTimeSeries object. More...
 
mspass::algorithms::deconvolution::ComplexArray transfer_function (const int n)
 Return the response of the filter in the frequency domain. More...
 
void change_dt (const double dtnew)
 set the sample interval assumed for input data. More...
 
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)

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

◆ 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
47 {
48  dt=sample_interval;
49  zerophase=zp;
50  use_lo=lcon;
51  use_hi=hcon;
52  this->bfdesign(fpasslo*dt,apasslo,fstoplo*dt,astoplo,
53  &(this->npoles_lo),&(this->f3db_lo));
54  this->bfdesign(fpasshi*dt,apasshi,fstophi*dt,astophi,
55  &(this->npoles_hi),&(this->f3db_hi));
56 };

◆ 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

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

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
61 {
62  this->dt=sample_interval;
63  this->zerophase=zero;
64  this->use_lo=locut;
65  this->use_hi=hicut;
66  this->f3db_hi=f3dbhi;
67  this->f3db_lo=f3dblo;
68  this->npoles_lo=npolelo;
69  this->npoles_hi=npolehi;
70  /* Convert the frequencies to nondimensional form */
71  this->f3db_lo *= dt;
72  this->f3db_hi *= dt;
73 }

◆ Butterworth() [5/5]

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

Standard copy conststructor.

214 {
215  use_lo=parent.use_lo;
216  use_hi=parent.use_hi;
217  zerophase=parent.zerophase;
218  f3db_lo=parent.f3db_lo;
219  f3db_hi=parent.f3db_hi;
220  npoles_lo=parent.npoles_lo;
221  npoles_hi=parent.npoles_hi;
222  dt=parent.dt;
223 }

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
358 {
359  /* we could just handle a MsPASSError to take care of exceptions
360  thrown by apply if the sample rate is illegal, but this is more adaptable. */
361  try{
362  double d_dt=d.dt();
363  if(this->dt != d_dt) this->change_dt(d_dt);
364  /* We copy each component to this buffer, filter, and then copy
365  back. Not as efficient as if we used a strike parameter in the filter
366  functions, but I did not want to rewrite those functions. */
367  vector<double> comp;
368  int npts=d.npts();
369  comp.reserve(npts);
370  /* This initializes the buffer to allow us a simpler loop from 0 to 2
371  using the blas function dcopy to handle the skip for a fortran style
372  array used for storing the 3c data in u*/
373  for(auto i=0;i<npts;++i)comp.push_back(0.0);
374  for(auto k=0;k<3;++k)
375  {
376  dcopy(npts,d.u.get_address(k,0),3,&(comp[0]),1);
377  this->apply(comp);
378  dcopy(npts,&(comp[0]),1,d.u.get_address(k,0),3);
379  }
380  }catch(...){throw;};
381 }
void change_dt(const double dtnew)
set the sample interval assumed for input data.
Definition: Butterworth.h:295
void apply(mspass::seismic::CoreTimeSeries &d)
pply the filter to a CoreTimeSeries object.
Definition: Butterworth.cc:254
size_t npts() const
Definition: BasicTimeSeries.h:183
double dt() const
Definition: BasicTimeSeries.h:157
mspass::utility::dmatrix u
Definition: CoreSeismogram.h:53

References 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
255 {
256  double d_dt=d.dt();
257  if(this->dt != d_dt)
258  {
259  /* Here we throw an exception if a requested sample rate is
260  illegal */
261  double fhtest=d_dt/(this->dt);
262  if(fhtest>FHighFloor)
263  {
264  stringstream ss;
265  ss << "Butterworth::apply: automatic dt change error"<<endl
266  << "Current operator dt="<<this->dt<<" data dt="<<d_dt<<endl
267  << "Change would produce a corner too close to Nyquist"
268  << " and create an unstable filter"<<endl
269  << "Use a different filter operator for data with this sample rate"
270  << endl;
271  throw MsPASSError(ss.str(),ErrorSeverity::Invalid);
272  }
273  this->change_dt(d_dt);
274  }
275  this->apply(d.s);
276 }
std::vector< double > s
Definition: CoreTimeSeries.h:28

References 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
386 {
387 
388 
389  double d_dt=d.dt();
390  if(this->dt != d_dt)
391  {
392  /* Here we throw an exception if a requested sample rate is
393  illegal */
394  double fhtest=d_dt/(this->dt);
395  if(use_hi && (fhtest>FHighFloor))
396  {
397  /*In this case we temporarily disable the upper corner and
398  cache the old dt to restore it before returning. */
399  double olddt=this->dt;
400  double flow_old=this->f3db_lo;
401  use_hi=false;
402  this->apply(d);
403  use_hi=true;
404  this->dt=olddt;
405  this->f3db_lo=flow_old;
406  stringstream ss;
407  ss <<"Auto adjust for sample rate change error"<<endl
408  << "Upper corner of filter="<<this->high_corner()
409  << " is near or above Nyquist frequency for requested sample "
410  << "interval="<<this->dt<<endl
411  << "Disabling upper corner (lowpass) and applying filter anyway"
412  <<endl;
413  d.elog.log_error(string("Butterworth::apply"),
414  ss.str(),ErrorSeverity::Complaint);
415  /* With this logic we have separate return here */
416  }
417  else
418  {
419  this->change_dt(d_dt);
420  }
421  }
422  vector<double> comp;
423  int npts=d.npts();
424  comp.reserve(npts);
425  /* This initializes the buffer to allow us a simpler loop from 0 to 2
426  using the blas function dcopy to handle the skip for a fortran style
427  array used for storing the 3c data in u*/
428  for(auto i=0;i<npts;++i)comp.push_back(0.0);
429  for(auto k=0;k<3;++k)
430  {
431  dcopy(npts,d.u.get_address(k,0),3,&(comp[0]),1);
432  this->apply(comp);
433  dcopy(npts,&(comp[0]),1,d.u.get_address(k,0),3);
434  }
435 }
double high_corner() const
Definition: Butterworth.h:307
int log_error(const mspass::utility::MsPASSError &merr)
Definition: ErrorLogger.cc:81

References mspass::seismic::BasicTimeSeries::dt(), 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
280 {
281  double d_dt=d.dt();
282  if(this->dt != d_dt)
283  {
284  /* Here we throw an exception if a requested sample rate is
285  illegal */
286  double fhtest=d_dt/(this->dt);
287  if(use_hi && (fhtest>FHighFloor))
288  {
289  /*In this case we temporarily disable the upper corner and
290  cache the old dt to restore it before returning. */
291  double olddt=this->dt;
292  double flow_old=this->f3db_lo;
293  use_hi=false;
294  this->apply(d.s);
295  use_hi=true;
296  this->dt=olddt;
297  this->f3db_lo=flow_old;
298  stringstream ss;
299  ss <<"Auto adjust for sample rate change error"<<endl
300  << "Upper corner of filter="<<this->high_corner()
301  << " is near or above Nyquist frequency for requested sample "
302  << "interval="<<this->dt<<endl
303  << "Disabling upper corner (lowpass) and applying filter anyway"
304  <<endl;
305  d.elog.log_error(string("Butterworth::apply"),
306  ss.str(),ErrorSeverity::Complaint);
307  /* With this logic we have separate return here */
308  }
309  else
310  {
311  this->change_dt(d_dt);
312  }
313  }
314  this->apply(d.s);
315 }

References mspass::seismic::BasicTimeSeries::dt(), 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.
296  {
297  this->f3db_lo *= (dtnew/(this->dt));
298  this->f3db_hi *= (dtnew/(this->dt));
299  this->dt=dtnew;
300  };

◆ current_dt()

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

Return the current operator sample interval.

318 {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".

329  {
330  if(use_lo)
331  {
332  if(use_hi)
333  return std::string("bandpass");
334  else
335  return std::string("highpass");
336  }
337  else
338  {
339  if(use_hi)
340  return std::string("lowpass");
341  else
342  return std::string("Undefined");
343  }
344  };

◆ high_corner()

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

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

308  {
309  return f3db_hi/dt;
310  };

◆ 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.
240 {
241  CoreTimeSeries result(n);
242  /* We use a feature that the above constructor initiallizes the buffer
243  to zeros so just a spike at n/2. */
244  result.s[n/2]=1.0;
245  result.set_t0( ((double)(-n/2))*(this->dt) );
246  result.set_dt(this->dt);
247  result.set_tref(TimeReferenceType::Relative);
248  result.set_live();
249  this->apply(result.s);
250  return result;
251 }

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

348  {
349  return zerophase;
350  };

◆ low_corner()

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

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

303  {
304  return f3db_lo/dt;
305  };

◆ npoles_high()

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

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

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

313 {return npoles_lo;};

◆ operator=()

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

Standard assignment operator.

225 {
226  if(this != &parent)
227  {
228  use_lo=parent.use_lo;
229  use_hi=parent.use_hi;
230  zerophase=parent.zerophase;
231  f3db_lo=parent.f3db_lo;
232  f3db_hi=parent.f3db_hi;
233  npoles_lo=parent.npoles_lo;
234  npoles_hi=parent.npoles_hi;
235  dt=parent.dt;
236  }
237  return *this;
238 }

◆ 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).
437 {
438  CoreTimeSeries imp=this->impulse_response(nfft);
439  /* the impulse response function uses a time shift and sets t0 to the
440  required position. A disconnect with any fft is that will introduce an
441  undesirable phase shift for many algorithms. We remove it here using our
442  circular shift function */
443  int ishift=imp.sample_number(0.0);
444  imp.s=circular_shift(imp.s,ishift);
445  gsl_fft_complex_wavetable *wavetable = gsl_fft_complex_wavetable_alloc (nfft);
446  gsl_fft_complex_workspace *workspace = gsl_fft_complex_workspace_alloc (nfft);
447  ComplexArray work(nfft,imp.s);
448  gsl_fft_complex_forward(work.ptr(), 1, nfft, wavetable, workspace);
449  gsl_fft_complex_wavetable_free (wavetable);
450  gsl_fft_complex_workspace_free (workspace);
451  return work;
452 }
mspass::seismic::CoreTimeSeries impulse_response(const int n)
Return the impulse response.
Definition: Butterworth.cc:239

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


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