Skip to content

Enhance DSP Core: Vectorization, IEC Standards, and Precision#35

Merged
jmrplens merged 43 commits intomainfrom
improvements/dsp-vectorization-and-standards
Jan 7, 2026
Merged

Enhance DSP Core: Vectorization, IEC Standards, and Precision#35
jmrplens merged 43 commits intomainfrom
improvements/dsp-vectorization-and-standards

Conversation

@jmrplens
Copy link
Owner

@jmrplens jmrplens commented Jan 7, 2026

No description provided.

- Fix RMS calculation in core.py (use sqrt(mean(x^2)))
- Implement asymmetric IEC 61672-1 time constants for 'impulse' weighting
- Vectorize core processing for efficient multichannel support
- Update Makefile to use pytest
- Improve filter visualization with dynamic frequency ticks
- Update README and generate new compliance graphs
@gemini-code-assist
Copy link

Summary of Changes

Hello @jmrplens, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the PyOctaveBand library by introducing full vectorization for multichannel signal processing, updating compliance with the latest IEC standards for time weighting, and improving overall numerical stability and documentation. These changes aim to boost performance, ensure accuracy, and provide clearer insights into the library's capabilities, particularly for advanced acoustic analysis.

Highlights

  • Core DSP Vectorization: Refactored the OctaveFilterBank's core processing to leverage full NumPy vectorization, eliminating channel-wise loops and significantly boosting performance for multichannel audio signals.
  • IEC Standard Compliance Update: Updated the README.md and the time_weighting implementation to reflect compliance with IEC 61672-1:2013 for Time Weighting, specifically implementing asymmetric ballistics for the 'impulse' mode.
  • Enhanced Documentation & Visualization: Improved the README.md to clearly highlight multichannel and vectorization performance, and updated the generate_graphs.py script to include a visualization of the new 'impulse' time weighting.
  • Test Infrastructure Upgrade: Migrated the test runner in the Makefile from individual Python script calls to pytest, streamlining the testing process.
  • Numerical Stability & Accuracy: Corrected the RMS calculation in _calculate_level and added safeguards against log(0) errors, improving the robustness and accuracy of sound level calculations.
  • Dynamic Plotting: Implemented dynamic x-axis tick generation for filter plots in filter_design.py for better readability across various frequency ranges.
  • Multichannel Utility Support: Enhanced the _resample_to_length utility function to correctly handle resampling and padding for both 1D and multichannel arrays.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This is an excellent pull request that significantly enhances the library's capabilities. The vectorization of the core processing logic for multichannel signals is a major performance improvement. The implementation of proper IEC-compliant impulse time weighting and the refinement of RMS calculations increase the precision and correctness of the library. The accompanying updates to documentation and plotting scripts are also well-executed. I have two minor suggestions for code simplification and a performance consideration for the new impulse weighting feature. Overall, great work.

Comment on lines +95 to +121
elif mode_lower == "impulse":
# IEC 61672-1: 35ms for rising, 1500ms for falling
tau_rise = 0.035
tau_fall = 1.5

alpha_rise = 1 - np.exp(-1 / (fs * tau_rise))
alpha_fall = 1 - np.exp(-1 / (fs * tau_fall))

# Iterate over time (last axis) to handle asymmetric logic
# Move time axis to front for iteration
x_t = np.moveaxis(x_sq, -1, 0)
y_t = np.zeros_like(x_t)

# Initialize state (channels shape)
curr_y = np.zeros(x_t.shape[1:])

# Simple loop over time samples
for i, val in enumerate(x_t):
# Vectorized over channels
rising = val > curr_y
diff = val - curr_y
curr_y += np.where(rising, alpha_rise, alpha_fall) * diff
y_t[i] = curr_y

# Move time axis back
return np.moveaxis(y_t, 0, -1)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The implementation of impulse weighting with asymmetric rise/fall times is correct according to IEC 61672-1. However, the use of a Python for loop to iterate over time samples can lead to poor performance on long audio signals compared to vectorized scipy.signal functions. For real-time or large file processing, this could become a bottleneck.

Consider exploring ways to optimize this, for example by using a JIT compiler like Numba. Adding a @numba.jit decorator to a slightly modified version of this function could provide a significant speedup with minimal code changes, though it would introduce a new dependency.

Comment on lines +39 to +55
if current_length > target_length:
# Slice along the last axis
if y_resampled.ndim == 1:
y_resampled = y_resampled[:target_length]
else:
y_resampled = y_resampled[..., :target_length]

elif current_length < target_length:
diff = target_length - current_length
if y_resampled.ndim == 1:
pad_width = (0, diff)
else:
# Pad only the last axis
pad_width = [(0, 0)] * (y_resampled.ndim - 1) + [(0, diff)]

y_resampled = np.pad(y_resampled, pad_width, mode='constant')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic to handle both 1D and 2D arrays for slicing and padding is correct. However, it can be simplified by removing the if y_resampled.ndim == 1: checks, as the logic in the else blocks already handles the 1D case correctly. Using ... for slicing and constructing pad_width with y_resampled.ndim works universally for arrays of one or more dimensions, making the code more concise and easier to maintain.

    if current_length > target_length:
        # Slice along the last axis (works for both 1D and 2D)
        y_resampled = y_resampled[..., :target_length]
            
    elif current_length < target_length:
        diff = target_length - current_length
        # Pad only the last axis. This works for both 1D and 2D arrays.
        # For 1D, pad_width becomes `[(0, diff)]`.
        # For 2D, pad_width becomes `[(0, 0), (0, diff)]`.
        pad_width = [(0, 0)] * (y_resampled.ndim - 1) + [(0, diff)]
        y_resampled = np.pad(y_resampled, pad_width, mode='constant')

- Fix mypy errors in core.py and utils.py
- Add tests/test_coverage_fix.py to restore 100% coverage
- Verify all checks pass
- Remove unused pytest import in test_coverage_fix.py
- Simplify _resample_to_length logic in utils.py
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
3.10 83 0 100.0% ✅ Passed
3.11 83 0 100.0% ✅ Passed
3.12 83 0 100.0% ✅ Passed
3.13 83 0 100.0% ✅ Passed
3.9 83 0 100.0% ✅ Passed

Filter Architecture Benchmark Report

This report compares the performance and characteristics of the available filter types.

1. Spectral Isolation (at 1kHz)

Filter Type Peak SPL (dB) Atten. -1 Oct (dB) Atten. +1 Oct (dB) Atten. -2 Oct (dB) Atten. +2 Oct (dB)
butter 90.96 40.0 32.3 46.8 57.7
cheby1 90.96 39.8 40.2 46.5 57.2
cheby2 90.96 42.5 50.4 49.2 61.6
ellip 90.95 39.9 45.1 46.6 57.1
bessel 90.54 41.6 33.6 48.4 60.1

2. Stability and Performance

Filter Type Max IR Tail Energy Stability Status Avg. Execution Time (s)
butter 1.29e-09 ✅ Stable 0.0383
cheby1 2.04e-07 ✅ Stable 0.0389
cheby2 2.12e-07 ✅ Stable 0.0393
ellip 4.95e-07 ✅ Stable 0.0402
bessel 2.34e-13 ✅ Stable 0.0500

3. Analysis Summary

  • Butterworth: Best compromise, maximally flat passband.
  • Chebyshev I: Steeper roll-off than Butterworth but with passband ripple.
  • Chebyshev II: Flat passband, ripple in the stopband.
  • Elliptic: Steepest transition but ripples in both passband and stopband.
  • Bessel: Best phase response and minimal ringing (group delay), but slowest roll-off.

Generated Graphs

🔍 View crossover_lr4.png

crossover_lr4.png

🔍 View filter_bessel_fraction_1_order_6.png

filter_bessel_fraction_1_order_6.png

🔍 View filter_bessel_fraction_3_order_6.png

filter_bessel_fraction_3_order_6.png

🔍 View filter_butter_fraction_1_order_6.png

filter_butter_fraction_1_order_6.png

🔍 View filter_butter_fraction_3_order_6.png

filter_butter_fraction_3_order_6.png

🔍 View filter_cheby1_fraction_1_order_6.png

filter_cheby1_fraction_1_order_6.png

🔍 View filter_cheby1_fraction_3_order_6.png

filter_cheby1_fraction_3_order_6.png

🔍 View filter_cheby2_fraction_1_order_6.png

filter_cheby2_fraction_1_order_6.png

🔍 View filter_cheby2_fraction_3_order_6.png

filter_cheby2_fraction_3_order_6.png

🔍 View filter_ellip_fraction_1_order_6.png

filter_ellip_fraction_1_order_6.png

🔍 View filter_ellip_fraction_3_order_6.png

filter_ellip_fraction_3_order_6.png

🔍 View filter_fraction_1.5_order_16.png

filter_fraction_1.5_order_16.png

🔍 View filter_fraction_1.5_order_6.png

filter_fraction_1.5_order_6.png

🔍 View filter_fraction_12_order_6.png

filter_fraction_12_order_6.png

🔍 View filter_fraction_1_order_16.png

filter_fraction_1_order_16.png

🔍 View filter_fraction_1_order_6.png

filter_fraction_1_order_6.png

🔍 View filter_fraction_24_order_6.png

filter_fraction_24_order_6.png

🔍 View filter_fraction_3_order_16.png

filter_fraction_3_order_16.png

🔍 View filter_fraction_3_order_6.png

filter_fraction_3_order_6.png

🔍 View filter_type_comparison.png

filter_type_comparison.png

🔍 View signal_decomposition.png

signal_decomposition.png

🔍 View signal_response_fraction_1.png

signal_response_fraction_1.png

🔍 View signal_response_fraction_3.png

signal_response_fraction_3.png

🔍 View signal_response_multichannel.png

signal_response_multichannel.png

🔍 View time_weighting_analysis.png

time_weighting_analysis.png

🔍 View weighting_responses.png

weighting_responses.png

View Full Artifacts

- Add numba dependency
- Implement JIT-compiled kernel for asymmetric time weighting loop
- Maintain pure Python fallback for robustness
- Update requires-python to >=3.11 in pyproject.toml
- Remove 3.9 and 3.10 from CI matrix
- Set mypy target version to 3.11
- Set Python 3.11+ as minimum version
- Remove legacy fallbacks for typing.Literal
- Make numba a mandatory dependency and optimize impulse kernel
- Remove pure Python fallback for impulse weighting
- Refactor octavefilter API to be explicit (no more **kwargs)
- Add __version__ to package and __repr__ to OctaveFilterBank
- Consolidate coverage tests and achieve 100% traceable coverage
- Fix module-level import order in parametric_filters.py
- Fix mypy errors (redundant casts, Any returns)
- Remove unused imports
- Achieve clean ruff and mypy state
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
3.11 74 0 96.9% ✅ Passed
3.12 74 0 96.9% ✅ Passed
3.13 74 0 96.9% ✅ Passed

Filter Architecture Benchmark Report

This report compares the performance and characteristics of the available filter types.

1. Spectral Isolation (at 1kHz)

Filter Type Peak SPL (dB) Atten. -1 Oct (dB) Atten. +1 Oct (dB) Atten. -2 Oct (dB) Atten. +2 Oct (dB)
butter 90.96 40.0 32.3 46.8 57.7
cheby1 90.96 39.8 40.2 46.5 57.2
cheby2 90.96 42.5 50.4 49.2 61.6
ellip 90.95 39.9 45.1 46.6 57.1
bessel 90.54 41.6 33.6 48.4 60.1

2. Stability and Performance

Filter Type Max IR Tail Energy Stability Status Avg. Execution Time (s)
butter 1.29e-09 ✅ Stable 0.0422
cheby1 2.04e-07 ✅ Stable 0.0426
cheby2 2.12e-07 ✅ Stable 0.0433
ellip 4.95e-07 ✅ Stable 0.0446
bessel 2.34e-13 ✅ Stable 0.0558

3. Analysis Summary

  • Butterworth: Best compromise, maximally flat passband.
  • Chebyshev I: Steeper roll-off than Butterworth but with passband ripple.
  • Chebyshev II: Flat passband, ripple in the stopband.
  • Elliptic: Steepest transition but ripples in both passband and stopband.
  • Bessel: Best phase response and minimal ringing (group delay), but slowest roll-off.

Generated Graphs

🔍 View crossover_lr4.png

crossover_lr4.png

🔍 View filter_bessel_fraction_1_order_6.png

filter_bessel_fraction_1_order_6.png

🔍 View filter_bessel_fraction_3_order_6.png

filter_bessel_fraction_3_order_6.png

🔍 View filter_butter_fraction_1_order_6.png

filter_butter_fraction_1_order_6.png

🔍 View filter_butter_fraction_3_order_6.png

filter_butter_fraction_3_order_6.png

🔍 View filter_cheby1_fraction_1_order_6.png

filter_cheby1_fraction_1_order_6.png

🔍 View filter_cheby1_fraction_3_order_6.png

filter_cheby1_fraction_3_order_6.png

🔍 View filter_cheby2_fraction_1_order_6.png

filter_cheby2_fraction_1_order_6.png

🔍 View filter_cheby2_fraction_3_order_6.png

filter_cheby2_fraction_3_order_6.png

🔍 View filter_ellip_fraction_1_order_6.png

filter_ellip_fraction_1_order_6.png

🔍 View filter_ellip_fraction_3_order_6.png

filter_ellip_fraction_3_order_6.png

🔍 View filter_fraction_1.5_order_16.png

filter_fraction_1.5_order_16.png

🔍 View filter_fraction_1.5_order_6.png

filter_fraction_1.5_order_6.png

🔍 View filter_fraction_12_order_6.png

filter_fraction_12_order_6.png

🔍 View filter_fraction_1_order_16.png

filter_fraction_1_order_16.png

🔍 View filter_fraction_1_order_6.png

filter_fraction_1_order_6.png

🔍 View filter_fraction_24_order_6.png

filter_fraction_24_order_6.png

🔍 View filter_fraction_3_order_16.png

filter_fraction_3_order_16.png

🔍 View filter_fraction_3_order_6.png

filter_fraction_3_order_6.png

🔍 View filter_type_comparison.png

filter_type_comparison.png

🔍 View signal_decomposition.png

signal_decomposition.png

🔍 View signal_response_fraction_1.png

signal_response_fraction_1.png

🔍 View signal_response_fraction_3.png

signal_response_fraction_3.png

🔍 View signal_response_multichannel.png

signal_response_multichannel.png

🔍 View time_weighting_analysis.png

time_weighting_analysis.png

🔍 View weighting_responses.png

weighting_responses.png

View Full Artifacts

- Implement WeightingFilter class for pre-calculating A/C/Z coefficients
- Update weighting_filter to use the new class
- Update calculate_sensitivity to use real RMS formula for consistency
- Ensure all tests pass with 100% traceable coverage
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
3.11 75 0 96.9% ✅ Passed
3.12 75 0 96.9% ✅ Passed
3.13 75 0 96.9% ✅ Passed

Filter Architecture Benchmark Report

This report compares the performance and characteristics of the available filter types.

1. Spectral Isolation (at 1kHz)

Filter Type Peak SPL (dB) Atten. -1 Oct (dB) Atten. +1 Oct (dB) Atten. -2 Oct (dB) Atten. +2 Oct (dB)
butter 90.96 40.0 32.3 46.8 57.7
cheby1 90.96 39.8 40.2 46.5 57.2
cheby2 90.96 42.5 50.4 49.2 61.6
ellip 90.95 39.9 45.1 46.6 57.1
bessel 90.54 41.6 33.6 48.4 60.1

2. Stability and Performance

Filter Type Max IR Tail Energy Stability Status Avg. Execution Time (s)
butter 1.29e-09 ✅ Stable 0.0442
cheby1 2.04e-07 ✅ Stable 0.0432
cheby2 2.12e-07 ✅ Stable 0.0440
ellip 4.95e-07 ✅ Stable 0.0452
bessel 2.34e-13 ✅ Stable 0.0576

3. Analysis Summary

  • Butterworth: Best compromise, maximally flat passband.
  • Chebyshev I: Steeper roll-off than Butterworth but with passband ripple.
  • Chebyshev II: Flat passband, ripple in the stopband.
  • Elliptic: Steepest transition but ripples in both passband and stopband.
  • Bessel: Best phase response and minimal ringing (group delay), but slowest roll-off.

Generated Graphs

🔍 View crossover_lr4.png

crossover_lr4.png

🔍 View filter_bessel_fraction_1_order_6.png

filter_bessel_fraction_1_order_6.png

🔍 View filter_bessel_fraction_3_order_6.png

filter_bessel_fraction_3_order_6.png

🔍 View filter_butter_fraction_1_order_6.png

filter_butter_fraction_1_order_6.png

🔍 View filter_butter_fraction_3_order_6.png

filter_butter_fraction_3_order_6.png

🔍 View filter_cheby1_fraction_1_order_6.png

filter_cheby1_fraction_1_order_6.png

🔍 View filter_cheby1_fraction_3_order_6.png

filter_cheby1_fraction_3_order_6.png

🔍 View filter_cheby2_fraction_1_order_6.png

filter_cheby2_fraction_1_order_6.png

🔍 View filter_cheby2_fraction_3_order_6.png

filter_cheby2_fraction_3_order_6.png

🔍 View filter_ellip_fraction_1_order_6.png

filter_ellip_fraction_1_order_6.png

🔍 View filter_ellip_fraction_3_order_6.png

filter_ellip_fraction_3_order_6.png

🔍 View filter_fraction_1.5_order_16.png

filter_fraction_1.5_order_16.png

🔍 View filter_fraction_1.5_order_6.png

filter_fraction_1.5_order_6.png

🔍 View filter_fraction_12_order_6.png

filter_fraction_12_order_6.png

🔍 View filter_fraction_1_order_16.png

filter_fraction_1_order_16.png

🔍 View filter_fraction_1_order_6.png

filter_fraction_1_order_6.png

🔍 View filter_fraction_24_order_6.png

filter_fraction_24_order_6.png

🔍 View filter_fraction_3_order_16.png

filter_fraction_3_order_16.png

🔍 View filter_fraction_3_order_6.png

filter_fraction_3_order_6.png

🔍 View filter_type_comparison.png

filter_type_comparison.png

🔍 View signal_decomposition.png

signal_decomposition.png

🔍 View signal_response_fraction_1.png

signal_response_fraction_1.png

🔍 View signal_response_fraction_3.png

signal_response_fraction_3.png

🔍 View signal_response_multichannel.png

signal_response_multichannel.png

🔍 View time_weighting_analysis.png

time_weighting_analysis.png

🔍 View weighting_responses.png

weighting_responses.png

View Full Artifacts

- Add explicit type signatures and caching to Numba impulse kernel
- Double check and confirm utils.py simplicity according to PR suggestions
- Final verification of codebase consistency
…graphs

- Fix: remove explicit signature from _apply_impulse_kernel to support both 1D and 2D arrays automatically
- Regenerate all visualization assets including updated time weighting analysis
- Final verification of tests, linting and type checking
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
3.11 75 0 96.9% ✅ Passed
3.12 75 0 96.9% ✅ Passed
3.13 75 0 96.9% ✅ Passed

Filter Architecture Benchmark Report

This report compares the performance and characteristics of the available filter types.

1. Spectral Isolation (at 1kHz)

Filter Type Peak SPL (dB) Atten. -1 Oct (dB) Atten. +1 Oct (dB) Atten. -2 Oct (dB) Atten. +2 Oct (dB)
butter 90.96 40.0 32.3 46.8 57.7
cheby1 90.96 39.8 40.2 46.5 57.2
cheby2 90.96 42.5 50.4 49.2 61.6
ellip 90.95 39.9 45.1 46.6 57.1
bessel 90.54 41.6 33.6 48.4 60.1

2. Stability and Performance

Filter Type Max IR Tail Energy Stability Status Avg. Execution Time (s)
butter 1.29e-09 ✅ Stable 0.0424
cheby1 2.04e-07 ✅ Stable 0.0432
cheby2 2.12e-07 ✅ Stable 0.0440
ellip 4.95e-07 ✅ Stable 0.0450
bessel 2.34e-13 ✅ Stable 0.0556

3. Analysis Summary

  • Butterworth: Best compromise, maximally flat passband.
  • Chebyshev I: Steeper roll-off than Butterworth but with passband ripple.
  • Chebyshev II: Flat passband, ripple in the stopband.
  • Elliptic: Steepest transition but ripples in both passband and stopband.
  • Bessel: Best phase response and minimal ringing (group delay), but slowest roll-off.

Generated Graphs

🔍 View crossover_lr4.png

crossover_lr4.png

🔍 View filter_bessel_fraction_1_order_6.png

filter_bessel_fraction_1_order_6.png

🔍 View filter_bessel_fraction_3_order_6.png

filter_bessel_fraction_3_order_6.png

🔍 View filter_butter_fraction_1_order_6.png

filter_butter_fraction_1_order_6.png

🔍 View filter_butter_fraction_3_order_6.png

filter_butter_fraction_3_order_6.png

🔍 View filter_cheby1_fraction_1_order_6.png

filter_cheby1_fraction_1_order_6.png

🔍 View filter_cheby1_fraction_3_order_6.png

filter_cheby1_fraction_3_order_6.png

🔍 View filter_cheby2_fraction_1_order_6.png

filter_cheby2_fraction_1_order_6.png

🔍 View filter_cheby2_fraction_3_order_6.png

filter_cheby2_fraction_3_order_6.png

🔍 View filter_ellip_fraction_1_order_6.png

filter_ellip_fraction_1_order_6.png

🔍 View filter_ellip_fraction_3_order_6.png

filter_ellip_fraction_3_order_6.png

🔍 View filter_fraction_1.5_order_16.png

filter_fraction_1.5_order_16.png

🔍 View filter_fraction_1.5_order_6.png

filter_fraction_1.5_order_6.png

🔍 View filter_fraction_12_order_6.png

filter_fraction_12_order_6.png

🔍 View filter_fraction_1_order_16.png

filter_fraction_1_order_16.png

🔍 View filter_fraction_1_order_6.png

filter_fraction_1_order_6.png

🔍 View filter_fraction_24_order_6.png

filter_fraction_24_order_6.png

🔍 View filter_fraction_3_order_16.png

filter_fraction_3_order_16.png

🔍 View filter_fraction_3_order_6.png

filter_fraction_3_order_6.png

🔍 View filter_type_comparison.png

filter_type_comparison.png

🔍 View signal_decomposition.png

signal_decomposition.png

🔍 View signal_response_fraction_1.png

signal_response_fraction_1.png

🔍 View signal_response_fraction_3.png

signal_response_fraction_3.png

🔍 View signal_response_multichannel.png

signal_response_multichannel.png

🔍 View time_weighting_analysis.png

time_weighting_analysis.png

🔍 View weighting_responses.png

weighting_responses.png

View Full Artifacts

- Move 'ripple' and 'attenuation' to **kwargs
- Maintain explicit documentation and default values
- Ensure total parameters count is 13
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
3.11 75 0 96.9% ✅ Passed
3.12 75 0 96.9% ✅ Passed
3.13 75 0 96.9% ✅ Passed

Filter Architecture Benchmark Report

This report compares the performance and characteristics of the available filter types.

1. Spectral Isolation (at 1kHz)

Filter Type Peak SPL (dB) Atten. -1 Oct (dB) Atten. +1 Oct (dB) Atten. -2 Oct (dB) Atten. +2 Oct (dB)
butter 90.96 40.0 32.3 46.8 57.7
cheby1 90.96 39.8 40.2 46.5 57.2
cheby2 90.96 42.5 50.4 49.2 61.6
ellip 90.95 39.9 45.1 46.6 57.1
bessel 90.54 41.6 33.6 48.4 60.1

2. Stability and Performance

Filter Type Max IR Tail Energy Stability Status Avg. Execution Time (s)
butter 1.29e-09 ✅ Stable 0.0429
cheby1 2.04e-07 ✅ Stable 0.0429
cheby2 2.12e-07 ✅ Stable 0.0440
ellip 4.95e-07 ✅ Stable 0.0464
bessel 2.34e-13 ✅ Stable 0.0554

3. Analysis Summary

  • Butterworth: Best compromise, maximally flat passband.
  • Chebyshev I: Steeper roll-off than Butterworth but with passband ripple.
  • Chebyshev II: Flat passband, ripple in the stopband.
  • Elliptic: Steepest transition but ripples in both passband and stopband.
  • Bessel: Best phase response and minimal ringing (group delay), but slowest roll-off.

Generated Graphs

🔍 View crossover_lr4.png

crossover_lr4.png

🔍 View filter_bessel_fraction_1_order_6.png

filter_bessel_fraction_1_order_6.png

🔍 View filter_bessel_fraction_3_order_6.png

filter_bessel_fraction_3_order_6.png

🔍 View filter_butter_fraction_1_order_6.png

filter_butter_fraction_1_order_6.png

🔍 View filter_butter_fraction_3_order_6.png

filter_butter_fraction_3_order_6.png

🔍 View filter_cheby1_fraction_1_order_6.png

filter_cheby1_fraction_1_order_6.png

🔍 View filter_cheby1_fraction_3_order_6.png

filter_cheby1_fraction_3_order_6.png

🔍 View filter_cheby2_fraction_1_order_6.png

filter_cheby2_fraction_1_order_6.png

🔍 View filter_cheby2_fraction_3_order_6.png

filter_cheby2_fraction_3_order_6.png

🔍 View filter_ellip_fraction_1_order_6.png

filter_ellip_fraction_1_order_6.png

🔍 View filter_ellip_fraction_3_order_6.png

filter_ellip_fraction_3_order_6.png

🔍 View filter_fraction_1.5_order_16.png

filter_fraction_1.5_order_16.png

🔍 View filter_fraction_1.5_order_6.png

filter_fraction_1.5_order_6.png

🔍 View filter_fraction_12_order_6.png

filter_fraction_12_order_6.png

🔍 View filter_fraction_1_order_16.png

filter_fraction_1_order_16.png

🔍 View filter_fraction_1_order_6.png

filter_fraction_1_order_6.png

🔍 View filter_fraction_24_order_6.png

filter_fraction_24_order_6.png

🔍 View filter_fraction_3_order_16.png

filter_fraction_3_order_16.png

🔍 View filter_fraction_3_order_6.png

filter_fraction_3_order_6.png

🔍 View filter_type_comparison.png

filter_type_comparison.png

🔍 View signal_decomposition.png

signal_decomposition.png

🔍 View signal_response_fraction_1.png

signal_response_fraction_1.png

🔍 View signal_response_fraction_3.png

signal_response_fraction_3.png

🔍 View signal_response_multichannel.png

signal_response_multichannel.png

🔍 View time_weighting_analysis.png

time_weighting_analysis.png

🔍 View weighting_responses.png

weighting_responses.png

View Full Artifacts

… parameters

- Update sonar-project.properties to ignore S107 in __init__.py
- Restore explicit 'ripple' and 'attenuation' parameters in octavefilter
- Ensure high usability and discoverability of the main API
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
3.11 75 0 96.9% ✅ Passed
3.12 75 0 96.9% ✅ Passed
3.13 75 0 96.9% ✅ Passed

Filter Architecture Benchmark Report

This report compares the performance and characteristics of the available filter types.

1. Spectral Isolation (at 1kHz)

Filter Type Peak SPL (dB) Atten. -1 Oct (dB) Atten. +1 Oct (dB) Atten. -2 Oct (dB) Atten. +2 Oct (dB)
butter 90.96 40.0 32.3 46.8 57.7
cheby1 90.96 39.8 40.2 46.5 57.2
cheby2 90.96 42.5 50.4 49.2 61.6
ellip 90.95 39.9 45.1 46.6 57.1
bessel 90.54 41.6 33.6 48.4 60.1

2. Stability and Performance

Filter Type Max IR Tail Energy Stability Status Avg. Execution Time (s)
butter 1.29e-09 ✅ Stable 0.0431
cheby1 2.04e-07 ✅ Stable 0.0435
cheby2 2.12e-07 ✅ Stable 0.0443
ellip 4.95e-07 ✅ Stable 0.0453
bessel 2.34e-13 ✅ Stable 0.0560

3. Analysis Summary

  • Butterworth: Best compromise, maximally flat passband.
  • Chebyshev I: Steeper roll-off than Butterworth but with passband ripple.
  • Chebyshev II: Flat passband, ripple in the stopband.
  • Elliptic: Steepest transition but ripples in both passband and stopband.
  • Bessel: Best phase response and minimal ringing (group delay), but slowest roll-off.

Generated Graphs

🔍 View crossover_lr4.png

crossover_lr4.png

🔍 View filter_bessel_fraction_1_order_6.png

filter_bessel_fraction_1_order_6.png

🔍 View filter_bessel_fraction_3_order_6.png

filter_bessel_fraction_3_order_6.png

🔍 View filter_butter_fraction_1_order_6.png

filter_butter_fraction_1_order_6.png

🔍 View filter_butter_fraction_3_order_6.png

filter_butter_fraction_3_order_6.png

🔍 View filter_cheby1_fraction_1_order_6.png

filter_cheby1_fraction_1_order_6.png

🔍 View filter_cheby1_fraction_3_order_6.png

filter_cheby1_fraction_3_order_6.png

🔍 View filter_cheby2_fraction_1_order_6.png

filter_cheby2_fraction_1_order_6.png

🔍 View filter_cheby2_fraction_3_order_6.png

filter_cheby2_fraction_3_order_6.png

🔍 View filter_ellip_fraction_1_order_6.png

filter_ellip_fraction_1_order_6.png

🔍 View filter_ellip_fraction_3_order_6.png

filter_ellip_fraction_3_order_6.png

🔍 View filter_fraction_1.5_order_16.png

filter_fraction_1.5_order_16.png

🔍 View filter_fraction_1.5_order_6.png

filter_fraction_1.5_order_6.png

🔍 View filter_fraction_12_order_6.png

filter_fraction_12_order_6.png

🔍 View filter_fraction_1_order_16.png

filter_fraction_1_order_16.png

🔍 View filter_fraction_1_order_6.png

filter_fraction_1_order_6.png

🔍 View filter_fraction_24_order_6.png

filter_fraction_24_order_6.png

🔍 View filter_fraction_3_order_16.png

filter_fraction_3_order_16.png

🔍 View filter_fraction_3_order_6.png

filter_fraction_3_order_6.png

🔍 View filter_type_comparison.png

filter_type_comparison.png

🔍 View signal_decomposition.png

signal_decomposition.png

🔍 View signal_response_fraction_1.png

signal_response_fraction_1.png

🔍 View signal_response_fraction_3.png

signal_response_fraction_3.png

🔍 View signal_response_multichannel.png

signal_response_multichannel.png

🔍 View time_weighting_analysis.png

time_weighting_analysis.png

🔍 View weighting_responses.png

weighting_responses.png

View Full Artifacts

- Add passband ripple validation (central 80%)
- Add group delay variance (phase linearity) analysis
- Add crossover flatness evaluation
- Enhance multichannel performance metrics
- Add technical recommendations per filter architecture
- Silenced scipy signal warnings for cleaner console output
- Integrated visual charts into benchmark report
- Added executive summary and methodology sections
- Tracked new benchmark visualization assets
- Unified graphs and benchmark generation in 'assets' job
- Implemented auto-amend and force-push for asset synchronization
- Cleaned up redundant deployment steps
- Added tests/conftest.py to disable Numba JIT during tests automatically
- Ensured JIT is re-enabled for performance tests
- Added 'coverage' target to Makefile
- Updated CI environment for explicit coverage support
@jmrplens jmrplens force-pushed the improvements/dsp-vectorization-and-standards branch from 1eae280 to 596cbeb Compare January 7, 2026 07:48
@jmrplens jmrplens force-pushed the improvements/dsp-vectorization-and-standards branch 4 times, most recently from f54cf73 to a7c5880 Compare January 7, 2026 08:14
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
3.11 75 0 100.0% ✅ Passed
3.12 75 0 100.0% ✅ Passed
3.13 75 0 100.0% ✅ Passed

No images generated.

View Full Artifacts

@jmrplens jmrplens force-pushed the improvements/dsp-vectorization-and-standards branch 4 times, most recently from 528b818 to e591d18 Compare January 7, 2026 08:16
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
3.11 75 0 100.0% ✅ Passed
3.12 75 0 100.0% ✅ Passed
3.13 75 0 100.0% ✅ Passed

No images generated.

View Full Artifacts

@jmrplens jmrplens force-pushed the improvements/dsp-vectorization-and-standards branch 4 times, most recently from 817bbbf to 64f00de Compare January 7, 2026 08:22
@jmrplens jmrplens force-pushed the improvements/dsp-vectorization-and-standards branch from 64f00de to 8bba7de Compare January 7, 2026 08:23
- Avoid shell=True in benchmark script for B602 compliance
- Decouple pr-comment job from assets to prevent skip in PRs
- Ensure CI comments are posted even on failure for visibility
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
3.11 75 0 100.0% ✅ Passed
3.12 75 0 100.0% ✅ Passed
3.13 75 0 100.0% ✅ Passed

No images generated.

View Full Artifacts

- Use absolute path for grep in benchmark script
- Implement [skip ci] logic in assets job to avoid infinite workflow recursion
- Preserve original commit messages during asset amendments
@jmrplens jmrplens force-pushed the improvements/dsp-vectorization-and-standards branch from 16cec15 to b291fc5 Compare January 7, 2026 08:42
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
3.11 75 0 100.0% ✅ Passed
3.12 75 0 100.0% ✅ Passed
3.13 75 0 100.0% ✅ Passed

No images generated.

View Full Artifacts

@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

CI Results 🚀

Test Summary

Python Version Tests Failures Coverage Status
3.11 75 0 100.0% ✅ Passed
3.12 75 0 100.0% ✅ Passed
3.13 75 0 100.0% ✅ Passed

No images generated.

View Full Artifacts

@jmrplens jmrplens merged commit c8e804b into main Jan 7, 2026
13 checks passed
@sonarqubecloud
Copy link

sonarqubecloud bot commented Jan 7, 2026

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