Kaiser window (impl.)

This is the implementation guide for the Kaiser window. For theoretical background, including mathematical formula, frequency response, and spectral analysis, see the the article on Kaiser window.

All code examples are written in C for maximum performance and portability.


Direct Implementation

The following function computes the Kaiser window value for a given sample index n and total window length N. The Kaiser window uses a β (beta) parameter that controls the trade-off between main lobe width and sidelobe suppression.


#include <math.h>

/**
 * Compute modified Bessel function of the first kind (order zero).
 * Uses series expansion: I0(x) = sum_{k=0}^{∞} (x/2)^{2k} / (k!)^2
 *
 * @param x     Input value
 * @return      I0(x) approximation
 */
static double bessel_i0(double x) {
    double sum = 1.0;
    double term = 1.0;
    
    for (int k = 1; k <= 25; k++) {
        term *= (x / (2.0 * k)) * (x / (2.0 * k));
        sum += term;
        if (term < 1e-15 * sum) break;
    }
    
    return sum;
}

/**
 * Compute Kaiser window coefficient for a single sample.
 *
 * @param n     Sample index (0 to N-1)
 * @param N     Total window length
 * @param beta  Shape parameter (beta >= 0)
 *              beta = 0  → rectangular window
 *              beta = 4  → moderate sidelobe suppression
 *              beta = 8  → excellent sidelobe suppression
 * @return      Window coefficient (0.0 to 1.0)
 */
double kaiser_window_sample(int n, int N, double beta) {
    if (N <= 1) return 1.0;
    if (n < 0 || n >= N) return 0.0;
    
    double m = (N - 1) / 2.0;
    double alpha = m;
    double x = (n - m) / alpha;
    
    if (beta == 0.0) return 1.0;
    
    double numerator = bessel_i0(beta * sqrt(1.0 - x * x));
    double denominator = bessel_i0(beta);
    
    return numerator / denominator;
}

Full Array Implementation

For better performance when the entire window is needed, the following function fills a pre-allocated array with all coefficients at once.


#include <math.h>
#include <stdlib.h>

/**
 * Generate full Kaiser window array.
 *
 * @param N     Length of the window (number of samples)
 * @param beta  Shape parameter
 * @param out   Output array of length N (must be pre-allocated)
 */
void kaiser_window_array(int N, double beta, double *out) {
    if (N <= 0) return;
    
    if (N == 1) {
        out[0] = 1.0;
        return;
    }
    
    double m = (N - 1) / 2.0;
    double alpha = m;
    double denom = bessel_i0(beta);
    
    for (int i = 0; i < N; i++) {
        double x = (i - m) / alpha;
        double arg = beta * sqrt(1.0 - x * x);
        
        if (arg <= 0.0) {
            out[i] = 1.0;
        } else {
            out[i] = bessel_i0(arg) / denom;
        }
    }
}

Helper Function: Beta Selection

The following helper function computes the optimal β parameter for a desired sidelobe suppression level (in dB).


/**
 * Compute Kaiser window beta parameter from desired sidelobe attenuation (A).
 *
 * @param A     Desired sidelobe attenuation in dB (A > 0)
 *              Typical values: 30 dB, 40 dB, 50 dB, 60 dB, 70 dB, 80 dB
 * @return      Beta parameter
 */
double kaiser_beta_from_attenuation(double A) {
    if (A <= 21.0) {
        return 0.0;
    } else if (A <= 50.0) {
        return 0.5842 * pow(A - 21.0, 0.4) + 0.07886 * (A - 21.0);
    } else {
        return 0.1102 * (A - 8.7);
    }
}

Usage Example

The following example demonstrates how to apply the Kaiser window to a real signal with different β values.


#include <stdio.h>
#include <math.h>

#define N 64
#define BETA 4.0

int main() {
    double window[N];
    double signal[N];
    double windowed[N];
    
    // Generate Kaiser window (beta = 4.0)
    kaiser_window_array(N, BETA, window);
    
    // Generate test signal (sinusoid)
    for (int i = 0; i < N; i++) {
        signal[i] = sin(2 * M_PI * i / 9.5);
    }
    
    // Apply window to signal
    for (int i = 0; i < N; i++) {
        windowed[i] = signal[i] * window[i];
    }
    
    // Print first 10 samples
    printf("n\twindow\t\tsignal\t\twindowed\n");
    for (int i = 0; i < 10; i++) {
        printf("%d\t%.6f\t%.6f\t%.6f\n", 
               i, window[i], signal[i], windowed[i]);
    }
    
    return 0;
}

Expected Output (first 5 samples, N=64, β=4.0)

n    window      signal      windowed
0    0.001712    0.000000    0.000000
1    0.002482    0.647387    0.001607
2    0.004229    0.998351    0.004222
3    0.006974    0.907575    0.006330
4    0.010739    0.460073    0.004941

Implementation Notes

  • Bessel function: The Kaiser window requires computing the modified Bessel function of the first kind I₀(x). The series expansion converges quickly for typical β values.
  • β parameter:
    • β = 0 → Rectangular window
    • β = 4 → Sidelobes ≈ -50 dB (similar to Hann/Hamming)
    • β = 8 → Sidelobes ≈ -80 dB (excellent suppression)
    • β = 12 → Sidelobes ≈ -110 dB (exceptional)
  • Symmetry: The window is perfectly symmetric: w[n] = w[N-1-n] for all n.
  • Endpoints: For β > 0, endpoints are very close to zero but not exactly zero.
  • Numerical stability: When x approaches ±1, the argument sqrt(1 - x²) approaches zero, and we handle this explicitly.
  • Edge case N=1: The only coefficient is 1.0.
  • Precomputation: For real-time applications, precompute the window once and reuse it for multiple signal blocks.

Alternative: Precomputed Lookup Table

For embedded systems or when speed is critical, precompute the window at compile time. The values depend on the chosen β parameter:


#define N 64
#define BETA 4.0

static const double KAISER_WINDOW[N] = {
    0.001712, 0.002482, 0.004229, 0.006974, 0.010739, /* ... */
    /* Full table would be generated by a script */
};

// Usage
for (int i = 0; i < N; i++) {
    windowed[i] = signal[i] * KAISER_WINDOW[i];
}

Kaiser Window vs Other Windows

The Kaiser window's adjustable β parameter makes it the most flexible window function:

β value    Sidelobes (dB)    Main lobe width    Comparable to
0          -13               0.04               Rectangular
3          -30               0.08               Hann
4          -50               0.09               Hamming
6          -70               0.11               Blackman
8          -80               0.13               Blackman–Harris
12         -110              0.17               Dolph–Chebyshev