This is the implementation guide for the Blackman window. For theoretical background, including mathematical formula, frequency response, and spectral analysis, see the the article on Blackman window.
All code examples are written in C for maximum performance and portability.
Direct Implementation
The following function computes the Blackman window value for a given sample index n and total window length N. The window uses three cosine terms for superior sidelobe suppression.
#include <math.h>
/**
* Compute Blackman 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_window_sample(int n, int N) {
if (N <= 1) return 1.0;
if (n < 0 || n >= N) return 0.0;
const double a0 = 0.42;
const double a1 = 0.5;
const double a2 = 0.08;
double angle = 2 * M_PI * n / (N - 1);
return a0 - a1 * cos(angle) + a2 * cos(2 * 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 window array.
*
* @param N Length of the window (number of samples)
* @param out Output array of length N (must be pre-allocated)
*/
void blackman_window_array(int N, double *out) {
if (N <= 0) return;
if (N == 1) {
out[0] = 1.0;
return;
}
const double a0 = 0.42;
const double a1 = 0.5;
const double a2 = 0.08;
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);
}
}
Usage Example
The following example demonstrates how to apply the Blackman 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 window
blackman_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.000000 0.000000 0.000000
1 0.000049 0.647387 0.000032
2 0.000195 0.998351 0.000195
3 0.000437 0.907575 0.000397
4 0.000774 0.460073 0.000356
Implementation Notes
- Coefficients: The Blackman window uses a0 = 0.42, a1 = 0.5, and a2 = 0.08, which provides a first sidelobe level of approximately -58 dB.
- Three cosine terms: Unlike Hann (2 terms) and Hamming (2 terms), the Blackman window uses three terms for superior sidelobe suppression.
- Endpoints: The window tapers to exactly zero at both ends (n=0 and n=N-1).
- 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_WINDOW[N] = {
0.000000, 0.000049, 0.000195, 0.000437, 0.000774, /* ... */
/* Full table would be generated by a script */
};
// Usage
for (int i = 0; i < N; i++) {
windowed[i] = signal[i] * BLACKMAN_WINDOW[i];
}
Comparison of Cosine Windows
The following table compares the three cosine-based windows implemented in this series:
Window a0 a1 a2 First sidelobe Endpoint value
Hann 0.50 0.50 - -31 dB 0.000
Hamming 0.54 0.46 - -41 dB 0.080
Blackman 0.42 0.50 0.08 -58 dB 0.000