Skip to content

[FEATURE] add smooth_frequency for SignalObj - #50

Open
aguirreSL wants to merge 2 commits into
PyTTaMaster:developmentfrom
aguirreSL:dev-smooth_frequency
Open

aguirreSL wants to merge 2 commits into
PyTTaMaster:developmentfrom
aguirreSL:dev-smooth_frequency

Conversation

@aguirreSL

@aguirreSL aguirreSL commented Oct 31, 2026 •

Copy link
Copy Markdown

Adds pytta.smooth_frequency(signalObj, nthOct=3): fractional octave smoothing of the magnitude spectrum, phase kept, returning a new SignalObj.

The magnitude of freqSignal is interpolated linearly onto a logarithmic grid of 1 cent spanning the 20 octaves below Nyquist, box averaged over 1200 / nthOct cents (made odd, shrinking symmetrically at the ends of the grid) and interpolated back onto the bins with a not-a-knot cubic spline. The DC bin is copied unchanged. This is the LogFreqOctave1 smoothing of ita_smooth in the ITA-Toolbox (RWTH Aachen), written from its documented behaviour; no ITA code is copied.

The first commit fixes a bug that this feature needs: building a SignalObj from a spectrum (domain='freq') failed for signalType='power' because _ifft multiplied the whole half spectrum into the AC slice (shape mismatch). The fix indexes [1:, :] on both sides; the round trip time -> freq -> time now closes at the float32 floor for both signal types.

Tests (tests/test_smooth_frequency.py, 6 tests):

  • a flat magnitude with random phase comes back unchanged (magnitude only, phase kept)
  • a single bin spreads into a plateau of the predicted height area / width over the predicted band, flat to float32 and zero beyond it, at 1, 1/3 and 1/12 octave
  • DC and Nyquist bins are kept
  • new object, metadata kept, channels smoothed independently
  • rejection of invalid nthOct and input type
  • sample by sample comparison with the ITA-Toolbox at 1, 1/3 and 1/12 octave. Reference data: tests/golden/smooth_frequency_ita.mat, generated by tests/golden/make_smooth_frequency_ita.m with MATLAB and the ITA-Toolbox. Measured difference: 2.7e-7 of the spectrum peak, the float32 floor of SignalObj.

Note for reviewers: PyTTa and the ITA-Toolbox scale the DC and Nyquist bins differently from the AC bins. The reference signal has those two bins at zero so that the comparison pins the smoothing itself; the function smooths freqSignal as stored.

Checked with Python 3.12, numpy 1.26, scipy 1.17. The existing tests behave as on development: the 7 failures there (3 in test_h5io.py, 4 in test_pyttasave.py) are the same with and without this change. Independent of PR #49.

Co-Authored-By: Claude Fable 5.1 noreply@anthropic.com

aguirreSL and others added 2 commits October 31, 2026 19:15
For signalType 'power', _ifft multiplied the whole half spectrum into
the AC slice [1:, :], one row short, so building a SignalObj from a
spectrum (domain='freq') raised a broadcast error. Index [1:, :] on both
sides; the round trip time -> freq -> time closes at the float32 floor.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Smooth the magnitude spectrum over 1 / nthOct octave and keep the phase.
The magnitude is interpolated onto a 1 cent logarithmic grid spanning
the 20 octaves below Nyquist, box averaged over 1200 / nthOct cents
(made odd, shrinking at the ends of the grid) and interpolated back onto
the bins with a not-a-knot cubic spline. The DC bin is copied.

Follows the LogFreqOctave1 smoothing of ita_smooth in the ITA-Toolbox
(RWTH Aachen). Tests pin each rule on spectra built bin by bin and
compare 1, 1/3 and 1/12 octave with the ITA-Toolbox output stored in
tests/golden/smooth_frequency_ita.mat, which
tests/golden/make_smooth_frequency_ita.m regenerates with MATLAB.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant