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()