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

paulmthompson / WhiskerToolbox / 17335530769

29 Aug 2025 09:57PM UTC coverage: 66.478% (+0.3%) from 66.194%
17335530769

push

github

paulmthompson
update testing for analog interval threshold

113 of 116 new or added lines in 3 files covered. (97.41%)

103 existing lines in 6 files now uncovered.

27064 of 40711 relevant lines covered (66.48%)

1114.57 hits per line

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

85.37
/src/DataManager/transforms/AnalogTimeSeries/Analog_Event_Threshold/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(
23✔
33
        AnalogTimeSeries const * analog_time_series,
34
        ThresholdParams const & thresholdParams,
35
        ProgressCallback progressCallback) {
36
    auto event_series = std::make_shared<DigitalEventSeries>();
23✔
37

38
    if (!analog_time_series) {
23✔
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);
21✔
44
    std::vector<float> events;
21✔
45

46
    auto const & values = analog_time_series->getAnalogTimeSeries();
21✔
47
    auto const & time_storage = analog_time_series->getTimeStorage();
21✔
48

49
    if (values.empty()) {
21✔
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
19✔
57
    size_t const total_samples = values.size();
19✔
58

59
    for (size_t i = 0; i < total_samples; ++i) {
114✔
60
        bool event_detected = false;
95✔
61
        if (thresholdParams.direction == ThresholdParams::ThresholdDirection::POSITIVE) {
95✔
62
            if (values[i] > threshold) {
69✔
63
                event_detected = true;
39✔
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) {
95✔
82

83
            auto timestamp = std::visit([i](auto const & storage) -> TimeFrameIndex {
153✔
84
                return storage.getTimeFrameIndexAtDataArrayIndex(DataArrayIndex(i));
102✔
85
            }, time_storage);
51✔
86

87
            // Check if the event is not too close to the last one
88
            if (static_cast<double>(timestamp.getValue()) - last_ts >= thresholdParams.lockoutTime) {
51✔
89
                events.push_back(static_cast<float>(timestamp.getValue()));
42✔
90
                last_ts = static_cast<double>(timestamp.getValue());
42✔
91
            }
92
        }
93

94
        if (progressCallback && total_samples > 0) {
95✔
95
            int const current_progress = static_cast<int>((static_cast<double>(i + 1) / static_cast<double>(total_samples)) * 100.0);
34✔
96
            progressCallback(current_progress);
34✔
97
        }
98
    }
99

100
    event_series->setData(events);
19✔
101
    if (progressCallback) {
19✔
102
        progressCallback(100);// Ensure 100% is reported at the end.
6✔
103
    }
104
    return event_series;
19✔
105
}
21✔
106

107
///////////////////////////////////////////////////////////////////////////////
108

109
std::string EventThresholdOperation::getName() const {
24✔
110
    return "Threshold Event Detection";
72✔
111
}
112

113
std::type_index EventThresholdOperation::getTargetInputTypeIndex() const {
24✔
114
    return typeid(std::shared_ptr<AnalogTimeSeries>);
24✔
115
}
116

117
bool EventThresholdOperation::canApply(DataTypeVariant const & dataVariant) const {
4✔
118
    if (!std::holds_alternative<std::shared_ptr<AnalogTimeSeries>>(dataVariant)) {
4✔
119
        return false;
×
120
    }
121

122
    auto const * ptr_ptr = std::get_if<std::shared_ptr<AnalogTimeSeries>>(&dataVariant);
4✔
123

124
    // Return true only if get_if succeeded AND the contained shared_ptr is not null.
125
    return ptr_ptr && *ptr_ptr;
4✔
126
}
127

128
std::unique_ptr<TransformParametersBase> EventThresholdOperation::getDefaultParameters() const {
4✔
129
    return std::make_unique<ThresholdParams>();
4✔
130
}
131

132
DataTypeVariant EventThresholdOperation::execute(DataTypeVariant const & dataVariant, TransformParametersBase const * transformParameters) {
1✔
133
    // Call the version with a null progress callback
134
    return execute(dataVariant, transformParameters, nullptr);
1✔
135
}
136

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

162
    auto const * ptr_ptr = std::get_if<std::shared_ptr<AnalogTimeSeries>>(&dataVariant);
4✔
163

164
    if (!ptr_ptr || !(*ptr_ptr)) {
4✔
UNCOV
165
        std::cerr << "EventThresholdOperation::execute called with incompatible variant type or null data." << std::endl;
×
UNCOV
166
        if (progressCallback) progressCallback(100);// Indicate completion even on error
×
UNCOV
167
        return {};                                  // Return empty
×
168
    }
169

170
    AnalogTimeSeries const * analog_raw_ptr = (*ptr_ptr).get();
4✔
171

172
    ThresholdParams currentParams;// Default parameters
4✔
173

174
    if (transformParameters != nullptr) {
4✔
175
        auto const * specificParams = dynamic_cast<ThresholdParams const *>(transformParameters);
4✔
176

177
        if (specificParams) {
4✔
178
            currentParams = *specificParams;
4✔
179
            // std::cout << "Using parameters provided by UI." << std::endl; // Debug, consider removing
180
        } else {
UNCOV
181
            std::cerr << "Warning: EventThresholdOperation received incompatible parameter type (dynamic_cast failed)! Using default parameters." << std::endl;
×
182
            // Fall through to use the default 'currentParams'
183
        }
184
    } else {
185
        // std::cout << "ThresholdOperation received null parameters. Using default parameters." << std::endl; // Debug, consider removing
186
        // Fall through to use the default 'currentParams'
187
    }
188

189
    std::shared_ptr<DigitalEventSeries> result_ts = event_threshold(analog_raw_ptr,
4✔
190
                                                                    currentParams,
191
                                                                    progressCallback);
4✔
192

193
    if (!result_ts) {
4✔
UNCOV
194
        std::cerr << "EventThresholdOperation::execute: 'event_threshold' failed to produce a result." << std::endl;
×
UNCOV
195
        if (progressCallback) progressCallback(100);// Indicate completion even on error
×
UNCOV
196
        return {};                                  // Return empty
×
197
    }
198

199
    // std::cout << "EventThresholdOperation executed successfully using variant input." << std::endl; // Debug, consider removing
200
    if (progressCallback) progressCallback(100);// Ensure 100% is reported at the end.
4✔
201
    return result_ts;
4✔
202
}
4✔
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