Too many EQs?

DSP, Plug-in and Host development discussion.
mystran
KVRAF
6723 posts since 12 Feb, 2006 from Helsinki, Finland
_tweak_ wrote:
Fri Nov 05, 2021 9:39 am
mystran wrote:
Thu Nov 04, 2021 12:13 am
On top of that, numerical precision can actually come into play with naive implementations (ie. those "stock EQs" that tend to be otherwise pretty much the same), especially those using direct form filters, where the actual response isn't even quite what it says on the label.
I’m coming across numerical precision a lot the last few months, but what does it actually mean in regards to digital EQs?
Adding two floating point numbers with different magnitude involves scaling the smaller number to the range of the larger numbers (so their exponents are the same) which involves discarding bits. So adding small numbers to large numbers is not very accurate. Now, depending on the filter structure, this generally has the effect of changing the transfer function slightly or not so slightly and/or just leading to noise in general. The actual analys of what happens is rather arcane though.
So you don’t think it’s possible to emulate/simulate analog curves with direct form filters? What would be the alternative to make them sweet analog curves possible in a plugin?
The "curves" usually refer to the transfer function and every half-decent filter structure should be able to realize any transfer function. Direct form filters are numerically bad, but they can theoretically implement every (stable) transfer function. I'd generally recommend using the trapezoidal SVF instead for every single situation where you'd previously used a direct form, no exceptions whatsoever), because it costs just about exact the same as a DF-biquad, yet much better numerical and dynamic (ie. under modulation) behaviour.

As for curves, the general idea is to map the poles and/or zeroes directly (using z=exp(s)) and then you fit another filter to "correct" the response. For best results, use a FIR with some optimization procedure (least squares is cheap, one-pass and works fine). For a cheaper, less accurate approximation (eg. typically disregards phase) use MZTi or MIM or similar.
Preferred pronouns would be "it/it" because according to this country, I'm a piece of human trash.

juha_p
KVRian
699 posts since 21 Feb, 2006 from FI
_tweak_ wrote:
Fri Nov 05, 2021 1:56 pm
...

I'll look into MIM a bit more, checking it out for a bit made me realise that this stuff is way over my pay grade right now
MIM implementation I linked is not ready to do EQ filters right away but you need to modify the code a bit. Here's Octave example for to how to prepare the analog models of various filters to be used as an input parameter in c2dn() call.

Add this code to end of the c2dn() function:

Code: Select all

``````switch lower(ty); % normalize DC
case {'highpass', 'bandpass'}
%Dz = Dz/aE(1);
otherwise
Dz = (Dz/dcgain(Dz)) * dcgain(Ds);
end``````
This code calculates 6th order coefficients for a biquad peaking filter (IIR):

Code: Select all

``````pkg load control

% Dependencies: ---------------------------------------------------------------------------------------------------
% c2dn.m - https://soar.wichita.edu/bitstream/handle/10057/1564/t07116.pdf?sequence=3&isAllowed=y (source listing)
% eq_design_analog.m - https://users.aalto.fi/~ssarkka/pub/eq-design-demo.zip (source code)
% eq article - https://users.aalto.fi/~ssarkka/pub/eq-article.pdf (just FYI)
% ------------------------------------------------------------------------------------------------------------------------

%clear all;

clf;

fs = 44100;
fc = 10000;
Q  = 1/sqrt(2);
db = 12;
N  = 6; % order

mimpim = 'mim';
samplingtime = 1/fs;
numofsamples = 256^2; %more samples used gives better match

%ty = 'lowpass';
%ty = 'highpass';
%ty = 'bandpass'; % gain does not match
%ty = 'notch'; %
%ty = 'allpass'; %NOT WORKING
ty = 'peak';
%ty = 'lowshelf';
%ty = 'highshelf';

%%%% Analog design ============================================================
[b2,a2] = design_analog(ty,fc,Q,db);  % eq_design_analog.m
Ds = tf(b2, a2);

switch lower(ty); % normalize DC
case {'highpass', 'bandpass'}
%Ds = Ds/b2(1);
otherwise
Ds = Ds/dcgain(Ds);
end

%%%% Digital approximation
[Dz] = c2dn(Ds, samplingtime, mimpim, N, numofsamples, ty); % MIM method
[a, b, T] = tfdata(Dz)  % coefficients

%%%% Plot
fs2 = fs/2;
nf = logspace(0, 5, fs2);

figure(1);
[mag, pha] = bode(Ds,2*pi*nf);
semilogx(nf, 20*log10(abs(mag)), 'color', 'g', 'linewidth', 2);
axis([1 fs2 -20 20]);
hold on;
semilogx(nf, pha, 'color', 'g', 'linewidth', 2.0, 'linestyle', '--');
hold on;

[mag, pha] = bode(Dz,2*pi*nf);
semilogx(nf, 20*log10(abs(mag)), 'color', 'k', 'linewidth', 1.0);
hold on;
semilogx(nf, pha, 'color', 'k', 'linewidth', 1.0, 'linestyle', '--');

xlabel('Hz');ylabel('dB');
grid on;
``````
peakMIM.png

Because of some issues involved in this method (as written in thesis and this can be seen when set fc below 50Hz in my example code), when calculating coefficients for low order filter, with some filters, you need to increase or decrease the cut-off frequency or gain to match the analog design. Increasing N and/or numberofsamples helps in this but, you could make a formula which does this automatically by using (binary) search for to find the closest fc or gain value to be used.
You do not have the required permissions to view the files attached to this post.

kingozrecords
KVRian
1035 posts since 7 Apr, 2019 from Canada
99.99% of eq's have too much artifacts and grain. I sell the freq3 free/paid and it's ok. But that's an example of a grainy eq. Not as grainy as some. Do I like it? Noo. I like the vstplug freq better. I like vivid and clean. Rare to ever find that.

But maybe with rbj filters it would sound nicer. In My opinion it comes down to your technique to reduce the clash between float numbers and live dsp ones. That's what pops in the end. I like some fir stuff but it sounds bad often.
DSPplug Products https://www.kvraudio.com/marketplace/dspplug