Source code for voxatlas.features.acoustic.spectral.flux
import numpy as np
from voxatlas.acoustic.spectral_utils import spectral_flux
from voxatlas.features.base_extractor import BaseExtractor
from voxatlas.features.feature_output import VectorFeatureOutput
from voxatlas.registry.feature_registry import registry
[docs]
class SpectralFluxExtractor(BaseExtractor):
r"""
Extract the ``acoustic.spectral.flux`` feature within the VoxAtlas pipeline.
This public extractor defines the reusable API for computing ``acoustic.spectral.flux`` 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 inter-frame spectral change using Euclidean distance between adjacent spectra.
1. Frame differencing
Adjacent magnitude spectra are subtracted along the time axis.
2. Norm computation
Flux is defined as
.. math::
\mathrm{Flux}_t = \sqrt{\sum_k (S_{t,k} - S_{t-1,k})^2}.
3. Packaging
The distance value is returned on the frame grid used by the upstream spectrum feature.
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.flux import SpectralFluxExtractor
>>> from voxatlas.features.feature_input import FeatureInput
>>> from voxatlas.features.feature_output import MatrixFeatureOutput
>>> from voxatlas.pipeline.feature_store import FeatureStore
>>> store = FeatureStore()
>>> spectrum = np.array([[0.0, 0.0], [1.0, 0.0]], dtype=np.float32)
>>> freq = np.array([0.0, 1.0], dtype=np.float32)
>>> base = MatrixFeatureOutput(
... feature="acoustic.spectral.spectrum",
... unit="frame",
... time=np.array([0.0, 0.01], dtype=np.float32),
... frequency=freq,
... values=spectrum,
... )
>>> store.add("acoustic.spectral.spectrum", base)
>>> feature_input = FeatureInput(audio=None, units=None, context={"feature_store": store})
>>> out = SpectralFluxExtractor().compute(feature_input, {})
>>> out.values.tolist()
[0.0, 1.0]
"""
name = "acoustic.spectral.flux"
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.flux import SpectralFluxExtractor
>>> from voxatlas.features.feature_input import FeatureInput
>>> from voxatlas.features.feature_output import MatrixFeatureOutput
>>> from voxatlas.pipeline.feature_store import FeatureStore
>>> store = FeatureStore()
>>> spectrum = np.array([[0.0, 0.0], [1.0, 0.0]], dtype=np.float32)
>>> freq = np.array([0.0, 1.0], dtype=np.float32)
>>> base = MatrixFeatureOutput(
... feature="acoustic.spectral.spectrum",
... unit="frame",
... time=np.array([0.0, 0.01], dtype=np.float32),
... frequency=freq,
... values=spectrum,
... )
>>> store.add("acoustic.spectral.spectrum", base)
>>> feature_input = FeatureInput(audio=None, units=None, context={"feature_store": store})
>>> result = SpectralFluxExtractor().compute(feature_input, {})
>>> result.unit
'frame'
"""
spectrum_output = feature_input.context["feature_store"].get(
"acoustic.spectral.spectrum"
)
values = spectral_flux(spectrum_output.values)
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(SpectralFluxExtractor)