version  0.0.1
Defines the C++ API for MsPASS
Loading...
Searching...
No Matches
amplitudes.h
1#ifndef _AMPLITUDES_H_
2#define _AMPLITUDES_H_
3#include "mspass/algorithms/TimeWindow.h"
4#include "mspass/algorithms/algorithms.h"
5#include "mspass/seismic/Ensemble.h"
6#include "mspass/seismic/PowerSpectrum.h"
7#include "mspass/seismic/Seismogram.h"
8#include "mspass/seismic/TimeSeries.h"
9#include "mspass/utility/Metadata.h"
10#include "mspass/utility/MsPASSError.h"
11#include "mspass/utility/VectorStatistics.h"
12#include <sstream>
13namespace mspass::algorithms::amplitudes {
14double PeakAmplitude(const mspass::seismic::CoreTimeSeries &d);
15double PeakAmplitude(const mspass::seismic::CoreSeismogram &d);
16double RMSAmplitude(const mspass::seismic::CoreTimeSeries &d);
17double RMSAmplitude(const mspass::seismic::CoreSeismogram &d);
18double PercAmplitude(const mspass::seismic::CoreTimeSeries &d,
19 const double perf);
20double PercAmplitude(const mspass::seismic::CoreSeismogram &d,
21 const double perf);
22double MADAmplitude(const mspass::seismic::CoreTimeSeries &d);
23double MADAmplitude(const mspass::seismic::CoreSeismogram &d);
24enum class ScalingMethod {
25 Peak,
26 RMS,
27 ClipPerc,
28 MAD
29};
30const std::string scale_factor_key("calib");
56template <typename Tdata>
57double scale(Tdata &d, const ScalingMethod method, const double level,
59 if ((method == ScalingMethod::ClipPerc) && (level <= 0.0 || level > 1.0))
61 "scale function: illegal perf level specified for clip percentage "
62 "scale - must be between 0 and 1\nData unaltered - may cause "
63 "downstream problems",
64 mspass::utility::ErrorSeverity::Suspect);
65 try {
66 double newcalib(1.0);
67 /* the else condition here should perhaps generate an elog message but
68 did not implement to allow this template to be used for CoreTimeSeries
69 and CoreSeismogram that do not have an elog attribute.*/
70 if (d.is_defined(scale_factor_key)) {
71 newcalib = d.get_double(scale_factor_key);
72 }
73 /* Handle time windowing. Log window mismatches but silently handle
74 cast where the window is invalid - used as a way to override any
75 time windowing */
77 if (win.start > win.end) {
78 ampwindow.start = d.t0();
79 ampwindow.end = d.endtime();
80 } else if ((fabs(win.start - d.t0()) / d.dt() > 0.5) ||
81 (fabs(win.end - d.endtime()) / d.dt() > 0.5)) {
82 std::stringstream ss;
83 ss << "Window time range is inconsistent with input data range"
84 << std::endl
85 << "Input data starttime=" << d.t0()
86 << " and window start time=" << win.start
87 << " Difference=" << d.t0() - win.start << std::endl
88 << "Input data endtime=" << d.endtime()
89 << " and window end time=" << win.end
90 << " Difference=" << d.endtime() - win.end << std::endl
91 << "One or the other exceeds 1/sample interval=" << d.dt() << std::endl
92 << "Window for amplitude calculation changed to data range";
93 d.elog.log_error("scale", ss.str(),
94 mspass::utility::ErrorSeverity::Complaint);
95 ampwindow.start = d.t0();
96 ampwindow.end = d.endtime();
97 } else {
98 ampwindow = win;
99 }
100 Tdata windowed_data;
101 windowed_data = mspass::algorithms::WindowData(d, ampwindow);
102 double amplitude, dscale;
103 switch (method) {
104 case ScalingMethod::Peak:
105 amplitude = PeakAmplitude(windowed_data);
106 break;
107 case ScalingMethod::ClipPerc:
108 amplitude = PercAmplitude(windowed_data, level);
109 break;
110 case ScalingMethod::MAD:
111 amplitude = MADAmplitude(windowed_data);
112 break;
113 case ScalingMethod::RMS:
114 default:
115 amplitude = RMSAmplitude(windowed_data);
116 };
117 /* needed to handle case with a vector of all 0s*/
118 if (amplitude > 0.0) {
119 dscale = level / amplitude;
120 newcalib /= dscale;
121 d *= dscale;
122 d.put(scale_factor_key, newcalib);
123 } else {
124 std::stringstream ss;
125 ss << "Data array is all 0s and cannot be scaled";
126 d.elog.log_error("scale", ss.str(),
127 mspass::utility::ErrorSeverity::Complaint);
128 /* This may not be necessary but it assures this value is always set on
129 return even if it means nothing*/
130 d.put(scale_factor_key, newcalib);
131 }
132 return amplitude;
133 } catch (...) {
134 throw;
135 };
136}
161template <typename Tdata>
162std::vector<double>
163scale_ensemble_members(mspass::seismic::Ensemble<Tdata> &d,
164 const ScalingMethod &method, const double level,
166 if ((method == ScalingMethod::ClipPerc) && (level <= 0.0 || level > 1.0))
168 "scale_ensemble_members function: illegal perf level specified for "
169 "clip percentage scale - must be between 0 and 1\nData unaltered - may "
170 "cause downstream problems",
171 mspass::utility::ErrorSeverity::Suspect);
172 try {
173 typename std::vector<Tdata>::iterator dptr;
174 std::vector<double> amps;
175 amps.reserve(d.member.size());
176 for (dptr = d.member.begin(); dptr != d.member.end(); ++dptr) {
177 double thisamp;
178 thisamp = scale(*dptr, method, level, win);
179 amps.push_back(thisamp);
180 }
181 return amps;
182 } catch (...) {
183 throw;
184 };
185}
206template <typename Tdata>
207double scale_ensemble(mspass::seismic::Ensemble<Tdata> &d,
208 const ScalingMethod &method, const double level,
209 const bool use_mean) {
210 if ((method == ScalingMethod::ClipPerc) && (level <= 0.0 || level > 1.0))
212 "scale_ensemble function: illegal perf level specified for clip "
213 "percentage scale - must be between 0 and 1\nData unaltered - may "
214 "cause downstream problems",
215 mspass::utility::ErrorSeverity::Suspect);
216 try {
217 double avgamp; // defined here because the value computed here is returned
218 // on success
219 typename std::vector<Tdata>::iterator dptr;
220 std::vector<double> amps;
221 amps.reserve(d.member.size());
222 size_t nlive(0);
223 for (dptr = d.member.begin(); dptr != d.member.end(); ++dptr) {
224 double amplitude;
225 if (dptr->dead())
226 continue;
227 switch (method) {
228 case ScalingMethod::Peak:
229 amplitude = PeakAmplitude(*dptr);
230 break;
231 case ScalingMethod::ClipPerc:
232 amplitude = PercAmplitude(*dptr, level);
233 break;
234 case ScalingMethod::MAD:
235 amplitude = MADAmplitude(*dptr);
236 break;
237 case ScalingMethod::RMS:
238 default:
239 amplitude = RMSAmplitude(*dptr);
240 };
241 ++nlive;
242 amps.push_back(log(amplitude));
243 }
244 /*Silently return a 0 if there are no live data members*/
245 if (nlive == 0)
246 return 0.0;
248 if (use_mean) {
249 avgamp = ampstats.mean();
250 } else {
251 avgamp = ampstats.median();
252 }
253
254 /* restore to a value instead of natural log*/
255 avgamp = exp(avgamp);
256 /* Silently do nothing if all the data are zero. Would be better to
257 log an error but use as a "Core" object doesn't contain an elog attribute*/
258 if (avgamp <= 0.0) {
259 return 0.0;
260 }
261 double dscale = level / avgamp;
262 /* Now scale the data and apply calib */
263 for (dptr = d.member.begin(); dptr != d.member.end(); ++dptr) {
264 if (dptr->live()) {
265 double calib;
266 (*dptr) *= dscale;
267 if (dptr->is_defined(scale_factor_key)) {
268 calib = dptr->get_double(scale_factor_key);
269 } else {
270 calib = 1.0;
271 }
272 calib /= dscale;
273 dptr->put(scale_factor_key, calib);
274 }
275 }
276 return avgamp;
277 } catch (...) {
278 throw;
279 };
280}
282template <class T> std::vector<T> normalize(const std::vector<T> &d) {
283 size_t N = d.size();
284 std::vector<T> result;
285 result.reserve(N);
286 double d_nrm(0.0);
287 ;
288 for (size_t i = 0; i < N; ++i) {
289 d_nrm += (d[i] * d[i]);
290 result.push_back(d[i]);
291 }
292 d_nrm = sqrt(d_nrm);
293 for (size_t i = 0; i < N; ++i)
294 result[i] /= d_nrm;
295 return result;
296}
307public:
316 /* This is the frequency range of the original data */
317 double f_range;
318 BandwidthData() {
319 low_edge_f = 0.0;
320 high_edge_f = 0.0;
321 low_edge_snr = 0.0;
322 high_edge_snr = 0.0;
323 f_range = 0.0;
324 };
327 double bandwidth_fraction() const {
328 if (f_range <= 0.0)
329 return 0.0;
330 else
331 return (high_edge_f - low_edge_f) / f_range;
332 };
334 double bandwidth() const {
335 if (f_range <= 0.0)
336 return 0.0;
337 else {
338 double ratio = high_edge_f / low_edge_f;
339 return 20.0 * log10(ratio);
340 }
341 };
342};
400BandwidthData EstimateBandwidth(const double signal_df,
403 const double snr_threshold, const double tbp,
404 const double fhs = -1.0,
405 const bool fix_high_edge_to_fhs = false);
447BandwidthStatistics(const mspass::seismic::PowerSpectrum &s,
449 const BandwidthData &bwd);
450} // namespace mspass::algorithms::amplitudes
451#endif
Defines a time window.
Definition TimeWindow.h:12
double start
Definition TimeWindow.h:17
double end
Definition TimeWindow.h:21
Holds parameters defining a passband computed from snr.
Definition amplitudes.h:306
double low_edge_f
Definition amplitudes.h:309
double bandwidth() const
Definition amplitudes.h:334
double bandwidth_fraction() const
Definition amplitudes.h:327
double high_edge_f
Definition amplitudes.h:311
double low_edge_snr
Definition amplitudes.h:313
double high_edge_snr
Definition amplitudes.h:315
Vector (three-component) seismogram data object.
Definition CoreSeismogram.h:39
Scalar time series data object.
Definition CoreTimeSeries.h:17
Definition Ensemble.h:9
std::vector< Tdata > member
Container holding data objects.
Definition Ensemble.h:20
Definition PowerSpectrum.h:11
Definition Metadata.h:71
Base class for error object thrown by MsPASS library routines.
Definition MsPASSError.h:38
Generic object to compute common robust statistics from a vector container of data.
Definition VectorStatistics.h:16