Too many EQs?

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

_tweak_ wrote: Fri Nov 05, 2021 5:39 pm
mystran wrote: Thu Nov 04, 2021 8: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.

Post

_tweak_ wrote: Fri Nov 05, 2021 9: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
pkg load signal

% 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.

Post

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.

Post

Vicious wild hungry troll attacks have been reported on my area. Keep you and your math safe fellas.

Post Reply

Return to “DSP and Plugin Development”