Classic FIR Filter Bank — User Guide

Finite Impulse Response filter implementations with guaranteed linear phase: windowed-sinc designs, moving average, raised-cosine, and Hilbert transform for perfect 90° phase shift.

Author: Shai Cohen Affiliation: Department of Music, Bar-Ilan University, Israel Version: 0.1 (Linear Phase Edition, 2025) License: MIT License Repo: https://github.com/ShaiCohen-ops/Praat-plugin_AudioTools
Contents:

What this does

This script implements a comprehensive Finite Impulse Response (FIR) filter bank with guaranteed linear phase characteristics. Unlike IIR filters which can introduce phase distortion, all FIR filters in this collection maintain perfect phase linearity, making them ideal for applications where phase preservation is critical. The implementation includes 9 distinct filter types: 6 windowed-sinc designs (Rectangular, Hamming, Hann, Blackman, Kaiser, Bartlett), moving average filters, raised-cosine filters for communication systems, and Hilbert transforms for analytic signal creation. Each filter is implemented with symmetric coefficients to ensure linear phase, and utilizes fast convolution for efficient processing.

Key Features:

Why FIR Filters for Linear Phase? Finite Impulse Response filters achieve linear phase through coefficient symmetry: h[n] = h[N-1-n]. This symmetry ensures the frequency response has constant group delay, meaning all frequency components experience the same time delay through the filter. Benefits: (1) No phase distortion: Waveform shape preserved (critical for audio transients). (2) Stability guaranteed: FIR filters are always stable (no poles outside unit circle). (3) Precise linear phase: Can achieve exact 90° shift (Hilbert transform). (4) Arbitrary frequency response: Can approximate any desired response with sufficient length. Tradeoffs: (1) Higher computational cost: Longer filters than IIR for same sharpness. (2) Transition width: Limited by filter length. This implementation balances these tradeoffs with optimized convolution.

Technical Implementation: (1) Coefficient calculation: Each filter type computes symmetric coefficients h[n] for n=0..N-1. (2) Window application: Windowed-sinc filters multiply ideal sinc by window function. (3) Symmetry enforcement: Odd filter length ensures center coefficient exists. (4) Fast convolution: Uses Praat's Convolve function (C-optimized) rather than manual filtering. (5) Highpass transformation: Spectral inversion: h_HP[n] = -h_LP[n] + δ[n-M]. (6) Response calculation: Direct DFT of coefficients for frequency/phase plots. (7) Normalization: DC gain normalized to unity for lowpass filters. The implementation prioritizes both mathematical correctness and computational efficiency.

Quick start

  1. In Praat, select exactly one Sound object (mono or stereo).
  2. Run script…classic_fir_filter_bank.praat.
  3. Choose Filter_type: Start with "Windowed-sinc (Hamming)" for good balance.
  4. Select Filter_mode: Lowpass or Highpass (except Hilbert transform).
  5. Set Filter_length_(N): 101 samples typical (automatically made odd).
  6. Set Cutoff_frequency_(Hz): Must be below Nyquist (fs/2).
  7. For Kaiser window, adjust Kaiser_beta (0-10, higher = narrower main lobe).
  8. For Raised-cosine, set Rolloff_factor (0-1, 0.5 typical).
  9. Enable Plot_responses to see frequency/phase characteristics.
  10. Enable Plot_impulse_response to verify symmetry.
  11. Enable Apply_filter to process audio.
  12. Enable Play_result to hear output.
  13. Click OK — filter designed and applied with visual verification.
Quick tip: For general audio filtering, use "Windowed-sinc (Hamming)" with length 101-201 samples. Longer filters produce sharper cutoffs but more computation. Verify linear phase by enabling impulse response plot — it should be perfectly symmetric. For communication systems, use "Raised-cosine" with rolloff 0.2-0.5. For simple smoothing, use "Moving Average" (all coefficients equal). For analytic signals or single-sideband modulation, use "Hilbert Transform". The fast convolution implementation handles long files efficiently. Always check phase plot — it should be perfectly linear (straight line) for all filters except Hilbert (which has constant -90° shift).
Important: LINEAR PHASE REQUIREMENT: Filter length must be odd to maintain perfect symmetry. Script automatically adjusts even lengths by adding 1. TRANSITION BAND: FIR filters have inherent transition width ≈ fs/N. Very sharp cutoffs require very long filters. KAISER WINDOW: Beta parameter controls sidelobe suppression vs. main lobe width (0 = rectangular, 10 = very narrow). HILBERT TRANSFORM: Only works on real signals, produces imaginary part for analytic signal. NYQUIST CONSIDERATIONS: Cutoffs near fs/2 may produce poor results due to windowing effects. COMPUTATIONAL LOAD: Convolution is O(N×M) but Praat's implementation is optimized. GROUP DELAY: All filters have constant group delay = (N-1)/(2fs) seconds. STEREO PROCESSING: Both channels filtered independently with same coefficients.

FIR Filter Theory & Design

Finite Impulse Response Fundamentals

🔢 Discrete Convolution Implementation

Difference equation: y[n] = Σ_{k=0}^{N-1} h[k]·x[n-k]

Impulse response: h[n] finite length N samples

Linear phase condition: h[n] = h[N-1-n] (symmetry)

Frequency response: H(ω) = Σ_{n=0}^{N-1} h[n]·e^{-jωn}

Constant group delay: τ_g = (N-1)/2 samples

FIR Filter Mathematics

# FIR FILTER FUNDAMENTALS # Difference equation (time domain): y[n] = h[0]·x[n] + h[1]·x[n-1] + ... + h[N-1]·x[n-(N-1)] # Transfer function (z-domain): H(z) = Σ_{n=0}^{N-1} h[n]·z^{-n} # Frequency response (ω = 2πf/fs): H(e^{jω}) = Σ_{n=0}^{N-1} h[n]·e^{-jωn} # For linear phase (symmetric coefficients): h[n] = h[N-1-n] for n = 0, 1, ..., N-1 # Resulting phase response: ∠H(e^{jω}) = -ω·(N-1)/2 + constant # Group delay (constant for all frequencies): τ_g(ω) = -d∠H/dω = (N-1)/2 samples # IMPLEMENTATION IN SCRIPT: # All filters ensure symmetry by: 1. Requiring odd N: N = 2M + 1 2. Center coefficient at index M = (N-1)/2 3. h[n] = h[N-1-n] for all n # CONVOLUTION METHOD: # Uses Praat's optimized Convolve: output = Convolve(input, impulse_response, "sum", "zero") # Much faster than manual implementation in Praat script

Windowed-Sinc Design Method

Ideal Lowpass Filter Approximation

The window method for FIR design:

# IDEAL LOWPASS FILTER (SINC FUNCTION) # Continuous-time ideal lowpass impulse response: h_ideal(t) = 2f_c · sinc(2f_c t) where sinc(x) = sin(πx)/(πx) # Sampled version (discrete time): n = -∞ to ∞ h_ideal[n] = 2f_c/fs · sinc(2f_c n/fs) # Truncated to finite length N: n = 0 to N-1 m = n - M where M = (N-1)/2 (center index) h_truncated[n] = 2·(f_c/fs) · sinc(2·(f_c/fs)·m) # Special case for m = 0 (center): h_truncated[M] = 2·(f_c/fs) # In script implementation: wc = f_c / (f_s/2) # normalized cutoff (0 to 1) IF m = 0: h[n] = 2 * wc ELSE: h[n] = sin(2 * pi * wc * m) / (pi * m) # WINDOWING TO REDUCE GIBBS PHENOMENON: # Multiply truncated sinc by window function w[n]: h_windowed[n] = h_truncated[n] × w[n] # Window functions trade off: # - Main lobe width (affects transition band) # - Side lobe suppression (affects stopband ripple) # NORMALIZATION FOR UNITY DC GAIN: sum = Σ h_windowed[n] IF sum ≠ 0: h_normalized[n] = h_windowed[n] / sum

Window Function Characteristics

Rectangular Window (No Window)

📏 Simple Truncation (Poor Performance)

Formula: w[n] = 1 for all n

Main lobe width: Narrowest (4π/N)

Side lobe level: -13dB (worst)

Transition width: Sharpest but with Gibbs oscillation

Use: Theoretical reference, not recommended for practical filtering

Hamming Window

📊 Excellent General Purpose

Formula: w[n] = 0.54 - 0.46·cos(2πn/(N-1))

Main lobe width: 8π/N

Side lobe level: -43dB

Transition width: Good balance

Use: Default choice for most filtering applications

Hann (Hanning) Window

📈 Good Spectral Leakage Reduction

Formula: w[n] = 0.5 - 0.5·cos(2πn/(N-1))

Main lobe width: 8π/N

Side lobe level: -31dB

Transition width: Similar to Hamming

Use: Spectral analysis, compromise between main lobe and sidelobes

Blackman Window

📉 Excellent Sideband Suppression

Formula: w[n] = 0.42 - 0.5·cos(2πn/(N-1)) + 0.08·cos(4πn/(N-1))

Main lobe width: 12π/N (widest)

Side lobe level: -58dB (best suppression)

Transition width: Widest

Use: When stopband attenuation is critical

Kaiser Window

🎚️ Adjustable Parameter (Beta)

Formula: w[n] = I₀(β√(1-[(n-M)/M]²)) / I₀(β)

Main lobe width: Adjustable via β parameter

Side lobe level: Adjustable via β parameter

Parameter β: 0 (rectangular) to 10+ (narrow main lobe)

Use: When precise control over sidelobes vs. main lobe is needed

Bartlett (Triangular) Window

🔺 Simple Triangular Shape

Formula: w[n] = 1 - |2n/(N-1) - 1|

Main lobe width: 8π/N

Side lobe level: -25dB

Transition width: Moderate

Use: Simple smoothing, computational efficiency

Window Comparison Table

WindowMain Lobe WidthSide Lobe LevelTransition WidthStopband AttenuationTypical Use
Rectangular4π/N-13dB0.9/N21dBReference only
Bartlett8π/N-25dB2.4/N25dBSimple smoothing
Hann8π/N-31dB3.1/N44dBGeneral purpose
Hamming8π/N-41dB3.3/N53dBDefault choice
Blackman12π/N-57dB5.5/N74dBHigh stopband rejection
Kaiser (β=5)10π/N-45dB4.6/N55dBAdjustable performance
Kaiser (β=8)12π/N-57dB5.7/N75dBHigh rejection needed

Filter Type Implementations

Windowed-Sinc Filters (Types 1-6)

🎛️ Most Common FIR Design Method

Design principle: Ideal sinc impulse response × window function

Formula: h[n] = 2f_c·sinc(2f_c(n-M)) × w[n]

Characteristics: Linear phase, controllable transition width

Window tradeoffs: Different windows provide different sidelobe/transition balances

Implementation: 6 window types with identical sinc core

Windowed-Sinc Implementation Details

# WINDOWED-SINC IMPLEMENTATION (procedure designWindowedSinc) # Inputs: filter_length N, cutoff wc (normalized 0-1) M = (N-1)/2 # Center index (odd N guaranteed) FOR n = 0 TO N-1: m = n - M # Shift to symmetric indexing # Ideal sinc lowpass IF m = 0: h_ideal = 2 * wc ELSE: h_ideal = sin(2 * pi * wc * m) / (pi * m) # Apply selected window IF filter_type = 1: # Rectangular w = 1 ELSIF filter_type = 2: # Hamming w = 0.54 - 0.46 * cos(2 * pi * n / (N-1)) ELSIF filter_type = 3: # Hann w = 0.5 - 0.5 * cos(2 * pi * n / (N-1)) ELSIF filter_type = 4: # Blackman w = 0.42 - 0.5 * cos(2 * pi * n / (N-1)) + 0.08 * cos(4 * pi * n / (N-1)) ELSIF filter_type = 5: # Kaiser # Bessel I0 computation for Kaiser window arg = kaiser_beta * sqrt(1 - ((2*n/(N-1)) - 1)^2) w = besselI0(arg) / besselI0(kaiser_beta) ELSIF filter_type = 6: # Bartlett (triangular) w = 1 - abs(2*n/(N-1) - 1) # Windowed coefficient h[n] = h_ideal * w # Normalize for unity DC gain sum = Σ h[n] IF abs(sum) > 0.0001: FOR n = 0 TO N-1: h[n] = h[n] / sum # RESULT: Linear phase lowpass FIR filter # Cutoff at exactly wc (normalized frequency) # Window controls sidelobe suppression

Moving Average Filter (Type 7)

📊 Simplest FIR Filter

Formula: h[n] = 1/N for all n

Frequency response: H(ω) = sin(ωN/2)/(N·sin(ω/2))·e^{-jω(N-1)/2}

Characteristics: Very simple, poor frequency selectivity

Use: Simple smoothing, DC averaging, computational simplicity

Implementation: All coefficients equal, automatically symmetric

Raised-Cosine Filter (Type 8)

📡 Communication Systems Standard

Formula: h(t) = sinc(t/T)·cos(παt/T)/[1-(2αt/T)²]

Rolloff factor α: 0 (rectangular) to 1 (slow rolloff)

Characteristics: Zero intersymbol interference, controlled bandwidth

Use: Digital communications, pulse shaping, matched filtering

Implementation: Sampled raised-cosine function with rolloff parameter

Raised-Cosine Implementation

# RAISED-COSINE FILTER IMPLEMENTATION # Used for pulse shaping in digital communications # Parameters: rolloff_factor α (0 to 1), cutoff wc α = rolloff_factor T_symbol = 1 / (2 * wc) # Symbol period in samples FOR n = 0 TO N-1: m = n - M # Center offset t = m / fs # Time in seconds # Special cases to avoid division by zero IF abs(t) < 0.00001: # t = 0 h[n] = 1 / T_symbol ELSIF abs(abs(t) - T_symbol/(2*α)) < 0.00001 AND α > 0: # t = ±T_symbol/(2α) h[n] = (pi/(4*T_symbol)) * sin(pi/(2*α)) / (pi*t) ELSE: # General raised-cosine formula sinc_part = sin(pi*t/T_symbol) / (pi*t/T_symbol) cos_part = cos(pi*α*t/T_symbol) denom = 1 - (2*α*t/T_symbol)^2 IF abs(denom) > 0.00001: h[n] = sinc_part * cos_part / denom ELSE: h[n] = 0 # Normalize for unity DC gain sum = Σ h[n] IF abs(sum) > 0.0001: FOR n = 0 TO N-1: h[n] = h[n] / sum # CHARACTERISTICS: # - Zero intersymbol interference at sampling instants # - Controlled excess bandwidth via α # - Perfect linear phase (symmetric in time) # - Used as transmit/receive matched filter pair

Hilbert Transform (Type 9)

🔄 90° Phase Shift for Analytic Signals

Formula: h[n] = 2/(π·n) for odd n, 0 for even n

Frequency response: H(ω) = -j·sign(ω) for |ω|≤π

Characteristics: Exactly 90° phase shift for all frequencies

Use: Analytic signal creation, single-sideband modulation, envelope detection

Implementation: Windowed ideal Hilbert transform coefficients

Hilbert Transform Implementation

# HILBERT TRANSFORM IMPLEMENTATION # Ideal discrete-time Hilbert transform: # h_ideal[n] = 2/(π·n) for odd n, 0 for even n # Provides exactly 90° phase shift FOR n = 0 TO N-1: m = n - M # Center offset IF m = 0: h[n] = 0 # Center coefficient zero ELSIF m mod 2 = 0: h[n] = 0 # Even indices zero ELSE: h[n] = 2 / (pi * m) # Odd indices: 2/(πm) # Apply Hamming window to reduce truncation effects FOR n = 0 TO N-1: w = 0.54 - 0.46 * cos(2 * pi * n / (N-1)) h[n] = h[n] * w # NO DC GAIN NORMALIZATION (Hilbert has zero DC response) # FREQUENCY RESPONSE CHARACTERISTICS: # Magnitude: |H(ω)| = 1 for all ω ≠ 0 # Phase: ∠H(ω) = -90° for ω > 0, +90° for ω < 0 # Group delay: constant (N-1)/2 samples # APPLICATIONS: 1. Analytic signal: x_a[n] = x[n] + j·H{x[n]} 2. Envelope detection: |x_a[n]| = √(x²[n] + H{x[n]}²) 3. Single-sideband modulation 4. Phase shifting networks

Linear Phase Advantages & Characteristics

Why Linear Phase Matters

⏱️ Constant Group Delay Benefits

Phase response: ∠H(ω) = -ω·τ + constant

Group delay: τ_g = -d∠H/dω = constant

Waveform preservation: All frequencies delayed equally

No phase distortion: Critical for transient signals

Symmetry requirement: h[n] = h[N-1-n]

Linear Phase Mathematics

# LINEAR PHASE CONDITIONS FOR FIR FILTERS # Condition 1: Symmetric coefficients h[n] = h[N-1-n] for n = 0, 1, ..., N-1 # Resulting frequency response: H(ω) = e^{-jω(N-1)/2} × A(ω) where A(ω) is real-valued amplitude response: A(ω) = h[M] + 2·Σ_{n=1}^{M} h[M-n]·cos(ω·n) with M = (N-1)/2 # Phase response: ∠H(ω) = -ω·(N-1)/2 + {0 if A(ω) ≥ 0 π if A(ω) < 0} # Group delay (constant for all ω): τ_g(ω) = -d∠H/dω = (N-1)/2 samples # Time delay in seconds: delay_seconds = (N-1) / (2·fs) # IMPLICATIONS: 1. All frequency components delayed by same amount 2. No phase distortion of waveforms 3. Impulse response symmetric around center 4. Can achieve exactly linear phase (not just approximately) # VERIFICATION IN SCRIPT: - Impulse response plot shows perfect symmetry - Phase plot shows straight line with slope -(N-1)/2 - Group delay constant across frequency

Constant Group Delay Implications

Applications Requiring Linear Phase

# APPLICATIONS WHERE LINEAR PHASE IS CRITICAL # 1. AUDIO PROCESSING (Transient preservation) - Percussive sounds (drums, piano attacks) - Speech transients (plosives, consonants) - Any signal where waveform shape matters - Example: Equalization without smearing transients # 2. IMAGE PROCESSING - Edge detection (no phase distortion of edges) - Image filtering (preserves spatial relationships) - Medical imaging (accurate feature localization) # 3. COMMUNICATIONS - Pulse shaping (no intersymbol interference) - Matched filtering (optimal SNR with linear phase) - Radar/sonar (accurate time-of-arrival estimation) # 4. MEASUREMENT SYSTEMS - Oscilloscope filtering (accurate timing) - Vibration analysis (preserve transient events) - Electrocardiography (ECG waveform preservation) # TRADEOFFS vs. IIR FILTERS: Advantages of FIR with linear phase: 1. Perfect phase linearity (IIR can only approximate) 2. Always stable (no poles outside unit circle) 3. Can achieve arbitrary frequency response 4. Quantization effects less severe Disadvantages: 1. Higher computational cost for same selectivity 2. Longer filters needed for sharp cutoffs 3. More memory required for coefficient storage # IN THIS IMPLEMENTATION: - All filters guarantee linear phase - Odd N enforced for perfect symmetry - Group delay = (N-1)/(2fs) seconds - Phase plots verify linearity

Highpass Transformation with Linear Phase

Spectral Inversion Method

Converting lowpass to highpass while maintaining linear phase:

# HIGH-PASS TRANSFORMATION FOR LINEAR PHASE FIR # Start with lowpass coefficients h_LP[n] (symmetric) # Create highpass via spectral inversion: H_HP(z) = H_LP(-z) # Time domain transformation: h_HP[n] = (-1)^n · h_LP[n] # Alternative implementation (used in script): h_HP[n] = -h_LP[n] for all n h_HP[M] = h_HP[M] + 1 where M = (N-1)/2 # Mathematical justification: H_HP(e^{jω}) = H_LP(e^{j(ω+π)}) = H_LP(-e^{jω}) # Properties preserved: 1. Symmetry: h_HP[n] = h_HP[N-1-n] 2. Linear phase 3. Constant group delay # Frequency response relationship: |H_HP(ω)| = |H_LP(ω+π)| ∠H_HP(ω) = ∠H_LP(ω+π) # IMPLEMENTATION IN SCRIPT: IF filter_mode = 2: # Highpass FOR n = 0 TO N-1: h[n] = -h[n] # Negate all coefficients h[M] = h[M] + 1 # Add 1 to center coefficient # RESULT: Highpass filter with same linear phase characteristics # Cutoff frequency same as lowpass design # Transition width same as lowpass # Stopband attenuation same as lowpass

Parameters & Specifications

Filter Selection

ParameterTypeDefaultDescription
Filter_typeoptionWindowed-sinc (Hamming)9 FIR filter types with linear phase
Filter_modeoptionLowpassLowpass or Highpass (Hilbert is neither)

Core Filter Parameters

ParameterTypeDefaultRangeDescription
Filter_length_(N)integer1013-4097Number of filter taps (automatically made odd)
Cutoff_frequency_(Hz)positive100020 - 0.45×f_s-6dB cutoff frequency (except Hilbert)

Specialized Parameters

ParameterTypeDefaultRangeFilter TypesDescription
Kaiser_betapositive5.00-20Kaiser window onlyShape parameter: 0=rectangular, higher=narrower main lobe
Rolloff_factorpositive0.50-1Raised-cosine onlyExcess bandwidth factor: 0=rectangular, 1=full cosine rolloff

Visualization & Output

ParameterTypeDefaultDescription
Plot_responsesboolean1 (yes)Generate magnitude and phase response plots
Plot_impulse_responseboolean1 (yes)Generate impulse response plot (verify symmetry)
Apply_filterboolean1 (yes)Apply filter to selected sound (fast convolution)
Play_resultboolean1 (yes)Auto-play filtered sound

Performance Characteristics

CharacteristicTypical ValueDependenceNotes
Group Delay(N-1)/(2f_s) secondsLinear with filter lengthConstant for all frequencies
Transition Width~3.3f_s/N (Hamming)Inversely proportional to NWindow-dependent
Stopband Attenuation53dB (Hamming)Window-dependentBlackman: 74dB, Rectangular: 21dB
Computational CostO(N×L) for L samplesLinear in filter lengthPraat's Convolve is optimized C code
Memory UsageO(N) coefficientsLinear in filter lengthPlus working memory for convolution

Applications

Audio Processing & Mastering

Use case: Equalization without phase distortion, transient preservation

Recommended filters: Windowed-sinc (Hamming or Blackman)

Typical settings: Length 101-401, cutoff as needed, verify linear phase

Digital Communications

Use case: Pulse shaping, matched filtering, raised-cosine filtering

Recommended filters: Raised-cosine (Type 8)

Workflow:

Signal Analysis & Measurement

Use case: Analytic signal creation, envelope detection, phase shifting

Recommended filters: Hilbert Transform (Type 9)

Advantages:

Practical Workflow Examples

🎵 Phase-Preserving Audio Equalization

Goal: Apply lowpass filter without smearing transients

Settings:

  • Filter type: Windowed-sinc (Blackman)
  • Filter mode: Lowpass
  • Length: 201 samples (good sharpness)
  • Cutoff: 5000Hz (gentle high-frequency rolloff)
  • Plot_impulse_response: Yes (verify symmetry)
  • Plot_responses: Yes (check linear phase)

Result: High frequencies attenuated with zero phase distortion

📡 Raised-Cosine Pulse Shaping

Goal: Prepare signal for digital transmission

Settings:

  • Filter type: Raised-cosine
  • Length: 101 samples
  • Cutoff: Symbol rate/2 (e.g., 2400Hz for 4800 baud)
  • Rolloff_factor: 0.35 (35% excess bandwidth)
  • Plot_impulse_response: Yes (verify zero ISI at sampling instants)

Result: Bandlimited signal with controlled intersymbol interference

🔄 Analytic Signal for Envelope Detection

Goal: Extract amplitude envelope of modulated signal

Settings:

  • Filter type: Hilbert Transform
  • Length: 101 samples (good 90° approximation)
  • Plot_responses: Yes (verify 90° phase shift and unity magnitude)
  • Apply_filter: Yes (produces imaginary part)

Result: Analytic signal x_a[n] = x[n] + j·H{x[n]} for envelope calculation

Advanced Techniques

Cascading FIR filters for complex responses:
  • Lowpass + Highpass = Bandpass: Convolution of both impulse responses
  • Multiple identical filters = Sharper rolloff: h_total[n] = h[n] * h[n] (convolution)
  • Parallel filters = Filter banks: Different cutoffs, sum or select outputs
  • Hilbert + Delay = Analytic signal delay correction: Compensate for group delay

Remember: Cascading preserves linear phase if all filters have linear phase

Filter length selection guidelines:
  • General audio: 101-201 taps (good compromise)
  • Sharp cutoff needed: 401-801 taps (longer = sharper)
  • Simple smoothing: 21-51 taps (moving average or short FIR)
  • Hilbert transform: 101-201 taps (good 90° approximation)
  • Rule of thumb: Transition width ≈ (window_constant × f_s)/N

Always check frequency response plots to verify performance

Troubleshooting Common Issues

Problem: Filter has poor stopband rejection
Cause: Window with high sidelobes (Rectangular), or filter too short
Solution: Use Blackman or Kaiser window, increase filter length
Problem: Transition band too wide
Cause: Filter too short, or window with wide main lobe
Solution: Increase filter length, use Kaiser with lower beta
Problem: Impulse response not perfectly symmetric
Cause: Even filter length (script should fix this)
Solution: Ensure filter_length is odd, check script adjustment
Problem: Phase plot not perfectly linear
Cause: Numerical precision, or response near zeros
Solution: Normal phase wrapping is okay; check magnitude response