A window function is a mathematical function that applies a weighting (often between 0 and 1) to each discrete time series sample in a finite set. It should be noted that window functions can be applied in the frequency-domain, though this is a somewhat convoluted process and beyond the scope of this article. As a simple example, assume the finite set x of length N. If each value within x is assigned a weighting of 1 then it can be said that a new set y has been created to which the rectangular window function w (also of length N) has been applied:
\[y(n) = x(n) . w(n)\qquad0 \leq n \leq N\]
The above equation essentially states that a new set should be created whereby each value at index n is the product of the values at the nth index of the sample set x and window function w. Figure 1 depicts both an unmodified sine wave and a sine wave to which a rectangular window has been applied – they are analogous to each other.
Figure 1: Both a raw sine wave and, technically, a sine wave to which a rectangular window been applied.
Window functions are, of course, not limited to being rectangular in shape and, whilst most are symmetrical, this is not always the case. A plethora of shapes (types) exist for different purposes with Hamming, Hann, Blackman-Harris and Kaiser amongst the most common. So why exactly do we need window functions?
Primary Use Cases
One primary application of window functions is to mitigate against spectral leakage during transform functions. The Fourier transform assumes that the signal to be transformed is periodic over its length - though this is rarely the case. Any disparity between the last sample in the set and the repeated first sample will lead to anomalies (rogue frequency components that are not present in the input signal) being introduced into the resulting spectrum. By reducing the magnitude of samples towards the edges of the input set, the resulting frequency components are lower in magnitude, thus, the amount of error is reduced.
Window functions are also integral components of Finite Impulse Response (FIR) filters in that they can be used to directly control the level of attenuation. For example, a rectangular window (i.e. not actually applying a window function) provides a maximum level of attenuation in the stopband of 21 decibels (dB) whereas a Hamming window can result in attenuation levels approaching 53 dB.
Below is an example, written in Python, of how to programmatically generate a sample sine wave and either a rectangular or Hamming window and then apply the window to the generated signal and visualise the output.
import matplotlib.pyplot as plt import numpy as np
# Define window type variables for clarity RECTANGULAR = 'rectangular' HAMMING = 'hamming'
def get_sine_wave(num_samples, num_peaks): """ @brief: Return array of data of length num_samples that represents a sine wave
@param Int num_samples: Total length of data @param Int num_peaks: Total number of peaks in data
@returns Array signal: Array of floats containing data that represents a sine wave """
sample_points = np.arange(num_samples) signal = np.sin(2 * np.pi * num_peaks * sample_points / num_samples)
def get_window(type, length): """ @brief: Return an array containing window coefficients for a given type of window function at a specified length
@param Str type: Type of window function to return @param Int length: Length of window function to return
@returns Array window: Array of window function coefficients as floats """
window = list()
if type == RECTANGULAR: for i in range(0, length): window.append(1)
elif type == HAMMING: a = 0.53836 b = 0.46164
for i in range(0, length): window.append(a - b * np.cos( (2 * np.pi * i)/(length - 1)))
def apply_window(signal, window): """ @brief: Apply the given window function to signal
@param Array signal: Array of floats representing a signal @param Array window: Array of window function coefficients
@returns Array windowed: Array of floats representing windowed signal """
windowed = list()
for idx, sample in enumerate(signal): windowed.append(sample * window[idx])
if __name__ == '__main__': signal = get_sine_wave(1000, 20) window = get_window(HAMMING, len(signal)) windowed_signal = apply_window(signal, window)
plt.plot(windowed_signal) plt.xlabel('Time') plt.ylabel('Amplitude') plt.show()
Figure 1 depicts the raw input signal generated from the
get_sine_wave() function. Figure 2 is a visualisation of the application of a Hamming window to the raw signal from Figure 1.
Figure 2 Sine wave with Hamming window applied.
- Rorabaugh, C. (2000). DSP Primer. 1st ed. Blacklick, USA: McGraw-Hill.
- Harris, F. (1978). On the use of windows for harmonic analysis with the discrete Fourier transform. Proceedings of the IEEE, 66(1), pp.51-83.
- Greensted, A. (2010). FIR Filters by Windowing. [online] LabBookPages. Available at: http://www.labbookpages.co.uk/audio/firWindowing.html