Fix IndexError in THD() for low/fractional fundamental frequencies - #42
Fix IndexError in THD() for low/fractional fundamental frequencies#42youdie006 wants to merge 1 commit into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review. 📝 WalkthroughWalkthroughTHD now stops harmonic analysis before it accesses FFT bins beyond the spectrum. A regression test covers a low fractional frequency that rounds to an FFT-bin boundary. ChangesTHD harmonic bounds
Estimated code review effort: 2 (Simple) | ~5 minutes Merge Risk: ⚪ Minimal · up to The change prevents THD() from indexing harmonics beyond the Nyquist limit while preserving in-range calculations, with a focused regression test covering the failure case. No actionable merge-blocking risk remains beyond normal checks and review. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
THD() computes the harmonic count from the continuous fundamental (num_harmonics = int((fs/2)/frequency)) but indexes each harmonic with the rounded fundamental bin i = int(round(frequency*N/fs)). When the fractional bin rounds up, i * num_harmonics overshoots the rfft length len(f) = N//2+1, so the last harmonic's bin lands past Nyquist and f[i*h] is out of bounds. For a low fundamental (e.g. THD(sig, 12000, freq=5.994): i=6, num_harmonics=1001, i*1001=6006 > 6001) this raises IndexError. Guard the index and break the loop once i*h reaches len(f). A harmonic at bin >= len(f) is above the Nyquist frequency and cannot exist in the sampled spectrum, so it must be excluded; break (not continue) is correct because h increases monotonically. Harmonics in range are summed exactly as before, so results for normal signals are unchanged. Fixes endolith#38.
1d0b4ce to
647d8d8
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #42 +/- ##
==========================================
+ Coverage 80.34% 80.44% +0.09%
==========================================
Files 12 12
Lines 407 409 +2
==========================================
+ Hits 327 329 +2
Misses 80 80 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Repro
THD()raisesIndexErrorwhen the fundamental is low enough that its FFT bin rounds up:This is the case described in #38 (fundamental low, rounded bin on the wrong side).
Root cause
THD()computes the number of harmonics from the continuous fundamental:but indexes each harmonic with the rounded fundamental bin
i = int(round(frequency * N / fs)):When the fractional bin rounds up,
i * num_harmonicsovershoots the rfft lengthlen(f) = N//2 + 1, so the last harmonic's bin lands past Nyquist and the index is out of bounds. In the repro,i = round(5.994) = 6,num_harmonics = 1001, andi * 1001 = 6006 > 6001.Fix
Guard the index before use and stop the loop:
Physics oracle: a harmonic at bin
>= len(f)corresponds to a frequency>= fs/2, above Nyquist, which cannot exist in the sampled spectrum, so it must be excluded.break(notcontinue) is correct becausehincreases monotonically -- once one harmonic is out of range, every later one is too. Harmonics whose bin is in range are summed exactly as before, so results for normal signals are unchanged (existingtest_sine/test_sawtooth/test_freq_parameterstill pass).Test
Added a regression test that reproduces #38 and asserts a finite THD:
Before the fix it raises
IndexError: index 6006 is out of bounds for axis 0 with size 6001; after, it returns a finite ratio.Thanks to @khaut for reporting.
AI-assisted: this change was prepared with the help of an AI coding assistant and reviewed by me.
Summary by CodeRabbit
Bug Fixes
Tests