Exponential Moving Average (EMA)
The Exponential Moving Average (EMA) is a popular method for smoothing time series data. It computes a new smoothed value by applying a weighted combination of the current observation and the previous smoothed value.
\[ y*t = (1 - \alpha) y*{t-1} + \alpha x_t \]Where:
- \(y_t\): EMA value at time \(t\)
- \(x_t\): Original observation at time \(t\)
- \(\alpha\): Smoothing coefficient (\(0 < \alpha \le 1\))
This formula places greater weight on recent data while still retaining some information from older observations.
Frequency Characteristics: Gain and Phase
The frequency characteristics of a filter describe how the frequency components of an input signal are altered by the filter. This is analyzed using the filter’s transfer function \(G(s)\).
Applying the Z-transform (used for analyzing discrete-time systems) to the EMA equation, we get the transfer function \(G(z)\):
\[ Y(z) = (1 - \alpha) z^{-1} Y(z) + \alpha X(z) \]\[ G(z) = \frac{Y(z)}{X(z)} = \frac{\alpha}{1 - (1 - \alpha) z^{-1}} \]By substituting \(z = e^{j\omega T}\) (where \(T\) is the sampling period, assumed to be \(T=1\) here), we obtain the frequency response \(G(j\omega)\):
\[ G(j\omega) = \frac{\alpha}{1 - (1 - \alpha) e^{-j\omega}} \]From this frequency response, we can derive the gain characteristic \(|G(j\omega)|\) and the phase characteristic \(\angle G(j\omega)\).
Gain Characteristic
\[ |G(j\omega)| = \frac{\alpha}{\sqrt{1 - 2(1 - \alpha) \cos \omega + (1 - \alpha)^2}} \]Phase Characteristic
\[ \angle G(j\omega) = \arctan\left(\frac{(1 - \alpha) \sin \omega}{1 - (1 - \alpha) \cos \omega}\right) \]Discussion:
- Small \(\alpha\) (e.g., \(\alpha=0.1\)): The filter’s frequency bandwidth becomes narrower, resulting in a stronger smoothing effect. However, this also leads to a larger phase lag.
- Large \(\alpha\) (e.g., \(\alpha=0.9\)): The smoothing capability decreases, but the phase lag is smaller.
This demonstrates a trade-off between the degree of smoothing and the response speed (phase lag).
Program
The following Python code computes and plots the gain and phase characteristics of the EMA filter.
import math
import numpy as np
import matplotlib.pyplot as plt
# List of smoothing coefficient alpha values
ALPHAS = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
# Frequency range (rad/s)
FREQ_MAX = 300
NUM_POINTS = 500
def get_gain(alpha, omega):
"""Compute the gain of the EMA filter"""
denominator = np.sqrt(1 - 2 * (1 - alpha) * np.cos(omega) + (1 - alpha)**2)
return alpha / denominator
def get_phase(alpha, omega):
"""Compute the phase of the EMA filter (radians)"""
numerator = (1 - alpha) * np.sin(omega)
denominator = 1 - (1 - alpha) * np.cos(omega)
return np.arctan2(numerator, denominator)
# Data storage lists for plotting
frequencies = [[] for _ in range(len(ALPHAS))]
gains = [[] for _ in range(len(ALPHAS))]
phases = [[] for _ in range(len(ALPHAS))]
# Compute for each alpha value
for alpha_idx, alpha_val in enumerate(ALPHAS):
for i in range(NUM_POINTS):
omega = i * (np.pi / NUM_POINTS)
frequencies[alpha_idx].append(omega)
gains[alpha_idx].append(get_gain(alpha_val, omega))
phases[alpha_idx].append(np.degrees(get_phase(alpha_val, omega)))
# Plot gain characteristics
plt.figure(figsize=(10, 6))
plt.xlabel('Frequency (rad/s)')
plt.ylabel('Gain')
plt.title('EMA Filter Gain Characteristics')
for alpha_idx, alpha_val in enumerate(ALPHAS):
plt.plot(frequencies[alpha_idx], gains[alpha_idx], label=f"alpha={alpha_val}")
plt.legend(bbox_to_anchor=(1.05, 1.0), loc='upper left')
plt.grid(True)
plt.tight_layout()
plt.show()
# Plot phase characteristics
plt.figure(figsize=(10, 6))
plt.xlabel('Frequency (rad/s)')
plt.ylabel('Phase (degrees)')
plt.title('EMA Filter Phase Characteristics')
for alpha_idx, alpha_val in enumerate(ALPHAS):
plt.plot(frequencies[alpha_idx], phases[alpha_idx], label=f"alpha={alpha_val}")
plt.legend(bbox_to_anchor=(1.05, 1.0), loc='upper left')
plt.grid(True)
plt.tight_layout()
plt.show()
Comparison of EMA with Other Filters
The EMA filter is simple to implement and has low computational cost, but it has different characteristics compared to other filters.
| Filter | Cutoff Characteristics | Computational Cost | Parameters | Real-time Capability |
|---|---|---|---|---|
| EMA | Gentle | \(O(1)\) | 1 (\(\alpha\)) | Excellent |
| Moving Average | Gentle | \(O(N)\) | 1 (window size \(N\)) | Excellent |
| Butterworth | Sharp (order-dependent) | \(O(N)\) | 2 (order, cutoff frequency) | Good |
| FIR/IIR | Design-dependent | \(O(N)\) | Multiple | FIR: Good, IIR: Excellent |
The EMA can be viewed as a first-order IIR filter, and the fact that it is controlled by a single parameter \(\alpha\) is a significant practical advantage. For sharper cutoff characteristics, consider a Butterworth filter; to minimize phase lag, consider a Wiener filter.
EMA Implementation Using scipy.signal
Python’s scipy.signal module allows you to implement EMA as an IIR filter.
import numpy as np
from scipy import signal
def ema_scipy(x, alpha):
"""EMA implementation using scipy.signal"""
# EMA: y[n] = alpha * x[n] + (1 - alpha) * y[n-1]
# IIR transfer function: H(z) = alpha / (1 - (1-alpha) * z^{-1})
b = [alpha] # Numerator coefficients
a = [1, -(1 - alpha)] # Denominator coefficients
return signal.lfilter(b, a, x)
# Usage example
np.random.seed(42)
t = np.linspace(0, 1, 1000)
x = np.sin(2 * np.pi * 5 * t) + 0.5 * np.random.randn(len(t))
y = ema_scipy(x, alpha=0.1)
This implementation is faster than a manual loop and provides a unified interface with other scipy.signal filter functions (butter, firwin, etc.).
Related Articles
- Low-Pass Filter Design and Comparison: Moving Average, Butterworth, and Chebyshev - A comparison of various low-pass filters including EMA, analyzing frequency response, group delay, and step response.
- Kalman Smoother (RTS Smoother): Theory and Python Implementation - Extends the Kalman filter (a generalization of EMA) by using all observations to improve estimation accuracy.
- Savitzky-Golay Filter: Theory and Python Implementation - Unlike EMA, smooths signals while preserving their shape through polynomial fitting.
- Adaptive Filters (LMS/RLS): Theory and Python Implementation - While EMA uses fixed parameters, adaptive filters automatically adjust their parameters to changing environments.
