visualdynamics.core.octave¶
octave
¶
Proportional-band spectra: a PSD resampled onto octave bands.
A narrowband PSD gives the power per hertz at each frequency line. A proportional-band PSD gives the power in each band, where the bands get wider as the frequency increases. Responses are usually specified this way, and it is also how the ear hears.
The bands are the base-ten system of ANSI S1.11 / IEC 61260:
- One octave is a factor of ten to the three tenths, which is close to
two but not equal to it. For 1/n octave the band ratio is
10 ** (3 / (10 n)). At a sixth of an octave that is 1.122018, where a base-two ratio would be 1.122462. The two differ in the fourth digit, which is enough to move every band edge. - The grid is absolute. It does not depend on the frequency range requested or on any specification; the range only selects which bands of the one fixed grid are returned. 1000 Hz is on the grid.
- Whether the edges or the centers land on
10 ** (3 k / (10 n))depends on whethernis odd or even. For odd fractions (whole octaves, thirds) the band centers are on the grid. For even fractions (sixths, twelfths) the edges are, and the centers fall half a step between. Getting this backwards moves every band by half a step, which is a real difference in the result and much larger than rounding. - The bands tile: each band's upper edge is the next band's lower edge, and a band's center is the geometric mean of its edges.
Converting a spectrum is an integration. The value in a band is the mean-square content of that band divided by its width, so the area under the spectrum is unchanged and the RMS is the same before and after. Reading the narrowband curve at each band center would ignore everything between the centers and would not conserve the RMS.
References
The bands are the ones these two standards define; they agree on every band this module builds.
- ANSI/ASA S1.11-2014, Electroacoustics - Octave-band and Fractional-octave-band Filters - Part 1: Specifications.
- IEC 61260-1:2014, Electroacoustics - Octave-band and fractional-octave-band filters - Part 1: Specifications.
- Bendat, J. S., & Piersol, A. G. (2010). Random Data: Analysis and Measurement Procedures, 4th ed. Wiley. On the relation between a density and the power in a band, which is why a band takes the integral over its width rather than a reading at its center.
Functions:
| Name | Description |
|---|---|
ratio |
The ratio of each band's center to the center of the band below it. |
edges |
The edges of every band that overlaps |
bands |
(centers, widths, edges) for every band that overlaps the range. |
per_octave_of |
The number of bands per octave that a set of band centers is on. |
bin_bounds |
(left, right) edges of the bin that each line represents. |
resample |
|
Functions:¶
ratio
¶
The ratio of each band's center to the center of the band below it.
Raises ValueError when per_octave is less than one.
Source code in src/visualdynamics/core/octave.py
edges
¶
The edges of every band that overlaps low to high, in Hz.
There is one more edge than there are bands, since the bands tile.
The edges are taken from the fixed grid instead of starting at
low, so two spectra covering different ranges land on the same
bands and can be compared. Raises ValueError unless
0 < low < high.
Source code in src/visualdynamics/core/octave.py
bands
¶
(centers, widths, edges) for every band that overlaps the range.
The center is the geometric mean of the band's edges. The arithmetic mean would be higher, and on a log axis the band would then be drawn off center from the frequency that names it.
Source code in src/visualdynamics/core/octave.py
per_octave_of
¶
The number of bands per octave that a set of band centers is on.
It is read from the ratio of the first two positive centers, so two
bands are enough. Raises ValueError with fewer than two.
Source code in src/visualdynamics/core/octave.py
bin_bounds
¶
(left, right) edges of the bin that each line represents.
With no widths, the bin edges are the midpoints between neighboring
lines, which is exact for evenly spaced FFT lines. With widths, the
edges follow from c = sqrt(l u) and w = u - l:
u = (w + sqrt(w^2 + 4 c^2)) / 2, l = u - w
using the positive root. Taking c +/- w/2 would assume the center
is the arithmetic mean of the edges, which is not true for a
proportional band.
Source code in src/visualdynamics/core/octave.py
resample
¶
resample(frequencies: ArrayLike, values: ArrayLike, bounds: ArrayLike, widths: ArrayLike | None = None, source: ArrayLike | None = None) -> ndarray
values integrated onto the bands whose edges are bounds.
Each line represents its own bin and is constant across it, which
is what a discrete density is. A band's content is the part of each
bin that falls inside the band, and the band's value is that
content divided by the band's width, so the area under the spectrum
is unchanged. source gives the (left, right) bin edges of the
input lines; without it they are taken from bin_bounds, which is
only exact for evenly spaced lines. widths overrides the band
widths, which are otherwise the differences of bounds.
Complex values stay complex: the cross terms of a CPSD are averaged over a band the same way the diagonal is.
A band that the data only partly covers holds that content over its
whole width, so it reads lower than its neighbors. The bands are
fixed frequency bands and are never cut down to the part that has
data. A band with no data under it at all is NaN. Raises
ValueError with fewer than two lines.