diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index 69f1657da64d48125dda6e99f2a9316de6ce2cf5..0f75be2c14fcf920d42b89f47e5f424a347dfd3f 100644 --- a/algo/CMakeLists.txt +++ b/algo/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory (data) set(SRCS evbuild/EventBuilder.cxx + trigger/TimeClusterTrigger.cxx ) add_library(Algo SHARED ${SRCS}) diff --git a/algo/trigger/TimeClusterTrigger.cxx b/algo/trigger/TimeClusterTrigger.cxx new file mode 100644 index 0000000000000000000000000000000000000000..21ed7f8b288dff0b8a67b9a82cfaf52649851ad3 --- /dev/null +++ b/algo/trigger/TimeClusterTrigger.cxx @@ -0,0 +1,52 @@ +/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Volker Friese [committer], Dominik Smith */ + +#include "TimeClusterTrigger.h" + +#include <algorithm> +#include <cassert> +#include <iterator> +#include <vector> + +using std::vector; + +namespace cbm::algo +{ + + vector<double> TimeClusterTrigger::operator()(const vector<double>& dataVec, double winSize, int32_t minNumData, + double deadTime) const + { + + assert(std::is_sorted(dataVec.begin(), dataVec.end())); + + vector<double> triggerVec; + auto winStart = dataVec.begin(); + auto current = dataVec.begin(); + + while (current != dataVec.end()) { + + // If window size is exceeded, adjust window start + while (*current - *winStart > winSize) + winStart++; + + // Create trigger if threshold is reached + if (std::distance(winStart, current) >= minNumData - 1) { + triggerVec.push_back(0.5 * (*current + *winStart)); + + // Start new window after dead time + winStart = current + 1; + while (winStart != dataVec.end() && *winStart - *current < deadTime) + winStart++; + current = winStart; + } + + // If threshold is not reached, check with next element + else + current++; + } + + return triggerVec; + } + +} // namespace cbm::algo diff --git a/algo/trigger/TimeClusterTrigger.h b/algo/trigger/TimeClusterTrigger.h new file mode 100644 index 0000000000000000000000000000000000000000..e3794533e8a4af59bdbdfcdb6adb7ecafd5ed525 --- /dev/null +++ b/algo/trigger/TimeClusterTrigger.h @@ -0,0 +1,43 @@ +/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Volker Friese [committer], Dominik Smith */ + +#ifndef CBM_ALGO_TIMECLUSTERTRIGGER_H +#define CBM_ALGO_TIMECLUSTERTRIGGER_H 1 + + +#include <cstdint> +#include <vector> + +namespace cbm::algo +{ + + /** @class TimeClusterTrigger + ** @author Volker Friese <v.friese@gsi.de> + ** @author Dominik Smith <d.smith@gsi.de> + ** @since 2021 + ** @brief Finds clusters in time-series data + ** + ** A trigger is generated when the number density of data exceeds a given threshold. Each datum + ** can contribute to only one trigger. Consecutive triggers are separated by at least the dead time. + ** + ** The input vector must be sorted, otherwise the behaviour is undefined. + **/ + class TimeClusterTrigger { + + public: + /** @brief Execution + ** @param dataVec Source data vector + ** @param winSize Size of trigger window + ** @param minNumData Threshold on number of data within the trigger window + ** @param deadTime Minimum time between two triggers + ** @return Vector of trigger times + **/ + std::vector<double> operator()(const std::vector<double>& dataVec, double winSize, int32_t minNumData, + double deadTime) const; + }; + + +} // namespace cbm::algo + +#endif /* CBM_ALGO_TIMECLUSTERTRIGGER_H */