Source code for voxatlas.features.acoustic.spectral.spread

import numpy as np

from voxatlas.acoustic.spectral_utils import spectral_spread
from voxatlas.features.base_extractor import BaseExtractor
from voxatlas.features.feature_output import VectorFeatureOutput
from voxatlas.registry.feature_registry import registry


[docs] class SpectralSpreadExtractor(BaseExtractor): r""" Extract the ``acoustic.spectral.spread`` feature within the VoxAtlas pipeline. This public extractor defines the reusable API for computing ``acoustic.spectral.spread`` from VoxAtlas structured inputs. It consumes ``None`` units and produces values aligned to ``frame`` units, making the extractor a stable pipeline node that can be cited independently of the surrounding execution machinery. Algorithm --------- The extractor measures second-moment dispersion of spectral energy around the centroid. 1. Centroid preparation The spectrum and frequency axis are combined with either a supplied or internally computed centroid :math:`C_t`. 2. Spread computation The spread is .. math:: \mathrm{Spread}_t = \sqrt{\frac{\sum_k S_{t,k}(f_k-C_t)^2}{\sum_k S_{t,k}}}. 3. Packaging The resulting contour remains aligned to the source spectrum frames. Notes ----- This extractor declares the upstream dependencies ['acoustic.spectral.spectrum'] and is executed only after those features are available in the pipeline feature store. Examples -------- >>> import numpy as np >>> from voxatlas.features.acoustic.spectral.spread import SpectralSpreadExtractor >>> from voxatlas.features.feature_input import FeatureInput >>> from voxatlas.features.feature_output import MatrixFeatureOutput >>> from voxatlas.pipeline.feature_store import FeatureStore >>> store = FeatureStore() >>> spectrum = MatrixFeatureOutput( ... feature="acoustic.spectral.spectrum", ... unit="frame", ... time=np.array([0.0, 0.01], dtype=np.float32), ... frequency=np.array([0.0, 1000.0, 2000.0], dtype=np.float32), ... values=np.array([[0.0, 1.0, 0.0], [1.0, 1.0, 1.0]], dtype=np.float32), ... ) >>> store.add("acoustic.spectral.spectrum", spectrum) >>> feature_input = FeatureInput(audio=None, units=None, context={"feature_store": store}) >>> out = SpectralSpreadExtractor().compute(feature_input, {}) >>> out.values.shape (2,) >>> float(out.values[0]) 0.0 >>> round(float(out.values[1]), 1) 816.5 """ name = "acoustic.spectral.spread" input_units = None output_units = "frame" dependencies = ["acoustic.spectral.spectrum"] default_config = {}
[docs] def compute(self, feature_input, params): """ Compute the extractor output for a single pipeline invocation. This method is the reusable execution entry point for the extractor. It receives the standard ``FeatureInput`` bundle, applies the configured algorithm, and returns feature values aligned to the extractor output units for storage in the pipeline feature store. Parameters ---------- feature_input : object Structured extractor input bundling audio, hierarchical units, and execution context for this feature computation. params : object Resolved feature configuration for this invocation. Keys are feature-specific and merged from defaults and pipeline settings. Returns ------- FeatureOutput Structured output aligned to the ``frame`` unit level when applicable. Examples -------- >>> import numpy as np >>> from voxatlas.features.acoustic.spectral.spread import SpectralSpreadExtractor >>> from voxatlas.features.feature_input import FeatureInput >>> from voxatlas.features.feature_output import MatrixFeatureOutput >>> from voxatlas.pipeline.feature_store import FeatureStore >>> store = FeatureStore() >>> spectrum = MatrixFeatureOutput( ... feature="acoustic.spectral.spectrum", ... unit="frame", ... time=np.array([0.0], dtype=np.float32), ... frequency=np.array([0.0, 1000.0, 2000.0], dtype=np.float32), ... values=np.array([[0.0, 1.0, 0.0]], dtype=np.float32), ... ) >>> store.add("acoustic.spectral.spectrum", spectrum) >>> feature_input = FeatureInput(audio=None, units=None, context={"feature_store": store}) >>> result = SpectralSpreadExtractor().compute(feature_input, {}) >>> result.unit 'frame' """ spectrum_output = feature_input.context["feature_store"].get( "acoustic.spectral.spectrum" ) values = spectral_spread( spectrum_output.values, spectrum_output.frequency, ) return VectorFeatureOutput( feature=self.name, unit="frame", time=np.asarray(spectrum_output.time, dtype=np.float32), values=np.asarray(values, dtype=np.float32), )
registry.register(SpectralSpreadExtractor)