SPANDAN (स्पंदन)

Advanced Real-Time Polyphonic Synthesizer

By Prashant Singh & Parth Srivastava

One-Pole Recursive Filter & Linear Interpolation with an Exponential Coefficient

The one-pole recursive filter is the simplest stable Infinite Impulse Response (IIR) filter. It is commonly called an exponential moving average (EMA), a leaky integrator, or a first-order low-pass filter.


Table of Contents

  1. Overview
  2. Difference Equation
  3. Intuitive Interpretation
  4. Z-Transform and Transfer Function
  5. Poles, Zeros, and Stability
  6. Impulse Response
  7. Step Response
  8. Frequency Response
  9. Relationship to Linear Interpolation
  10. Continuous-Time Analog: The RC Filter
  11. Parameterization and Cutoff Frequency
  12. Design Examples
  13. Applications
  14. Implementations
  15. Common Pitfalls and Tips
  16. Summary Comparison Table
  17. Glossary
  18. References

Overview

A one-pole recursive filter computes each output sample as a weighted combination of the current input and the previous output:

\[y[n] = \alpha x[n] + (1 - \alpha) y[n-1]\]

where:

This equation has one pole and no finite zeros except at the origin, making it the simplest nontrivial recursive filter.


Difference Equation

The standard discrete-time difference equation is:

\[y[n] = \alpha x[n] + (1 - \alpha) y[n-1]\]

An equivalent and often more intuitive form is:

\[y[n] = y[n-1] + \alpha \bigl( x[n] - y[n-1] \bigr)\]

This second form reveals the filter’s behavior clearly:

The output moves a fraction \(\alpha\) of the way from the current output toward the current input.

If \(\alpha\) is small, the output changes slowly and smooths the input heavily. If \(\alpha\) is close to 1, the output follows the input more quickly.


Intuitive Interpretation

Imagine a ball rolling on a surface with friction:

This gives the filter a “memory” of past inputs that decays exponentially. The older an input is, the less influence it has on the current output.


Z-Transform and Transfer Function

Taking the Z-transform of the difference equation, assuming zero initial conditions:

\[Y(z) = \alpha X(z) + (1 - \alpha) z^{-1} Y(z)\]

Solving for the transfer function \(H(z) = Y(z) / X(z)\):

\[H(z) = \frac{\alpha}{1 - (1 - \alpha) z^{-1}}\]

Multiplying numerator and denominator by \(z\):

\[H(z) = \frac{\alpha z}{z - (1 - \alpha)}\]

Poles and Zeros

Because the pole lies inside the unit circle for \(0 < \alpha \le 1\), the filter is BIBO stable.


Poles, Zeros, and Stability

Stability in discrete-time systems requires all poles to lie inside the unit circle in the z-plane:

\[|z_{\text{pole}}| < 1\]

For this filter:

\[|1 - \alpha| < 1\]

This condition holds when:

\[0 < \alpha < 2\]

However, for a valid low-pass smoothing filter with non-negative weights and monotonic decay, we usually restrict:

\[0 < \alpha \le 1\]

If \(\alpha > 1\), the pole becomes negative and the output alternates sign, which is usually undesirable for simple smoothing.


Impulse Response

For an input impulse \(\delta[n]\), the impulse response is:

\[h[n] = \alpha (1 - \alpha)^n \, u[n]\]

where \(u[n]\) is the unit step function.

This is a decaying exponential. The impulse response never becomes exactly zero, but it shrinks rapidly.

The impulse response confirms that the filter is:


Step Response

For a unit step input \(x[n] = 1\) for \(n \ge 0\), with initial rest condition \(y[-1] = 0\), the step response is:

\[y[n] = 1 - (1 - \alpha)^n\]

The error between the output and the final value decays exponentially:

\[\text{error}[n] = (1 - \alpha)^n\]

After \(n\) samples, the remaining error is \((1 - \alpha)^n\). For example:


Frequency Response

Substituting \(z = e^{j\omega}\) into the transfer function gives the frequency response:

\[H(e^{j\omega}) = \frac{\alpha}{1 - (1 - \alpha) e^{-j\omega}}\]

The magnitude response is:

\[|H(e^{j\omega})| = \frac{\alpha}{\sqrt{1 + (1 - \alpha)^2 - 2(1 - \alpha) \cos \omega}}\]

The phase response is:

\[\angle H(e^{j\omega}) = -\arctan\left(\frac{(1 - \alpha) \sin \omega}{1 - (1 - \alpha) \cos \omega}\right)\]

This filter behaves as a first-order low-pass filter:

3 dB Cutoff Frequency

The exact -3 dB cutoff frequency \(\omega_c\) satisfies:

\[\cos \omega_c = 1 - \frac{\alpha^2}{2(1 - \alpha)}\]

For small \(\alpha\), this is well approximated by:

\[\omega_c \approx \alpha\]

in radians per sample. If the sampling rate is \(f_s\), the corresponding analog cutoff frequency is approximately:

\[f_c \approx \frac{\alpha \, f_s}{2\pi}\]

Relationship to Linear Interpolation

Linear interpolation between two values is:

\[\text{lerp}(a, b, t) = (1 - t)a + t b\]

If we interpret \(a = y[n-1]\) and \(b = x[n]\), and set \(t = \alpha\), then:

\[y[n] = (1 - \alpha) y[n-1] + \alpha x[n]\]

This is exactly the one-pole recursive filter.

Therefore, a one-pole recursive filter is a recursive form of linear interpolation where the interpolation coefficient is constant and derived from an exponential decay model.

Animation and Real-Time Smoothing

In animation and user interface design, people often want a value to move smoothly toward a target. The standard lerp formula:

\[y = (1 - t) y_{\text{prev}} + t \, y_{\text{target}}\]

is used repeatedly over frames. If \(t\) is fixed, this is identical to the one-pole filter.

When the time step \(\Delta t\) varies, designers often choose:

\[t = 1 - e^{-\Delta t / \tau}\]

where \(\tau\) is a time constant. For small \(\Delta t / \tau\), this is approximately:

\[t \approx \frac{\Delta t}{\tau}\]

which again matches the discrete-time recursive filter.


Continuous-Time Analog: The RC Filter

The continuous-time analog of the one-pole recursive filter is the RC low-pass filter, described by:

\[RC \frac{dy(t)}{dt} + y(t) = x(t)\]

Discretizing with the backward Euler method (step size \(\Delta t\)) gives:

\[RC \frac{y[n] - y[n-1]}{\Delta t} + y[n] = x[n]\]

Solving for \(y[n]\):

\[y[n] = \frac{RC}{RC + \Delta t} y[n-1] + \frac{\Delta t}{RC + \Delta t} x[n]\]

This is precisely the same recursive structure as the discrete-time filter, confirming the equivalence between the discrete one-pole filter and the continuous RC low-pass filter. The time constant \(\tau = RC\) determines how quickly the system responds: larger \(\tau\) means slower, smoother filtering.

For small \(\Delta t / \tau\), the discrete-time update simplifies further to:

\[y[n] \approx \left(1 - \frac{\Delta t}{\tau}\right) y[n-1] + \frac{\Delta t}{\tau} x[n]\]

which recovers the familiar \(\alpha = \Delta t / \tau\) form of the one-pole filter.


Parameterization and Cutoff Frequency

The coefficient \(\alpha\) is the most important design parameter. It controls both the time-domain and frequency-domain behavior of the filter.

Time-Domain Interpretation

Frequency-Domain Interpretation

Common Alpha Values

Alpha Behavior Approx. cutoff (rad/sample)
0.01 Very smooth, slow response 0.01
0.05 Smooth, moderate response 0.05
0.10 Noticeable smoothing 0.10
0.25 Fast smoothing 0.25
0.50 Very responsive 0.50

Design Examples

Example 1: Slow Sensor Smoothing

If you want to smooth a noisy sensor reading at 100 Hz, choose a small alpha such as 0.05. The output will respond slowly and remove much of the high-frequency noise.

Example 2: Audio Envelope Smoothing

In audio processing, a one-pole filter is often used to smooth control voltages, envelope followers, or parameter ramps. Because it is cheap and stable, it is ideal for real-time audio code.

Example 3: UI Animation

In animation, a one-pole filter is often used to make a value glide toward a target. If the frame rate varies, use a time-based coefficient such as:

\[t = 1 - e^{-\Delta t / \tau}\]

where \(\tau\) is a time constant. For small \(\Delta t / \tau\), this is approximately:

\[t \approx \frac{\Delta t}{\tau}\]

which again matches the discrete-time recursive filter.


Applications


Implementations

Python

def one_pole_filter(x, alpha, y_prev):
    y = alpha * x + (1.0 - alpha) * y_prev
    return y, y

# Example usage:
alpha = 0.1
y = 0.0
for x in [0.0, 1.0, 1.0, 0.5, 0.0]:
    y, _ = one_pole_filter(x, alpha, y)
    print(y)

C / C++

double filter(double x, double *y, double alpha) {
    *y = alpha * x + (1.0 - alpha) * *y;
    return *y;
}

/* Usage:
double y = 0.0;
double alpha = 0.1;
for (int i = 0; i < N; ++i) {
    y = filter(input[i], &y, alpha);
}
*/

JavaScript

let y = 0;
const alpha = 0.1;

function onePole(x) {
  y = alpha * x + (1 - alpha) * y;
  return y;
}

Common Pitfalls and Tips


Summary Comparison Table

Concept Formula Main Use Key Parameter
One-pole recursive filter y[n] = alpha*x[n] + (1-alpha)*y[n-1] DSP smoothing alpha
Exponential moving average Same as above Time-series smoothing alpha
Linear interpolation lerp(a,b,t) = (1-t)a + tb Blending values t
Time-based smoothing alpha = 1 - exp(-dt/tau) Animation and variable frame rates tau

Glossary


References


Stay Updated
💻 GitHub Repo 🔗 Prashant's LinkedIn 🔗 Parth's LinkedIn