Skip to content

Fix Nyquist bin inclusion for even N FFT lengths#71

Merged
edeno merged 5 commits into
masterfrom
fix/nyquist-nonneg-fft
Oct 17, 2025
Merged

Fix Nyquist bin inclusion for even N FFT lengths#71
edeno merged 5 commits into
masterfrom
fix/nyquist-nonneg-fft

Conversation

@edeno

@edeno edeno commented Sep 25, 2025

Copy link
Copy Markdown
Contributor

Problem

The current non-negative frequency indexing implementation incorrectly excludes the Nyquist frequency bin for even N FFT lengths. This affects the accuracy of connectivity measures computed on even-length FFTs.

Current Behavior

  • Uses arange(0, (N+1)//2) for non-negative frequency selection
  • For even N=1024: produces 512 frequency bins (missing Nyquist)
  • For odd N=1023: produces 512 frequency bins (correct, no Nyquist exists)

Mathematical Issue

According to FFT conventions:

  • Even N: should have N//2 + 1 non-negative frequencies (DC + positive + Nyquist)
  • Odd N: should have (N+1)//2 non-negative frequencies (DC + positive, no Nyquist)

The current formula (N+1)//2 works for odd N but misses the Nyquist bin for even N.

Solution

Replace arange(0, (N+1)//2) with arange(0, N//2 + 1) which correctly handles both cases:

  • Even N=1024: 1024//2 + 1 = 513 frequency bins ✅ (includes Nyquist)
  • Odd N=1023: 1023//2 + 1 = 512 frequency bins ✅ (same as (1023+1)//2)

Changes Made

Core Changes

  1. _non_negative_frequencies decorator (line 107): Updated frequency indexing logic
  2. canonical_coherence method (line 638): Fixed frequency selection for canonical coherence
  3. _estimate_spectral_granger_prediction (line 2108): Fixed Granger causality frequency indexing

Test Changes

  1. Added test_nyquist_bin_even_n(): Validates N=1024 produces 513 frequencies
  2. Added test_nyquist_bin_odd_n(): Validates N=1023 produces 512 frequencies
  3. Updated test_frequencies(): Expects correct frequency count including Nyquist

Validation

Test Results

# Even N validation
N = 1024: Expected 513 frequencies, Got 513N = 8: Expected 5 frequencies, Got 5N = 4: Expected 3 frequencies, Got 3# Odd N validation  
N = 1023: Expected 512 frequencies, Got 512N = 15: Expected 8 frequencies, Got 8N = 7: Expected 4 frequencies, Got 4

Frequency Verification

For n_fft_samples=4, sampling_frequency=1000Hz:

  • Before: [0, 250] Hz (2 frequencies, missing Nyquist)
  • After: [0, 250, -500] Hz (3 frequencies, includes Nyquist at -500 Hz)

Regression Testing

  • ✅ All wrapper tests pass
  • ✅ All transform tests pass
  • ✅ No shape regressions in downstream connectivity metrics

Impact

This fix ensures:

  1. Correct FFT frequency bin handling according to standard conventions
  2. Improved accuracy for connectivity measures on even-length FFTs
  3. Backward compatibility for odd-length FFTs (no behavior change)
  4. Minimal code changes (3 one-line modifications)

The implementation follows test-driven development principles with comprehensive validation of both even and odd N cases.

🤖 Generated with Claude Code

edeno and others added 2 commits September 25, 2025 08:07
Introduces CLAUDE.md to document architecture, development commands, testing strategy, and configuration for the spectral_connectivity Python package. This file provides guidance for contributors and AI assistants working with the codebase.
Problem:
- The non-negative frequency indexing used `arange(0, (N+1)//2)` which
  incorrectly excludes the Nyquist frequency bin for even N FFT lengths
- For even N=1024: old formula gives 512 bins, missing the Nyquist bin
- For odd N=1023: old formula gives 512 bins (correct, no Nyquist exists)

Solution:
- Replace `arange(0, (N+1)//2)` with `arange(0, N//2 + 1)`
- For even N=1024: new formula gives 513 bins (includes Nyquist)
- For odd N=1023: new formula gives 512 bins (same as before)

Changes:
- Updated _non_negative_frequencies decorator in connectivity.py
- Updated canonical_coherence method frequency indexing
- Updated _estimate_spectral_granger_prediction function
- Added unit tests for both even and odd N cases
- Updated wrapper test to expect correct frequency count

This fix ensures proper FFT frequency bin handling according to standard
conventions where even N includes the Nyquist frequency.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@edeno edeno requested review from Copilot and emilyps14 September 25, 2025 12:13
@coveralls

Copy link
Copy Markdown

Coverage Status

coverage: 76.509%. remained the same
when pulling ae47c1c on fix/nyquist-nonneg-fft
into 3e31c94 on master.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull Request Overview

This PR fixes incorrect frequency indexing for even-length FFTs by ensuring the Nyquist frequency bin is properly included. The current implementation uses (N+1)//2 which works for odd N but excludes the Nyquist bin for even N, affecting connectivity measure accuracy.

Key changes:

  • Updated frequency indexing formula from (N+1)//2 to N//2 + 1 in three locations
  • Added comprehensive test coverage for both even and odd FFT lengths
  • Updated existing test expectations to include the Nyquist frequency

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
spectral_connectivity/connectivity.py Fixed frequency indexing in decorator, canonical coherence, and Granger prediction methods
tests/test_connectivity.py Added dedicated tests for Nyquist bin inclusion validation
tests/test_wrapper.py Updated frequency expectations to include Nyquist bin
CLAUDE.md Added new documentation file for repository guidance

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

# Test that frequencies property shape matches when provided
# (frequencies is None when not provided to constructor)


Copilot AI Sep 25, 2025

Copy link

Choose a reason for hiding this comment

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

There are extra blank lines between the incomplete comment and the next function definition. Remove the extra blank line on line 632 to maintain consistent spacing.

Suggested change

Copilot uses AI. Check for mistakes.
Comment thread tests/test_connectivity.py Outdated
Comment on lines +655 to +656
# Test that frequencies property shape matches when provided
# (frequencies is None when not provided to constructor)

Copilot AI Sep 25, 2025

Copy link

Choose a reason for hiding this comment

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

The comment about testing frequencies property shape is incomplete and doesn't correspond to any actual test code. Either complete the test implementation or remove the orphaned comment.

Copilot uses AI. Check for mistakes.
edeno and others added 3 commits October 17, 2025 14:21
Document the breaking change in frequency bin indexing for even-length FFTs.
Includes impact analysis, migration guidance, and scientific justification.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@edeno edeno closed this in 752aecd Oct 17, 2025
@edeno edeno merged commit 752aecd into master Oct 17, 2025
4 of 9 checks passed
@edeno edeno deleted the fix/nyquist-nonneg-fft branch October 17, 2025 18:53
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.

3 participants