What is convolution?
Convolution is an operation that is performed between two signals to produce a third signal that represents how one input signal modifies the other. The convolution h(t) of two signals, f(t) and g(t), is defined as:
or more concisely,
where * represents the convolution operator. The former equation can also be written discretely as:
where f(t) and g(t) are no longer continuous signals, but rather discrete sequences of numbers (vectors).
The steps to perform a convolution can be summarized as follows:
Step 1: Replace the variable t in f(t) and g(t) with a dummy variable u to obtain f(u) and g(u).
Step 2: Flip the second signal to obtain g(-u).
Step 3: Shift the flipped signal by t to get g(t-u), so that the signal can slide along the u axis.
Step 4: Start t at -∞ and wherever the two functions intersect, find the integral of their product.
Step 5: Continue shifting and integrating until second signal has completely passed over the first signal. The result, h(t), is the convolution of f(t) and g(t).
The animation below illustrates the convolution of a boxcar signal with itself, resulting in a triangle function.
Convolution is used extensively in signal processing to determine the output of a system as a response to a set of inputs, but it has applications in many fields. For example, in image processing, an image (essentially an array) can be convolved with a 2D kernel (a smaller array) that, depending on the kernel size and values, can be used to blur, sharpen, or detect edges in an image. Convolution is also implemented in audio processing to simulate reverberation or to produce new sounds. Other applications that utilize convolution include neural networks, optics, and probability theory2. Perhaps most relevant to the field of water resources is the use of convolution to create a moving average.
A moving average is a form of a convolution often used in time series analysis to smooth out noise in data by replacing a data point with the average of neighboring values in a moving window. A moving average is essentially a low-pass filter because it removes short-term fluctuations to highlight a deeper underlying trend.
The mathematical definition of a moving average is:
where the average data point is calculated from averaging the points contained in the moving window that is defined as +/- M and centered around xi .
A moving average is commonly referred to as boxcar smoothing because it is implemented by convolving the time series signal with a box-shaped function of width 2M+1, with an amplitude of 1/(2M+1).
Shown below is an example of how a moving average can be implemented using both the convolution function and the Astropy library in Python.
Example: Daily Minimum Temperatures in Melbourne, Australia
Figure 1 is a graph of daily minimum temperatures in Melbourne, Australia from 1981-1990. Our goal is to use a moving average to smooth out some of the noise in this graph to highlight the underlying signal.
The first step is to read in the raw data, which can be downloaded here. Then, define a window size, w, that is equal to 2M+1. Choosing the width of the moving window is not trivial and very application-specific. If the window is too big, the trends in the data may be masked, while too small of a window may not show the larger underlying trend. Therefore, you must have some intuition as to what trends might lie in the data. If the data are seasonal or periodic in nature, consider choosing a window size consistent with the seasonality. Because daily minimum temperatures will have a seasonal component depending on the month of the year, the window width is set at 31 (30 days+1 to account for the center point).
""" ====================================================== Smoothing of TimeSeries Data Using Convolution ====================================================== """ #Import libraries import matplotlib.pyplot as plt import numpy as np from pandas import Series #Upload raw data as a pandas series series = Series.from_csv('daily-minimum-temperatures.csv') #Define window size w=31
Then, a mask is created that is a vector of length w, with each element having a value of 1/w (a boxcar signal of length w and amplitude 1/w).
#Define mask and store as an array mask=np.ones((1,w))/w mask=mask[0,:]
The final step is to convolve the data with the boxcar signal and plot the final result, shown in Figure 2.
#Convolve the mask with the raw data convolved_data=np.convolve(series,mask,'same') #Change series to data frame and add convolved data as a new column series=Series.to_frame(series) series['convolved_data']=convolved_data #Plot both original and smooth data plt.ylabel('Temperature (C)') plt.xlabel('Time') plt.title('Daily Minimum Temperatures in Melbourne (1981-1990)') plt.plot(series) plt.legend(('Original','Smooth')) plt.show()
Because I wanted the output signal to be the same length as the input signal, I used the parameter option, “same” which will add a padding of zeros around the boundaries of the data to preserve the length. The effect of this can be seen by the sharp boundaries of the smooth data. Other parameter options such as “valid” will only return points that fall inside the intersection of the two signals.
Once you understand the math behind the moving average, you can easily do the same convolution in a single line using the AstroPy library.
from astropy.convolution import convolve, Box1DKernel smooth_data=convolve(series,kernel=Box1DKernel(31))
All information not specifically cited came from class notes from Dr. Greg McLaskey’s class, CEE 6790: Times Series Data Analysis for Civil, Mechanical, and Geophysical Applications
 Animation authorship details here