# How does this “simple filter” work?

I'm new to DSP, and I'm using this basic "1-pole LPF" Param Smooth filter which "smooth" param when I change it. The code is pretty simple:

class CParamSmooth
{
public:
double a, b, z;

CParamSmooth() {
a = 0.8;
b = 1. - a;
z = 0.;
}

double Process(double in) {
z = (in * b) + (z * a);
return z;
}
};


If I try some values with "strong" a coefficients, I can see that it starts heavy on increment, then becomes smooth till "rounding" happen, setting z = in:

0 | 0.16
1 | 0.288
2 | 0.3904
3 | 0.47232
4 | 0.537856
5 | 0.590285
6 | 0.632228
7 | 0.665782
8 | 0.692626
9 | 0.714101
10 | 0.731281
11 | 0.745024
12 | 0.75602
13 | 0.764816
14 | 0.771853
15 | 0.777482
16 | 0.781986
17 | 0.785588
18 | 0.788471
19 | 0.790777
20 | 0.792621
21 | 0.794097
22 | 0.795278
23 | 0.796222
24 | 0.796978
25 | 0.797582
26 | 0.798066
27 | 0.798453
28 | 0.798762
29 | 0.79901
30 | 0.799208
31 | 0.799366
32 | 0.799493
33 | 0.799594
34 | 0.799675
35 | 0.79974
36 | 0.799792
37 | 0.799834
38 | 0.799867
39 | 0.799894
40 | 0.799915
41 | 0.799932
42 | 0.799946
43 | 0.799956
44 | 0.799965
45 | 0.799972
46 | 0.799978
47 | 0.799982
48 | 0.799986
49 | 0.799989
50 | 0.799991
51 | 0.799993
52 | 0.799994
53 | 0.799995
54 | 0.799996
55 | 0.799997
56 | 0.799998
57 | 0.799998
58 | 0.799998
59 | 0.799999
60 | 0.799999
61 | 0.799999
62 | 0.799999
63 | 0.799999
64 | 0.8
65 | 0.8
66 | 0.8
...


So, basically, each iteration is a sum of 0.16 + prev z * 0.8. And here is where I don't understand: why 0.16 + prev z * 0.8 can't go "over" 0.8?

In fact, this become stable when z = in. Without rounding, z will always be < in. Why it can't go > in?

It's a sum on each iteration... who limits it?

• You might want to try to compute the values by hand, drawing them on an axis one by one. Each iteration is computing a weighted mean between the previous result and the input, and with constant input it can be easy to get why you can't cross it. – TonioElGringo Aug 24 '16 at 12:56

In more standard DSP terms, you have the following filter:

$$y[n] = (1-a) x[n] + a y[n-1]$$

where $x[n]$ and $y[n]$ are the input and output signals at time $n$ respectively.

The transfer function (which you didn't ask for) is:

$$H(z) = \frac{1-a}{1 - az^{-1}}$$

so here is your single pole, at $z=a$ in the complex plane. This filter is also known as exponential smoothing, exponential moving average (EMA), or exponentially weighted moving average (EWMA).

The infinite impulse response is $h[n] = (1-a) u[n] a^n$. In layman terms, when the input signal is 0 except for $x=1$, the output signal is an exponential $(1-a) \times a^n$ starting at $n=0$.

What you want is the step response (i.e. what happens if the input signal is a constant $K$ starting at time $n=0$).

In this case, the output signal is the convolution $h \star Ku$ of the impulse response and the step signal. This is (for time $n \ge 0$):

$$y[n] = \sum_{k=0}^{k=n} K \times h[k] = K(1-a) \sum_{k=0}^{k=n} a^k = K(1-a)\frac{1-a^{n+1}}{1-a} = K (1-a^{n+1})$$

As the time $n$ grows, $a^{n+1}$ vanishes, and the step response grows monotonically to its limit value $y = K$, which is the value of the input signal.

This is what you get in your simulation.

• I dared to add a few more common names for this filter, to help find literature. Corrections welcome – Laurent Duval Aug 24 '16 at 11:49
• Beautiful answer ! – Gilles Aug 24 '16 at 12:27
• Thanks for the answer! Well, for step: "This filter is also known as exponential smoothing, exponential moving average (EMA), or exponentially weighted moving average (EWMA)." The formula you have put (y[n] = (1−a)*x[n] + a*y[n−1]) is like my formula, but the one on the wiki is different: its y[n] = a*x[n] + (1-a)*y[n-1]. Why? – markzzz Aug 24 '16 at 12:30
• @markzzz The difference is just in how you name your parameters. In the answer above, the exponent is a. In the wikipedia article notation, the exponent is (1-a_wiki). – Juancho Aug 24 '16 at 12:45
• Right! Thanks! So basically, the formula become z = in - (in - z)*a and it subtracts from in (step by step) an amount smaller at each step, till at some points (due to computer rounding) (in - z)*a become 0, so in. Is it right? If it wasn't "rounding", it really was a "infinite response", without returning in...! Not sure if that's correct anyway hehehe – markzzz Aug 24 '16 at 12:52