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

paulmthompson / WhiskerToolbox / 14803779026

02 May 2025 09:35PM UTC coverage: 15.881% (-0.4%) from 16.234%
14803779026

push

github

paulmthompson
working hilbert transform with armadillo

1 of 50 new or added lines in 3 files covered. (2.0%)

2 existing lines in 1 file now uncovered.

320 of 2015 relevant lines covered (15.88%)

1.59 hits per line

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

0.0
/src/WhiskerToolbox/DataManager/transforms/AnalogTimeSeries/analog_hilbert_phase.cpp
1

2
#include "analog_hilbert_phase.hpp"
3

4
#include "AnalogTimeSeries/Analog_Time_Series.hpp"
5
#include "utils/armadillo_wrap/analog_armadillo.hpp"
6

7
#include <armadillo>
8

9
#include <complex>
10

11
std::shared_ptr<AnalogTimeSeries> hilbert_phase(
×
12
        AnalogTimeSeries const * analog_time_series,
13
        HilbertPhaseParams const & phaseParams) {
14
    auto phase_series = std::make_shared<AnalogTimeSeries>();
×
15

16
    // Get input data
NEW
17
    auto const & timestamps = analog_time_series->getTimeSeries(); // Copy because we will use these to construct output
×
NEW
18
    auto const & values = analog_time_series->getAnalogTimeSeries();
×
NEW
19
    auto output_timestamps = std::vector<size_t>(timestamps.back());
×
NEW
20
    std::iota(output_timestamps.begin(), output_timestamps.end(), 0);
×
21

NEW
22
    if (timestamps.empty()) {
×
NEW
23
        return phase_series;
×
24
    }
25

26
    // Convert to arma::vec for processing
NEW
27
    auto signal = convertAnalogTimeSeriesToMlpackArray(analog_time_series, output_timestamps);
×
NEW
28
    signal.replace(arma::datum::nan, 0.0);
×
29

30
    // Calculate sampling rate from timestamps
NEW
31
    double dt = 0;
×
NEW
32
    if (timestamps.size() > 1) {
×
NEW
33
        dt = (timestamps[timestamps.size()-1] - timestamps[0]) / (timestamps.size() - 1);
×
34
    }
NEW
35
    double Fs = 1.0 / dt;
×
36

37
    // Bandpass filter design
38
    // Convert Hz to normalized frequency (0 to 1, where 1 is Nyquist frequency)
NEW
39
    double low_norm = phaseParams.lowFrequency / (Fs/2.0);
×
NEW
40
    double high_norm = phaseParams.highFrequency / (Fs/2.0);
×
41

42
    // Check if frequencies are valid
NEW
43
    if (low_norm >= 1.0 || high_norm >= 1.0 || low_norm <= 0 || high_norm <= 0) {
×
NEW
44
        std::cerr << "Invalid cutoff frequencies for bandpass filter" << std::endl;
×
45
        //return phase_series;
46
    }
47

48
    // Use Armadillo's built-in filter functions
49
    // For simplicity, using a basic butterworth filter design
NEW
50
    arma::vec b, a;
×
51

52
    // Design bandpass filter (4th order Butterworth)
NEW
53
    arma::vec filtered_signal = signal.as_col(); // Placeholder for filtered signal
×
54

55
    // Perform FFT
NEW
56
    auto X = arma::fft(signal).eval();
×
57

58
    // Set negative frequencies to zero
NEW
59
    int const halfway = 1 + X.n_elem / 2;
×
NEW
60
    for (int i = halfway; i < X.n_elem; i++) {
×
NEW
61
        X(i) = std::complex<double>(0, 0);
×
62
    }
63

64
    // Compute inverse FFT to get the analytic signal
NEW
65
    auto analytic_signal = arma::ifft(X).eval();
×
66

67
    // Extract phase
NEW
68
    arma::vec phase(analytic_signal.n_elem);
×
NEW
69
    for (int i = 0; i < analytic_signal.n_elem; i++) {
×
NEW
70
        phase(i) = std::arg(analytic_signal(i));
×
71
    }
72

73
    // Convert back to standard vector and set in the output time series
NEW
74
    auto phase_vec = arma::conv_to<std::vector<float>>::from(phase);
×
NEW
75
    phase_series->setData(phase_vec, output_timestamps);
×
76

NEW
77
    std::cout << "Total size of phase is " << phase_vec.size() << std::endl;
×
NEW
78
    std::cout << "Max value is " << phase_series->getMaxValue() << std::endl;
×
NEW
79
    std::cout << "Min value is " << phase_series->getMinValue() << std::endl;
×
80

UNCOV
81
    return phase_series;
×
UNCOV
82
}
×
83

84
std::string HilbertPhaseOperation::getName() const {
×
85
    return "Hilbert Phase";
×
86
}
87

88
std::type_index HilbertPhaseOperation::getTargetInputTypeIndex() const {
×
89
    return typeid(std::shared_ptr<AnalogTimeSeries>);
×
90
}
91

92
bool HilbertPhaseOperation::canApply(DataTypeVariant const & dataVariant) const {
×
93
    if (!std::holds_alternative<std::shared_ptr<AnalogTimeSeries>>(dataVariant)) {
×
94
        return false;
×
95
    }
96

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

99
    // Return true only if get_if succeeded AND the contained shared_ptr is not null.
100
    return ptr_ptr && *ptr_ptr;
×
101
}
102

103
DataTypeVariant HilbertPhaseOperation::execute(DataTypeVariant const & dataVariant, TransformParametersBase const * transformParameters) {
×
104

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

107
    if (!ptr_ptr || !(*ptr_ptr)) {
×
108
        std::cerr << "HilbertPhaseOperation::execute called with incompatible variant type or null data." << std::endl;
×
109
        return {};// Return empty
×
110
    }
111

112
    AnalogTimeSeries const * analog_raw_ptr = (*ptr_ptr).get();
×
113

114
    HilbertPhaseParams currentParams;
×
115

116
    if (transformParameters != nullptr) {
×
117
        HilbertPhaseParams const * specificParams = dynamic_cast<HilbertPhaseParams const *>(transformParameters);
×
118

119
        if (specificParams) {
×
120
            currentParams = *specificParams;
×
121
            std::cout << "Using parameters provided by UI." << std::endl;
×
122
        } else {
NEW
123
            std::cerr << "Warning: HilbertPhaseOperation received incompatible parameter type (dynamic_cast failed)! Using default parameters." << std::endl;
×
124
        }
125
    } else {
126
        // No parameter object was provided (nullptr). This might be expected if the
127
        // operation can run with defaults or was called programmatically.
128
        std::cout << "HilbertPhaseOperation received null parameters. Using default parameters." << std::endl;
×
129
    }
130

131
    std::shared_ptr<AnalogTimeSeries> result = hilbert_phase(analog_raw_ptr,
×
132
                                                             currentParams);
×
133

134
    if (!result) {
×
135
        std::cerr << "HilbertPhaseOperation::execute: 'calculate_intervals' failed to produce a result." << std::endl;
×
136
        return {};// Return empty
×
137
    }
138

139
    std::cout << "HilbertPhaseOperation executed successfully using variant input." << std::endl;
×
140
    return result;
×
141
}
×
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