CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-spectrum

Spectrum Analysis Tools - contains tools to estimate Power Spectral Densities using methods based on Fourier transform, Parametric methods or eigenvalues analysis

Pending
Overview
Eval results
Files

window-functions.mddocs/

Window Functions

Comprehensive collection of window functions for signal processing applications. Windows are used to reduce spectral leakage in Fourier analysis, control sidelobe levels, and provide different trade-offs between main lobe width and sidelobe suppression.

Capabilities

Window Creation and Management

High-level interface for creating and managing window functions with automatic parameter validation.

def create_window(N, name=None, **kargs):
    """
    Create window function with specified parameters.
    
    Parameters:
    - N: int, window length
    - name: str, window function name
    - **kargs: dict, window-specific parameters
    
    Returns:
    array: Window function values
    """

class Window(N, name=None, **kargs):
    """
    Window function generator and analyzer.
    
    Parameters:
    - N: int, window length
    - name: str, window type ('hamming', 'hanning', 'kaiser', etc.)
    - **kargs: dict, window parameters (beta, alpha, etc.)
    
    Methods:
    - plot(): visualize window and its frequency response
    - info(): display window properties
    """

def enbw(data):
    """
    Calculate equivalent noise bandwidth of window function.
    
    Parameters:
    - data: array-like, window function values
    
    Returns:
    float: Equivalent noise bandwidth (normalized)
    """

def window_visu(N=51, name="hamming", **kargs):
    """
    Visualize window function and its frequency response.
    
    Parameters:
    - N: int, window length
    - name: str, window function name
    - **kargs: dict, window parameters
    
    Returns:
    None: displays plots directly
    """

Common Window Functions

Standard window functions commonly used in signal processing applications.

def window_rectangle(N):
    """
    Rectangular (boxcar) window.
    
    Parameters:
    - N: int, window length
    
    Returns:
    array: Rectangular window values
    """

def window_hamming(N):
    """
    Hamming window with optimized coefficients.
    
    Parameters:
    - N: int, window length
    
    Returns:
    array: Hamming window values
    """

def window_hann(N):
    """
    Hann (Hanning) window - raised cosine.
    
    Parameters:
    - N: int, window length
    
    Returns:
    array: Hann window values
    """

def window_bartlett(N):
    """
    Bartlett (triangular) window.
    
    Parameters:
    - N: int, window length
    
    Returns:
    array: Bartlett window values
    """

def window_blackman(N, alpha=0.16):
    """
    Blackman window with adjustable parameter.
    
    Parameters:
    - N: int, window length
    - alpha: float, window parameter (0.16 for standard Blackman)
    
    Returns:
    array: Blackman window values
    """

def window_kaiser(N, beta=8.6):
    """
    Kaiser window using modified Bessel function.
    
    Parameters:
    - N: int, window length
    - beta: float, shape parameter (higher = more suppression)
    
    Returns:
    array: Kaiser window values
    """

Specialized Window Functions

Advanced window functions for specific applications and requirements.

def window_gaussian(N, alpha=2.5):
    """
    Gaussian window for smooth spectral characteristics.
    
    Parameters:
    - N: int, window length
    - alpha: float, shape parameter (higher = narrower window)
    
    Returns:
    array: Gaussian window values
    """

def window_chebwin(N, attenuation=50):
    """
    Chebyshev window with specified sidelobe attenuation.
    
    Parameters:
    - N: int, window length
    - attenuation: float, sidelobe attenuation in dB
    
    Returns:
    array: Chebyshev window values
    """

def window_taylor(N, nbar=4, sll=-30):
    """
    Taylor window for array processing applications.
    
    Parameters:
    - N: int, window length
    - nbar: int, number of nearly equal sidelobes
    - sll: float, sidelobe level in dB
    
    Returns:
    array: Taylor window values
    """

def window_flattop(N, mode="symmetric", precision=None):
    """
    Flat-top window for amplitude measurements.
    
    Parameters:
    - N: int, window length
    - mode: str, symmetry mode ('symmetric', 'periodic')
    - precision: str, precision level (None, 'octave')
    
    Returns:
    array: Flat-top window values
    """

def window_tukey(N, r=0.5):
    """
    Tukey (tapered cosine) window.
    
    Parameters:
    - N: int, window length
    - r: float, taper ratio (0=rectangular, 1=Hann)
    
    Returns:
    array: Tukey window values
    """

Extended Window Collection

Additional window functions for specialized applications.

def window_cosine(N):
    """
    Simple cosine window.
    
    Parameters:
    - N: int, window length
    
    Returns:
    array: Cosine window values
    """

def window_lanczos(N):
    """
    Lanczos window (sinc function).
    
    Parameters:
    - N: int, window length
    
    Returns:
    array: Lanczos window values
    """

def window_bartlett_hann(N):
    """
    Bartlett-Hann window (hybrid design).
    
    Parameters:
    - N: int, window length
    
    Returns:
    array: Bartlett-Hann window values
    """

def window_nuttall(N):
    """
    Nuttall window (4-term Blackman-Harris).
    
    Parameters:
    - N: int, window length
    
    Returns:
    array: Nuttall window values
    """

def window_blackman_nuttall(N):
    """
    Blackman-Nuttall window.
    
    Parameters:
    - N: int, window length
    
    Returns:
    array: Blackman-Nuttall window values
    """

def window_blackman_harris(N):
    """
    Blackman-Harris window for low sidelobes.
    
    Parameters:
    - N: int, window length
    
    Returns:
    array: Blackman-Harris window values
    """

def window_bohman(N):
    """
    Bohman window (convolution of triangular functions).
    
    Parameters:
    - N: int, window length
    
    Returns:
    array: Bohman window values
    """

def window_parzen(N):
    """
    Parzen window (4th-order B-spline).
    
    Parameters:
    - N: int, window length
    
    Returns:
    array: Parzen window values
    """

Probability-Based Windows

Window functions based on probability density functions.

def window_riesz(N):
    """
    Riesz window.
    
    Parameters:
    - N: int, window length
    
    Returns:
    array: Riesz window values
    """

def window_riemann(N):
    """
    Riemann window.
    
    Parameters:
    - N: int, window length
    
    Returns:
    array: Riemann window values
    """

def window_poisson(N, alpha=2):
    """
    Poisson window (exponential).
    
    Parameters:
    - N: int, window length
    - alpha: float, decay parameter
    
    Returns:
    array: Poisson window values
    """

def window_poisson_hanning(N, alpha=2):
    """
    Poisson-Hanning hybrid window.
    
    Parameters:
    - N: int, window length
    - alpha: float, Poisson parameter
    
    Returns:
    array: Poisson-Hanning window values
    """

def window_cauchy(N, alpha=3):
    """
    Cauchy window (Lorentzian).
    
    Parameters:
    - N: int, window length
    - alpha: float, shape parameter
    
    Returns:
    array: Cauchy window values
    """

Usage Examples

Window Comparison and Analysis

import spectrum
import numpy as np
import matplotlib.pyplot as plt

# Compare common window functions
N = 64
windows = {
    'Rectangular': spectrum.window_rectangle(N),
    'Hamming': spectrum.window_hamming(N),
    'Hanning': spectrum.window_hann(N),
    'Blackman': spectrum.window_blackman(N),
    'Kaiser (β=8.6)': spectrum.window_kaiser(N, beta=8.6),
    'Gaussian': spectrum.window_gaussian(N, alpha=2.5)
}

# Plot window shapes
plt.figure(figsize=(15, 10))

plt.subplot(2, 2, 1)
for name, window in windows.items():
    plt.plot(window, label=name, linewidth=2)
plt.title('Window Functions (Time Domain)')
plt.xlabel('Sample')
plt.ylabel('Amplitude')
plt.legend()
plt.grid(True)

# Plot frequency responses
plt.subplot(2, 2, 2)
NFFT = 512
freqs = np.linspace(0, 0.5, NFFT//2)

for name, window in windows.items():
    # Zero-pad and compute FFT
    windowed_padded = np.concatenate([window, np.zeros(NFFT - N)])
    W = np.fft.fft(windowed_padded)
    W_mag = 20 * np.log10(np.abs(W[:NFFT//2]) / np.max(np.abs(W)))
    plt.plot(freqs, W_mag, label=name, linewidth=2)

plt.title('Window Frequency Responses')
plt.xlabel('Normalized Frequency')
plt.ylabel('Magnitude (dB)')
plt.ylim(-120, 10)
plt.legend()
plt.grid(True)

# Compute and display window properties
plt.subplot(2, 2, 3)
properties = {}
for name, window in windows.items():
    enbw_val = spectrum.enbw(window)
    coherent_gain = np.mean(window)
    processing_gain = np.sum(window**2) / len(window)
    properties[name] = [enbw_val, coherent_gain, processing_gain]

prop_names = ['ENBW', 'Coherent Gain', 'Processing Gain']
x_pos = np.arange(len(windows))

for i, prop in enumerate(prop_names):
    values = [properties[name][i] for name in windows.keys()]
    plt.subplot(2, 2, 3)
    if i == 0:  # ENBW
        plt.bar(x_pos, values, alpha=0.7, label=prop)
        plt.xticks(x_pos, list(windows.keys()), rotation=45)
        plt.ylabel('ENBW')
        plt.title('Equivalent Noise Bandwidth')
        plt.grid(True)

plt.subplot(2, 2, 4)
# Detailed properties table
props_text = "Window Properties:\n\n"
for name in windows.keys():
    enbw_val, cg, pg = properties[name]
    props_text += f"{name}:\n"
    props_text += f"  ENBW: {enbw_val:.3f}\n"
    props_text += f"  Coherent Gain: {cg:.3f}\n"
    props_text += f"  Processing Gain: {pg:.3f}\n\n"

plt.text(0.05, 0.95, props_text, transform=plt.gca().transAxes, 
         fontfamily='monospace', fontsize=8, verticalalignment='top')
plt.axis('off')

plt.tight_layout()
plt.show()

Kaiser Window Parameter Study

import spectrum
import numpy as np
import matplotlib.pyplot as plt

# Study Kaiser window for different β values
N = 128
beta_values = [0, 2, 5, 8.6, 12, 20]
colors = plt.cm.viridis(np.linspace(0, 1, len(beta_values)))

plt.figure(figsize=(15, 8))

# Time domain
plt.subplot(1, 3, 1)
for i, beta in enumerate(beta_values):
    kaiser_win = spectrum.window_kaiser(N, beta=beta)
    plt.plot(kaiser_win, color=colors[i], linewidth=2, 
             label=f'β = {beta}')
plt.title('Kaiser Windows - Time Domain')
plt.xlabel('Sample')
plt.ylabel('Amplitude')
plt.legend()
plt.grid(True)

# Frequency domain
plt.subplot(1, 3, 2)
NFFT = 1024
freqs = np.linspace(0, 0.5, NFFT//2)

for i, beta in enumerate(beta_values):
    kaiser_win = spectrum.window_kaiser(N, beta=beta)
    # Zero-pad and compute FFT
    padded = np.concatenate([kaiser_win, np.zeros(NFFT - N)])
    W = np.fft.fft(padded)
    W_mag = 20 * np.log10(np.abs(W[:NFFT//2]) / np.max(np.abs(W)))
    plt.plot(freqs, W_mag, color=colors[i], linewidth=2, 
             label=f'β = {beta}')

plt.title('Kaiser Windows - Frequency Domain')
plt.xlabel('Normalized Frequency')
plt.ylabel('Magnitude (dB)')
plt.ylim(-140, 10)
plt.legend()
plt.grid(True)

# Properties vs β
plt.subplot(1, 3, 3)
beta_range = np.linspace(0, 20, 50)
enbw_values = []
main_lobe_width = []
peak_sidelobe = []

for beta in beta_range:
    kaiser_win = spectrum.window_kaiser(N, beta=beta)
    enbw_val = spectrum.enbw(kaiser_win)
    enbw_values.append(enbw_val)
    
    # Compute frequency response for main lobe and sidelobe analysis
    padded = np.concatenate([kaiser_win, np.zeros(1024 - N)])
    W = np.fft.fft(padded)
    W_mag = np.abs(W[:512])
    W_mag_db = 20 * np.log10(W_mag / np.max(W_mag))
    
    # Find main lobe width (3dB points)
    peak_idx = np.argmax(W_mag)
    main_lobe_3db = np.where(W_mag_db >= -3)[0]
    main_lobe_width.append(len(main_lobe_3db))
    
    # Find peak sidelobe level
    # Find first null after main lobe
    first_null = peak_idx + np.argmin(W_mag[peak_idx:peak_idx+50])
    if first_null + 10 < len(W_mag_db):
        sidelobe_region = W_mag_db[first_null+5:]
        peak_sidelobe.append(np.max(sidelobe_region))
    else:
        peak_sidelobe.append(-100)

plt.plot(beta_range, enbw_values, 'b-', linewidth=2, label='ENBW')
plt.xlabel('Kaiser β Parameter')
plt.ylabel('ENBW')
plt.title('Kaiser Window Properties vs β')
plt.grid(True)

# Add second y-axis for sidelobe level
ax2 = plt.gca().twinx()
ax2.plot(beta_range, peak_sidelobe, 'r--', linewidth=2, label='Peak Sidelobe (dB)')
ax2.set_ylabel('Peak Sidelobe Level (dB)')
ax2.set_ylim(-120, -20)

# Combined legend
lines1, labels1 = plt.gca().get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
plt.gca().legend(lines1 + lines2, labels1 + labels2, loc='center right')

plt.tight_layout()
plt.show()

# Print some specific values
print("Kaiser Window Design Guidelines:")
print("β = 0:    Rectangular window")
print("β = 5:    Good compromise (≈ Hamming)")  
print("β = 8.6:  Similar to Blackman")
print("β = 12:   High sidelobe suppression")
print("β > 15:   Very high suppression, wide main lobe")

Window Selection for Different Applications

import spectrum
import numpy as np
import matplotlib.pyplot as plt

def demonstrate_windowing_effects(signal, windows_dict, title=""):
    """Demonstrate the effect of different windows on spectral analysis."""
    
    plt.figure(figsize=(15, 12))
    
    # Plot original signal
    plt.subplot(3, 3, 1)
    plt.plot(signal)
    plt.title(f'{title} - Time Domain')
    plt.xlabel('Sample')
    plt.ylabel('Amplitude')
    plt.grid(True)
    
    # Compute and plot windowed signals and spectra
    for i, (window_name, window_func) in enumerate(windows_dict.items()):
        # Apply window
        windowed_signal = signal * window_func
        
        # Compute FFT
        N_fft = 1024
        fft_result = np.fft.fft(windowed_signal, N_fft)
        freqs = np.linspace(0, 0.5, N_fft//2)
        psd = np.abs(fft_result[:N_fft//2])**2
        psd_db = 10 * np.log10(psd / np.max(psd))
        
        # Plot windowed signal
        plt.subplot(3, 3, 2 + i)
        plt.plot(windowed_signal, 'b-', alpha=0.7)
        plt.plot(window_func, 'r--', alpha=0.7, label='Window')
        plt.title(f'{window_name} Windowed')
        plt.xlabel('Sample')
        plt.grid(True)
        if i == 0:
            plt.legend()
        
        # Plot spectrum
        plt.subplot(3, 3, 6 + i)
        plt.plot(freqs, psd_db, linewidth=2)
        plt.title(f'{window_name} Spectrum')
        plt.xlabel('Normalized Frequency')
        plt.ylabel('PSD (dB)')
        plt.ylim(-80, 5)
        plt.grid(True)
    
    plt.tight_layout()
    plt.show()

# Test Case 1: Single sinusoid (spectral leakage)
N = 128
n = np.arange(N)
f = 0.1234  # Non-integer number of cycles
signal1 = np.sin(2 * np.pi * f * n)

windows1 = {
    'Rectangular': spectrum.window_rectangle(N),
    'Hamming': spectrum.window_hamming(N),
    'Kaiser β=8.6': spectrum.window_kaiser(N, beta=8.6),
    'Blackman': spectrum.window_blackman(N)
}

demonstrate_windowing_effects(signal1, windows1, "Single Sinusoid (Leakage Test)")

# Test Case 2: Two close sinusoids (resolution test)
f1, f2 = 0.2, 0.22  # Close frequencies
signal2 = np.sin(2*np.pi*f1*n) + np.sin(2*np.pi*f2*n)

windows2 = {
    'Rectangular': spectrum.window_rectangle(N),
    'Hanning': spectrum.window_hann(N),
    'Flat-top': spectrum.window_flattop(N),
    'Gaussian': spectrum.window_gaussian(N, alpha=2.5)
}

demonstrate_windowing_effects(signal2, windows2, "Two Close Sinusoids (Resolution Test)")

# Test Case 3: Amplitude measurement test
signal3 = 2.5 * np.sin(2*np.pi*0.1*n) + 1.8 * np.sin(2*np.pi*0.3*n)

windows3 = {
    'Rectangular': spectrum.window_rectangle(N),
    'Flat-top': spectrum.window_flattop(N),
    'Kaiser β=12': spectrum.window_kaiser(N, beta=12),
    'Nuttall': spectrum.window_nuttall(N)
}

demonstrate_windowing_effects(signal3, windows3, "Amplitude Measurement Test")

# Window selection guidelines
print("\n" + "="*60)
print("WINDOW SELECTION GUIDELINES")
print("="*60)
print("Application                  | Recommended Windows")
print("-" * 60)
print("General purpose             | Hamming, Hanning")
print("Spectral analysis          | Kaiser (β=8.6), Blackman")  
print("Amplitude measurements     | Flat-top, Kaiser (β=12)")
print("Frequency resolution       | Rectangular, Tukey")
print("Sidelobe suppression       | Chebyshev, Kaiser (β>10)")
print("Transient analysis         | Gaussian, Hamming")
print("Array processing           | Taylor, Chebyshev")
print("Low noise floor            | Blackman-Harris, Nuttall")

Custom Window Design

import spectrum
import numpy as np
import matplotlib.pyplot as plt

def design_custom_window(N, target_sidelobe_db=-60):
    """Design custom Kaiser window for target sidelobe level."""
    
    # Kaiser window design formula
    if target_sidelobe_db > -21:
        beta = 0
    elif target_sidelobe_db >= -50:
        beta = 0.5842 * (abs(target_sidelobe_db) - 21)**0.4 + 0.07886 * (abs(target_sidelobe_db) - 21)
    else:
        beta = 0.1102 * (abs(target_sidelobe_db) - 8.7)
    
    return spectrum.window_kaiser(N, beta=beta), beta

def optimize_window_parameters():
    """Demonstrate window parameter optimization."""
    
    N = 64
    target_levels = [-40, -60, -80, -100]
    
    plt.figure(figsize=(15, 10))
    
    # Design windows for different sidelobe targets
    plt.subplot(2, 2, 1)
    for target_db in target_levels:
        custom_window, beta_used = design_custom_window(N, target_db)
        plt.plot(custom_window, label=f'Target: {target_db}dB (β={beta_used:.2f})', linewidth=2)
    
    plt.title('Custom Kaiser Windows for Different Sidelobe Targets')
    plt.xlabel('Sample')
    plt.ylabel('Amplitude')
    plt.legend()
    plt.grid(True)
    
    # Frequency responses
    plt.subplot(2, 2, 2)
    NFFT = 1024
    freqs = np.linspace(0, 0.5, NFFT//2)
    
    for target_db in target_levels:
        custom_window, beta_used = design_custom_window(N, target_db)
        padded = np.concatenate([custom_window, np.zeros(NFFT - N)])
        W = np.fft.fft(padded)
        W_mag_db = 20 * np.log10(np.abs(W[:NFFT//2]) / np.max(np.abs(W)))
        plt.plot(freqs, W_mag_db, label=f'{target_db}dB target', linewidth=2)
    
    plt.title('Frequency Responses of Custom Windows')
    plt.xlabel('Normalized Frequency')
    plt.ylabel('Magnitude (dB)')
    plt.ylim(-120, 10)
    plt.legend()
    plt.grid(True)
    
    # Parameter relationships
    plt.subplot(2, 2, 3)
    target_range = np.linspace(-20, -120, 100)
    beta_values = []
    enbw_values = []
    
    for target in target_range:
        window, beta = design_custom_window(N, target)
        beta_values.append(beta)
        enbw_values.append(spectrum.enbw(window))
    
    plt.plot(target_range, beta_values, 'b-', linewidth=2, label='Kaiser β')
    plt.xlabel('Target Sidelobe Level (dB)')
    plt.ylabel('Kaiser β Parameter')
    plt.title('Kaiser β vs Sidelobe Target')
    plt.grid(True)
    
    # ENBW vs sidelobe level
    plt.subplot(2, 2, 4)
    plt.plot(target_range, enbw_values, 'r-', linewidth=2)
    plt.xlabel('Target Sidelobe Level (dB)')
    plt.ylabel('Equivalent Noise Bandwidth')
    plt.title('ENBW vs Sidelobe Level Trade-off')
    plt.grid(True)
    
    plt.tight_layout()
    plt.show()

# Demonstrate window class usage
print("Using Window Class for Analysis:")
print("-" * 40)

# Create window object
N = 64
w = spectrum.Window(N, name='kaiser', beta=10.0)

# Get window properties
print(f"Window type: {w.name if hasattr(w, 'name') else 'Kaiser'}")
print(f"Window length: {N}")
print(f"ENBW: {spectrum.enbw(w.data if hasattr(w, 'data') else spectrum.window_kaiser(N, 10.0)):.4f}")

# Visualize multiple windows with the visualization function
print("\nGenerating window visualizations...")
spectrum.window_visu(N=64, name="hamming")
spectrum.window_visu(N=64, name="kaiser", beta=8.6)

# Run the optimization demonstration
optimize_window_parameters()

Install with Tessl CLI

npx tessl i tessl/pypi-spectrum

docs

arma-methods.md

correlation-signal.md

eigenvalue-methods.md

index.md

linear-prediction.md

math-tools.md

nonparametric-methods.md

parametric-ar.md

window-functions.md

tile.json