60 double mean_energy {};
66 std::array<int, 5> level_counts {};
81 uint32_t window_size {};
106template <ComputeData InputType = std::vector<Kakshya::DataVariant>, ComputeData OutputType = Eigen::VectorXd>
119 : m_window_size(window_size)
120 , m_hop_size(hop_size)
122 validate_window_parameters();
132 auto result = this->analyze_data(data);
133 return safe_any_cast_or_throw<EnergyAnalysis>(result);
142 return safe_any_cast_or_throw<EnergyAnalysis>(this->get_current_analysis());
151 return AnalysisType::FEATURE;
160 return Utils::get_enum_names_lowercase<EnergyMethod>();
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); });
175 != get_available_methods().end();
195 m_window_size = window_size;
196 m_hop_size = hop_size;
197 validate_window_parameters();
209 if (silent >= quiet || quiet >= moderate || moderate >= loud) {
210 throw std::invalid_argument(
"Energy thresholds must be in ascending order");
212 m_silent_threshold = silent;
213 m_quiet_threshold = quiet;
214 m_moderate_threshold = moderate;
215 m_loud_threshold = loud;
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;
251 return channel.
level_counts[
static_cast<size_t>(level)];
261 return Utils::enum_to_lowercase_string(method);
271 if (str ==
"default")
272 return EnergyMethod::RMS;
273 return Utils::string_to_enum_or_throw_case_insensitive<EnergyMethod>(str,
"EnergyMethod");
283 return Utils::enum_to_lowercase_string(level);
293 return "EnergyAnalyzer";
304 auto [data_span, structure_info] = OperationHelper::extract_structured_double(
307 std::vector<std::span<const double>> channel_spans;
308 for (
auto& span : data_span)
309 channel_spans.emplace_back(span.data(), span.size());
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) +
")");
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));
324 energy_values, channel_spans, structure_info);
326 this->store_current_analysis(analysis_result);
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';
333 error_result.
metadata[
"error"] = std::string(
"Analysis failed: ") + e.what();
343 if (name ==
"method") {
345 auto method_str = safe_any_cast_or_throw<std::string>(value);
346 m_method = string_to_method(method_str);
348 }
catch (
const std::runtime_error&) {
349 throw std::invalid_argument(
"Invalid method parameter - expected string or EnergyMethod enum");
351 if (
auto* method_enum = std::any_cast<EnergyMethod>(&value)) {
352 m_method = *method_enum;
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();
361 }
else if (name ==
"hop_size") {
362 if (
auto* size = std::any_cast<uint32_t>(&value)) {
364 validate_window_parameters();
367 }
else if (name ==
"classification_enabled") {
368 if (
auto* enabled = std::any_cast<bool>(&value)) {
369 m_classification_enabled = *enabled;
374 base_type::set_analysis_parameter(name, std::move(value));
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);
391 return base_type::get_analysis_parameter(name);
395 uint32_t m_window_size { 512 };
396 uint32_t m_hop_size { 256 };
398 bool m_classification_enabled {
false };
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 };
407 if (m_window_size == 0) {
408 throw std::invalid_argument(
"Window size must be greater than 0");
410 if (m_hop_size == 0) {
411 throw std::invalid_argument(
"Hop size must be greater than 0");
413 if (m_hop_size > m_window_size) {
414 throw std::invalid_argument(
"Hop size should not exceed window size");
422 const std::vector<std::vector<double>>& energy_values,
423 std::vector<std::span<const double>> original_data,
431 if (energy_values.empty()) {
435 result.
channels.resize(energy_values.size());
437 for (
size_t ch = 0; ch < energy_values.size(); ch++) {
439 auto& channel_result = result.
channels[ch];
440 const auto& ch_energy = energy_values[ch];
442 channel_result.energy_values = ch_energy;
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;
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());
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());
459 const size_t data_size = (ch < original_data.size()) ? original_data[ch].size() : 0;
460 channel_result.window_positions.reserve(ch_energy.size());
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);
468 if (ch < original_data.size()) {
470 case EnergyMethod::ZERO_CROSSING:
472 original_data[ch], 0.0);
475 case EnergyMethod::PEAK: {
476 double peak_threshold = m_classification_enabled ? m_quiet_threshold : 0.01;
478 original_data[ch], peak_threshold, m_hop_size / 4);
482 case EnergyMethod::RMS:
483 case EnergyMethod::POWER:
484 case EnergyMethod::SPECTRAL:
485 case EnergyMethod::HARMONIC:
486 case EnergyMethod::DYNAMIC_RANGE:
493 if (m_classification_enabled) {
494 channel_result.classifications.reserve(ch_energy.size());
495 channel_result.level_counts.fill(0);
497 for (
double energy : ch_energy) {
499 channel_result.classifications.push_back(level);
500 channel_result.level_counts[
static_cast<size_t>(level)]++;
513 std::vector<std::vector<double>> channel_energies;
514 channel_energies.reserve(analysis_result.
channels.size());
516 for (
const auto& ch : analysis_result.
channels) {
517 channel_energies.push_back(ch.energy_values);
520 output_type output = this->convert_result(channel_energies, info);
524 output.
metadata[
"source_analyzer"] =
"EnergyAnalyzer";
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;
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());
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;
557 const size_t num_windows = calculate_num_windows(data.size());
560 case EnergyMethod::PEAK:
562 case EnergyMethod::ZERO_CROSSING:
564 case EnergyMethod::POWER:
566 case EnergyMethod::DYNAMIC_RANGE:
568 case EnergyMethod::SPECTRAL:
570 case EnergyMethod::HARMONIC:
572 case EnergyMethod::RMS:
583 if (data_size < m_window_size)
585 return (data_size - m_window_size) / m_hop_size + 1;
599template <ComputeData InputType = std::vector<Kakshya::DataVariant>>
603template <ComputeData InputType = std::vector<Kakshya::DataVariant>>
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 validate_window_parameters() const
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.
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.
Input/Output container for computation pipeline data flow with structure preservation.