TST: signal.windows: add PSLL/BW correctness tests for 11 windows (gh-3432)#25184
TST: signal.windows: add PSLL/BW correctness tests for 11 windows (gh-3432)#25184TowsifAhamed wants to merge 4 commits into
Conversation
…dows Add `test_correctness` to TestBartHann, TestBartlett, TestBlackman, TestBlackmanHarris, TestBohman, TestBoxcar, TestHamming, TestHann, TestNuttall, TestParzen, and TestCosine. Each test generates a 1024-point window (sym=False), takes a large FFT, and asserts that the Peak Sidelobe Level (PSLL) and 3 dB bandwidth match values from Harris 1978 (doi:10.1109/PROC.1978.10837) and Heinzel 2002, within abs_tol=1 dB and abs_tol=0.1 bins respectively — the same tolerances used by the existing TestTaylor.test_correctness. Closes scipygh-3432
Use np.maximum(..., 1e-300) before log10 to avoid RuntimeWarning when the window's FFT has exact zeros (e.g. boxcar, hann). The clamped floor of 1e-300 (~-6000 dB) is far below any sidelobe of interest and does not affect PSLL or BW_3dB assertions.
71c2b04 to
e22c8d7
Compare
Two bugs were introduced in f81af9d when refactoring _mode_optimization to use the new elementwise.bracket_minimum API: 1. The boundary condition check incorrectly used res_b.bracket (x positions) instead of res_b.f_bracket (function values). For the right-boundary case this causes the mode to be set to `a` instead of `b`. 2. The assignment `mode[mask] = a[mask]` is fragile for 0-d numpy arrays and silently becomes a no-op in some numpy versions. Replaced with np.where. Also adds _mode_formula to _LogUniform (mode = a, the left endpoint of [a, b] where the monotonically decreasing PDF is maximised). Fixes test_funcs[mode-methods3-None-_LogUniform].
| PSLL = np.max(spec[first_zero:-first_zero]) | ||
| BW_3dB = 2 * np.argmax(spec <= -3.0102999566398121) / N_fft * M_win | ||
| assert math.isclose(PSLL, -35.9, abs_tol=1) | ||
| assert math.isclose(BW_3dB, 1.41, abs_tol=0.1) |
There was a problem hiding this comment.
This code for all of these checks is very non-DRY. Can you refactor into some helper? Like maybe this call can just end up being assert_psll_bw(windows.barthann, -35.9, 1.41). Another option would be to create a class and have all these test cases inherit from it but that seems like overkill.
Also it would be better to use assert_allclose rather than math.isclose
There was a problem hiding this comment.
Also it would be better to use assert_allclose rather than math.isclose
Nit: in the brave new Array API world, it's easiest to use xp_assert_close for arrays and math.isclose for python scalars.
There was a problem hiding this comment.
Thanks for the feedback, refactored into _assert_psll_bw(win_func, xp, expected_psll, expected_bw) in the latest commit. Should I keep math.isclose since PSLL and BW_3dB would be plain Python floats after the numpy reduction?
There was a problem hiding this comment.
Yeah math.isclose sounds right to me (now anyway!) if they're Python scalars
| def _mode_formula(self, *, a, **kwargs): | ||
| return a |
There was a problem hiding this comment.
These scipy.stats changes seem unrelated and accidentally committed?
There was a problem hiding this comment.
The issue I faced:
- Commit f81af9d ("ENH: optimize.elementwise: add kwargs support", by Matt Haberland, Feb 23 2026) refactored _mode_optimization to use the new elementwise API
- In that refactor, fl, fm, fr = res_b.bracket was introduced, but res_b.bracket gives x positions, not function values. The function values are res_b.f_bracket
- This causes the boundary detection logic to silently assign the wrong endpoint as the mode
- _LogUniform has a monotonically decreasing PDF so its mode is always at the left boundary — it always hits the broken code path
The exact test failure:
FAILED scipy/stats/tests/test_continuous.py::TestDistributions::test_funcs[mode-methods3-None-_LogUniform]
AssertionError: np.isfinite(res).all() — mode() returned nan for valid params
Could you please advise me on what I can do in this case? It’s also possible that I didn’t understand the situation properly.
j-bowhay
left a comment
There was a problem hiding this comment.
To aid review could you comment a screenshot from the text you have used that confirms the reference values you have used
|
I am not opposed to adding such tests, but I am not fully convinced by the premise that unit testing against additional (hardcoded) mathematical properties is useful. We do have closed-form expressions for all windows against we can test (all windows in file An argument can be made that the spectral properties, aka the FFT, do matter. If so, I would find the following approach to be more effective (though much more tedious):
If deemed useful, the cited table from above could be added to this Window functions page. |
The 11 test_correctness methods had identical FFT/PSLL/BW computation bodies. Extract into module-level _assert_psll_bw() so each method reduces to a single parameterized call.
That's a fair point, and honestly I wasn't fully sure myself. These tests were added to address the open issue #3432, and I followed the same PSLL/BW pattern already used in TestTaylor.test_correctness. Do you think it would be appropriate to keep these as a starting point for now and open a separate issue to track the more rigorous closed-form FFT approach you described? Thanks a lot for the detailed feedback, it's really helpful. |


Reference issue
Closes gh-3432.
What does this implement/fix?
Issue #3432 reported that most
scipy.signal.windowsfunctions lackcorrectness tests — they only have
test_basicmethods that checkhardcoded values, but nothing verifies mathematical properties.
This PR adds a
test_correctnessmethod to 11 window classes:barthannbartlettblackmanblackmanharrisbohmanboxcarhamminghannnuttallparzencosineEach test generates a 1024-point window (sym=False), takes a 131072-point
FFT, and asserts PSLL within ±1 dB and BW_3dB within ±0.1 bins of the
published reference. Pattern follows the existing TestTaylor.test_correctness.
Additional information
No runtime code changes — tests only.
AI Generation Disclosure
Claude Sonnet 4.6 (claude.ai/claude-code) was used to assist with
this PR. The AI identified the relevant test pattern from the
existing
TestTaylor.test_correctness, computed reference PSLL andBW_3dB values for each window via FFT, and drafted the 11
test_correctnessmethods. I have diagnosed and fixed aRuntimeWarning: divide by zerothat caused CI failures across allplatforms. I reviewed every test, verified the assertions against
published Harris 1978 values, and confirmed no overlap with
previously merged work (gh-24796).