• 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

0.0
/src/WhiskerToolbox/DataManager/transforms/AnalogTimeSeries/analog_interval_threshold.cpp
1
#include "analog_interval_threshold.hpp"
2

3
#include "AnalogTimeSeries/Analog_Time_Series.hpp"
4
#include "DigitalTimeSeries/Digital_Interval_Series.hpp"
5
#include "DigitalTimeSeries/interval_data.hpp"
6

7
#include <cmath>
8
#include <iostream>
9
#include <vector>
10

11

12
std::shared_ptr<DigitalIntervalSeries> interval_threshold(
×
13
        AnalogTimeSeries const * analog_time_series,
14
        IntervalThresholdParams const & thresholdParams) {
15
    return interval_threshold(analog_time_series, thresholdParams, [](int) {});
×
16
}
17

18
std::shared_ptr<DigitalIntervalSeries> interval_threshold(
×
19
        AnalogTimeSeries const * analog_time_series,
20
        IntervalThresholdParams const & thresholdParams,
21
        ProgressCallback progressCallback) {
22
    auto interval_series = std::make_shared<DigitalIntervalSeries>();
×
23

24
    // Input validation
25
    if (!analog_time_series) {
×
26
        std::cerr << "interval_threshold: Input AnalogTimeSeries is null" << std::endl;
×
27
        return interval_series;
×
28
    }
29

30
    auto const & timestamps = analog_time_series->getTimeSeries();
×
31
    auto const & values = analog_time_series->getAnalogTimeSeries();
×
32

33
    if (timestamps.empty()) {
×
34
        std::cerr << "interval_threshold: Input time series is empty" << std::endl;
×
35
        return interval_series;
×
36
    }
37

38
    if (progressCallback) {
×
39
        progressCallback(10);
×
40
    }
41

42
    auto const threshold = static_cast<float>(thresholdParams.thresholdValue);
×
43
    double const minDuration = thresholdParams.minDuration;
×
44
    std::vector<Interval> intervals;
×
45

46
    // Variables to track interval state
47
    bool in_interval = false;
×
48
    int64_t interval_start = 0;
×
49
    double last_interval_end = -thresholdParams.lockoutTime - 1.0;// Initialize to allow first interval
×
50

51
    auto addIntervalIfValid = [&intervals, minDuration](int64_t start, int64_t end) {
×
52
        // Check if the interval meets the minimum duration requirement
53
        if (static_cast<double>(end - start + 1) >= minDuration) {
×
54
            intervals.push_back({start, end});
×
55
        }
56
    };
×
57

58
    if (progressCallback) {
×
59
        progressCallback(20);
×
60
    }
61

62
    // Lambda to check if value meets threshold criteria
63
    auto meetsThreshold = [&thresholdParams, threshold](float value) -> bool {
×
64
        switch (thresholdParams.direction) {
×
65
            case IntervalThresholdParams::ThresholdDirection::POSITIVE:
×
66
                return value > threshold;
×
67
            case IntervalThresholdParams::ThresholdDirection::NEGATIVE:
×
68
                return value < threshold;
×
69
            case IntervalThresholdParams::ThresholdDirection::ABSOLUTE:
×
70
                return std::abs(value) > threshold;
×
71
            default:
×
72
                return false;
×
73
        }
74
    };
×
75

76
    // Process the time series
77
    size_t const total_samples = timestamps.size();
×
78
    for (size_t i = 0; i < total_samples; ++i) {
×
79
        if (progressCallback && i % 1000 == 0) {
×
80
            int const progress = 20 + static_cast<int>((i * 70) / total_samples);
×
81
            progressCallback(progress);
×
82
        }
83

84
        bool const threshold_met = meetsThreshold(values[i]);
×
85

86
        if (threshold_met && !in_interval) {
×
87
            // Start of a new interval
88
            if (static_cast<double>(timestamps[i] - last_interval_end) >= thresholdParams.lockoutTime) {
×
89
                interval_start = static_cast<int64_t>(timestamps[i]);
×
90
                in_interval = true;
×
91
            }
92
        } else if (!threshold_met && in_interval) {
×
93
            // End of current interval
94
            int64_t const interval_end = (i > 0) ? static_cast<int64_t>(timestamps[i - 1]) : interval_start;
×
95
            addIntervalIfValid(interval_start, interval_end);
×
96
            last_interval_end = static_cast<double>(interval_end);
×
97
            in_interval = false;
×
98
        }
99
    }
100

101
    // Handle case where signal still meets threshold at the end
102
    if (in_interval) {
×
103
        addIntervalIfValid(interval_start, static_cast<int64_t>(timestamps.back()));
×
104
    }
105

106
    if (progressCallback) {
×
107
        progressCallback(90);
×
108
    }
109

110
    interval_series->setData(intervals);
×
111

112
    if (progressCallback) {
×
113
        progressCallback(100);
×
114
    }
115

116
    return interval_series;
×
117
}
×
118

119
///////////////////////////////////////////////////////////////////////////////
120

121
std::string IntervalThresholdOperation::getName() const {
×
122
    return "Threshold Interval Detection";
×
123
}
124

125
std::type_index IntervalThresholdOperation::getTargetInputTypeIndex() const {
×
126
    return typeid(std::shared_ptr<AnalogTimeSeries>);
×
127
}
128

129
bool IntervalThresholdOperation::canApply(DataTypeVariant const & dataVariant) const {
×
130
    if (!std::holds_alternative<std::shared_ptr<AnalogTimeSeries>>(dataVariant)) {
×
131
        return false;
×
132
    }
133

134
    auto const * ptr_ptr = std::get_if<std::shared_ptr<AnalogTimeSeries>>(&dataVariant);
×
135
    return ptr_ptr && *ptr_ptr;
×
136
}
137

138
DataTypeVariant IntervalThresholdOperation::execute(
×
139
        DataTypeVariant const & dataVariant,
140
        TransformParametersBase const * transformParameters) {
141
    return execute(dataVariant, transformParameters, nullptr);
×
142
}
143

144
DataTypeVariant IntervalThresholdOperation::execute(
×
145
        DataTypeVariant const & dataVariant,
146
        TransformParametersBase const * transformParameters,
147
        ProgressCallback progressCallback) {
148

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

151
    if (!ptr_ptr || !(*ptr_ptr)) {
×
152
        std::cerr << "IntervalThresholdOperation::execute: Invalid input data variant" << std::endl;
×
153
        return {};
×
154
    }
155

156
    AnalogTimeSeries const * analog_raw_ptr = (*ptr_ptr).get();
×
157

158
    IntervalThresholdParams currentParams;
×
159

160
    if (transformParameters != nullptr) {
×
161
        auto const * specificParams =
162
                dynamic_cast<IntervalThresholdParams const *>(transformParameters);
×
163

164
        if (specificParams) {
×
165
            currentParams = *specificParams;
×
166
        } else {
167
            std::cerr << "IntervalThresholdOperation::execute: Incompatible parameter type, using defaults" << std::endl;
×
168
        }
169
    }
170

171
    std::shared_ptr<DigitalIntervalSeries> result = interval_threshold(
×
172
            analog_raw_ptr, currentParams, progressCallback);
×
173

174
    if (!result) {
×
175
        std::cerr << "IntervalThresholdOperation::execute: Interval detection failed" << std::endl;
×
176
        return {};
×
177
    }
178

179
    return result;
×
180
}
×
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