HOWTO: a “Perfect Reconstruction” Graphic Equalizer
If you’ve ever looked at a hi-fi component stereo system you’ve probably seen a graphic equalizer. Traditional analog ones look like this one sold by Crutchfield:

Each slider lets you raise or lower the volume of certain sounds in your music. If you know that a flute is in a frequency range of 250 Hz - 2500 Hz, you could make the flute part louder by raising the sliders that corresponded to that range. (As you see from this acoustics chart, frequency ranges for instruments do overlap—so raising a flute can possibly also affect other things like Oboes or vocals.)
Cheaper stereo systems usually only offer “bass” and “treble” knobs. Yet nearly every MP3 player has a digital EQ. Even iTunes has one, if you click Show Equalizer on the View menu:

But here’s a problem: because graphic equalizers break your signals into pieces and then put them together again, they introduce some distortion. There’s a simple way to get a sense that this distortion exists: you can set all the sliders to “flat”… run the equalizer algorithm… and see that you don’t get the same data out that you put in.
Back in 1996, I came up with a way you can design a digital graphic equalizer so the algorithm will exactly output the original signal when sliders are flat, even after running your audio through a barrage of filtering mathematics. Practically speaking, you would want to bypass the equalizer in that case for performance reasons. Yet there is an alluring elegance to an approach which would converge to the original signal if you ran it… and it strongly suggests you’d have overall less distortion when the sliders weren’t at zero. (This turns out to be true!)
I employ only two digital filters: a specially matched highpass and lowpass. Recursively applying these filters on downsampled versions of the data creates the exact logarithmic bands that are found in graphic equalizers. The process additionally leads to a phenomenon known as “perfect reconstruction”. I explain the details below.
How do other equalizers work?
There are many different ways you might choose to implement a graphic equalizer. Here’s a brief survey of methods I’m aware of:
-
Frequency Sampling: A graphic equalizer can be seen as a simple digital filter which is redesigned each time the equalization settings change. When looked at this way, the obvious method for creating a graphic equalizer is to incorporate a filter design routine into your digital device, and change the desired frequency response Hd(ω) according to the equalization levels. Since frequency sampling design is as simple as an inverse discrete fourier transform (IDFT) of the desired filter curve, it is entirely possible to implement this on inexpensive hardware.
The advantage to this approach is that it is relatively easy to understand and implement. Only one filter is required at any given time, so it uses memory effectively. Unfortunately, since a complex filter design algorithm is not feasible on inexpensive hardware, there will undoubtedly be ripple and Gibbs phenomena from the IDFT. Reducing this ripple will require filters of somewhat extreme length. More importantly, because the low frequency bands have so few points relative to the high frequency bands, the response in these regions will always be relatively poorer.
-
Filter Banks: Equalization using filter banks means that you would design a high quality band-pass filter for each frequency range, then run the data through each filter in parallel and take the weighted sum of the outputs to form your final signal. The weights used in the sum would be derived from the equalization settings. This method is directly related to analog graphic equalizers, where a potentiometer is used to change the contribution of a different band-pass filter for each band.
This approach could quite possibly achieve a better response than the frequency sampling technique. Because the band-pass filters are designed in advance, they could be made using a more sophisticated algorithm than the IDFT. Also, no run-time filter redesign process is needed, thus simplifying the DSP routine. However, since all the filters would still be the same length, the fundamental problem would remain of the low frequency bands being more poorly filtered than the high frequency bands. In addition, if you are going to have N levels of equalization, this technique will need to apply N filters and hence need N times the number of mathematical operations that the single-filter frequency sampling technique required!
-
Algorithmic Modification: Rather than applying several different filters to the data and then constructing a weighted sum from the outputs, it may be possible to determine the relationship between an equalization slider value and the impulse response of the filter to be designed. This way, whenever a user modifies an equalization level, the impulse response of the filter can be affected in a predetermined way for that modification. One can imagine the impulse response starting out as a unit impulse when the equalization levels are flat, and adjustments to the equalization levels causing the filter’s impulse response to undergo mathematical corrections.
This approach could achieve much the same result as the filter bank example, except that it would only generate a single filter (as in the frequency sampling case). Additionally, the frequency response could be perfectly flat if all the equalization levels were flat. The biggest disadvantage of this approach is the complexity involved in figuring out if such an algorithm exists, and if so…exactly what it is.
My Downsampling Approach to Graphic Equalization
The method I came up with involves using only two pre-created filters to provide any number of equalization levels. The signal is recursively split into its high half and low half of the frequency spectrum—and the low half is then downsampled to pull down the band edge to half the former Nyquist rate. Then the high half is weighted according to the appropriate equalization setting and added into the total result. I’ve drawn out this procedure in the figure below (Eq1..EqN represent multiplication by the weightings of the frequency bands from the graphic equalization levels.):

The recursive binary division of the low half of the frequency spectrum results in a logarithmic drop in the bandwidth as the frequency becomes lower. The low-pass filter causes the data to only occupy the lower half of the frequency spectrum, and we take advantage of this by cutting the sampling rate in half. Then the same high and low pass filters can be applied to the data again.
It would seem that since it is not possible to create an ideal high pass or low pass filter, that this technique will always throw out some important data. However, if the high and low pass filters are exactly complementary, the theory is that this process will provide the original signal when the equalizer weightings are at 1.
If this is the case, then this technique should provide a completely flat frequency response graph when there are flat equalization levels—and the output will merely be a time-delayed version of the input. There also are not resolution-limiting problems seen in the low frequency (narrow-width) bands from the other techniques, since the same size filter is being used to produce each band.
This method is somewhat more complicated than the others. Yet depending on the order of the filters used it could represent a drastic increase in equalizer quality.
Implementation of the Downsampling Equalizer
In order to code the block diagram as an actual program, we need to clearly define what the ↓2 and ↑N boxes are doing. Though we theoretically only need half of the samples to represent the information once it has been low-pass filtered, this cannot be suitably accomplished in this algorithm by throwing away every other sample and then restoring samples through a hold function. Full interpolation would be required to restore the missing samples.
Instead of using interpolation, I used an alternate method to to downsample, filter, and then upsample again. Two levels of recursion are shown, and the time domain representations of each graphic equalizer band are shown as the partial results (band 1 and band 2). If this procedure is applied, then these arrays merely need to be weighted and then added together to produce the output signal:

It may appear that a lot of calculation is being performed to produce these equalization bands. However, the parallelism and logarithmic decrease of the array widths being operated upon makes it so that each level really only corresponds to the application of a low pass and a high pass filter to an array the size of the original data. Also, the “odd/even split” steps and the “interleave” steps can actually done in-place—and require no processing time.
The “lowpass” and “highpass” functions were performed by convolving the data with a linear phase filter created using the Remez Algorithm. The filter was specified in two bands—one from 0 to 0.45 and the other from 0.55 to 1.0. The bands were set at values of 0 and 1, appropriate to whether it was high or low pass.
The frequency response of this equalizer could not be directly calculated, so it was performed by measuring the response to a unit impulse. Applying a “midrange boost” ([1 2 3 2 1]) forms a very good response using length 32 lowpass and highpass filters, and has a respectable response even with length 16 filters.
Applying the algorithm using a level set of equalization values was the true test of whether or not it held up to one of the few tangible criteria for a graphic equalizer, and the results were encouraging. Despite several levels of data operations (5 applied levels of recursion) the response was perfectly flat for filters of length 32 and 16.
Investigations into the limits of the equalizer show that it performs quite well with almost any number of bands, and the bass bands do not degrade terribly even though they become quite narrow. A truly fair comparison of this technique with other possible methods would involve a detailed measure of the number of operations required as well as psycho-acoustics, but this filter nevertheless performs remarkably well.
Postscript: Why is it called a “graphic equalizer”?
Looking at the arrangement of sliders you can see kind of a “graph”, whose X-axis is the frequency you want to modify and whose Y-axis is whether you are amplifying that range or cutting it out. This is how it gets the name “graphic equalizer”. Because of that troublesome word “graphic”, while researching for this article I found that a lot of people confuse this with the dancing animated bars while you play music. Those are called spectrum analyzers, and if you’re geeky you can buy a shirt with one on it:

Spectrum analyzers are related to graphic equalizers, because they show you what frequencies are currently playing in your music. Bars closer to the left represent how much bass is playing, and bars closer to the right correspond to the treble. So if you were playing a flute, you would expect to see the bars jump in the range that corresponds to the flute. However, a spectrum analyzer doesn’t let you change how much flute you hear… it just displays it.
As a sidenote, many flash-animated spectrum analyzers are fake and have nothing to do with what music is playing. For instance, even when you’re listening to dead silence in the Myspace music player, the bars will still hop along. This kind of thing upsets me because it complicates technical education by showing people random nonsense to seem advanced.

December 16th, 2007 at 10:51 pm
Why is it that, thinking about wave mechanics always leads me to go just a little bit more mad?
I still remember when my 6th-grade science teacher told us that the Sun emitted light at all frequencies equally (which theoretically requires infinite energy). I think that’s when I popped. Now I’m more careful in questioning Dirac’s constant.
My undestanding, last I looked at these issues, was that the more accurate a frequency manipulation you desired, the more latency needed to be introduced, the bane of live performance, and the irritant of synchronized-sound applications (A/V players).
I also understand that almost all software frequency analyzers and most hardware ones use various methods to cheat to make their tasks easier, figuring that no one will ever notice their lack of frequency response fidelity.
October 14th, 2008 at 11:02 am
Hello, I’m trying to reproduce your nicely explained EQ. I’m a little confused about your arrowed diagram showing two bands. Basically you state that it’s efficient because of the down-sampling and halving of data. But the diagram shows the lower side interleaved and the same size as the original. Can you explain at which point the next band is created from please?
Cheers,
D
October 14th, 2008 at 2:39 pm
Hello Dave,
Would be interesting to have someone reproduce it! I actually had coded this for a Texas Instruments DSP chip. Lost the source code but still had the writeup and diagrams, so I figured…well, might as well post them…
Not sure I understand your question, but I’ll try and answer. (Note that this algorithm isn’t suitable for processing real-time data; you must know how long your input signal is…let’s call that length L).
This is a recursive process. Each time you apply “the process” you will get two signals of length L. One of those is the time-domain representation of a higher pass band which you’re done filtering. It’s suitable for weighting and adding together to get a band in the overall signal. The other you have a choice: (1) you can take it as it is as a band in its own right, or (2) you can run the algorithm again on it to get another two signals of length L.
So if you refer to the “Implementation Diagram”, it does two steps on your data to produce two completed series of length L (the black ones: labeled band 1 and band 2). Then after the second step you’ve got a band on the left that you may choose to run the process on again, or consider yourself done and use it as band 3.
Make sense? Each time you get a completed band it needs to be the same size as the original. Then you multiply the samples in that signal by your EQ setting for that band, and add them all up.
If you write a modern reference implementation I’d appreciate you sharing your findings or tools used. I looked into tweaking Audacity to use the method but it looked like more of a project than I wanted at the time…
October 14th, 2008 at 4:57 pm
Hi, thanks for replying quickly. I took your statement “..logarithmic decrease of the array widths..” to be like a discrete wavelet type of algorithm structure. For a second iteration you will need to halve the filter values because it’s the same length of data, is that correct? If that was the case then why not simply put it through successive filters without the interleave stuff.
I think probably having a dumb-arse day(!), I guess I’m just not getting it.
October 14th, 2008 at 6:22 pm
(Note: It’s been a long time since I did this. Er, 12 years ago? I was an undergraduate electrical engineer, and I haven’t done much DSP since. So I’d be surprised if someone didn’t have a better idea of how to do it than what I came up with for a project, or if I was wrong about something!)
The decreasing of array widths is a conceptual thing…and really the data can all be processed in place. But to more clearly explicitly show what’s happening and what all the bookkeeping needs to do, I tried to “pull it apart”. Here I’ll badly hack up the “next step” if you want more than 3 bands in your EQ…and you’ll see why I preferred to stop after 2 steps.
So imagine that if you have a low pass Remez filter that basically passes everything below 2kHz, and you want to pass everything below 1kHz instead. To get an equivalent to a low pass 1kHz Remez filter, just use the 2kHz design on the even samples, the odd samples, and then interleave them back together in time. (The idea of taking a 4kHz Remez filter and dropping it to 1kHz by taking every 1st, 2nd, 3rd, and 4th sample… running the process…and then putting the samples back in their sequence post-filtering would be expected if this were true.)
This process is what I’m referring to as a “logarithmic drop”. I almost certainly can’t prove myself today that process would give you another perfect reconstruction. That must have been something I read or learned at the time, because I don’t know how I’d have just taken that for granted unless the professor said I could! Still—it would be very interesting to me if someone could recreate the effect (or debunk it). Please let me know how it goes…
(P.S. I found an old C program that generates Remez filter coefficients if you don’t have Matlab or something like that available.)
October 15th, 2008 at 8:41 am
Hello thank-you for the extra information on this, it’s much clearer now, especially with the new diagram. There’s a lot of filtering going on there, so I was wondering why you couldn’t just bandpass filter the original signal at different frequencies. I might look at some wavelet stuff, although I hear that aliasing is an issue, so it could end up very similar to your technique.
I found some C code by Jake Janovetz to do the remez coefficients, it seems to work O.K, but it does crash with certain values, did you use his code?
Thanks again,
Dave H
October 15th, 2008 at 10:11 pm
A bandpass approach for E equalization levels would use E filter operations on the original signal length. This method uses roughly 2+(E-2)*2. It is more filtering, but not catastrophically more…and it solves a particular problem that I explained in the article.
I’ll restate the motivation: Imagine you make a set of B bandpass filters, and then set the EQ so it’s all level (e.g. the weight for each band that you use to sum into the signal is at 1). Now ask: will running this “null equalization” on an arbitrary signal always give you the original signal back, or will the different characteristics of the filters cause interference and noise to appear?
I’m not aware of a way to design a set of bandpass filters that would not introduce some noise. Especially when you’re trying to capture different frequencies covering logarithmic ranges, and thus possibly using different size filters…! If you know how to do it, I’d be interested to know.
What I came up with is trickier because it was trying to take the principles of Perfect Reconstruction and apply them to a graphic equalizer. In addition to acting like you’d expect an equalizer to act when you have the weights set at different values, the process of all this turmoil spits out the exact original bytes you put in when the weights are 1! I believed I’d proven it to work, and my TAs in college did too, so maybe it’s for real…but we could have been wrong.
The Remez code I found is by Egil Kvaleberg, ported from Fortran. I will email it to you.
October 17th, 2008 at 10:23 am
Thanks for all your help, the code is much appreciated, as the only other Remez (by Jake) appears to have some very serious memory issues.
I might look at the A’Trous wavelets stuff as well, it all seems a very interesting field, I just hope my brain can take it! ; )
October 29th, 2008 at 3:01 pm
O.K. just a quick followup. I got this to work, and a single pulse can be reconstructed! The problem was that the descending cascade of FIR filters were creating an ever increasing delay. This needs to be compensated with a large delay for the first (top) band and decreasing through to nothing for the lower bands.
I’ve got 6 bands with a 12 point (SSE) FIR’s running at about 15% of my P4 cpu, which isn’t great, but I can take advantage of the fact that every other sample is zero which would take nearly half the time. I might also look at QMF’s now you’ve got me started, although I think that the delay aspect might get a bit…interesting…
Thanks again.
Dave