Blackman–Harris window (impl.)

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

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


Direct Implementation

The following function computes the Blackman–Harris window value for a given sample index n and total window length N. This is a four-term cosine window offering exceptional sidelobe suppression.


#include <math.h>

/**
 * Compute Blackman–Harris window coefficient for a single sample.
 *
 * @param n     Sample index (0 to N-1)
 * @param N     Total window length
 * @return      Window coefficient (0.0 to 1.0)
 */
double blackman_harris_window_sample(int n, int N) {
    if (N <= 1) return 1.0;
    if (n < 0 || n >= N) return 0.0;
    
    const double a0 = 0.35875;
    const double a1 = 0.48829;
    const double a2 = 0.14128;
    const double a3 = 0.01168;
    
    double angle = 2 * M_PI * n / (N - 1);
    
    return a0 - a1 * cos(angle) + a2 * cos(2 * angle) - a3 * cos(6 * angle);
}

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 Blackman–Harris window array.
 *
 * @param N     Length of the window (number of samples)
 * @param out   Output array of length N (must be pre-allocated)
 */
void blackman_harris_window_array(int N, double *out) {
    if (N <= 0) return;
    
    if (N == 1) {
        out[0] = 1.0;
        return;
    }
    
    const double a0 = 0.35875;
    const double a1 = 0.48829;
    const double a2 = 0.14128;
    const double a3 = 0.01168;
    
    for (int i = 0; i < N; i++) {
        double angle = 2 * M_PI * i / (N - 1);
        out[i] = a0 - a1 * cos(angle) + a2 * cos(2 * angle) - a3 * cos(6 * angle);
    }
}

Usage Example

The following example demonstrates how to apply the Blackman–Harris window to a real signal.


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

#define N 512

int main() {
    double window[N];
    double signal[N];
    double windowed[N];
    
    // Generate Blackman–Harris window
    blackman_harris_window_array(N, window);
    
    // Generate test signal (sinusoid with non-integer period)
    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\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	window	signal		windowed
0	0.000009	0.000000	0.000000
1	0.000038	0.647387	0.000025
2	0.000150	0.998351	0.000150
3	0.000335	0.907575	0.000304
4	0.000591	0.460073	0.000272

Implementation Notes

  • Coefficients: The Blackman–Harris window uses a0 = 0.35875, a1 = 0.48829, a2 = 0.14128, and a3 = 0.01168.
  • Four cosine terms: This window uses four terms, providing a first sidelobe level of approximately -92 dB – exceptional suppression.
  • Endpoints: The window values at the endpoints are very close to zero (approximately 0.000009 at n=0 for N=512).
  • Cosine argument: Note the third term uses cos(6 * angle) (not cos(4 * angle)). The standard Blackman–Harris skip the 4th harmonic term.
  • Symmetry: The window is perfectly symmetric: w[n] = w[N-1-n] for all n.
  • 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:


#define N 512

static const double BLACKMAN_HARRIS_WINDOW[N] = {
    0.000009, 0.000038, 0.000150, 0.000335, 0.000591, /* ... */
    /* Full table would be generated by a script */
};

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

Comparison of Cosine Windows

The following table compares all cosine-based windows implemented in this series:

Window              a0      a1      a2      a3      First sidelobe
Hann                0.50    0.50    -       -       -31 dB
Hamming             0.54    0.46    -       -       -41 dB
Blackman            0.42    0.50    0.08    -       -58 dB
Blackman–Harris     0.35875 0.48829 0.14128 0.01168  -92 dB

See also: The Blackman–Harris Window in DSP