MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
EnergyAnalyzer.hpp
Go to the documentation of this file.
1#pragma once
2
5
7#include <Eigen/Dense>
8
9#include "AnalysisHelper.hpp"
10
11/**
12 * @file EnergyAnalyzer.hpp
13 * @brief Span-based energy analysis for digital signals in Maya Flux
14 *
15 * Defines the EnergyAnalyzer using the new UniversalAnalyzer framework with
16 * zero-copy span processing and automatic structure handling via OperationHelper.
17 * This analyzer extracts energy-related features from digital signals with multiple
18 * computation methods and flexible output configurations.
19 *
20 * Key Features:
21 * - **Zero-copy processing:** Uses spans for maximum efficiency
22 * - **Template-flexible I/O:** Instance defines input/output types at construction
23 * - **Multiple energy methods:** RMS, peak, spectral, zero-crossing, harmonic, power, dynamic range
24 * - **Parallel processing:** Utilizes std::execution for performance
25 * - **Energy classification:** Maps values to qualitative levels (silent, quiet, etc.)
26 * - **Window-based analysis:** Configurable window size and hop size
27 * - **Automatic data handling:** OperationHelper manages all extraction/conversion
28 */
29
30namespace MayaFlux::Yantra {
31
32/**
33 * @enum EnergyMethod
34 * @brief Supported energy computation methods
35 */
36enum class EnergyMethod : uint8_t {
37 RMS, ///< Root Mean Square energy
38 PEAK, ///< Peak amplitude
39 SPECTRAL, ///< Spectral energy (FFT-based)
40 ZERO_CROSSING, ///< Zero-crossing rate
41 HARMONIC, ///< Harmonic energy (low-frequency content)
42 POWER, ///< Power (sum of squares)
43 DYNAMIC_RANGE ///< Dynamic range (dB)
44};
45
46/**
47 * @enum EnergyLevel
48 * @brief Qualitative classification of energy values
49 */
50enum class EnergyLevel : uint8_t {
51 SILENT,
52 QUIET,
54 LOUD,
55 PEAK
56};
57
58struct MAYAFLUX_API ChannelEnergy {
59 std::vector<double> energy_values;
60 double mean_energy {};
61 double max_energy {};
62 double min_energy {};
63 double variance {};
64
65 std::vector<EnergyLevel> classifications;
66 std::array<int, 5> level_counts {}; // [SILENT, QUIET, MODERATE, LOUD, PEAK]
67 std::vector<std::pair<size_t, size_t>> window_positions;
68
69 // Positions of detected energy events (e.g., peaks, zero crossings, flux)
70 std::vector<size_t> event_positions;
71};
72
73/**
74 * @struct EnergyAnalysis
75 * @brief Analysis result structure for energy analysis
76 */
77struct MAYAFLUX_API EnergyAnalysis {
78 std::vector<ChannelEnergy> channels;
79
80 EnergyMethod method_used {};
81 uint32_t window_size {};
82 uint32_t hop_size {};
83};
84
85/**
86 * @class EnergyAnalyzer
87 * @brief High-performance energy analyzer with zero-copy processing
88 *
89 * The EnergyAnalyzer provides comprehensive energy analysis capabilities for
90 * digital signals using span-based processing for maximum efficiency.
91 * All data extraction and conversion is handled automatically by OperationHelper.
92 *
93 * Example usage:
94 * ```cpp
95 * // DataVariant -> VectorXd analyzer
96 * auto energy_analyzer = std::make_shared<EnergyAnalyzer<Kakshya::DataVariant, Eigen::VectorXd>>();
97 *
98 * // User-facing analysis
99 * auto analysis = energy_analyzer->analyze_data(audio_data);
100 * auto energy_result = safe_any_cast<EnergyAnalysis>(analysis);
101 *
102 * // Pipeline usage
103 * auto pipeline_output = energy_analyzer->apply_operation(IO{audio_data});
104 * ```
105 */
106template <ComputeData InputType = std::vector<Kakshya::DataVariant>, ComputeData OutputType = Eigen::VectorXd>
107class MAYAFLUX_API EnergyAnalyzer : public UniversalAnalyzer<InputType, OutputType> {
108public:
112
113 /**
114 * @brief Construct EnergyAnalyzer with configurable window parameters
115 * @param window_size Size of analysis window in samples (default: 512)
116 * @param hop_size Step size between windows in samples (default: 256)
117 */
118 explicit EnergyAnalyzer(uint32_t window_size = 256, uint32_t hop_size = 128)
119 : m_window_size(window_size)
120 , m_hop_size(hop_size)
121 {
122 validate_window_parameters();
123 }
124
125 /**
126 * @brief Type-safe energy analysis method
127 * @param data Input data
128 * @return EnergyAnalysis directly
129 */
130 EnergyAnalysis analyze_energy(const InputType& data)
131 {
132 auto result = this->analyze_data(data);
133 return safe_any_cast_or_throw<EnergyAnalysis>(result);
134 }
135
136 /**
137 * @brief Get last energy analysis result (type-safe)
138 * @return EnergyAnalysis from last operation
139 */
141 {
142 return safe_any_cast_or_throw<EnergyAnalysis>(this->get_current_analysis());
143 }
144
145 /**
146 * @brief Get analysis type category
147 * @return AnalysisType::FEATURE (energy is a feature extraction operation)
148 */
149 [[nodiscard]] AnalysisType get_analysis_type() const override
150 {
151 return AnalysisType::FEATURE;
152 }
153
154 /**
155 * @brief Get available analysis methods
156 * @return Vector of supported energy method names
157 */
158 [[nodiscard]] std::vector<std::string> get_available_methods() const override
159 {
160 return Utils::get_enum_names_lowercase<EnergyMethod>();
161 }
162
163 /**
164 * @brief Check if a specific method is supported
165 * @param method Method name to check
166 * @return True if method is supported
167 */
168 [[nodiscard]] bool supports_method(const std::string& method) const override
169 {
170 return std::find_if(get_available_methods().begin(), get_available_methods().end(),
171 [&method](const std::string& m) {
172 return std::equal(method.begin(), method.end(), m.begin(), m.end(),
173 [](char a, char b) { return std::tolower(a) == std::tolower(b); });
174 })
175 != get_available_methods().end();
176 }
177
178 /**
179 * @brief Set energy computation method
180 */
181 void set_energy_method(EnergyMethod method) { m_method = method; }
182
183 /**
184 * @brief Get current energy computation method
185 */
186 [[nodiscard]] EnergyMethod get_energy_method() const { return m_method; }
187
188 /**
189 * @brief Set window parameters for analysis
190 * @param window_size Window size in samples
191 * @param hop_size Hop size in samples
192 */
193 void set_window_parameters(uint32_t window_size, uint32_t hop_size)
194 {
195 m_window_size = window_size;
196 m_hop_size = hop_size;
197 validate_window_parameters();
198 }
199
200 /**
201 * @brief Set energy level classification thresholds
202 * @param silent Threshold for silent level
203 * @param quiet Threshold for quiet level
204 * @param moderate Threshold for moderate level
205 * @param loud Threshold for loud level
206 */
207 void set_energy_thresholds(double silent, double quiet, double moderate, double loud)
208 {
209 if (silent >= quiet || quiet >= moderate || moderate >= loud) {
210 throw std::invalid_argument("Energy thresholds must be in ascending order");
211 }
212 m_silent_threshold = silent;
213 m_quiet_threshold = quiet;
214 m_moderate_threshold = moderate;
215 m_loud_threshold = loud;
216 }
217
218 /**
219 * @brief Enable or disable energy level classification
220 * @param enabled True to enable classification
221 */
222 void enable_classification(bool enabled) { m_classification_enabled = enabled; }
223
224 /**
225 * @brief Classify energy value into qualitative level
226 * @param energy Energy value to classify
227 * @return EnergyLevel classification
228 */
229 [[nodiscard]] EnergyLevel classify_energy_level(double energy) const
230 {
231 if (energy <= m_silent_threshold)
232 return EnergyLevel::SILENT;
233 if (energy <= m_quiet_threshold)
234 return EnergyLevel::QUIET;
235 if (energy <= m_moderate_threshold)
236 return EnergyLevel::MODERATE;
237 if (energy <= m_loud_threshold)
238 return EnergyLevel::LOUD;
239 return EnergyLevel::PEAK;
240 }
241
242 /**
243 * @brief Get count of windows in a specific energy level for a channel
244 * @param channel ChannelEnergy result
245 * @param level EnergyLevel to query
246 * @return Count of windows in that level
247 */
248 [[nodiscard]]
249 int get_level_count(const ChannelEnergy& channel, EnergyLevel level)
250 {
251 return channel.level_counts[static_cast<size_t>(level)];
252 }
253
254 /**
255 * @brief Convert energy method enum to string
256 * @param method EnergyMethod value
257 * @return String representation
258 */
259 static std::string method_to_string(EnergyMethod method)
260 {
261 return Utils::enum_to_lowercase_string(method);
262 }
263
264 /**
265 * @brief Convert string to energy method enum
266 * @param str String representation
267 * @return EnergyMethod value
268 */
269 static EnergyMethod string_to_method(const std::string& str)
270 {
271 if (str == "default")
272 return EnergyMethod::RMS;
273 return Utils::string_to_enum_or_throw_case_insensitive<EnergyMethod>(str, "EnergyMethod");
274 }
275
276 /**
277 * @brief Convert energy level enum to string
278 * @param level EnergyLevel value
279 * @return String representation
280 */
281 static std::string energy_level_to_string(EnergyLevel level)
282 {
283 return Utils::enum_to_lowercase_string(level);
284 }
285
286protected:
287 /**
288 * @brief Get analyzer name
289 * @return "EnergyAnalyzer"
290 */
291 [[nodiscard]] std::string get_analyzer_name() const override
292 {
293 return "EnergyAnalyzer";
294 }
295
296 /**
297 * @brief Core analysis implementation - creates analysis result AND pipeline output
298 * @param input Input data wrapped in IO container
299 * @return Pipeline output (data flow for chaining operations)
300 */
302 {
303 try {
304 auto [data_span, structure_info] = OperationHelper::extract_structured_double(
305 const_cast<input_type&>(input));
306
307 std::vector<std::span<const double>> channel_spans;
308 for (auto& span : data_span)
309 channel_spans.emplace_back(span.data(), span.size());
310
311 for (const auto& channel_span : channel_spans) {
312 if (channel_span.size() < m_window_size) {
313 throw std::runtime_error("One or more channels in input data are smaller than window size (" + std::to_string(m_window_size) + ")");
314 }
315 }
316
317 std::vector<std::vector<double>> energy_values;
318 energy_values.reserve(channel_spans.size());
319 for (const auto& channel_span : channel_spans) {
320 energy_values.push_back(compute_energy_values(channel_span, m_method));
321 }
322
323 EnergyAnalysis analysis_result = create_analysis_result(
324 energy_values, channel_spans, structure_info);
325
326 this->store_current_analysis(analysis_result);
327
328 return create_pipeline_output(input, analysis_result, structure_info);
329 } catch (const std::exception& e) {
330 std::cerr << "Energy analysis failed: " << e.what() << '\n';
331 output_type error_result;
332 error_result.metadata = input.metadata;
333 error_result.metadata["error"] = std::string("Analysis failed: ") + e.what();
334 return error_result;
335 }
336 }
337
338 /**
339 * @brief Handle analysis-specific parameters
340 */
341 void set_analysis_parameter(const std::string& name, std::any value) override
342 {
343 if (name == "method") {
344 try {
345 auto method_str = safe_any_cast_or_throw<std::string>(value);
346 m_method = string_to_method(method_str);
347 return;
348 } catch (const std::runtime_error&) {
349 throw std::invalid_argument("Invalid method parameter - expected string or EnergyMethod enum");
350 }
351 if (auto* method_enum = std::any_cast<EnergyMethod>(&value)) {
352 m_method = *method_enum;
353 return;
354 }
355 } else if (name == "window_size") {
356 if (auto* size = std::any_cast<uint32_t>(&value)) {
357 m_window_size = *size;
358 validate_window_parameters();
359 return;
360 }
361 } else if (name == "hop_size") {
362 if (auto* size = std::any_cast<uint32_t>(&value)) {
363 m_hop_size = *size;
364 validate_window_parameters();
365 return;
366 }
367 } else if (name == "classification_enabled") {
368 if (auto* enabled = std::any_cast<bool>(&value)) {
369 m_classification_enabled = *enabled;
370 return;
371 }
372 }
373
374 base_type::set_analysis_parameter(name, std::move(value));
375 }
376
377 /**
378 * @brief Get analysis-specific parameter
379 */
380 [[nodiscard]] std::any get_analysis_parameter(const std::string& name) const override
381 {
382 if (name == "method")
383 return std::any(method_to_string(m_method));
384 if (name == "window_size")
385 return std::any(m_window_size);
386 if (name == "hop_size")
387 return std::any(m_hop_size);
388 if (name == "classification_enabled")
389 return std::any(m_classification_enabled);
390
391 return base_type::get_analysis_parameter(name);
392 }
393
394private:
395 uint32_t m_window_size { 512 };
396 uint32_t m_hop_size { 256 };
397 EnergyMethod m_method { EnergyMethod::RMS };
398 bool m_classification_enabled { false };
399
400 double m_silent_threshold { 0.01 };
401 double m_quiet_threshold = { 0.1 };
402 double m_moderate_threshold { 0.5 };
403 double m_loud_threshold { 0.8 };
404
406 {
407 if (m_window_size == 0) {
408 throw std::invalid_argument("Window size must be greater than 0");
409 }
410 if (m_hop_size == 0) {
411 throw std::invalid_argument("Hop size must be greater than 0");
412 }
413 if (m_hop_size > m_window_size) {
414 throw std::invalid_argument("Hop size should not exceed window size");
415 }
416 }
417
418 /**
419 * @brief Create comprehensive analysis result from energy computation
420 */
422 const std::vector<std::vector<double>>& energy_values,
423 std::vector<std::span<const double>> original_data,
424 const DataStructureInfo& /*structure_info*/) const
425 {
426 EnergyAnalysis result;
427 result.method_used = m_method;
428 result.window_size = m_window_size;
429 result.hop_size = m_hop_size;
430
431 if (energy_values.empty()) {
432 return result;
433 }
434
435 result.channels.resize(energy_values.size());
436
437 for (size_t ch = 0; ch < energy_values.size(); ch++) {
438
439 auto& channel_result = result.channels[ch];
440 const auto& ch_energy = energy_values[ch];
441
442 channel_result.energy_values = ch_energy;
443
444 if (!ch_energy.empty()) {
445 auto [min_it, max_it] = std::ranges::minmax_element(ch_energy);
446 channel_result.min_energy = *min_it;
447 channel_result.max_energy = *max_it;
448
449 const double sum = std::accumulate(ch_energy.begin(), ch_energy.end(), 0.0);
450 channel_result.mean_energy = sum / static_cast<double>(ch_energy.size());
451
452 const double mean = channel_result.mean_energy;
453 const double var_sum = std::transform_reduce(
454 ch_energy.begin(), ch_energy.end(), 0.0, std::plus {},
455 [mean](double val) { return (val - mean) * (val - mean); });
456 channel_result.variance = var_sum / static_cast<double>(ch_energy.size());
457 }
458
459 const size_t data_size = (ch < original_data.size()) ? original_data[ch].size() : 0;
460 channel_result.window_positions.reserve(ch_energy.size());
461
462 for (size_t i = 0; i < ch_energy.size(); ++i) {
463 const size_t start = i * m_hop_size;
464 const size_t end = std::min(start + m_window_size, data_size);
465 channel_result.window_positions.emplace_back(start, end);
466 }
467
468 if (ch < original_data.size()) {
469 switch (m_method) {
470 case EnergyMethod::ZERO_CROSSING:
471 channel_result.event_positions = find_zero_crossing_positions(
472 original_data[ch], 0.0);
473 break;
474
475 case EnergyMethod::PEAK: {
476 double peak_threshold = m_classification_enabled ? m_quiet_threshold : 0.01;
477 channel_result.event_positions = find_peak_positions(
478 original_data[ch], peak_threshold, m_hop_size / 4);
479 break;
480 }
481
482 case EnergyMethod::RMS:
483 case EnergyMethod::POWER:
484 case EnergyMethod::SPECTRAL:
485 case EnergyMethod::HARMONIC:
486 case EnergyMethod::DYNAMIC_RANGE:
487 default:
488 // event_positions remains empty
489 break;
490 }
491 }
492
493 if (m_classification_enabled) {
494 channel_result.classifications.reserve(ch_energy.size());
495 channel_result.level_counts.fill(0);
496
497 for (double energy : ch_energy) {
498 EnergyLevel level = classify_energy_level(energy);
499 channel_result.classifications.push_back(level);
500 channel_result.level_counts[static_cast<size_t>(level)]++;
501 }
502 }
503 }
504
505 return result;
506 }
507
508 /**
509 * @brief Create pipeline output from input and energy values
510 */
512 {
513 std::vector<std::vector<double>> channel_energies;
514 channel_energies.reserve(analysis_result.channels.size());
515
516 for (const auto& ch : analysis_result.channels) {
517 channel_energies.push_back(ch.energy_values);
518 }
519
520 output_type output = this->convert_result(channel_energies, info);
521
522 output.metadata = input.metadata;
523
524 output.metadata["source_analyzer"] = "EnergyAnalyzer";
525 output.metadata["energy_method"] = method_to_string(analysis_result.method_used);
526 output.metadata["window_size"] = analysis_result.window_size;
527 output.metadata["hop_size"] = analysis_result.hop_size;
528 output.metadata["num_channels"] = analysis_result.channels.size();
529
530 if (!analysis_result.channels.empty()) {
531 std::vector<double> channel_means, channel_maxs, channel_mins, channel_variances;
532 std::vector<size_t> channel_window_counts;
533
534 for (const auto& ch : analysis_result.channels) {
535 channel_means.push_back(ch.mean_energy);
536 channel_maxs.push_back(ch.max_energy);
537 channel_mins.push_back(ch.min_energy);
538 channel_variances.push_back(ch.variance);
539 channel_window_counts.push_back(ch.energy_values.size());
540 }
541
542 output.metadata["mean_energy_per_channel"] = channel_means;
543 output.metadata["max_energy_per_channel"] = channel_maxs;
544 output.metadata["min_energy_per_channel"] = channel_mins;
545 output.metadata["variance_per_channel"] = channel_variances;
546 output.metadata["window_count_per_channel"] = channel_window_counts;
547 }
548
549 return output;
550 }
551
552 /**
553 * @brief Compute energy values using span (zero-copy processing)
554 */
555 [[nodiscard]] std::vector<double> compute_energy_values(std::span<const double> data, EnergyMethod method) const
556 {
557 const size_t num_windows = calculate_num_windows(data.size());
558
559 switch (method) {
560 case EnergyMethod::PEAK:
561 return compute_peak_energy(data, num_windows, m_hop_size, m_window_size);
562 case EnergyMethod::ZERO_CROSSING:
563 return compute_zero_crossing_energy(data, num_windows, m_hop_size, m_window_size);
564 case EnergyMethod::POWER:
565 return compute_power_energy(data, num_windows, m_hop_size, m_window_size);
566 case EnergyMethod::DYNAMIC_RANGE:
567 return compute_dynamic_range_energy(data, num_windows, m_hop_size, m_window_size);
568 case EnergyMethod::SPECTRAL:
569 return compute_spectral_energy(data, num_windows, m_hop_size, m_window_size);
570 case EnergyMethod::HARMONIC:
571 return compute_harmonic_energy(data, num_windows, m_hop_size, m_window_size);
572 case EnergyMethod::RMS:
573 default:
574 return compute_rms_energy(data, num_windows, m_hop_size, m_window_size);
575 }
576 }
577
578 /**
579 * @brief Calculate number of windows for given data size
580 */
581 [[nodiscard]] size_t calculate_num_windows(size_t data_size) const
582 {
583 if (data_size < m_window_size)
584 return 0;
585 return (data_size - m_window_size) / m_hop_size + 1;
586 }
587};
588
589/// Standard energy analyzer: DataVariant -> MatrixXd
591
592/// Container energy analyzer: SignalContainer -> MatrixXd
594
595/// Region energy analyzer: Region -> MatrixXd
597
598/// Raw energy analyzer: produces double vectors
599template <ComputeData InputType = std::vector<Kakshya::DataVariant>>
601
602/// Variant energy analyzer: produces DataVariant output
603template <ComputeData InputType = std::vector<Kakshya::DataVariant>>
605
606} // namespace MayaFlux::Yantra
Modern, digital-first universal analyzer framework for Maya Flux.
EnergyMethod get_energy_method() const
Get current energy computation method.
size_t calculate_num_windows(size_t data_size) const
Calculate number of windows for given data size.
bool supports_method(const std::string &method) const override
Check if a specific method is supported.
output_type create_pipeline_output(const input_type &input, const EnergyAnalysis &analysis_result, DataStructureInfo &info)
Create pipeline output from input and energy values.
static EnergyMethod string_to_method(const std::string &str)
Convert string to energy method enum.
void enable_classification(bool enabled)
Enable or disable energy level classification.
AnalysisType get_analysis_type() const override
Get analysis type category.
EnergyAnalyzer(uint32_t window_size=256, uint32_t hop_size=128)
Construct EnergyAnalyzer with configurable window parameters.
EnergyAnalysis create_analysis_result(const std::vector< std::vector< double > > &energy_values, std::vector< std::span< const double > > original_data, const DataStructureInfo &) const
Create comprehensive analysis result from energy computation.
void set_energy_method(EnergyMethod method)
Set energy computation method.
std::any get_analysis_parameter(const std::string &name) const override
Get analysis-specific parameter.
int get_level_count(const ChannelEnergy &channel, EnergyLevel level)
Get count of windows in a specific energy level for a channel.
static std::string method_to_string(EnergyMethod method)
Convert energy method enum to string.
output_type analyze_implementation(const input_type &input) override
Core analysis implementation - creates analysis result AND pipeline output.
void set_energy_thresholds(double silent, double quiet, double moderate, double loud)
Set energy level classification thresholds.
std::vector< double > compute_energy_values(std::span< const double > data, EnergyMethod method) const
Compute energy values using span (zero-copy processing)
std::vector< std::string > get_available_methods() const override
Get available analysis methods.
void set_window_parameters(uint32_t window_size, uint32_t hop_size)
Set window parameters for analysis.
static std::string energy_level_to_string(EnergyLevel level)
Convert energy level enum to string.
std::string get_analyzer_name() const override
Get analyzer name.
EnergyAnalysis analyze_energy(const InputType &data)
Type-safe energy analysis method.
void set_analysis_parameter(const std::string &name, std::any value) override
Handle analysis-specific parameters.
EnergyLevel classify_energy_level(double energy) const
Classify energy value into qualitative level.
EnergyAnalysis get_energy_analysis() const
Get last energy analysis result (type-safe)
High-performance energy analyzer with zero-copy processing.
Template-flexible analyzer base with instance-defined I/O types.
AnalysisType
Categories of analysis operations for discovery and organization.
EnergyMethod
Supported energy computation methods.
@ SPECTRAL
Spectral energy (FFT-based)
@ DYNAMIC_RANGE
Dynamic range (dB)
@ RMS
Root Mean Square energy.
@ ZERO_CROSSING
Zero-crossing rate.
@ HARMONIC
Harmonic energy (low-frequency content)
@ POWER
Power (sum of squares)
std::vector< double > compute_dynamic_range_energy(std::span< const double > data, const size_t num_windows, const uint32_t hop_size, const uint32_t window_size)
Compute dynamic range energy using zero-copy processing.
std::vector< double > compute_harmonic_energy(std::span< const double > data, const size_t num_windows, const uint32_t hop_size, const uint32_t window_size)
Compute harmonic energy using low-frequency FFT analysis.
std::vector< double > compute_peak_energy(std::span< const double > data, const uint32_t num_windows, const uint32_t hop_size, const uint32_t window_size)
Compute peak energy using zero-copy processing.
std::vector< double > compute_power_energy(std::span< const double > data, const size_t num_windows, const uint32_t hop_size, const uint32_t window_size)
Compute power energy using zero-copy processing.
EnergyLevel
Qualitative classification of energy values.
std::vector< size_t > find_peak_positions(std::span< const double > data, double threshold, size_t min_distance)
Find actual peak positions in the signal.
std::vector< double > compute_rms_energy(std::span< const double > data, const uint32_t num_windows, const uint32_t hop_size, const uint32_t window_size)
Compute RMS energy using zero-copy processing.
std::vector< double > compute_zero_crossing_energy(std::span< const double > data, const size_t num_windows, const uint32_t hop_size, const uint32_t window_size)
Compute zero-crossing energy using zero-copy processing.
std::vector< size_t > find_zero_crossing_positions(std::span< const double > data, double threshold)
Find actual zero-crossing positions in the signal.
std::vector< double > compute_spectral_energy(std::span< const double > data, const size_t num_windows, const uint32_t hop_size, const uint32_t window_size)
Compute spectral energy using FFT-based analysis.
double mean(const std::vector< double > &data)
Calculate mean of single-channel data.
Definition Yantra.cpp:39
std::vector< size_t > event_positions
std::vector< EnergyLevel > classifications
std::vector< std::pair< size_t, size_t > > window_positions
std::array< int, 5 > level_counts
std::vector< double > energy_values
Metadata about data structure for reconstruction.
std::vector< ChannelEnergy > channels
Analysis result structure for energy analysis.
std::unordered_map< std::string, std::any > metadata
Associated metadata.
Definition DataIO.hpp:28
Input/Output container for computation pipeline data flow with structure preservation.
Definition DataIO.hpp:24