• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

paulmthompson / WhiskerToolbox / 15538997985

09 Jun 2025 04:05PM UTC coverage: 51.194% (+10.2%) from 40.974%
15538997985

push

github

paulmthompson
mac install should include dataviewer library

4609 of 9003 relevant lines covered (51.19%)

783.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

51.95
/src/WhiskerToolbox/DataManager/transforms/AnalogTimeSeries/analog_event_threshold.cpp
1
#include "analog_event_threshold.hpp"
2

3
#include "AnalogTimeSeries/Analog_Time_Series.hpp"
4
#include "DigitalTimeSeries/Digital_Event_Series.hpp"
5

6
#include <iostream>
7
#include <vector>// std::vector
8

9

10
std::shared_ptr<DigitalEventSeries> event_threshold(
14✔
11
        AnalogTimeSeries const * analog_time_series,
12
        ThresholdParams const & thresholdParams) {
13
    // Call the version with a null progress callback
14
    return event_threshold(analog_time_series, thresholdParams, nullptr);
14✔
15
}
16

17
/**
18
 * @brief Detects events in an AnalogTimeSeries based on a threshold, with progress reporting.
19
 *
20
 * This function identifies time points where the analog signal crosses a specified threshold,
21
 * considering a lockout period to prevent multiple detections for a single event.
22
 *
23
 * @param analog_time_series A pointer to the input AnalogTimeSeries data. Must not be null.
24
 * @param thresholdParams A struct containing the threshold value, detection direction (positive, negative, or absolute),
25
 *                        and lockout time (in the same units as the timestamps in analog_time_series).
26
 * @param progressCallback An optional function that can be called to report progress (0-100).
27
 *                         If nullptr, progress is not reported.
28
 * @return A std::shared_ptr<DigitalEventSeries> containing the timestamps of detected events.
29
 *         Returns an empty DigitalEventSeries if analog_time_series is null, has no data,
30
 *         or if no events are detected.
31
 */
32
std::shared_ptr<DigitalEventSeries> event_threshold(
19✔
33
        AnalogTimeSeries const * analog_time_series,
34
        ThresholdParams const & thresholdParams,
35
        ProgressCallback progressCallback) {
36
    auto event_series = std::make_shared<DigitalEventSeries>();
19✔
37

38
    if (!analog_time_series) {
19✔
39
        std::cerr << "Error: analog_time_series is null." << std::endl;
2✔
40
        return event_series;
2✔
41
    }
42

43
    float const threshold = static_cast<float>(thresholdParams.thresholdValue);
17✔
44
    std::vector<float> events;
17✔
45

46
    auto const & timestamps = analog_time_series->getTimeSeries();
17✔
47
    auto const & values = analog_time_series->getAnalogTimeSeries();
17✔
48

49
    if (timestamps.empty()) {
17✔
50
        if (progressCallback) {
2✔
51
            progressCallback(100);// No data to process, so 100% complete.
1✔
52
        }
53
        return event_series;
2✔
54
    }
55

56
    double last_ts = -thresholdParams.lockoutTime - 1.0;// Initialize to allow first event
15✔
57
    size_t const total_samples = timestamps.size();
15✔
58

59
    for (size_t i = 0; i < total_samples; ++i) {
87✔
60
        bool event_detected = false;
72✔
61
        if (thresholdParams.direction == ThresholdParams::ThresholdDirection::POSITIVE) {
72✔
62
            if (values[i] > threshold) {
46✔
63
                event_detected = true;
28✔
64
            }
65
        } else if (thresholdParams.direction == ThresholdParams::ThresholdDirection::NEGATIVE) {
26✔
66
            if (values[i] < threshold) {
14✔
67
                event_detected = true;
6✔
68
            }
69
        } else if (thresholdParams.direction == ThresholdParams::ThresholdDirection::ABSOLUTE) {
12✔
70
            if (std::abs(values[i]) > threshold) {
12✔
71
                event_detected = true;
6✔
72
            }
73
        } else {
74
            std::cerr << "Unknown threshold direction!" << std::endl;
×
75
            if (progressCallback) {
×
76
                progressCallback(100);// Error case, consider it done.
×
77
            }
78
            return event_series;// Return empty series on error
×
79
        }
80

81
        if (event_detected) {
72✔
82
            // Check if the event is not too close to the last one
83
            if (static_cast<double>(timestamps[i]) - last_ts >= thresholdParams.lockoutTime) {
40✔
84
                events.push_back(static_cast<float>(timestamps[i]));
32✔
85
                last_ts = static_cast<double>(timestamps[i]);
32✔
86
            }
87
        }
88

89
        if (progressCallback && total_samples > 0) {
72✔
90
            int const current_progress = static_cast<int>((static_cast<double>(i + 1) / static_cast<double>(total_samples)) * 100.0);
16✔
91
            progressCallback(current_progress);
16✔
92
        }
93
    }
94

95
    event_series->setData(events);
15✔
96
    if (progressCallback) {
15✔
97
        progressCallback(100);// Ensure 100% is reported at the end.
3✔
98
    }
99
    return event_series;
15✔
100
}
17✔
101

102
///////////////////////////////////////////////////////////////////////////////
103

104
std::string EventThresholdOperation::getName() const {
×
105
    return "Threshold Event Detection";
×
106
}
107

108
std::type_index EventThresholdOperation::getTargetInputTypeIndex() const {
×
109
    return typeid(std::shared_ptr<AnalogTimeSeries>);
×
110
}
111

112
bool EventThresholdOperation::canApply(DataTypeVariant const & dataVariant) const {
×
113
    if (!std::holds_alternative<std::shared_ptr<AnalogTimeSeries>>(dataVariant)) {
×
114
        return false;
×
115
    }
116

117
    auto const * ptr_ptr = std::get_if<std::shared_ptr<AnalogTimeSeries>>(&dataVariant);
×
118

119
    // Return true only if get_if succeeded AND the contained shared_ptr is not null.
120
    return ptr_ptr && *ptr_ptr;
×
121
}
122

123
DataTypeVariant EventThresholdOperation::execute(DataTypeVariant const & dataVariant, TransformParametersBase const * transformParameters) {
×
124
    // Call the version with a null progress callback
125
    return execute(dataVariant, transformParameters, nullptr);
×
126
}
127

128
/**
129
 * @brief Executes the event thresholding operation with progress reporting.
130
 *
131
 * This method retrieves an AnalogTimeSeries from the input dataVariant,
132
 * applies the event thresholding logic using the provided parameters,
133
 * and reports progress via the progressCallback.
134
 *
135
 * @param dataVariant A variant holding a std::shared_ptr<AnalogTimeSeries>.
136
 *                    The operation will fail if the variant holds a different type,
137
 *                    or if the shared_ptr is null.
138
 * @param transformParameters A pointer to TransformParametersBase, which is expected
139
 *                            to be dynamically castable to ThresholdParams. If null or
140
 *                            of an incorrect type, default ThresholdParams will be used
141
 *                            (if appropriate for the operation) or an error may occur.
142
 * @param progressCallback An optional function to report progress (0-100).
143
 *                         If nullptr, progress is not reported.
144
 * @return A DataTypeVariant containing a std::shared_ptr<DigitalEventSeries> with the
145
 *         detected event times on success. Returns an empty DataTypeVariant on failure
146
 *         (e.g., type mismatch, null input data, or if the underlying
147
 *         event_threshold function fails).
148
 */
149
DataTypeVariant EventThresholdOperation::execute(DataTypeVariant const & dataVariant,
×
150
                                                 TransformParametersBase const * transformParameters,
151
                                                 ProgressCallback progressCallback) {
152

153
    auto const * ptr_ptr = std::get_if<std::shared_ptr<AnalogTimeSeries>>(&dataVariant);
×
154

155
    if (!ptr_ptr || !(*ptr_ptr)) {
×
156
        std::cerr << "EventThresholdOperation::execute called with incompatible variant type or null data." << std::endl;
×
157
        if (progressCallback) progressCallback(100);// Indicate completion even on error
×
158
        return {};                                  // Return empty
×
159
    }
160

161
    AnalogTimeSeries const * analog_raw_ptr = (*ptr_ptr).get();
×
162

163
    ThresholdParams currentParams;// Default parameters
×
164

165
    if (transformParameters != nullptr) {
×
166
        auto const * specificParams = dynamic_cast<ThresholdParams const *>(transformParameters);
×
167

168
        if (specificParams) {
×
169
            currentParams = *specificParams;
×
170
            // std::cout << "Using parameters provided by UI." << std::endl; // Debug, consider removing
171
        } else {
172
            std::cerr << "Warning: EventThresholdOperation received incompatible parameter type (dynamic_cast failed)! Using default parameters." << std::endl;
×
173
            // Fall through to use the default 'currentParams'
174
        }
175
    } else {
176
        // std::cout << "ThresholdOperation received null parameters. Using default parameters." << std::endl; // Debug, consider removing
177
        // Fall through to use the default 'currentParams'
178
    }
179

180
    std::shared_ptr<DigitalEventSeries> result_ts = event_threshold(analog_raw_ptr,
×
181
                                                                    currentParams,
182
                                                                    progressCallback);
×
183

184
    if (!result_ts) {
×
185
        std::cerr << "EventThresholdOperation::execute: 'event_threshold' failed to produce a result." << std::endl;
×
186
        if (progressCallback) progressCallback(100);// Indicate completion even on error
×
187
        return {};                                  // Return empty
×
188
    }
189

190
    // std::cout << "EventThresholdOperation executed successfully using variant input." << std::endl; // Debug, consider removing
191
    if (progressCallback) progressCallback(100);// Ensure 100% is reported at the end.
×
192
    return result_ts;
×
193
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc