Accelerate/vDSP Biquad filter

DSP, Plugin and Host development discussion.
Post Reply New Topic
RELATED
PRODUCTS

Post

niarn wrote:Do you mean inserting non-linearities into the svf itself? like some saturation on the states? because this is what is happening in the analog svf?
In non-tunable analog filters, opamp (or transistor follower) clipping might be the main nonlinearity. That would often be rather hard clipping, just depending on the component. Some opamps would run out of oomph nearing the rails, and some opamps couldn't get all the way to the rails. Some opamps and perhaps voltage follower transistors had assymetrical drive-- Some could source more current than they could sink or vice-versa, so on large signals perhaps they could charge a capacitor harder than they could discharge it, or vice-versa..

In tunable filters directly controlled by potentiometers, such as parametric equalizers, or tunable speaker active crossovers or benchtop filter test sets, perhaps about the same conditions as above, unless someone can think of special cases.

In sweepable filters such as synthesizer filters, or auto-wah effects, or some flavors of de-esser, etc-- The job of the variable resistor had to be done by some form of "voltage controlled resistor" or "current controlled resistor". To my knowledge, at least in the old days, there was no ideal well-behaved "voltage controlled resistor". All options had various flaws and nonlinearities so far as I know.

Common methods included modulation of transistor transconductance, or diode transconductance, or OTA (operational transconductance amp), or CDS cell optoisolator.

Each voltage controlled resistor had its own characteristic nonlinearities. In a second order state variable filter there would be two of them sitting in the circuit waiting for an opportunity to distort. :)

Also, there were at least a couple of obvious ways to wire up a synth filter. The "clean well-behaved" wiring would have constant gain on the loudest part of the resonance peak. Not likely to blatantly long-term overload if you crank up the resonance. But this kind of filter didn't have much "balls". If you turn up the resonance of such a low-pass filter, it would turn down the gain of the passband, to keep the gain of the resonant peak constant. The higher you crank the resonance, the lower the gain in the passband. To some musicians it felt like turning up the resonance caused the sound to "lose power".

Another way of wiring, you always keep the passband gain the same, and when you crank up the resonance, the resonant peak gets loud as hell. Which if the filter did not distort somehow, and you sweep down thru a ramp wave at high resonance, the volume jumps when the resonance peak passes thru loud harmonics might hurt the ears or blow speakers. So some "sonorous" soft clipping was beneficial in getting a fat ballsy sound with a high-resonance filter without hurting people's ears.

**** There was one method that perhaps in theory would be fairly linear, a switched-capacitor scheme. Use a fast CMOS or FET switch in place of the tuning resistor, and drive it with an ultrasonic pulse train. Modulate the width or density of pulses to modulate the charging of the capacitor. But using old off the shelf parts, that was kinda a nasty circuit to build and get it to behave correctly. You normally wouldn't want high-amplitude ultrasonic digital signals sitting right beside an audio signal on a circuit board. Nowadays that is how digital power amplifiers work, and so maybe some of the digital power amp chips could somehow be re-purposed for use in tunable analog filters, dunno.

Post

Z1202 wrote:
andy-cytomic wrote:
niarn wrote:Do you mean inserting non-linearities into the svf itself? like some saturation on the states? because this is what is happening in the analog svf?
Analog doesn't saturate the states as such, but saturates various voltages and currents in the circuit, which are then integrated to form the states. There are such things as non-linear capacitors as well, such as diffusion capacitors, but in most analog filter circuits the capacitors are pretty well linear, perhaps with some serial and parallel resistances.
At some points the state will saturate as well. E.g. if a state is capacitor voltage, it can't grow infinitely and normally will be limited by something like the power supply voltage. Whether this threshold can be reached practically depends on the circuit.
But that isn't due to the non-linear properties of the capacitor, that will be due to current be drawn out of the capacitor by other parts of the circuit, the only time the capacitor will stop charging is just before it goes *pop* near its manufacturing voltage limits, which are usually well above the voltage rails so not of concern in most analog circuit models.
The Glue, The Drop, The Scream - www.cytomic.com

Post

andy-cytomic wrote:
niarn wrote:
earlevel wrote:For instance, I could sweep Andy's filter—no changes from the pdf—from 20 kHz to 80 Hz, sound good, like a synth. The same sweep blows up and yields no audio output (blows to big numbers in a few samples, then -inf, +inf recirculate to ensure output is screwed thereafter) with the Chamberlin. But if I drop the top of the sweep to, say, 8500 Hz, it sounds good fine.

There are other reasons, but that's reason enough.
Let's pretend we have the sweep issue fixed as explained above can you give just one more reason?
It depends on the application, so what do you want to use it for?

Some reasons to use the full trapezoidal implicit version over a warped / corrected forward euler:
Are you making some super generic claims or are we talking
http://www.cytomic.com/files/dsp/SvfLin ... mised2.pdf p.6 (andy svf)
vs
Chamberlin svf ?
Anyway, thanks for giving some more reasons.
andy-cytomic wrote: 1) all sin computation of coefficients and excellent numerical performance which is good for accuracy in critical engineering applications
What is sin computation? Do you mean that andy svf provides superior SNR over chamberlin svf? What exactly are you referring to when you say excellent numerical performance?
andy-cytomic wrote: 3) reasonably low cpu count if you want to mix the outputs - the warped forward Euler versions op count increases if you want all the outputs
Can you be more specific, don't both version need 3 additional multiplications in the generic case (linear combination of the states)?
andy-cytomic wrote: 4) although it's easier to add non-linearities to the warped / corrected forward euler they don't sound as good, you don't quite get the right self FM behaviour when it drives because it's not being solved implicitly. A full implicit non-linear solver allows for more parallel execution of the non-linearities, so only ends up costing a tiny bit more than the semi-implicit warped /corrected forward euler version, and it ends up that evaluation of the non-linearities dominates the cpu
I think maybe it can be debated whether a biquad is really a biquad if non-linarities are being added but can you give an example of where in these equations a nonlinearity would be added?

Code: Select all

v3 = v0 - ic2eq;
v1 = a1*ic1eq + a2*v3;
v2 = ic2eq + a2*ic1eq + a3*v3;
ic1eq = 2*v1 - ic1eq;
ic2eq = 2*v2 - ic2eq;

Post

niarn wrote:
andy-cytomic wrote: It depends on the application, so what do you want to use it for?

Some reasons to use the full trapezoidal implicit version over a warped / corrected forward euler:
Are you making some super generic claims or are we talking
http://www.cytomic.com/files/dsp/SvfLin ... mised2.pdf p.6 (andy svf)
vs
Chamberlin svf ?
Anyway, thanks for giving some more reasons.
They are both generic and specific to that link, as the linked pdf uses Trapezoidal integration
niarn wrote:
andy-cytomic wrote: 1) all sin computation of coefficients and excellent numerical performance which is good for accuracy in critical engineering applications
What is sin computation? Do you mean that andy svf provides superior SNR over chamberlin svf? What exactly are you referring to when you say excellent numerical performance?
Normal SVF coefficients use Tan to warp the cutoff, but tan gets big with high cutoffs, but you can transform all the coefficient calculation to use only Sins instead, which is much better for accuracy, and also noise performance of the final implementation.
niarn wrote:
andy-cytomic wrote: 3) reasonably low cpu count if you want to mix the outputs - the warped forward Euler versions op count increases if you want all the outputs
Can you be more specific, don't both version need 3 additional multiplications in the generic case (linear combination of the states)?
Have a look at the total operation count of any implementation you want to use and decide based on that as well as the other benefits / drawbacks.
niarn wrote:
andy-cytomic wrote: 4) although it's easier to add non-linearities to the warped / corrected forward euler they don't sound as good, you don't quite get the right self FM behaviour when it drives because it's not being solved implicitly. A full implicit non-linear solver allows for more parallel execution of the non-linearities, so only ends up costing a tiny bit more than the semi-implicit warped /corrected forward euler version, and it ends up that evaluation of the non-linearities dominates the cpu
I think maybe it can be debated whether a biquad is really a biquad if non-linarities are being added but can you give an example of where in these equations a nonlinearity would be added?

Code: Select all

v3 = v0 - ic2eq;
v1 = a1*ic1eq + a2*v3;
v2 = ic2eq + a2*ic1eq + a3*v3;
ic1eq = 2*v1 - ic1eq;
ic2eq = 2*v2 - ic2eq;
You will need to read up on implicit equation solver to be able to add non-linearities the the above code as the whole solution changes. It is easier to add them to the forward Euler version, but where they are and what they are depends on the SVF circuit and how much detail you want to go into modelling. I won't go into details, but I suggest you go and grab a copy of LTSpice or Qucs and start simulating away so you can find out yourself :tu:
The Glue, The Drop, The Scream - www.cytomic.com

Post

andy-cytomic wrote: You will need to read up on implicit equation solver to be able to add non-linearities the the above code as the whole solution changes. It is easier to add them to the forward Euler version, but where they are and what they are depends on the SVF circuit and how much detail you want to go into modelling. I won't go into details, but I suggest you go and grab a copy of LTSpice or Qucs and start simulating away so you can find out yourself :tu:
I'm in a business where I do everything I can to remove non-linearities so I will be killed if I started adding some of my own non-linearities. I just can't imagine that adding non-linearities to a filter in an audio signal path will sound very nice or be desired as such, that is why I'm finding this topic interesting.
But I think I start to understand what you are saying. Because all your arguments are not really valid (has any effect) when talking about biquads in the normal understanding. You are really talking about solving non-linear equations. Anyway, its been interesting to follow the debate both the part on biquads and the one on non-linear equation solving.

Post

niarn wrote:
andy-cytomic wrote: You will need to read up on implicit equation solver to be able to add non-linearities the the above code as the whole solution changes. It is easier to add them to the forward Euler version, but where they are and what they are depends on the SVF circuit and how much detail you want to go into modelling. I won't go into details, but I suggest you go and grab a copy of LTSpice or Qucs and start simulating away so you can find out yourself :tu:
I'm in a business where I do everything I can to remove non-linearities so I will be killed if I started adding some of my own non-linearities. I just can't imagine that adding non-linearities to a filter in an audio signal path will sound very nice or be desired as such, that is why I'm finding this topic interesting.
But I think I start to understand what you are saying. Because all your arguments are not really valid (has any effect) when talking about biquads in the normal understanding. You are really talking about solving non-linear equations. Anyway, its been interesting to follow the debate both the part on biquads and the one on non-linear equation solving.
My comments have a great deal to do with both solving the linear and non-linear equations, you're probably just not taking it all in right now.

If you want the cleanest, most linear, and most accurate (in terms of actual cutoff and q), 2 pole digital filter to compute using all same precision floating point numbers that also has excellent modulation properties then this is the one to use:
http://cytomic.com/files/dsp/SvfLinearT ... dalSin.pdf
The Glue, The Drop, The Scream - www.cytomic.com

Post

andy-cytomic wrote: If you want the cleanest, most linear, and most accurate (in terms of actual cutoff and q), 2 pole digital filter to compute using all same precision floating point numbers that also has excellent modulation properties then this is the one to use:
http://cytomic.com/files/dsp/SvfLinearT ... dalSin.pdf
Thank you very much for the great work, andy-cytomic.

A coupe of a layman questions for the SvfLinearTrapezoidalSin:

1. In what kind of range should the damp factor be? And what is it?
2. Are these filers stable even with big jumps in Q and cutoff, or should we smoothen sudden changes?
3. What if i want a steeper 24db, is it reasonable to stack two of these?

Post

CurryPaste wrote: Thank you very much for the great work, andy-cytomic.

A coupe of a layman questions for the SvfLinearTrapezoidalSin:

1. In what kind of range should the damp factor be? And what is it?
2. Are these filers stable even with big jumps in Q and cutoff, or should we smoothen sudden changes?
3. What if i want a steeper 24db, is it reasonable to stack two of these?
You're welcome!

1: Damping can be whatever you want, the normal range is 2 to 0, with 0 being self oscillation, and 2 being the same as cascading two one pole low pass filters together. Higher and lower damping are possible.
2: With analog if you have a jump in Q or cutoff you will get a click, the same goes for this filter, but it won't do odd things like a DF1 with abrupt changes altering the energy in the system
3: Yes you can cascade sections to create steeper filters, you can do that with any filters. You can also create a 4 pole SVF with simultaneous inputs/outputs for 4 pole high pass and 4 pole low pass, which is handy for crossover applications.
The Glue, The Drop, The Scream - www.cytomic.com

Post

I am playing around with Andy's SVF filters, and they are really nice. I have tried both the Tan and Sin versions, and they both work well.

One thing I am struggling with is trying to calculate the magnitude response. I know that previous comments in this thread indicate that the response is the same as the biquad response; however, I am playing around with Andy' "mixing" versions of the filters. These filters are using the m0, m1, and m2 coefficients to calculate the summed output of the LP, HP, and BP filters. I am trying out some non-standard mixing, so the response will be different than textbook.

How can I calculate the magnitude response at a given frequency? I assume I can calculate the LP, HP, and BP responses and sum everything with the correct m0, m1, and m2 values. But in all of my attempts to figure out an LP response, I am failing very badly.

Andy's paper entitled "Solving the continuous SVF equations using trapezoidal integration and equivalent currents" has some useful equations on page 11, but I am having a problem with k. It appears to be inverse, and then blows-up all crazy at certain values.

Post

random_id wrote:I am playing around with Andy's SVF filters, and they are really nice. I have tried both the Tan and Sin versions, and they both work well.

One thing I am struggling with is trying to calculate the magnitude response. I know that previous comments in this thread indicate that the response is the same as the biquad response; however, I am playing around with Andy' "mixing" versions of the filters. These filters are using the m0, m1, and m2 coefficients to calculate the summed output of the LP, HP, and BP filters. I am trying out some non-standard mixing, so the response will be different than textbook.

How can I calculate the magnitude response at a given frequency? I assume I can calculate the LP, HP, and BP responses and sum everything with the correct m0, m1, and m2 values. But in all of my attempts to figure out an LP response, I am failing very badly.

Andy's paper entitled "Solving the continuous SVF equations using trapezoidal integration and equivalent currents" has some useful equations on page 11, but I am having a problem with k. It appears to be inverse, and then blows-up all crazy at certain values.
There are no "non standard mixings" m0, m1, and m2 can be set to anything you want, they are parameters. The idea is to allow you to use these SVFs to do morphing filters or decamp the amplitude response near nyquist.

Please keep on trying to work it out yourself, hopefully you'll get there. If you want to cheat to get the the solution remember that the transfer function is LTI, so you can use normal filter theory to transform the Laplace version to the cramped version and you'll get the same result as solving the direct trapezoidal equations.
The Glue, The Drop, The Scream - www.cytomic.com

Post

andy-cytomic wrote:
Chris-S wrote:I just tested the general response algo in Reaper and I think peak and notch is switched.....
I always get mixed up with the notch / peak, for the SVF from memory I think it is notch = low + high, and peak = low - high (or high - low depending on the phase you want). I think I fixed this is a couple of places but I'll double check the documents again.
Hi,
I was referencing this doc (general algo at the end):
http://www.cytomic.com/files/dsp/SvfLin ... mised2.pdf
which is not yet updated.

Post

Chris-S wrote:
andy-cytomic wrote:
Chris-S wrote:I just tested the general response algo in Reaper and I think peak and notch is switched.....
I always get mixed up with the notch / peak, for the SVF from memory I think it is notch = low + high, and peak = low - high (or high - low depending on the phase you want). I think I fixed this is a couple of places but I'll double check the documents again.
Hi,
I was referencing this doc (general algo at the end):
http://www.cytomic.com/files/dsp/SvfLin ... mised2.pdf
which is not yet updated.
That document already looks correct to me, apart from the phase of the peak output which is a matter of taste anyway depending if you want it in phase with the high pass or low pass output:

Code: Select all

notch = high + low = v0 - k*v1 - v2 + v2 = v0 - k*v1
peak = high - low = v0 - k*v1 - v2 - v2 = v0 - k*v1 - 2*v2
The Glue, The Drop, The Scream - www.cytomic.com

Post

Hmmm, I don't think I made an error when translating the code to JS (was 90% cut&paste).
http://www.kvraudio.com/forum/viewtopic ... 5#p6373856
This is a notch, isn't it?

Post

Chris-S wrote:Hmmm, I don't think I made an error when translating the code to JS (was 90% cut&paste).
http://www.kvraudio.com/forum/viewtopic ... 5#p6373856
This is a notch, isn't it?
I can't comment on code I've not seen. There was another document that had them flipped which I fixed, perhaps you used that without knowing. Either way it doesn't matter, just use the correct one.
The Glue, The Drop, The Scream - www.cytomic.com

Post

Hi Andy,
this is the JS code:

Code: Select all

 desc: state var filter test

slider1:-3<-60,6,1>output wet (dB)
slider2:1000<10,20000,1>cutoff
slider3:0.5<0.1,10,0.01>Q
slider4:0<-12,12,0.1>bellGain (dB)
slider5:0<0,7,1{low,band,high,notch,peak,bell,low shelf,high shelf}>filtertype

@init

v1=v2=v3 = 0;
ic1eq = 0;
ic2eq = 0;
bellgaindB = 0;
cutoff = 100;
Q = 0.5;
output = 0;

@slider

vol = 2 ^(slider1/6);
cutoff = slider2;
Q = slider3;
bellgaindB = slider4;
filtertype = slider5;

filtertype == 0 ?     // low
(
 g = tan($pi * cutoff / srate);
 k = 1/Q;
 a1 = 1/(1 + g*(g + k));
 a2 = g*a1;
 a3 = g*a2;
 m0 = 0;
 m1 = 0;
 m2 = 1;
);

filtertype == 1 ?     // band 
(
 g = tan($pi * cutoff/srate);
 k = 1/Q;
 a1 = 1/(1 + g*(g + k));
 a2 = g*a1;
 a3 = g*a2;
 m0 = 0;
 m1 = 1;
 m2 = 0;
);

filtertype == 2 ?      // high
(
 g = tan($pi*cutoff/srate);
 k = 1/Q;
 a1 = 1/(1 + g*(g + k));
 a2 = g*a1;
 a3 = g*a2;
 m0 = 1;
 m1 = -k;
 m2 = -1;
);

filtertype == 3 ?    // notch
(
 A = 10 ^ (bellgaindB/40);
 g = tan($pi*cutoff/srate);
 k = 1/Q;
 a1 = 1/(1 + g*(g + k));
 a2 = g*a1;
 a3 = g*a2;
 m0 = 1;
 m1 = -k;
 m2 = -2;
);

filtertype == 4 ?   // peak
(
 g = tan($pi*cutoff/srate);
 k = 1/Q;
 a1 = 1/(1 + g*(g + k));
 a2 = g*a1;
 a3 = g*a2;
 m0 = 1;
 m1 = -k;
 m2 = 0;
);

filtertype == 5 ?      // bell 
(
 A = 10 ^ (bellgaindB/40);
 g = tan($pi * cutoff/srate);
 k = 1/(Q*A);
 a1 = 1/(1 + g*(g + k));
 a2 = g*a1;
 a3 = g*a2;
 m0 = 1;
 m1 = k*(A*A - 1);
 m2 = 0;
);

filtertype == 6 ?    // low shelf 
(
 A = 10 ^ (bellgaindB/40);
 g = tan($pi*cutoff/srate) / sqrt(A);
 k = 1/Q;
 a1 = 1/(1 + g*(g + k));
 a2 = g*a1;
 a3 = g*a2;
 m0 = 1;
 m1 = k*(A - 1);
 m2 = (A*A - 1);
);

filtertype == 7 ?   // high shelf
(
 A = 10^(bellgaindB/40);
 g = tan($pi*cutoff/srate)*sqrt(A);
 k = 1/Q;
 a1 = 1/(1 + g*(g + k));
 a2 = g*a1;
 a3 = g*a2;
 m0 = A*A;
 m1 = k*(1 - A)*A;
 m2 = (1 - A*A);
);

@sample
// Tick
v0 = spl0;
v3 = v0 - ic2eq;
v1 = a1*ic1eq + a2*v3;
v2 = ic2eq + a2*ic1eq + a3*v3;
ic1eq = 2*v1 - ic1eq;
ic2eq = 2*v2 - ic2eq;

output = m0*v0 + m1*v1 + m2*v2;

spl0 = output * vol;
spl1 = output * vol;

Post Reply

Return to “DSP and Plugin Development”