This is the implementation guide for the Triangular window (also known as the Fejér or Bartlett–Fejér window). For theoretical background, including mathematical formula, frequency response, and spectral analysis, see the the article on Triangular window.
All code examples are written in C for maximum performance and portability.
Direct Implementation
The following function computes the Triangular window value for a given sample index n and total window length N. Unlike the Bartlett window, the Triangular window does not go to zero at the endpoints.
#include <math.h>
/**
* Compute Triangular 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 triangular_window_sample(int n, int N) {
if (N <= 1) return 1.0;
if (n < 0 || n >= N) return 0.0;
double m = (N - 1) / 2.0;
double k = fabs(n - m);
/* Triangular window endpoints are NOT zero */
return 1.0 - k / m;
}
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 Triangular window array.
*
* @param N Length of the window (number of samples)
* @param out Output array of length N (must be pre-allocated)
*/
void triangular_window_array(int N, double *out) {
if (N <= 0) return;
if (N == 1) {
out[0] = 1.0;
return;
}
double m = (N - 1) / 2.0;
for (int i = 0; i < N; i++) {
double k = fabs(i - m);
out[i] = 1.0 - k / m;
}
}
Detailed Implementation with Even/Odd Handling
The Triangular window responds differently to even and odd lengths:
/**
* Generate Triangular window with correct even/odd handling.
*
* @param N Length of the window (number of samples)
* @param out Output array of length N (must be pre-allocated)
*/
void triangular_window_array_exact(int N, double *out) {
if (N <= 0) return;
if (N == 1) {
out[0] = 1.0;
return;
}
if (N % 2 == 1) {
/* Odd length – symmetric with a single peak at center */
double m = (N - 1) / 2.0;
for (int i = 0; i < N; i++) {
double k = fabs(i - m);
out[i] = 1.0 - k / m;
}
} else {
/* Even length – symmetric with two equal peak samples at center */
double m = N / 2.0;
for (int i = 0; i < N; i++) {
double k = fabs(i - m + 0.5);
out[i] = 1.0 - k / m;
}
}
}
Usage Example
The following example demonstrates how to apply the Triangular window to a real signal.
#include <stdio.h>
#include <math.h>
#define N 64
int main() {
double window[N];
double signal[N];
double windowed[N];
/* Generate Triangular window */
triangular_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 window signal windowed\n");
for (int i = 0; i < 10; i++) {
printf("%d %.6f %.6f %.6f\n",
i, window[i], signal[i], windowed[i]);
}
return 0;
}
Expected Output (first 5 samples, N=64)
n window signal windowed 0 0.031746 0.000000 0.000000 1 0.063492 0.647387 0.041101 2 0.095238 0.998351 0.095080 3 0.126984 0.907575 0.115261 4 0.158730 0.460073 0.073043
Implementation Notes
- Non-zero endpoints: Unlike the Bartlett window, the Triangular window has endpoints > 0.
- Even vs odd lengths: For even N, there is a flat top of two adjacent samples at the peak.
- Bartlett difference: Triangular window uses
1.0 - k/m; Bartlett uses1.0 - 2*k/(N-1). - Sidelobe level: Approximately -26 dB – similar to Bartlett.
- Main lobe width: Approximately 0.07–0.08 normalized frequency.
- 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 64
static const double TRIANGULAR_WINDOW[N] = {
0.031746, 0.063492, 0.095238, 0.126984, 0.158730, /* ... */
/* Full table would be generated by a script */
};
/* Usage */
for (int i = 0; i < N; i++) {
windowed[i] = signal[i] * TRIANGULAR_WINDOW[i];
}
Bartlett vs Triangular vs Hann
Window Endpoints Peak value Main lobe First sidelobe Rectangular 1.0 1.0 0.04 -13 dB Bartlett 0.0 1.0 0.07 -26 dB Triangular >0.0 1.0 0.08 -26 dB Hann 0.0 1.0 0.08 -31 dB
When to Use Triangular
- Simple tapered window: Easier to compute than cosine-based windows.
- No zero endpoints: When you want a triangular shape but need endpoints > 0.
- Convolution applications: The Triangular window is the convolution of two rectangular windows (with overlap).
- Educational purposes: Demonstrating the transition from rectangular to tapered windows.
Triangular vs Bartlett – Quick Reference
Property Bartlett Triangular
Formula w[n] = 1 - 2|n|/(N) w[n] = 1 - |n|/m
Endpoints 0.0 >0.0
Peak 1.0 1.0
Convolution of Two rectangular Two rectangular
(equal length) (shifted)
See also: The Triangular Window in DSP | Bartlett Window Implementation | Bartlett Window in DSP