version  0.0.1
Defines the C++ API for MsPASS
amplitudes.h
1 #ifndef _AMPLITUDES_H_
2 #define _AMPLITUDES_H_
3 #include <sstream>
4 #include "mspass/utility/MsPASSError.h"
5 #include "mspass/seismic/TimeSeries.h"
6 #include "mspass/seismic/Seismogram.h"
7 #include "mspass/seismic/Ensemble.h"
8 #include "mspass/seismic/PowerSpectrum.h"
9 #include "mspass/utility/VectorStatistics.h"
10 #include "mspass/utility/Metadata.h"
11 #include "mspass/algorithms/TimeWindow.h"
12 #include "mspass/algorithms/algorithms.h"
13 namespace mspass::algorithms::amplitudes{
14 double PeakAmplitude(const mspass::seismic::CoreTimeSeries& d);
15 double PeakAmplitude(const mspass::seismic::CoreSeismogram& d);
16 double RMSAmplitude(const mspass::seismic::CoreTimeSeries& d);
17 double RMSAmplitude(const mspass::seismic::CoreSeismogram& d);
18 double PercAmplitude(const mspass::seismic::CoreTimeSeries& d,const double perf);
19 double PercAmplitude(const mspass::seismic::CoreSeismogram& d,const double perf);
20 double MADAmplitude(const mspass::seismic::CoreTimeSeries& d);
21 double MADAmplitude(const mspass::seismic::CoreSeismogram& d);
22 enum class ScalingMethod
23 {
24  Peak,
25  RMS,
26  ClipPerc,
27  MAD
28 };
29 const std::string scale_factor_key("calib");
55 template <typename Tdata> double scale(Tdata& d,const ScalingMethod method,
56  const double level, const mspass::algorithms::TimeWindow win)
57 {
58  if((method==ScalingMethod::ClipPerc) && (level<=0.0 || level>1.0))
59  throw mspass::utility::MsPASSError("scale function: illegal perf level specified for clip percentage scale - must be between 0 and 1\nData unaltered - may cause downstream problems",
60  mspass::utility::ErrorSeverity::Suspect);
61  try{
62  double newcalib(1.0);
63  /* the else condition here should perhaps generate an elog message but
64  did not implement to allow this template to be used for CoreTimeSeries
65  and CoreSeismogram that do not have an elog attribute.*/
66  if(d.is_defined(scale_factor_key))
67  {
68  newcalib=d.get_double(scale_factor_key);
69  }
70  /* Handle time windowing. Log window mismatches but silently handle
71  cast where the window is invalid - used as a way to override any
72  time windowing */
74  if(win.start>win.end)
75  {
76  ampwindow.start=d.t0();
77  ampwindow.end=d.endtime();
78  }
79  else if( (fabs(win.start-d.t0())/d.dt()>0.5)
80  || (fabs(win.end-d.endtime())/d.dt() > 0.5) )
81  {
82  std::stringstream ss;
83  ss << "Window time range is inconsistent with input data range"<<std::endl
84  << "Input data starttime="<<d.t0()<<" and window start time="
85  << win.start <<" Difference="<<d.t0()-win.start<<std::endl
86  << "Input data endtime="<<d.endtime()<<" and window end time="
87  << win.end <<" Difference="<<d.endtime()-win.end<<std::endl
88  << "One or the other exceeds 1/sample interval="<<d.dt()<<std::endl
89  << "Window for amplitude calculation changed to data range";
90  d.elog.log_error("scale",ss.str(),mspass::utility::ErrorSeverity::Complaint);
91  ampwindow.start=d.t0();
92  ampwindow.end=d.endtime();
93  }
94  else
95  {
96  ampwindow=win;
97  }
98  Tdata windowed_data;
99  windowed_data=mspass::algorithms::WindowData(d,ampwindow);
100  double amplitude,dscale;
101  switch(method)
102  {
103  case ScalingMethod::Peak:
104  amplitude=PeakAmplitude(windowed_data);
105  dscale = level/amplitude;
106  newcalib /= dscale;
107  break;
108  case ScalingMethod::ClipPerc:
109  amplitude=PercAmplitude(windowed_data,level);
110  /* for this scaling we use level as perf and output level is frozen
111  to be scaled to order unity*/
112  dscale = 1.0/amplitude;
113  newcalib /= dscale;
114  break;
115  case ScalingMethod::MAD:
116  amplitude=MADAmplitude(windowed_data);
117  dscale = level/amplitude;
118  newcalib /= dscale;
119  break;
120  case ScalingMethod::RMS:
121  default:
122  amplitude=RMSAmplitude(windowed_data);
123  dscale = level/amplitude;
124  newcalib /= dscale;
125  };
126  d *= dscale;
127  d.put(scale_factor_key,newcalib);
128  return amplitude;
129  }catch(...){throw;};
130 }
155 template <typename Tdata> std::vector<double> scale_ensemble_members(mspass::seismic::Ensemble<Tdata>& d,
156  const ScalingMethod& method, const double level, const mspass::algorithms::TimeWindow win)
157 {
158  if((method==ScalingMethod::ClipPerc) && (level<=0.0 || level>1.0))
159  throw mspass::utility::MsPASSError("scale_ensemble_members function: illegal perf level specified for clip percentage scale - must be between 0 and 1\nData unaltered - may cause downstream problems",
160  mspass::utility::ErrorSeverity::Suspect);
161  try{
162  typename std::vector<Tdata>::iterator dptr;
163  std::vector<double> amps;
164  amps.reserve(d.member.size());
165  for(dptr=d.member.begin();dptr!=d.member.end();++dptr)
166  {
167  double thisamp;
168  thisamp=scale(*dptr,method,level,win);
169  amps.push_back(thisamp);
170  }
171  return amps;
172  }catch(...){throw;};
173 }
194 template <typename Tdata> double scale_ensemble(mspass::seismic::Ensemble<Tdata>& d,
195  const ScalingMethod& method, const double level, const bool use_mean)
196 {
197  if((method==ScalingMethod::ClipPerc) && (level<=0.0 || level>1.0))
198  throw mspass::utility::MsPASSError("scale_ensemble function: illegal perf level specified for clip percentage scale - must be between 0 and 1\nData unaltered - may cause downstream problems",
199  mspass::utility::ErrorSeverity::Suspect);
200  try{
201  double avgamp; //defined here because the value computed here is returned on success
202  typename std::vector<Tdata>::iterator dptr;
203  std::vector<double> amps;
204  amps.reserve(d.member.size());
205  size_t nlive(0);
206  for(dptr=d.member.begin();dptr!=d.member.end();++dptr)
207  {
208  double amplitude;
209  if(dptr->dead()) continue;
210  switch(method)
211  {
212  case ScalingMethod::Peak:
213  amplitude=PeakAmplitude(*dptr);
214  break;
215  case ScalingMethod::ClipPerc:
216  amplitude=PercAmplitude(*dptr,level);
217  break;
218  case ScalingMethod::MAD:
219  amplitude=MADAmplitude(*dptr);
220  break;
221  case ScalingMethod::RMS:
222  default:
223  amplitude=RMSAmplitude(*dptr);
224  };
225  ++nlive;
226  amps.push_back(log(amplitude));
227  }
228  /*Silently return a 0 if there are no live data members*/
229  if(nlive==0) return 0.0;
231  if(use_mean)
232  {
233  avgamp=ampstats.mean();
234  }
235  else
236  {
237  avgamp=ampstats.median();
238  }
239 
240  /* restore to a value instead of natural log*/
241  avgamp=exp(avgamp);
242  double dscale=level/avgamp;
243  /* Now scale the data and apply calib */
244  for(dptr=d.member.begin();dptr!=d.member.end();++dptr)
245  {
246  if(dptr->live())
247  {
248  double calib;
249  (*dptr) *= dscale;
250  if(dptr->is_defined(scale_factor_key))
251  {
252  calib=dptr->get_double(scale_factor_key);
253  }
254  else
255  {
256  calib=1.0;
257  }
258  calib/=dscale;
259  dptr->put(scale_factor_key,calib);
260  }
261  }
262  return avgamp;
263  }catch(...){throw;};
264 }
275 {
276 public:
278  double low_edge_f;
280  double high_edge_f;
282  double low_edge_snr;
285  /* This is the frequency range of the original data */
286  double f_range;
287  BandwidthData()
288  {
289  low_edge_f=0.0;
290  high_edge_f=0.0;
291  low_edge_snr=0.0;
292  high_edge_snr=0.0;
293  f_range=0.0;
294  };
296  double bandwidth_fraction() const
297  {
298  if(f_range<=0.0)
299  return 0.0;
300  else
301  return (high_edge_f-low_edge_f)/f_range;
302  };
304  double bandwidth() const
305  {
306  if(f_range<=0.0)
307  return 0.0;
308  else
309  {
310  double ratio=high_edge_f/low_edge_f;
311  return 20.0*log10(ratio);
312  }
313  };
314 };
371 BandwidthData EstimateBandwidth(const double signal_df,
373  const double snr_threshold, const double tbp,const double fhs=-1.0,
374  const bool fix_high_edge_to_fhs=false);
412 mspass::utility::Metadata BandwidthStatistics(const mspass::seismic::PowerSpectrum& s,
414  const BandwidthData& bwd);
415 } // namespace end
416 #endif
Defines a time window.
Definition: TimeWindow.h:14
double start
Definition: TimeWindow.h:19
double end
Definition: TimeWindow.h:23
Holds parameters defining a passband computed from snr.
Definition: amplitudes.h:275
double low_edge_f
Definition: amplitudes.h:278
double bandwidth() const
Definition: amplitudes.h:304
double bandwidth_fraction() const
Definition: amplitudes.h:296
double high_edge_f
Definition: amplitudes.h:280
double low_edge_snr
Definition: amplitudes.h:282
double high_edge_snr
Definition: amplitudes.h:284
Vector (three-component) seismogram data object.
Definition: CoreSeismogram.h:40
Scalar time series data object.
Definition: CoreTimeSeries.h:18
Definition: Ensemble.h:10
std::vector< Tdata > member
Container holding data objects.
Definition: Ensemble.h:21
Definition: PowerSpectrum.h:13
Definition: Metadata.h:76
Base class for error object thrown by MsPASS library routines.
Definition: MsPASSError.h:40
Generic object to compute common robust statistics from a vector container of data.
Definition: VectorStatistics.h:16