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

paulmthompson / WhiskerToolbox / 17282283436

28 Aug 2025 12:35AM UTC coverage: 66.075% (-0.2%) from 66.266%
17282283436

push

github

web-flow
Merge pull request #104 from paulmthompson/feature/analog-filter

feat: Implement Analog Filter transform

152 of 179 new or added lines in 4 files covered. (84.92%)

25 existing lines in 3 files now uncovered.

26703 of 40413 relevant lines covered (66.08%)

1115.66 hits per line

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

51.85
/src/DataManager/transforms/AnalogTimeSeries/AnalogFilter/analog_filter.cpp
1
#include "analog_filter.hpp"
2
#include "AnalogTimeSeries/Analog_Time_Series.hpp"
3
#include "utils/filter/FilterFactory.hpp"
4
#include "utils/filter/FilterImplementations.hpp"
5
#include "utils/filter/ZeroPhaseDecorator.hpp"
6

7
#include <stdexcept>
8

9
// Helper function to create a filter with a runtime order
10
template<template<int> class Filter, typename... Args>
11
std::unique_ptr<IFilter> create_filter_with_order(int order, Args... args) {
4✔
12
    switch (order) {
4✔
NEW
13
        case 1:
×
NEW
14
            return std::make_unique<Filter<1>>(args...);
×
NEW
15
        case 2:
×
NEW
16
            return std::make_unique<Filter<2>>(args...);
×
NEW
17
        case 3:
×
NEW
18
            return std::make_unique<Filter<3>>(args...);
×
19
        case 4:
4✔
20
            return std::make_unique<Filter<4>>(args...);
4✔
NEW
21
        case 5:
×
NEW
22
            return std::make_unique<Filter<5>>(args...);
×
NEW
23
        case 6:
×
NEW
24
            return std::make_unique<Filter<6>>(args...);
×
NEW
25
        case 7:
×
NEW
26
            return std::make_unique<Filter<7>>(args...);
×
NEW
27
        case 8:
×
NEW
28
            return std::make_unique<Filter<8>>(args...);
×
NEW
29
        default:
×
NEW
30
            throw std::invalid_argument("Unsupported filter order");
×
31
    }
32
}
33

34
std::shared_ptr<AnalogTimeSeries> filter_analog(
4✔
35
        AnalogTimeSeries const * analog_time_series,
36
        AnalogFilterParams const & filterParams,
37
        ProgressCallback progressCallback) {
38
    if (!analog_time_series) {
4✔
39
        throw std::invalid_argument("Input analog time series is null");
×
40
    }
41

42
    progressCallback(0);
4✔
43

44
    if (filterParams.sampling_rate <= 0) {
4✔
NEW
45
        throw std::invalid_argument("Sampling rate must be positive.");
×
46
    }
47

48
    double sampling_rate = filterParams.sampling_rate;
4✔
49
    std::unique_ptr<IFilter> filter;
4✔
50

51
    switch (filterParams.filter_type) {
4✔
52
        case AnalogFilterParams::FilterType::Lowpass:
1✔
53
            filter = create_filter_with_order<ButterworthLowpassFilter>(filterParams.order, filterParams.cutoff_frequency, sampling_rate);
1✔
54
            break;
1✔
55
        case AnalogFilterParams::FilterType::Highpass:
1✔
56
            filter = create_filter_with_order<ButterworthHighpassFilter>(filterParams.order, filterParams.cutoff_frequency, sampling_rate);
1✔
57
            break;
1✔
58
        case AnalogFilterParams::FilterType::Bandpass:
1✔
59
            filter = create_filter_with_order<ButterworthBandpassFilter>(filterParams.order, filterParams.cutoff_frequency, filterParams.cutoff_frequency2, sampling_rate);
1✔
60
            break;
1✔
61
        case AnalogFilterParams::FilterType::Bandstop:
1✔
62
            filter = create_filter_with_order<ButterworthBandstopFilter>(filterParams.order, filterParams.cutoff_frequency, filterParams.cutoff_frequency2, sampling_rate);
1✔
63
            break;
1✔
64
    }
65

66
    if (filterParams.zero_phase) {
4✔
NEW
67
        filter = std::make_unique<ZeroPhaseDecorator>(std::move(filter));
×
68
    }
69

70
    if (!filter) {
4✔
NEW
71
        throw std::runtime_error("Failed to create filter");
×
72
    }
73

74
    auto & data_span = analog_time_series->getAnalogTimeSeries();
4✔
75
    auto time_series = analog_time_series->getTimeSeries();
4✔
76

77
    if (data_span.empty()) {
4✔
78
        throw std::invalid_argument("No data found in time series");
×
79
    }
80

81
    std::vector<float> filtered_data(data_span.begin(), data_span.end());
16✔
82
    std::vector<TimeFrameIndex> filtered_times(time_series.begin(), time_series.end());
16✔
83

84
    std::span<float> data_span_mutable(filtered_data);
4✔
85
    filter->process(data_span_mutable);
4✔
86

87
    progressCallback(100);
4✔
88

89
    return std::make_shared<AnalogTimeSeries>(
90
            std::move(filtered_data),
4✔
91
            std::move(filtered_times));
12✔
92
}
4✔
93

94

95
std::shared_ptr<AnalogTimeSeries> filter_analog(
4✔
96
        AnalogTimeSeries const * analog_time_series,
97
        AnalogFilterParams const & filterParams) {
98
    return filter_analog(analog_time_series, filterParams, [](int) {});
4✔
99
}
100

101
std::string AnalogFilterOperation::getName() const {
2✔
102
    return "Analog Filter";
6✔
103
}
104

105
std::type_index AnalogFilterOperation::getTargetInputTypeIndex() const {
2✔
106
    return typeid(std::shared_ptr<AnalogTimeSeries>);
2✔
107
}
108

109
std::unique_ptr<TransformParametersBase> AnalogFilterOperation::getDefaultParameters() const {
×
NEW
110
    return std::make_unique<AnalogFilterParams>();
×
111
}
112

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

117
DataTypeVariant AnalogFilterOperation::execute(
×
118
        DataTypeVariant const & dataVariant,
119
        TransformParametersBase const * params) {
120
    return execute(dataVariant, params, [](int) {});
×
121
}
122

123
DataTypeVariant AnalogFilterOperation::execute(
×
124
        DataTypeVariant const & dataVariant,
125
        TransformParametersBase const * params,
126
        ProgressCallback progressCallback) {
127
    if (!params) {
×
128
        throw std::invalid_argument("Filter parameters are null");
×
129
    }
130

131
    auto const * filterParams = dynamic_cast<AnalogFilterParams const *>(params);
×
132
    if (!filterParams) {
×
133
        throw std::invalid_argument("Invalid parameter type for filter operation");
×
134
    }
135

136
    auto const * analog_time_series = std::get_if<std::shared_ptr<AnalogTimeSeries>>(&dataVariant);
×
137
    if (!analog_time_series || !*analog_time_series) {
×
138
        throw std::invalid_argument("Invalid input data type or null pointer");
×
139
    }
140

141
    auto filtered_data = filter_analog(analog_time_series->get(), *filterParams, progressCallback);
×
142
    return DataTypeVariant(filtered_data);
×
143
}
×
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