31
$\begingroup$

Firstly, I am new to DSP and have no real education in it, but I am developing an audio visualization program and I am representing an FFT array as vertical bars as in a typical frequency spectrum visualization.

The problem I had was that the audio signal values changed too rapidly to produce a pleasing visual output if I just mapped the FFT values directly:

enter image description here

So I apply a simple function to the values in order to "smooth out" the result:

// pseudo-code
delta = fftValue - smoothedFftValue;
smoothedFftValue += delta * 0.2; 
// 0.2 is arbitrary - the lower the number, the more "smoothing"

In other words, I am taking the current value and comparing it to the last, and then adding a fraction of that delta to the last value. The result looks like this:

enter image description here

So my question is:

  1. Is this a well-established pattern or function for which a term already exsits? Is so, what is the term? I use "smoothing" above but I am aware that this means something very specific in DSP and may not be correct. Other than that it seemed maybe related to a volume envelope, but also not quite the same thing.

  2. Are there better approaches or further study on solutions to this which I should look at?

Thanks for your time and apologies if this is a stupid question (reading other discussions here, I am aware that my knowledge is much lower than the average it seems).

$\endgroup$
6
  • 1
    $\begingroup$ Now I'm wondering what you get if you take the smoothed FFT and inverse-FFT it. $\endgroup$
    – user253751
    Nov 2, 2016 at 1:05
  • $\begingroup$ Would it be more straightforward to just do the first answer in a different order? current_value = current_value * decay; if (new_value > current_value) { current_value = new_value; } $\endgroup$ Nov 2, 2016 at 14:03
  • $\begingroup$ @immibis This should be a reverb from my understanding. Correct me, if I'm wrong. $\endgroup$
    – Andreas
    Nov 2, 2016 at 15:15
  • $\begingroup$ Sure, and an optimizing compiler will produce the same implementation. The key point was to get the correct result when (current_value*decay) < new_value < current_value. $\endgroup$ Nov 2, 2016 at 19:53
  • 2
    $\begingroup$ I really like this question. It is one of those where someone trying a few things out accidentally discovers themselves at the bottom of an enormous tree of knowledge (Infinite Impulse Response filters, specifically). Meanwhile, people who are already climbing up the tree can describe all the cool things that they have already discovered amongst the branches... $\endgroup$
    – DrMcCleod
    Nov 4, 2016 at 11:08

5 Answers 5

40
$\begingroup$

What you've implemented is a single-pole lowpass filter, sometimes called a leaky integrator. Your signal has the difference equation:

$$ y[n] = 0.8 y[n-1] + 0.2 x[n] $$

where $x[n]$ is the input (the unsmoothed bin value) and $y[n]$ is the smoothed bin value. This is a common way of implementing a simple, low-complexity lowpass filter. I've written about them several times before in previous answers; see [1] [2] [3].

$\endgroup$
7
  • 4
    $\begingroup$ Thanks a lot for this. So, so helpful. Googling on my own is like being lost at sea when it comes to DSP stuff. Just having a couple of terms to search gives me something to grasp. $\endgroup$ Nov 1, 2016 at 19:45
  • 3
    $\begingroup$ I wonder. I think the OP applies this filter on the series of values in the individual bins in the frequency domain. A normal low-pass is applied on the series of samples in the time domain. Is the effect the same (I don’t think so, because the high frequency parts are still in the signal, but … their intensity changes more slowly?)? If not, could you elaborate on what the filter actually does to the signal in the time domain? $\endgroup$ Nov 2, 2016 at 6:30
  • 3
    $\begingroup$ @JonasWielicki I think aim is smoothning each individual bin value, so that it does not change very rapidly. also the low pass filter(as explained in answer) is applicable to any time series irrespective of its domain(time or frequency or anything else). $\endgroup$
    – Arpit Jain
    Nov 2, 2016 at 8:43
  • $\begingroup$ @arpitjain I understand that. I’d simply like to know if there’s any understanding (not necessarily by you, the OP or the answerer) how it affects the time domain when you do that. $\endgroup$ Nov 2, 2016 at 13:20
  • $\begingroup$ @JonasWielicki The operation is a convolution in the frequency domain, so it translates to a multiplication (of the corresponding (inverse) Fourier transforms) in the time domain. $\endgroup$
    – MBaz
    Nov 2, 2016 at 14:01
21
$\begingroup$

Warning: include some history, old papers (I love them) and punch cards!

You used, with $a=0.2$ the form: $$y(n) = y(n–1) + a[x(n) – y(n–1)]\,,$$ sometimes written as: $$y(n) = ax(n) + (1 – a)y(n–1)\,.$$

The first above version is less natural, but it avoids one multiply, and is somehow more efficient. Both formulae yield a linear, causal and infinite impulse response filter. Story goes back to and through Poisson, Kolmogorov-Zurbenko Adaptive Filters, Brown (Statistical Forecasting for Inventory Control. McGraw-Hill, 1959), Holt (1957) and Winters (1960). It is implemented as a recursive filtering scheme known under different names across the literature:

The "exponential" in the name is related to the impulse response with the geometric progression, that samples an exponential decay: $h[n]=(1-a)u[n]a^n$.

For an historical note, Robert G. Brown and Arthur D. Little used this method in 1956 in Exponential smoothing for predicting demand, apparently for the tobacco industry. A little more history and explanations can be found in Holt-Winters Forecasting for Dummies (or Developers) - Part I. Peter Zehna offers a critical review in Some remarks on exponential smoothing, 1966. A chapter by R. Brown in Encyclopedia of Operations Research and Management Science (Google books) dates the history back to 1944, the readable pages are reproduced here:

Exponential smoothing, p. 205, Encyclopedia of Operations Research and Management Science

Exponential smoothing, p. 206, Encyclopedia of Operations Research and Management Science

Many methods extend this smoothing, which lacks validity when the data has a trend or seasonality. Some of such are known as double or triple exponential smoothing, and Holt-Winters filters.

You can also check: How does this “simple filter” work?

$\endgroup$
2
  • 1
    $\begingroup$ Thanks, this is excellent. As mentioned, I am totally new to this so some of your answer will take further research for me to fully appreciate, but it certainly answers my question and then some. If not for the other, earlier answer, this is also of course worthy of acceptance as the answer. $\endgroup$ Nov 1, 2016 at 19:58
  • 1
    $\begingroup$ Small correction, Winters 1(960) should be Winters (1960) I assume $\endgroup$
    – SGR
    Nov 2, 2016 at 15:36
10
$\begingroup$

Are there better approaches or further study on solutions to this which I should look at?

The normal approach for audio meters is a "lossy peak detector".

if new_value > current_value
  current_value = new_value;
else
 current_value = current_value * decay;  

This reacts immediately to any new or peak or transient in the signal but it lingers on for a while so it creates a much less hectic picture. Decay should be a constant between 0 and 1. It controls how quickly the bars come done with 0 being instantaneous and 1 being never.

$\endgroup$
6
  • $\begingroup$ I note that this bears similarities to an assignment I did in college, a very tinny-sounding MIDI (created in a previous assignment) was improved by convolving (and scaling to match peaks and durations) the (completely rectangular) note signals with a triangular signal that ramped up very sharply (though not instantly), and then decayed gradually, to produce a sharp note that died off “naturally.” Vast improvement in the sound of the song (Fur Elise in this case). $\endgroup$
    – KRyan
    Nov 3, 2016 at 4:36
  • 1
    $\begingroup$ I guess you'd want to keep new_value if it's greater than current_value * decay $\endgroup$
    – user276648
    May 24, 2017 at 7:39
  • $\begingroup$ This doesn't look right. I'd think you'd want the "droop" to be faster if the difference between current_value and new_value is large negative vs. small negative. $\endgroup$ Sep 29, 2021 at 1:01
  • $\begingroup$ @JohnR.Strohm: Nope. That's standard meter bridge behavior. Decay rate is fixed. $\endgroup$
    – Hilmar
    Sep 29, 2021 at 19:09
  • $\begingroup$ @Hilmar, let current_value = 1.0, new_value = 0.95, and decay = 0.1. Those values will give a new current_value of 0.9, which went past new_value. On the next cycle, it will snap back to 0.95. Is that the intended behavior? $\endgroup$ Sep 30, 2021 at 1:53
7
$\begingroup$

Around US DoD contractor circles, this particular filter is frequently called an "alpha filter", because it can be characterized with one parameter that is traditionally named "alpha".

It is directly analogous to a simpe analog RC low-pass filter.

They are extremely simple, have serious limitations, but they have the undeniable advantage over more complex (and complicated!) filters that, if you steer clear of their problem areas, they get the job done.

$\endgroup$
3
$\begingroup$

As mentioned in other answers, this is a Single Pole Recursive filter, a type of infinite impulse response (IIR) filter.

A great resource for information on this and other DSP features is Steven W. Smith's The Scientist and Engineer's Guide to Digital Signal Processing: infinite impulse response (IIR)

...each point in the output signal is found by multiplying the values from the input signal by the "a" coefficients, multiplying the previously calculated values from the output signal by the "b" coefficients, and adding the products together.. Notice that there isn't a value for b0, because this corresponds to the sample being calculated. Equation 19-1 is called the recursion equation, and filters that use it are called recursive filters. The "a" and "b" values that define the filter are called the recursion coefficients.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.