Skip to content

Window Functions

A window is a finite sequence of weights applied to a block of samples. It reduces discontinuities at block boundaries before spectrum analysis, or controls the transition-width and stopband-attenuation trade-off in a windowed-sinc FIR filter. KFR provides every window_type family as a finite one-dimensional expression.

Include the DSP umbrella header or the focused header:

// or: #include <kfr/dsp/window.hpp>

Creating and rendering a window

Named constructors return concrete lazy expressions. No coefficient array is allocated or calculated until the expression is assigned to a destination or passed to render. A window can therefore be multiplied with a frame in one expression pipeline, or rendered once and reused.

univector<float, 1024> frame = counter<float>();

// Apply a symmetric Hann window without a separate coefficient array.
frame = frame * window_hann<float>(frame.size());

// Materialize coefficients when they will be reused.
univector<float> weights = render(window_kaiser<float>(1024, 8.0f));

The returned window has the requested length and no evolving processing state, so it can be rendered repeatedly. As with all composed expressions, retain any lvalue operands until evaluation; see Expression fundamentals.

Symmetric and periodic sampling

window_symmetry selects how KFR samples the continuous window:

  • symmetric includes both endpoints and is symmetric about the centre. Use it for FIR coefficients and other finite, non-repeating sequences.
  • periodic samples one period without duplicating its final endpoint. Use it for a DFT or other spectral-analysis frame.

For the ordinary window grids, a periodic window of length \(N\) is the first \(N\) values of the corresponding symmetric window of length \(N + 1\). For example, symmetric seven-sample Hann coefficients are { 0, 0.25, 0.75, 1, 0.75, 0.25, 0 }; the periodic eight-sample form is { 0, 0.14644661, 0.5, 0.85355339, 1, 0.85355339, 0.5, 0.14644661 }. Thus an even symmetric centred window commonly has two equal peak-adjacent values below one, while an even periodic one can contain the single centre value one.

Only the named Blackman, Blackman-Harris, Planck-taper, and Tukey functions expose a symmetry argument. The remaining named constructors create symmetric windows. Use the compile-time generic window API for a periodic form of any other family:

univector<float> symmetric_hann = render(window_hann<float>(9));

auto analysis_window = window<float>(
    8,
    cwindow_type<window_type::kaiser>,
    8.0f,
    window_symmetry::periodic);
univector<float> periodic_hann = render(analysis_window);

Named window constructors

The following constructors select a concrete window type at compile time. The scalar type defaults to KFR's default floating-point type; specify it explicitly, such as window_hann<float>(size), when the destination does not establish the desired type.

Family Constructor Shape and parameter
Rectangular window_rectangular All coefficients are one.
Triangular window_triangular Linear peak with nonzero end samples. Its sampling differs from Bartlett.
Bartlett window_bartlett Linear peak that reaches zero at symmetric endpoints.
Cosine window_cosine A single sine lobe.
Cosine, NumPy-compatible window_cosine_np Cosine-family sampling compatible with NumPy's cosine window.
Hann window_hann Raised cosine, \(0.5(1 - \cos(2\pi x))\).
Bartlett-Hann window_bartlett_hann Combination of linear and cosine tapers.
Hamming window_hamming Raised cosine with alpha, default 0.54.
Bohman window_bohman Cosine-and-linear taper.
Blackman window_blackman Three-term cosine with alpha, default 0.16; accepts symmetry.
Blackman-Harris window_blackman_harris Four-term minimum-sidelobe window; accepts symmetry.
Kaiser window_kaiser Modified-Bessel window with beta, default 0.5. Larger beta increases tapering and sidelobe attenuation.
Flat-top window_flattop Five-term window for accurate amplitude estimates. Small negative values near the ends are part of its definition.
Gaussian window_gaussian Gaussian with alpha, default 2.5. Larger alpha produces a narrower taper.
Lanczos window_lanczos Sinc-based taper.
Planck-taper window_planck_taper Smooth flat-top taper with epsilon, where \(0 < \epsilon < 1\); accepts symmetry.
Tukey window_tukey Cosine-tapered flat-top window with alpha, where \(0 < \alpha < 1\); accepts symmetry.

epsilon is the fraction at each end occupied by the Planck-taper transition. Tukey's alpha controls the total fraction in its cosine-tapered region: smaller values leave a wider flat portion, while values nearer one approach a fully tapered cosine shape. KFR does not validate either range, so supply values strictly between zero and one.

The named constructors provide useful defaults for parameterized families:

auto hamming  = window_hamming<float>(256);         // alpha = 0.54
auto blackman = window_blackman<float>(256);        // alpha = 0.16
auto kaiser   = window_kaiser<float>(256, 7.5f);    // choose beta explicitly
auto gaussian = window_gaussian<float>(256, 3.0f);  // choose alpha explicitly

auto tapered = window_tukey<float>(
    256, 0.25f, window_symmetry::periodic);

Selecting a family with window_type

Use cwindow_type with the compile-time overload of window when the family is known while compiling. It returns the same concrete expression type as the matching named constructor, which makes it suitable for templates:

auto periodic_blackman = window<float>(
    1024,
    cwindow_type<window_type::blackman>,
    0.16f,
    window_symmetry::periodic);

univector<float> weights = render(periodic_blackman);

Pass the window-specific value as win_param: it is ignored for parameterless families, is alpha for Hamming, Blackman, Gaussian, and Tukey, is beta for Kaiser, and is epsilon for Planck-taper. Although this overload has a default-constructed win_param, it does not substitute the named constructors' defaults. In particular, omitting it selects zero for Hamming, Blackman, Kaiser, and Gaussian rather than 0.54, 0.16, 0.5, or 2.5. Always pass a meaningful value for a parameterized family; for Planck-taper and Tukey zero is outside the valid range.

When the family is chosen at run time, use window. It returns an owning expression_handle, hiding the concrete family while preserving its scalar type and one-dimensional shape:

window_type selected = window_type::kaiser;

expression_handle<float> weights = window<float>(
    1024, selected, 8.0f, window_symmetry::periodic);

univector<float> values = render(weights);

Both generic overloads support every window_type value: rectangular, triangular, bartlett, cosine, hann, bartlett_hann, hamming, bohman, blackman, blackman_harris, kaiser, flattop, gaussian, lanczos, cosine_np, planck_taper, and tukey.

The runtime overload owns the temporary expression it creates, so the handle above remains valid after the call returns. It is useful for menus, configuration files, and interfaces that must store several possible window families. Named and compile-time-selected expressions retain a concrete type and avoid type-erasure dispatch; prefer those APIs when the choice is static. See Expression handles for ownership and performance details.

Using a window for FIR design

The FIR design functions accept an expression_handle for the window. Convert a temporary named window with the owning overload of to_handle:

univector<float, 127> taps;

fir_lowpass(
    taps,
    0.2f,
    to_handle(window_kaiser<float>(taps.size(), 5.0f)),
    true);

This is a symmetric Kaiser window, appropriate for a finite FIR tap sequence. The 0.2f cutoff is normalized to the sample rate, so it represents \(0.2 f_s\); Nyquist is \(0.5 f_s\). The final true asks fir_lowpass to normalize DC gain. See FIR filters for the complete design and application workflow.

Practical selection notes

  • Start with Hann for general spectral work and use Kaiser for FIR designs that need an adjustable trade-off.
  • Use flat-top when amplitude accuracy is more important than narrow spectral peaks; do not clamp its small negative edge coefficients.
  • Do not interchange triangular and Bartlett merely because both have a linear profile. Their endpoint sampling differs, especially for even lengths.
  • Match the window length to the frame or tap count. A window expression is finite; assigning it to a differently sized destination is a shape error.
  • Use periodic for a DFT frame and symmetric for FIR coefficients to avoid an unintended duplicate endpoint in a periodic analysis frame.