Simple Moving Average
Pieter PTable of Contents list
Difference equation
The difference equation of the Simple Moving Average filter is derived from
the mathematical definition of the average of
Impulse and step response
From the previous equation, we can now easily calculate the impulse and step response.
The impulse response is the output of the filter when a Kronecker delta function is applied to the input.
Recall the definition of the Kronecker delta:
The step response is the output of the filter when a Heaviside step function is applied to the input.
The Heaviside step function is defined as
Transfer function
The output of discrete-time linear time-invariant (DTLTI) systems, of which the SMA is an example, can be expressed as the convolution of the input with the impulse response. In other words, the impulse response describes the behavior of the system, for all possible inputs.
To prove the previous statement, we'll start with the following trivial property:
any signal
You can also interpret this as the signal being made up of a sum of infinitely many scaled and shifted Kronecker
delta functions.
Let
Analysis of such systems is usually easier in the Z-domain, in which the convolution is reduced to a simple
product.
The (unilateral) Z-transform is defined as:
Let's calculate the transfer function of the SMA.
We can use one of two approaches: use the difference equation and use some of
the properties of the Z-transform to calculate
Using the difference equation
All you have to do is apply the time shifting property of the Z transform:
Using the impulse response
For this derivation, we can use the fact that the impulse response
We can solve the summation in a different way using the formula for the sum
of a
geometric series:
In these expressions,
There are a couple of interesting values for
They can be found as the roots of the numerator and the denominator
respectively, after eliminating any common factors.
The roots of the numerator are the solutions of
The roots of the denominator are the solutions of
Since both the numerator and the denominator have the root
This leaves us with the following
Frequency response
An important property of discrete-time linear time-invariant systems is that it preserves the pulsatance (angular
frequency) of sinusoidal signals, only the phase shift and the amplitude are altered.
In other words, sines and cosines are eigenfunctions of DTLTI systems.
This makes it relatively easy to express the frequency response (sometimes called magnitude response) of a filter.
We're interested in the spectrum of frequencies that a signal contains, so it makes sense to decompose it as a sum
of sines and cosines. That's exactly what the discrete-time Fourier transform does:
The frequency response of the filter describes how the spectrum of a signal is altered when it passes
through the filter. It relates the spectrum of the output signal
We use the formula
We can now plot the filter's gain in function of the frequency. These plots often use a logarithmic scale, to
show the gain in decibels. In order to calculate the power gain, the amplitude is squared.
We can also plot the phase shift introduced by the SMA. This is just the
complex argument of the transfer function.
The image below shows the bode plot of an SMA with a length of
Also note the zeros, where the magnitude plot goes to
To get a better understanding of where this curve comes from, we can plot
the entire
The image of the unit circle is shown in red. Notice that this is the same curve as the blue curve in the
magnitude response graph above:
close to 0 when
Cutoff frequency
The cutoff frequency is defined as the frequency of the half-power point, where the power gain is a half. It's
often called the
To find it, just solve the following equation:
A possible approach to find the intersection is to use the
Newton-Raphson
method.
A good starting point seems to be at half the period of the high-frequency
sine wave.
We don't have to keep the squares, because both sines will be positive in
the region of the intersection.
get_sma_cutoff
function in the snippet below.
Plotting the frequency response, impulse response and step response in Python
We can use the SciPy and Matplotlib modules to plot the frequency response in Python.
This is the script that was used to generate the plots in the previous paragraphs.
from scipy.optimize import newton
from scipy.signal import freqz, dimpulse, dstep
from math import sin, cos, sqrt, pi
import numpy as np
import matplotlib.pyplot as plt
# Function for calculating the cut-off frequency of a moving average filter
def get_sma_cutoff(N, **kwargs):
func = lambda w: sin(N*w/2) - N/sqrt(2) * sin(w/2) # |H(e^jω)| = √2/2
deriv = lambda w: cos(N*w/2) * N/2 - N/sqrt(2) * cos(w/2) / 2 # dfunc/dx
omega_0 = pi/N # Starting condition: halfway the first period of sin(Nω/2)
return newton(func, omega_0, deriv, **kwargs)
# Simple moving average design parameters
f_s = 100
N = 5
# Find the cut-off frequency of the SMA
w_c = get_sma_cutoff(N)
f_c = w_c * f_s / (2 * pi)
# SMA coefficients
b = np.ones(N)
a = np.array([N] + [0]*(N-1))
# Calculate the frequency response
w, h = freqz(b, a, worN=4096)
w *= f_s / (2 * pi) # Convert from rad/sample to Hz
# Plot the amplitude response
plt.subplot(2, 1, 1)
plt.suptitle('Bode Plot')
plt.plot(w, 20 * np.log10(abs(h))) # Convert modulus to dB
plt.ylabel('Magnitude [dB]')
plt.xlim(0, f_s / 2)
plt.ylim(-60, 10)
plt.axvline(f_c, color='red')
plt.axhline(-3.01, linewidth=0.8, color='black', linestyle=':')
# Plot the phase response
plt.subplot(2, 1, 2)
plt.plot(w, 180 * np.angle(h) / pi) # Convert argument to degrees
plt.xlabel('Frequency [Hz]')
plt.ylabel('Phase [°]')
plt.xlim(0, f_s / 2)
plt.ylim(-180, 90)
plt.yticks([-180, -135, -90, -45, 0, 45, 90])
plt.axvline(f_c, color='red')
plt.show()
# Plot the impulse response
t, y = dimpulse((b, a, 1/f_s), n=2*N)
plt.suptitle('Impulse Response')
_, _, baseline = plt.stem(t, y[0], basefmt='k:')
plt.setp(baseline, 'linewidth', 1)
baseline.set_xdata([0,1])
baseline.set_transform(plt.gca().get_yaxis_transform())
plt.xlabel('Time [seconds]')
plt.ylabel('Output')
plt.xlim(-1/f_s, 2*N/f_s)
plt.yticks([0, 0.5/N, 1.0/N])
plt.show()
# Plot the step response
t, y = dstep((b, a, 1/f_s), n=2*N)
plt.suptitle('Step Response')
_, _, baseline = plt.stem(t, y[0], basefmt='k:')
plt.setp(baseline, 'linewidth', 1)
baseline.set_xdata([0,1])
baseline.set_transform(plt.gca().get_yaxis_transform())
plt.xlabel('Time [seconds]')
plt.ylabel('Output')
plt.xlim(-1/f_s, 2*N/f_s)
plt.yticks([0, 0.2, 0.4, 0.6, 0.8, 1])
plt.show()
Comparing the Simple Moving Average filter to the Exponential Moving Average filter
Using the same Python functions as before, we can plot the responses of the EMA and the SMA on top of each other.First, the length
from scipy.optimize import newton
from scipy.signal import freqz, dimpulse, dstep
from math import sin, cos, sqrt, pi
import numpy as np
import matplotlib.pyplot as plt
# Function for calculating the cut-off frequency of a moving average filter
def get_sma_cutoff(N, **kwargs):
func = lambda w: sin(N*w/2) - N/sqrt(2) * sin(w/2) # |H(e^jω)| = √2/2
deriv = lambda w: cos(N*w/2) * N/2 - N/sqrt(2) * cos(w/2) / 2 # dfunc/dx
omega_0 = pi/N # Starting condition: halfway the first period of sin(Nω/2)
return newton(func, omega_0, deriv, **kwargs)
# Simple moving average design parameters
f_s = 360
N = 9
# Find the cut-off frequency of the SMA
w_c = get_sma_cutoff(N)
f_c = w_c * f_s / (2 * pi)
# Calculate the pole location of the EMA with the same cut-off frequency
b = 2 - 2*cos(w_c)
alpha = (-b + sqrt(b**2 + 4*b)) / 2
# SMA & EMA coefficients
b_sma = np.ones(N)
a_sma = np.array([N] + [0]*(N-1))
b_ema = np.array((alpha, 0))
a_ema = np.array((1, alpha - 1))
# Calculate the frequency response
w, h_sma = freqz(b_sma, a_sma, worN=4096)
w, h_ema = freqz(b_ema, a_ema, w)
w *= f_s / (2 * pi) # Convert from rad/sample to Hz
# Plot the amplitude response
plt.subplot(2, 1, 1)
plt.suptitle('Bode Plot')
plt.plot(w, 20 * np.log10(abs(h_sma)), # Convert modulus to dB
color='blue', label='SMA')
plt.plot(w, 20 * np.log10(abs(h_ema)),
color='green', label='EMA')
plt.ylabel('Magnitude [dB]')
plt.xlim(0, f_s / 2)
plt.ylim(-60, 10)
plt.axvline(f_c, color='red')
plt.axhline(-3.01, linewidth=0.8, color='black', linestyle=':')
plt.legend()
# Plot the phase response
plt.subplot(2, 1, 2)
plt.plot(w, 180 * np.angle(h_sma) / pi, # Convert argument to degrees
color='blue')
plt.plot(w, 180 * np.angle(h_ema) / pi,
color='green')
plt.xlabel('Frequency [Hz]')
plt.ylabel('Phase [°]')
plt.xlim(0, f_s / 2)
plt.ylim(-180, 90)
plt.yticks([-180, -135, -90, -45, 0, 45, 90])
plt.axvline(f_c, color='red')
plt.show()
# Plot the impulse response
t, y_sma = dimpulse((b_sma, a_sma, 1/f_s), n=2*N)
t, y_ema = dimpulse((b_ema, a_ema, 1/f_s), n=2*N)
plt.suptitle('Impulse Response')
plt.plot(t, y_sma[0], 'o-',
color='blue', label='SMA')
plt.plot(t, y_ema[0], 'o-',
color='green', label='EMA')
plt.xlabel('Time [seconds]')
plt.ylabel('Output')
plt.xlim(-1/f_s, 2*N/f_s)
plt.legend()
plt.show()
# Plot the step response
t, y_sma = dstep((b_sma, a_sma, 1/f_s), n=2*N)
t, y_ema = dstep((b_ema, a_ema, 1/f_s), n=2*N)
plt.suptitle('Step Response')
plt.plot(t, y_sma[0], 'o-',
color='blue', label='SMA')
plt.plot(t, y_ema[0], 'o-',
color='green', label='EMA')
plt.xlabel('Time [seconds]')
plt.ylabel('Output')
plt.xlim(-1/f_s, 2*N/f_s)
plt.legend()
plt.show()