You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
430 lines
14 KiB
C++
430 lines
14 KiB
C++
/***************************************************************************
|
|
* Copyright (C) gempa GmbH *
|
|
* All rights reserved. *
|
|
* Contact: gempa GmbH (seiscomp-dev@gempa.de) *
|
|
* *
|
|
* GNU Affero General Public License Usage *
|
|
* This file may be used under the terms of the GNU Affero *
|
|
* Public License version 3.0 as published by the Free Software Foundation *
|
|
* and appearing in the file LICENSE included in the packaging of this *
|
|
* file. Please review the following information to ensure the GNU Affero *
|
|
* Public License version 3.0 requirements will be met: *
|
|
* https://www.gnu.org/licenses/agpl-3.0.html. *
|
|
* *
|
|
* Other Usage *
|
|
* Alternatively, this file may be used in accordance with the terms and *
|
|
* conditions contained in a signed written agreement between you and *
|
|
* gempa GmbH. *
|
|
***************************************************************************/
|
|
|
|
|
|
#ifndef SEISCOMP_PROCESSING_WAVEFORMPROCESSOR_H
|
|
#define SEISCOMP_PROCESSING_WAVEFORMPROCESSOR_H
|
|
|
|
|
|
#include <seiscomp/core/record.h>
|
|
#include <seiscomp/core/recordsequence.h>
|
|
#include <seiscomp/core/typedarray.h>
|
|
#include <seiscomp/core/enumeration.h>
|
|
#include <seiscomp/math/filter.h>
|
|
#include <seiscomp/processing/processor.h>
|
|
#include <seiscomp/processing/stream.h>
|
|
|
|
|
|
namespace Seiscomp {
|
|
namespace Processing {
|
|
|
|
|
|
DEFINE_SMARTPOINTER(WaveformOperator);
|
|
DEFINE_SMARTPOINTER(WaveformProcessor);
|
|
|
|
|
|
class SC_SYSTEM_CLIENT_API WaveformProcessor : public Processor {
|
|
DECLARE_SC_CLASS(WaveformProcessor)
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Public types
|
|
// ----------------------------------------------------------------------
|
|
public:
|
|
enum Component {
|
|
VerticalComponent = 0, /* usually Z */
|
|
FirstHorizontalComponent = 1, /* usually N */
|
|
SecondHorizontalComponent = 2 /* usually E */
|
|
};
|
|
|
|
enum StreamComponent {
|
|
Vertical = 0, /* usually Z */
|
|
FirstHorizontal = 1, /* usually N */
|
|
SecondHorizontal = 2, /* usually E */
|
|
Horizontal, /* usually N + E */
|
|
Any /* all available components */
|
|
};
|
|
|
|
typedef Math::Filtering::InPlaceFilter<double> Filter;
|
|
|
|
enum ProcessingHint {
|
|
Distance,
|
|
Depth,
|
|
Time
|
|
};
|
|
|
|
MAKEENUM(
|
|
SignalUnit,
|
|
EVALUES(
|
|
//! Displacement
|
|
Meter,
|
|
//! Velocity
|
|
MeterPerSecond,
|
|
//! Acceleration
|
|
MeterPerSecondSquared
|
|
),
|
|
// SEED names: see SEEDManual, ch.5 / 34, p.47
|
|
ENAMES(
|
|
"M",
|
|
"M/S",
|
|
"M/S**2"
|
|
)
|
|
);
|
|
|
|
|
|
MAKEENUM(
|
|
Status,
|
|
EVALUES(
|
|
//! No associated value
|
|
WaitingForData,
|
|
//! Associated value is progress in [0,100]
|
|
InProgress,
|
|
//! Associated value is 100
|
|
Finished,
|
|
//! Associated value is the last status
|
|
Terminated,
|
|
//! Associated value is the failed snr value
|
|
LowSNR,
|
|
//! No associated value yet
|
|
QCError,
|
|
//! Data is clipped
|
|
DataClipped,
|
|
//! Error during deconvolution
|
|
DeconvolutionFailed,
|
|
//! Distance hint is out of range to continue processing
|
|
DistanceOutOfRange,
|
|
//! Depth hint is out of range to continue processing
|
|
DepthOutOfRange,
|
|
//! Unit is not supported, e.g. m/s <> m/s**2
|
|
IncompatibleUnit,
|
|
//! Orientation missing
|
|
MissingOrientation,
|
|
//! Gain missing
|
|
MissingGain,
|
|
//! Response missing
|
|
MissingResponse,
|
|
//! Sampling frequency does not match. Either records of
|
|
//! one trace have different sampling frequencies or
|
|
//! the sampling frequencies of different channels do not match.
|
|
InvalidSamplingFreq,
|
|
//! No associated value yet (error code?)
|
|
Error,
|
|
// -- The following enumerations were added with API 12 ---
|
|
//! No distance hint set
|
|
MissingDistance,
|
|
//! No depth hint set
|
|
MissingDepth,
|
|
//! No time hint set
|
|
MissingTime,
|
|
//! No hypocenter (Origin) given
|
|
MissingHypocenter,
|
|
//! No receiver (SensorLocation) given
|
|
MissingReceiver,
|
|
//! No pick (Pick) given
|
|
MissingPick,
|
|
//! Metadata is incomplete, e.g. a particualr stream attribute
|
|
//! is not set or empty
|
|
IncompleteMetadata,
|
|
//! The epicentre is out of supported regions
|
|
EpicenterOutOfRegions,
|
|
//! The receiver is out of supported regions
|
|
ReceiverOutOfRegions,
|
|
//! The entire raypath does not lie entirely in the supported
|
|
//! regions
|
|
RayPathOutOfRegions,
|
|
//! Travel time table lookup failed
|
|
TravelTimeEstimateFailed,
|
|
//! Configuration error
|
|
ConfigurationError
|
|
),
|
|
ENAMES(
|
|
"waiting for data",
|
|
"in progress",
|
|
"finished",
|
|
"terminated",
|
|
"low SNR",
|
|
"QC error",
|
|
"data clipped",
|
|
"deconvolution failed",
|
|
"distance out of range",
|
|
"depth out of range",
|
|
"incompatible unit",
|
|
"missing orientation",
|
|
"missing gain",
|
|
"missing response",
|
|
"invalid sampling frequency",
|
|
"error",
|
|
"missing distance hint",
|
|
"missing depth hint",
|
|
"missing time hint",
|
|
"missing hypocenter",
|
|
"missing receiver",
|
|
"missing pick",
|
|
"incomplete metadata",
|
|
"epicenter out of regions",
|
|
"receiver out of regions",
|
|
"ray path out of regions",
|
|
"travel time estimate failed",
|
|
"configuration error"
|
|
)
|
|
);
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
// X'truction
|
|
// ----------------------------------------------------------------------
|
|
public:
|
|
//! C'tor
|
|
WaveformProcessor(const Core::TimeSpan &initTime=0.0,
|
|
const Core::TimeSpan &gapThreshold=0.1);
|
|
|
|
//! D'tor
|
|
virtual ~WaveformProcessor();
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Public interface
|
|
// ----------------------------------------------------------------------
|
|
public:
|
|
//! Call this method in derived classes to make sure
|
|
//! the filters samplingFrequency will be set correctly
|
|
//! The feed method filters the data according to the
|
|
//! set filter and calls process.
|
|
//! NOTE: This method does not distinguish between different
|
|
//! channelcodes. Its just feeds what it gets into the
|
|
//! data array. If multiple channels need to be combined
|
|
//! this method must be reimplemented.
|
|
virtual bool feed(const Record *record);
|
|
|
|
//! Convenience function to feed a whole record sequence into
|
|
//! a WaveformProcessor.
|
|
//! feed(const Record *) is used to feed a single record
|
|
//! @return The number of records successfully fed
|
|
int feedSequence(const RecordSequence *sequence);
|
|
|
|
//! Sets a userdata pointer that is managed by the processor
|
|
//! (stored inside a SmartPointer).
|
|
void setUserData(Core::BaseObject *obj) const;
|
|
|
|
//! Returns the set userdata object. This object must not be
|
|
//! deleted by the caller. It is managed by the processor and
|
|
//! dereferenced (and deleted) automatically. But the
|
|
//! caller may hold a SmartPointer to that object.
|
|
Core::BaseObject *userData() const;
|
|
|
|
//! Sets up the waveform processor. By default it reads whether
|
|
//! to check for data saturation or not
|
|
virtual bool setup(const Settings &settings) override;
|
|
|
|
//! Initialize the filter for the given sampling frequency
|
|
virtual void initFilter(double fsamp);
|
|
|
|
//! Sets the filter to apply
|
|
virtual void setFilter(Filter *filter);
|
|
|
|
//! Sets a operator for all fed records. An operator sits between
|
|
//! feed and store.
|
|
void setOperator(WaveformOperator *pipe);
|
|
|
|
//! The gain is input unit -> sensor unit
|
|
Stream &streamConfig(Component c);
|
|
const Stream &streamConfig(Component c) const;
|
|
|
|
//! Sets the component to use to calculate the amplitude for
|
|
void setUsedComponent(StreamComponent c) { _usedComponent = c; }
|
|
|
|
//! Returns the used component
|
|
StreamComponent usedComponent() const { return _usedComponent; }
|
|
|
|
//! Sets the maximal gap length in seconds for that
|
|
//! missing samples are handled or tolerated. Default: no tolerance
|
|
void setGapTolerance(const Core::TimeSpan &length);
|
|
const Core::TimeSpan &gapTolerance() const;
|
|
|
|
//! Enables/disables the linear interpolation of missing samples
|
|
//! inside a set gap tolerance
|
|
void setGapInterpolationEnabled(bool enable);
|
|
bool isGapInterpolationEnabled() const;
|
|
|
|
//! Enables saturation check of absolute values of incoming samples and
|
|
//! sets the status to DataClipped if checked positive. The data
|
|
//! is checked in the fill method. If derived classes reimplement
|
|
//! this method without calling this implementation, the check is
|
|
//! not performed.
|
|
void setSaturationCheckEnabled(bool enable);
|
|
|
|
//! Sets the saturation threshold. The default is -1
|
|
void setSaturationThreshold(double t);
|
|
|
|
//! Returns whether saturation check is enabled
|
|
bool isSaturationCheckEnabled() const;
|
|
|
|
//! Returns the saturation threshold that is applied if saturation
|
|
//! check is enabled.
|
|
double saturationThreshold() const { return _saturationThreshold; }
|
|
|
|
/**
|
|
* @brief Resets the processing state
|
|
*
|
|
* This method resets the current processing states back to as if
|
|
* wouldn't have received any data yet. It not *not* meant to reset
|
|
* the processors configuration to its defaults. This method is going
|
|
* to be called when e.g. gaps are detected.
|
|
*/
|
|
virtual void reset();
|
|
|
|
//! Returns the data's sampling frequency
|
|
double samplingFrequency() const;
|
|
|
|
//! This methods can be called to set a hint for the
|
|
//! processor even while processing.
|
|
//! The hint can be used to tune certain processing
|
|
//! steps. Currently exists a distance and a depth hint.
|
|
//! Derived classes should reimplement this method to react
|
|
//! on this hints.
|
|
//! E.g. an amplitude processor can cut its endtime when
|
|
//! receiving a distance hint.
|
|
//! The default implementation does nothing.
|
|
virtual void setHint(ProcessingHint, double) {}
|
|
|
|
void setEnabled(bool e);
|
|
bool isEnabled() const { return _enabled; }
|
|
|
|
//! Returns the timewindow of already processed data
|
|
Core::TimeWindow dataTimeWindow() const;
|
|
|
|
//! Returns the last fed record
|
|
const Record *lastRecord() const;
|
|
|
|
//! Returns the current status of the processor
|
|
Status status() const;
|
|
|
|
//! Returns the value associated with the status
|
|
double statusValue() const;
|
|
|
|
//! Terminates the processor ignoring its current state
|
|
void terminate();
|
|
|
|
//! Default implementation returns if the status if greater
|
|
//! than InProgress.
|
|
virtual bool isFinished() const;
|
|
|
|
//! Closes the processor meaning that no more records
|
|
//! are going to be fed in. The processing has been finished.
|
|
virtual void close() const;
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Protected interface
|
|
// ----------------------------------------------------------------------
|
|
protected:
|
|
//! Callback methods to react on changes of the
|
|
//! enable state
|
|
virtual void disabled() {}
|
|
virtual void enabled() {}
|
|
|
|
//! Virtual method that must be used in derived classes to analyse
|
|
//! a datastream.
|
|
//! It gives the raw record and the filtered data array as parameter.
|
|
virtual void process(const Record *record,
|
|
const DoubleArray &filteredData) = 0;
|
|
|
|
//! Handles gaps. Returns whether the gap has been handled or not.
|
|
virtual bool handleGap(Filter *filter, const Core::TimeSpan&,
|
|
double lastSample, double nextSample,
|
|
size_t missingSamples);
|
|
|
|
virtual void fill(size_t n, double *samples);
|
|
virtual bool store(const Record *rec);
|
|
|
|
void setStatus(Status status, double value);
|
|
|
|
bool parseSaturationThreshold(const Settings &settings,
|
|
const std::string &optionName);
|
|
|
|
void setupStream(double fsamp);
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
// Members
|
|
// ----------------------------------------------------------------------
|
|
protected:
|
|
//! Describes the current state of a component (e.g. Z or N)
|
|
struct StreamState {
|
|
StreamState();
|
|
~StreamState();
|
|
|
|
//! Value of the last sample
|
|
double lastSample;
|
|
|
|
//! Number of samples required to finish initialization
|
|
size_t neededSamples;
|
|
//! Number of samples already received
|
|
size_t receivedSamples;
|
|
//! Initialization state
|
|
bool initialized;
|
|
|
|
//! The last received record on this component
|
|
RecordCPtr lastRecord;
|
|
//! The complete processed data time window so far
|
|
Core::TimeWindow dataTimeWindow;
|
|
|
|
//! The sampling frequency of the component
|
|
double fsamp;
|
|
//! The filter (if used)
|
|
Filter *filter;
|
|
};
|
|
|
|
bool _enabled;
|
|
|
|
Core::TimeSpan _initTime;
|
|
|
|
//! threshold to recognize a gap
|
|
Core::TimeSpan _gapThreshold;
|
|
//! gap length to tolerate
|
|
Core::TimeSpan _gapTolerance;
|
|
|
|
//! default: false
|
|
bool _enableSaturationCheck;
|
|
double _saturationThreshold;
|
|
|
|
//! default: false
|
|
bool _enableGapInterpolation;
|
|
|
|
StreamState _stream;
|
|
|
|
//! default: vertical
|
|
StreamComponent _usedComponent;
|
|
Stream _streamConfig[3];
|
|
|
|
|
|
private:
|
|
Status _status;
|
|
double _statusValue;
|
|
WaveformOperatorPtr _operator;
|
|
|
|
mutable Core::BaseObjectPtr _userData;
|
|
};
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
#endif
|