# Parallel equalizer, working for boosts but not cuts

I am trying to replicate the behaviour of a parallel equalizer.

The approach is to use a parallel sum of bandpass filters like so:

$$Response = 1 + bandpass1 * (gain1 - 1) + bandpass2 * (gain2 - 1) + ...$$

Boosts and cuts are separately grouped and run in series.

I have successfully got the model working for two boosts in parallel. But running two cuts in parallel produces an unexpected result.

The figure below illustrates the problem. The thick blue line illustrates two boosts in parallel (thin orange and red line show the individual boosts that are being combined). The thick purple line illustrates two cuts in parallel (thin green and light-blue line show individual cuts that have been combined). As can be seen the individual cuts are a mirror image of the individual boosts but the parallel sum doesn't work for cuts. Does anyone know what I'm missing so that that the thick purple line is a mirror image of the think blue line?

Here as my matlab code:

% boost 1
f1 = 176;
g1 = db2gain(12);
q1 = 1;

% boost 2
f2 = 672;
g2 = db2gain(12);
q2 = 1;

% cut 1
f3 = 176;
q3 = 1;
g3 = db2gain(-12);

% cut 2
f4 = 672;
g4 = db2gain(-12);
q4 = 1;

% bandpasses for boosts
[b1, a1] = bandpass(f1, proportionalQ(q1, g1));
[b2, a2] = bandpass(f2, proportionalQ(q2, g2));

% bandpasses for cuts
[b3, a3] = bandpass(f3, proportionalQ(q3, g3));
[b4, a4] = bandpass(f4, proportionalQ(q4, g4));

f = logspace(log10(20), log10(20000), 10000);

r1 = response(b1, a1, f); % bandpass response for boost 1
r2 = response(b2, a2, f); % bandpass response for boost 2
r3 = response(b3, a3, f); % bandpass response for cut 1
r4 = response(b4, a4, f); % bandpass response for cut 2

% run the analog bandpass filters in parallel as two boosts (OK)...
p1 = 1 + r1 .* (g1 - 1) + r2 .* (g2 - 1);

% run the analog bandpass filters in parallel as two cuts (NOT OK)...
p2 = 1 + r3 .* (g3 - 1) + r4 .* (g4 - 1);

figure;

semilogx(f, response2db(p1), 'LineWidth', 2); % parallel boosts (OK)

hold on;

semilogx(f, response2db(1 + r1 .* (g1 - 1))); % individual boost plot 1
semilogx(f, response2db(1 + r2 .* (g2 - 1))); % individual boost plot 2

semilogx(f, response2db(p2), 'LineWidth', 2); % parallel cuts (NOT OK)

semilogx(f, response2db(1 + r3 .* (g3 - 1))); % individual cut plot 1
semilogx(f, response2db(1 + r4 .* (g4 - 1))); % individual cut plot 2

xlabel('Frequency');
ylabel('Magnitude (dB)');

axis([20, 8000, -16, 16]);
grid;

hold off;


bandpass.m

function [b, a] = bandpass(f, q)
b = [0, f / q, 0];
a = [f * f, f / q, 1];
end


response2db.m

function [db] = response2db(r)
db = 20 .* log10(abs(r));
end


db2gain.m

function [g] = db2gain(db)
g = 10 .^ (db ./ 20);
end


proportionalQ.m

function [q] = proportionalQ(q, g)
q = q .* sqrt(g);
end


response.m

function [r] = response(b, a, f)
s = 1i .* f;

r = (b(1) + s .* b(2) + s .* s .* b(3)) ...
./ (a(1) + s .* a(2) + s .* s .* a(3));
end

• You are missing the function response() – Hilmar Sep 7 at 22:32
• @Hilmar, I've added the missing function - sorry! – onthefritz Sep 8 at 6:39

Cuts can simply be derived from boosts like so: p2 = 1 / p1

This is intuitive as this is how you would invert a bandshelf.

However, I'm not sure it leads to an elegant equation as inverting the sum of filters and recovering a rational filter expression might be messy, so there's potential a better way. I can't run your code since one function is missing.

In general, parallel EQs are a not a great idea. Since you add the responses, the exact phase responses of either boost or cut need to be carefully controlled, otherwise you see cancellation (as you probably do here).

It's much easier to parametric EQs in series instead. If the gain is 0, there is no interference in they add simply in dB.

This being said : this line looks strange to me

p2 = 1 + r3 .* (g3 - 1) + r4 .* (g4 - 1);


I assume g3 is supposed to be the amount of cut. You get no cut for g3 = 0dB but it's certainly NOT -12dB for g3 = -12dB. (gr-3) comes out to be -.75 and gives you a nasty phase flip as well

• It's worth keeping in mind that 1 + r3 .* (g3 - 1) and 1 + r4.* (g4 - 1) are individually giving the right result (shown in the graph) and are the mirror opposite of their respective boosts, it's just when they are used together it goes wrong. – onthefritz Sep 8 at 6:44