MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
ExtractionHelper.cpp
Go to the documentation of this file.
2
5
6namespace {
7
8/**
9 * @brief Remove duplicate indices from extracted window positions
10 * @param window_positions Vector of [start, end] pairs
11 * @return Merged non-overlapping regions
12 */
13std::vector<std::pair<size_t, size_t>> merge_overlapping_windows(
14 const std::vector<std::pair<size_t, size_t>>& window_positions)
15{
16 if (window_positions.empty()) {
17 return {};
18 }
19
20 auto sorted_windows = window_positions;
21 std::ranges::sort(sorted_windows, [](const auto& a, const auto& b) {
22 return a.first < b.first;
23 });
24
25 std::vector<std::pair<size_t, size_t>> merged;
26 merged.push_back(sorted_windows[0]);
27
28 for (size_t i = 1; i < sorted_windows.size(); ++i) {
29 auto& last_merged = merged.back();
30 const auto& current = sorted_windows[i];
31
32 if (current.first <= last_merged.second) {
33 last_merged.second = std::max(last_merged.second, current.second);
34 } else {
35
36 merged.push_back(current);
37 }
38 }
39
40 return merged;
41}
42}
43
44namespace MayaFlux::Yantra {
45
46std::vector<std::vector<double>> extract_high_energy_data(
47 const std::vector<std::span<const double>>& data,
48 double energy_threshold,
49 uint32_t window_size,
50 uint32_t hop_size)
51{
52 std::vector<std::vector<double>> result;
53 result.reserve(data.size());
54
55 for (const auto& channel : data) {
56 if (channel.empty()) {
57 result.emplace_back();
58 continue;
59 }
60
61 uint32_t effective_window_size = std::min(window_size, static_cast<uint32_t>(channel.size()));
62 uint32_t effective_hop_size = std::min(hop_size, effective_window_size / 2);
63 if (effective_hop_size == 0)
64 effective_hop_size = 1;
65
66 if (!validate_extraction_parameters(effective_window_size, effective_hop_size, channel.size())) {
67 result.emplace_back();
68 continue;
69 }
70
71 try {
72 auto energy_analyzer = std::make_shared<EnergyAnalyzer<std::vector<Kakshya::DataVariant>, Eigen::VectorXd>>(
73 effective_window_size, effective_hop_size);
74 energy_analyzer->set_parameter("method", "rms");
75
76 std::vector<Kakshya::DataVariant> data_variant { Kakshya::DataVariant { std::vector<double>(channel.begin(), channel.end()) } };
77 EnergyAnalysis energy_result = energy_analyzer->analyze_energy(data_variant);
78
79 if (energy_result.channels.empty() || energy_result.channels[0].energy_values.empty() || energy_result.channels[0].window_positions.empty()) {
80 result.emplace_back();
81 continue;
82 }
83
84 std::vector<std::pair<size_t, size_t>> qualifying_windows;
85 const auto& ch_energy = energy_result.channels[0].energy_values;
86 const auto& ch_windows = energy_result.channels[0].window_positions;
87 for (size_t i = 0; i < ch_energy.size(); ++i) {
88 if (ch_energy[i] > energy_threshold) {
89 auto [start_idx, end_idx] = ch_windows[i];
90 if (start_idx < channel.size() && end_idx <= channel.size() && start_idx < end_idx) {
91 qualifying_windows.emplace_back(start_idx, end_idx);
92 }
93 }
94 }
95
96 auto merged_windows = merge_overlapping_windows(qualifying_windows);
97
98 std::vector<double> extracted_data;
99 for (const auto& [start_idx, end_idx] : merged_windows) {
100 std::ranges::copy(channel.subspan(start_idx, end_idx - start_idx),
101 std::back_inserter(extracted_data));
102 }
103
104 result.push_back(std::move(extracted_data));
105 } catch (const std::exception&) {
106 result.emplace_back();
107 }
108 }
109
110 return result;
111}
112
113std::vector<std::vector<double>> extract_peak_data(
114 const std::vector<std::span<const double>>& data,
115 double threshold,
116 double min_distance,
117 uint32_t region_size)
118{
119 std::vector<std::vector<double>> result;
120 result.reserve(data.size());
121
122 for (const auto& channel : data) {
123 if (channel.size() < 3) {
124 result.emplace_back();
125 continue;
126 }
127
128 try {
129 auto analyzer = std::make_shared<EnergyAnalyzer<std::vector<Kakshya::DataVariant>, Eigen::VectorXd>>(
130 512, 256);
131 analyzer->set_parameter("method", "peak");
132 analyzer->set_parameter("threshold", threshold);
133
134 std::vector<Kakshya::DataVariant> data_variant {
135 Kakshya::DataVariant { std::vector<double>(channel.begin(), channel.end()) }
136 };
137 EnergyAnalysis energy_result = analyzer->analyze_energy(data_variant);
138
139 if (energy_result.channels.empty()) {
140 result.emplace_back();
141 continue;
142 }
143
144 const auto& peak_positions = energy_result.channels[0].event_positions;
145
146 if (peak_positions.empty()) {
147 result.emplace_back();
148 continue;
149 }
150
151 std::vector<size_t> filtered_positions;
152 size_t last_position = 0;
153
154 for (size_t pos : peak_positions) {
155 if (filtered_positions.empty() || (pos - last_position) >= static_cast<size_t>(min_distance)) {
156 filtered_positions.push_back(pos);
157 last_position = pos;
158 }
159 }
160
161 std::vector<double> extracted_data;
162 for (size_t peak_pos : filtered_positions) {
163 const size_t half_region = region_size / 2;
164 const size_t start_idx = (peak_pos >= half_region) ? peak_pos - half_region : 0;
165 const size_t end_idx = std::min(peak_pos + half_region, channel.size());
166
167 if (start_idx < channel.size() && end_idx <= channel.size() && start_idx < end_idx) {
168 std::ranges::copy(channel.subspan(start_idx, end_idx - start_idx),
169 std::back_inserter(extracted_data));
170 }
171 }
172
173 result.push_back(std::move(extracted_data));
174 } catch (const std::exception&) {
175 result.emplace_back();
176 }
177 }
178
179 return result;
180}
181
182std::vector<std::vector<double>> extract_outlier_data(
183 const std::vector<std::span<const double>>& data,
184 double std_dev_threshold,
185 uint32_t window_size,
186 uint32_t hop_size)
187{
188 std::vector<std::vector<double>> result;
189 result.reserve(data.size());
190
191 for (const auto& channel : data) {
192 if (channel.empty()) {
193 result.emplace_back();
194 continue;
195 }
196
197 uint32_t effective_window_size = std::min(window_size, static_cast<uint32_t>(channel.size()));
198 uint32_t effective_hop_size = std::min(hop_size, effective_window_size / 2);
199 if (effective_hop_size == 0)
200 effective_hop_size = 1;
201
202 if (!validate_extraction_parameters(effective_window_size, effective_hop_size, channel.size())) {
203 result.emplace_back();
204 continue;
205 }
206
207 try {
208 auto stat_analyzer = std::make_shared<StatisticalAnalyzer<std::vector<Kakshya::DataVariant>, Eigen::VectorXd>>(
209 effective_window_size, effective_hop_size);
210 stat_analyzer->set_parameter("method", "mean");
211
212 std::vector<Kakshya::DataVariant> data_variant { Kakshya::DataVariant { std::vector<double>(channel.begin(), channel.end()) } };
213 ChannelStatistics stat_result = stat_analyzer->analyze_statistics(data_variant).channel_statistics[0];
214
215 if (stat_result.statistical_values.empty() || stat_result.window_positions.empty() || stat_result.stat_std_dev <= 0.0) {
216 result.emplace_back();
217 continue;
218 }
219
220 const double global_mean = stat_result.mean_stat;
221 const double global_std_dev = stat_result.stat_std_dev;
222 const double outlier_threshold = std_dev_threshold * global_std_dev;
223
224 std::vector<std::pair<size_t, size_t>> qualifying_windows;
225 for (size_t i = 0; i < stat_result.statistical_values.size(); ++i) {
226 if (std::abs(stat_result.statistical_values[i] - global_mean) > outlier_threshold) {
227 auto [start_idx, end_idx] = stat_result.window_positions[i];
228 if (start_idx < channel.size() && end_idx <= channel.size() && start_idx < end_idx) {
229 qualifying_windows.emplace_back(start_idx, end_idx);
230 }
231 }
232 }
233
234 auto merged_windows = merge_overlapping_windows(qualifying_windows);
235
236 std::vector<double> extracted_data;
237 for (const auto& [start_idx, end_idx] : merged_windows) {
238 std::ranges::copy(channel.subspan(start_idx, end_idx - start_idx),
239 std::back_inserter(extracted_data));
240 }
241
242 result.push_back(std::move(extracted_data));
243 } catch (const std::exception&) {
244 result.emplace_back();
245 }
246 }
247
248 return result;
249}
250
251std::vector<std::vector<double>> extract_high_spectral_data(
252 const std::vector<std::span<const double>>& data,
253 double spectral_threshold,
254 uint32_t window_size,
255 uint32_t hop_size)
256{
257 std::vector<std::vector<double>> result;
258 result.reserve(data.size());
259
260 for (const auto& channel : data) {
261 if (channel.empty()) {
262 result.emplace_back();
263 continue;
264 }
265
266 uint32_t effective_window_size = std::min(window_size, static_cast<uint32_t>(channel.size()));
267 uint32_t effective_hop_size = std::min(hop_size, effective_window_size / 2);
268 if (effective_hop_size == 0)
269 effective_hop_size = 1;
270
271 if (!validate_extraction_parameters(effective_window_size, effective_hop_size, channel.size())) {
272 result.emplace_back();
273 continue;
274 }
275
276 try {
277 auto energy_analyzer = std::make_shared<EnergyAnalyzer<std::vector<Kakshya::DataVariant>, Eigen::VectorXd>>(
278 effective_window_size, effective_hop_size);
279 energy_analyzer->set_parameter("method", "spectral");
280
281 std::vector<Kakshya::DataVariant> data_variant { Kakshya::DataVariant { std::vector<double>(channel.begin(), channel.end()) } };
282 EnergyAnalysis energy_result = energy_analyzer->analyze_energy(data_variant);
283
284 if (energy_result.channels.empty() || energy_result.channels[0].energy_values.empty() || energy_result.channels[0].window_positions.empty()) {
285 result.emplace_back();
286 continue;
287 }
288
289 std::vector<std::pair<size_t, size_t>> qualifying_windows;
290 const auto& ch_energy = energy_result.channels[0].energy_values;
291 const auto& ch_windows = energy_result.channels[0].window_positions;
292 for (size_t i = 0; i < ch_energy.size(); ++i) {
293 if (ch_energy[i] > spectral_threshold) {
294 auto [start_idx, end_idx] = ch_windows[i];
295 if (start_idx < channel.size() && end_idx <= channel.size() && start_idx < end_idx) {
296 qualifying_windows.emplace_back(start_idx, end_idx);
297 }
298 }
299 }
300
301 auto merged_windows = merge_overlapping_windows(qualifying_windows);
302
303 std::vector<double> extracted_data;
304 for (const auto& [start_idx, end_idx] : merged_windows) {
305 std::ranges::copy(channel.subspan(start_idx, end_idx - start_idx),
306 std::back_inserter(extracted_data));
307 }
308
309 result.push_back(std::move(extracted_data));
310 } catch (const std::exception&) {
311 result.emplace_back();
312 }
313 }
314
315 return result;
316}
317
318std::vector<std::vector<double>> extract_above_mean_data(
319 const std::vector<std::span<const double>>& data,
320 double mean_multiplier,
321 uint32_t window_size,
322 uint32_t hop_size)
323{
324 std::vector<std::vector<double>> result;
325 result.reserve(data.size());
326
327 for (const auto& channel : data) {
328 if (channel.empty()) {
329 result.emplace_back();
330 continue;
331 }
332
333 uint32_t effective_window_size = std::min(window_size, static_cast<uint32_t>(channel.size()));
334 uint32_t effective_hop_size = std::min(hop_size, effective_window_size / 2);
335 if (effective_hop_size == 0)
336 effective_hop_size = 1;
337
338 if (!validate_extraction_parameters(effective_window_size, effective_hop_size, channel.size())) {
339 result.emplace_back();
340 continue;
341 }
342
343 try {
344 auto stat_analyzer = std::make_shared<StatisticalAnalyzer<std::vector<Kakshya::DataVariant>, Eigen::VectorXd>>(
345 effective_window_size, effective_hop_size);
346 stat_analyzer->set_parameter("method", "mean");
347
348 std::vector<Kakshya::DataVariant> data_variant { Kakshya::DataVariant { std::vector<double>(channel.begin(), channel.end()) } };
349 ChannelStatistics stat_result = stat_analyzer->analyze_statistics(data_variant).channel_statistics[0];
350
351 if (stat_result.statistical_values.empty() || stat_result.window_positions.empty()) {
352 result.emplace_back();
353 continue;
354 }
355
356 const double threshold = stat_result.mean_stat * mean_multiplier;
357
358 std::vector<std::pair<size_t, size_t>> qualifying_windows;
359 for (size_t i = 0; i < stat_result.statistical_values.size(); ++i) {
360 if (stat_result.statistical_values[i] > threshold) {
361 auto [start_idx, end_idx] = stat_result.window_positions[i];
362 if (start_idx < channel.size() && end_idx <= channel.size() && start_idx < end_idx) {
363 qualifying_windows.emplace_back(start_idx, end_idx);
364 }
365 }
366 }
367
368 auto merged_windows = merge_overlapping_windows(qualifying_windows);
369
370 std::vector<double> extracted_data;
371 for (const auto& [start_idx, end_idx] : merged_windows) {
372 std::ranges::copy(channel.subspan(start_idx, end_idx - start_idx),
373 std::back_inserter(extracted_data));
374 }
375
376 result.push_back(std::move(extracted_data));
377 } catch (const std::exception&) {
378 result.emplace_back();
379 }
380 }
381
382 return result;
383}
384
385std::vector<std::vector<double>> extract_overlapping_windows(
386 const std::vector<std::span<const double>>& data,
387 uint32_t window_size,
388 double overlap)
389{
390 std::vector<std::vector<double>> result;
391 result.reserve(data.size());
392
393 if (window_size == 0 || overlap < 0.0 || overlap >= 1.0) {
394 for (size_t i = 0; i < data.size(); ++i)
395 result.emplace_back();
396 return result;
397 }
398
399 for (const auto& channel : data) {
400 if (channel.empty() || window_size > channel.size()) {
401 result.emplace_back();
402 continue;
403 }
404
405 const auto hop_size = std::max(1U, static_cast<uint32_t>(window_size * (1.0 - overlap)));
406 std::vector<double> channel_windows;
407
408 for (size_t start = 0; start + window_size <= channel.size(); start += hop_size) {
409 channel_windows.insert(channel_windows.end(),
410 channel.begin() + start,
411 channel.begin() + start + window_size);
412 }
413
414 result.push_back(std::move(channel_windows));
415 }
416
417 return result;
418}
419
420std::vector<std::vector<double>> extract_windowed_data_by_indices(
421 const std::vector<std::span<const double>>& data,
422 const std::vector<size_t>& window_indices,
423 uint32_t window_size)
424{
425 std::vector<std::vector<double>> result;
426 result.reserve(data.size());
427
428 for (const auto& channel : data) {
429 std::vector<double> channel_windows;
430 if (channel.empty() || window_size == 0) {
431 result.emplace_back();
432 continue;
433 }
434
435 for (size_t start_idx : window_indices) {
436 if (start_idx + window_size <= channel.size()) {
437 auto window_span = channel.subspan(start_idx, window_size);
438 channel_windows.insert(channel_windows.end(), window_span.begin(), window_span.end());
439 }
440 }
441 result.push_back(std::move(channel_windows));
442 }
443
444 return result;
445}
446
447std::vector<std::string> get_available_extraction_methods()
448{
449 return {
450 "high_energy_data",
451 "peak_data",
452 "outlier_data",
453 "high_spectral_data",
454 "above_mean_data",
455 "overlapping_windows",
456 "data_from_regions"
457 };
458}
459
460bool validate_extraction_parameters(uint32_t window_size, uint32_t hop_size, size_t data_size)
461{
462 if (window_size == 0 || hop_size == 0) {
463 return false;
464 }
465
466 if (data_size == 0) {
467 return true;
468 }
469
470 if (data_size < window_size) {
471 return data_size >= 3;
472 }
473
474 return true;
475}
476
477std::vector<std::vector<double>> extract_zero_crossing_data(
478 const std::vector<std::span<const double>>& data,
479 double threshold,
480 double min_distance,
481 uint32_t region_size)
482{
483 std::vector<std::vector<double>> result;
484 result.reserve(data.size());
485
486 for (const auto& channel : data) {
487 if (channel.empty() || region_size == 0) {
488 result.emplace_back();
489 continue;
490 }
491
492 try {
493 auto analyzer = std::make_shared<EnergyAnalyzer<std::vector<Kakshya::DataVariant>, Eigen::VectorXd>>(
494 region_size * 2, static_cast<uint32_t>(min_distance));
495 analyzer->set_parameter("method", "zero_crossing");
496
497 std::vector<Kakshya::DataVariant> data_variant {
498 Kakshya::DataVariant { std::vector<double>(channel.begin(), channel.end()) }
499 };
500 EnergyAnalysis energy_result = analyzer->analyze_energy(data_variant);
501
502 if (energy_result.channels.empty()) {
503 result.emplace_back();
504 continue;
505 }
506
507 const auto& crossing_positions = energy_result.channels[0].event_positions;
508
509 if (crossing_positions.empty()) {
510 result.emplace_back();
511 continue;
512 }
513
514 std::vector<size_t> filtered_positions;
515 size_t last_position = 0;
516
517 for (size_t pos : crossing_positions) {
518 if (filtered_positions.empty() || (pos - last_position) >= static_cast<size_t>(min_distance)) {
519 filtered_positions.push_back(pos);
520 last_position = pos;
521 }
522 }
523
524 std::vector<size_t> qualified_positions;
525 for (size_t pos : filtered_positions) {
526 if (pos < channel.size() && std::abs(channel[pos]) >= threshold) {
527 qualified_positions.push_back(pos);
528 }
529 }
530
531 std::vector<double> extracted_data;
532 for (size_t pos : qualified_positions) {
533 const size_t half_region = region_size / 2;
534 const size_t region_start = (pos >= half_region) ? pos - half_region : 0;
535 const size_t region_end = std::min(pos + half_region, channel.size());
536
537 if (region_start < region_end) {
538 auto region = channel.subspan(region_start, region_end - region_start);
539 std::ranges::copy(region, std::back_inserter(extracted_data));
540 }
541 }
542
543 result.push_back(std::move(extracted_data));
544 } catch (const std::exception&) {
545 result.emplace_back();
546 }
547 }
548
549 return result;
550}
551
552std::vector<std::vector<double>> extract_silence_data(
553 const std::vector<std::span<const double>>& data,
554 double silence_threshold,
555 uint32_t min_duration,
556 uint32_t window_size,
557 uint32_t hop_size)
558{
559 std::vector<std::vector<double>> result;
560 result.reserve(data.size());
561
562 for (const auto& channel : data) {
563 if (channel.empty()) {
564 result.emplace_back();
565 continue;
566 }
567
568 uint32_t effective_window = std::min(window_size, static_cast<uint32_t>(channel.size()));
569 uint32_t effective_hop = std::max(1U, std::min(hop_size, window_size / 2));
570
571 try {
572 auto analyzer = std::make_shared<EnergyAnalyzer<std::vector<Kakshya::DataVariant>, Eigen::VectorXd>>(
573 effective_window, effective_hop);
574 analyzer->set_parameter("method", "rms");
575 analyzer->set_energy_thresholds(0.0, silence_threshold, silence_threshold * 2.0, silence_threshold * 5.0);
576 analyzer->enable_classification(true);
577
578 std::vector<Kakshya::DataVariant> data_variant { Kakshya::DataVariant { std::vector<double>(channel.begin(), channel.end()) } };
579 EnergyAnalysis energy_result = analyzer->analyze_energy(data_variant);
580
581 if (energy_result.channels.empty() || energy_result.channels[0].energy_values.empty() || energy_result.channels[0].window_positions.empty() || energy_result.channels[0].classifications.empty()) {
582 result.emplace_back();
583 continue;
584 }
585
586 const auto& classifications = energy_result.channels[0].classifications;
587 const auto& window_positions = energy_result.channels[0].window_positions;
588
589 std::vector<std::pair<size_t, size_t>> regions;
590 for (size_t idx = 0; idx < classifications.size(); ++idx) {
591 if (classifications[idx] == EnergyLevel::SILENT) {
592 auto [start_idx, end_idx] = window_positions[idx];
593 if (end_idx > start_idx && (end_idx - start_idx) >= min_duration) {
594 regions.emplace_back(start_idx, end_idx);
595 }
596 }
597 }
598
599 auto merged_regions = merge_overlapping_windows(regions);
600
601 std::vector<double> extracted_data;
602 for (const auto& [start_idx, end_idx] : merged_regions) {
603 if (start_idx < channel.size() && end_idx <= channel.size() && start_idx < end_idx) {
604 auto region = channel.subspan(start_idx, end_idx - start_idx);
605 std::ranges::copy(region, std::back_inserter(extracted_data));
606 }
607 }
608
609 result.push_back(std::move(extracted_data));
610 } catch (const std::exception&) {
611 result.emplace_back();
612 }
613 }
614
615 return result;
616}
617
618std::vector<std::vector<double>> extract_onset_data(
619 const std::vector<std::span<const double>>& data,
620 double threshold,
621 uint32_t region_size,
622 uint32_t window_size,
623 uint32_t hop_size)
624{
625 std::vector<std::vector<double>> result;
626 result.reserve(data.size());
627
628 for (const auto& channel : data) {
629 if (channel.empty()) {
630 result.emplace_back();
631 continue;
632 }
633
634 try {
635 std::vector<size_t> onset_positions = find_onset_positions(
636 channel, window_size, hop_size, threshold);
637
638 if (onset_positions.empty()) {
639 result.emplace_back();
640 continue;
641 }
642
643 std::vector<double> extracted_data;
644 for (size_t onset_pos : onset_positions) {
645 const size_t half_region = region_size / 2;
646 const size_t region_start = (onset_pos >= half_region) ? onset_pos - half_region : 0;
647 const size_t region_end = std::min(onset_pos + half_region, channel.size());
648
649 if (region_start < region_end) {
650 auto region = channel.subspan(region_start, region_end - region_start);
651 std::ranges::copy(region, std::back_inserter(extracted_data));
652 }
653 }
654
655 result.push_back(std::move(extracted_data));
656 } catch (const std::exception&) {
657 result.emplace_back();
658 }
659 }
660
661 return result;
662}
663
664}
Span-based energy analysis for digital signals in Maya Flux.
Central helper for extraction operations - uses analyzers to find data.
std::variant< std::vector< double >, std::vector< float >, std::vector< uint8_t >, std::vector< uint16_t >, std::vector< uint32_t >, std::vector< std::complex< float > >, std::vector< std::complex< double > >, std::vector< glm::vec2 >, std::vector< glm::vec3 >, std::vector< glm::vec4 >, std::vector< glm::mat4 > > DataVariant
Multi-type data storage for different precision needs.
Definition NDData.hpp:73
std::vector< std::vector< double > > extract_overlapping_windows(const std::vector< std::span< const double > > &data, uint32_t window_size, double overlap)
Extract overlapping windows of actual data.
std::vector< std::vector< double > > extract_outlier_data(const std::vector< std::span< const double > > &data, double std_dev_threshold, uint32_t window_size, uint32_t hop_size)
Extract data from statistical outlier regions.
std::vector< std::vector< double > > extract_silence_data(const std::vector< std::span< const double > > &data, double silence_threshold, uint32_t min_duration, uint32_t window_size, uint32_t hop_size)
Extract data from silent regions using existing EnergyAnalyzer.
bool validate_extraction_parameters(uint32_t window_size, uint32_t hop_size, size_t data_size)
Validate extraction parameters.
std::vector< size_t > find_onset_positions(std::span< const double > data, uint32_t window_size, uint32_t hop_size, double threshold)
Find onset positions using spectral flux.
std::vector< std::vector< double > > extract_high_spectral_data(const std::vector< std::span< const double > > &data, double spectral_threshold, uint32_t window_size, uint32_t hop_size)
Extract data from regions with high spectral energy.
std::vector< std::vector< double > > extract_onset_data(const std::vector< std::span< const double > > &data, double threshold, uint32_t region_size, uint32_t window_size, uint32_t hop_size)
Extract data at onset/transient positions using spectral flux.
std::vector< std::vector< double > > extract_windowed_data_by_indices(const std::vector< std::span< const double > > &data, const std::vector< size_t > &window_indices, uint32_t window_size)
Extract specific data windows by indices.
std::vector< std::vector< double > > extract_above_mean_data(const std::vector< std::span< const double > > &data, double mean_multiplier, uint32_t window_size, uint32_t hop_size)
Extract data from regions with values above statistical mean.
std::vector< std::vector< double > > extract_peak_data(const std::vector< std::span< const double > > &data, double threshold, double min_distance, uint32_t region_size)
Extract data from peak regions using peak detection.
std::vector< std::string > get_available_extraction_methods()
Get available extraction methods.
std::vector< std::vector< double > > extract_high_energy_data(const std::vector< std::span< const double > > &data, double energy_threshold, uint32_t window_size, uint32_t hop_size)
Extract data from high-energy regions using EnergyAnalyzer.
std::vector< std::vector< double > > extract_zero_crossing_data(const std::vector< std::span< const double > > &data, double threshold, double min_distance, uint32_t region_size)
Extract data at zero crossing points using existing EnergyAnalyzer.
std::vector< std::pair< size_t, size_t > > window_positions
Statistical results for a single data channel.
std::vector< ChannelEnergy > channels
Analysis result structure for energy analysis.