Cheap non-linear zero-delay filters

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

2*Vt = 1, so that can be omitted. Think I need to throw this into Maxima and see what pops out. Always actually wondered how different in output Maxima vs. Matlab is. Finding an efficient form is quite tedious. Once Maxima's 'simplifier' substituted 4 adds for 3 divides :evil:
Well, you should find more or less the same results in both cases, otherwise that means there is a problem :D When I do this kind of stuff, I always double-check my results in two different ways, so I'm sure my terms are right (they are never right on the first attempt :hihi: )

As a side note, I didn't want to get the "full solution", because in this filter case, it has a large number of terms. Instead, I solved for y3 depending only on the inputs, and then I got the solution depending on y3/y2/y1/y0 and the inputs. As you can see in my code, the result looks not that bad this way.

Post

Hi mystran,

tested this filter (post #2 of this thread) today in Reaper and it sounds very good.

One small issue: The volume drops to much when raising the resonance from 0 up, but this can easily be fixed by a correction factor.

Is this filter stable for example when modulating the cutoff at audio rate?
EDIT: added audio rate mod to my JS plug and yes, the filter is stable.

Chris
Last edited by Chris-S on Thu Mar 17, 2016 8:25 am, edited 2 times in total.

Post

Chris-S wrote:One small issue: The volume drops to much when raising the resonance from 0 up, but this can easily be fixed by a correction factor.
I compared with Monark (the best MOOG emulation) and I see also the volume drop there.
So this seems to be a property of the ladder filter and doesn't need to be corrected.

Post

It's only natural due to the negative feedback. It cancels out the input signal.

If you had full negative feedback and no integrators the output would be zero.

Although of course in this case we've replaced feedback with a prediction of the output state given the input and without feedback, then we use that as an additional input.

So it isn't much different than this:

x - x * (1/n)

The compensation is trivial:

Code: Select all

      // you must limit the compensation if feedback is clamped
      const T compensation = 1.0 + limit(feedback, 0.0, 4.0);
      return output * compensation;
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

Where can I find the feedback (in the code of post #2)?

For now I use:
korr = 1 + resonance/(resonance+1);

Post

"feedback" would be the level at which the prediction is mixed/subtracted at the input.

Going back to my post on the last page:
http://www.kvraudio.com/forum/viewtopic ... 5#p5972622

Code: Select all

const T xx = input - clamp(fb * estimate) * cgfbr;
You should read my refactored code to better understand what is happening. I also believe the code in post 2 may still contain some errors although I haven't bothered to check.

I know the linked post contains working code.

The code in post #2 would be this:

double xx = t0*(in[n] - r*y3);


Although I suspect it contains other errors.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

You have three main options for gain compensation. The amount you need to gain is 1+4*res. You can do any combination of:

1) increase the input signal level
2) increase the output signal level
3) add (subtract) some of the input signal to the resonance feedback signal

Each one has different advantages and disadvantages and will lead to a different sounding result in a non-linear system.
The Glue, The Drop, The Scream - www.cytomic.com

Post

andy-cytomic wrote:You have three main options for gain compensation. The amount you need to gain is 1+4*res. You can do any combination of:

1) increase the input signal level
2) increase the output signal level
3) add (subtract) some of the input signal to the resonance feedback signal

Each one has different advantages and disadvantages and will lead to a different sounding result in a non-linear system.
In classic transistor ladders, the distortion goes down with increasing resonance together with the gain: you get high distortion at low resonance, but the resonance is still strong when you turn it up. Even if you wanted to compensate the gain, you probably want to preserve this behaviour, so I'd normally go for output compensation with these. In my opinion, doing anything else makes the model (of a transistor ladder) feel wrong when tweaking the filter. YMMV.

I'm not sure if that's done in any classic hardware transistor ladder, but the related diode ladders suffer from this problem even more and consequently you can find such output compensation in TB-303 (and friends), where it basically amounts to an extra resistor that mixes some post-knob resonance to the summing op-amp (or buffer, but it doubles for the summing too) feeding the next stage. The same method could be retrofitted (by adding a resistor) to any (hardware) transistor ladder that is followed by suitable amp that can do the summing (and if you don't have such an amp, then you can still do it, but it takes a bit more than just a resistor then).

So .. personally I feel like the output compensation is good fit for transistor ladders, both in terms of artistic results and in terms of how it would fit into the circuitry (where it does not require any drastic changes, typically). Note that strong resonance (=less distortion) is exactly what you want if you plan on sending the output to a post-distortion stage for screaming acid sounds or similar.

For other 4-pole cascades you might want to do something else, depending on the particular filter. For ICs with the feature built-in, you might (or might not, depending on the IC) want to investigate the option 3 (which is basically the most natural way to implement option 1 in hardware). It basically comes down to similarly trivial implementation (eg. "one resistor") if you are doing VCA control of the resonance and can use that VCA to add the input and resonance together before scaling the sum.

Oh and finally I would like to repeat (once again) that the filter on the first page is NOT a good "analog model" in any sense of the word. It's a simple example application of a technique. The technique itself can be used with much better models for much better results. If you want your filters to compare favourably with actual transistor ladders or good models you need to model more than just the ladder itself, most importantly the linear and non-linear distortion (that is, phase-distortion and saturation effects) in the feedback path. This makes the code a lot longer and a bit harder to follow and there is more variation in terms of specific circuits, which is why I didn't try to do any of that. How accurately you model these will make a lot more difference than the specific method you use for solving non-linearities!

Post

The TB-303 compensates output gain, but it requires a linked pot and isn't particularly accurate.

I believe a few other synthesizers also compensate although the issue is of course that the result of the decrease in volume is actually that peak levels are maintained (more or less) across all settings. If compensating it is more likely to affect future stages by for example saturating the VCA inputs.

Most synthesizers therefore have an output gain up to ~20 dB where level adjustment can be made manually. (Although I almost always see people with this output gain set to max rather than around the mid position where it was intended to sit.)

In cases where compensation is used along with fully linear stages ahead of the filter a manual gain control can also be used to "undo" the compensation. So it is really up to the author to decide which seems most practical.

In my opinion I'd always prefer compensation as it saves me 90% of the time having to make additional gain adjustments.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

aciddose wrote:The TB-303 compensates output gain, but it requires a linked pot and isn't particularly accurate.
Check the schematic again, there's no requirement for linked pot. In TB-303 one is used, but that's because the resonance pot also controls the accent circuitry. The output gain compensation comes from the normal feedback path directly.

Post

Hi aciddose,

Code: Select all

const T c = coefficient
const T fb = from 0 to 4 for 100%, further "drives" feedback
c is the cutoff and fb the resonance?

Post

mystran wrote:
aciddose wrote:The TB-303 compensates output gain, but it requires a linked pot and isn't particularly accurate.
Check the schematic again, there's no requirement for linked pot. In TB-303 one is used, but that's because the resonance pot also controls the accent circuitry. The output gain compensation comes from the normal feedback path directly.
Ah right, my mistake.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

Chris-S wrote:Hi aciddose,

Code: Select all

const T c = coefficient
const T fb = from 0 to 4 for 100%, further "drives" feedback
c is the cutoff and fb the resonance?
Well, no. These are two coefficients named "C" and "FB". Yes, "C" corresponds to frequency and "FB" to feedback which therefore influences "resonance" but it isn't correct to say they "are" either.

One of the reasons for this is that "C" actually does not control frequency directly. A change in "C" will likely lead to a change in frequency, but it need not be proportionate and it need not directly or solely control frequency.

Likewise for "FB". It corresponds to feedback and yet it does not control feedback... in fact there is no feedback whatsoever (edit: well, other than integrator state) in this filter at all! The "FB" coefficient is a gain coefficient used to produce other coefficients which lead to the scaling of the inputs. A change in "FB" will likely lead to a change in "resonance", yet it need not be proportionate nor direct or a sole contributor to the amount of oscillation.

Also everything mystran said applies to this code. It is the same code! The only changes were the correction of a few errors (I believe some gains were incorrect) and a very simple refactor along with reducing the complexity of the "tanh-alike" function.
Last edited by aciddose on Sun Oct 18, 2020 5:51 pm, edited 1 time in total.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post

Ok, so I have to find a nice mapping cutoff -> c and reso -> fb.

Code: Select all

// clamp can be a hard clip, a diode + highpass is better
// if you implement a highpass do not forget to include it in the computation of the gain coefficients!
 const T xx = input - clamp(fb * estimate) * cgfbr; 
Can I use tanh as the clamp-function?

BTW The gain correction works very good in your algo.

Post

Well as I described it's 100% accurate because it's so simple. The same works in mystran's original post. Also note again this is mystran's code with a simple refactor and corrections.

All it does is directly compensate this:

x - (x / n)

By adding:

x + (x / n)

You can use whatever you want anywhere you want. tanh() isn't a good idea though first of all because it's incredibly unrealistic, secondly because the signal level to oscillation level will be very large and most importantly because unless you use an expensive approximation which can't lead to numerical instability (div by zero, inf, nan, etc), well, it definitely will.

Try limit(x, min, max) instead to start.

limit() otherwise known as a hard clip has a maximally steep edge and so will lead to a lot of aliasing, but it's relatively cheap and definitely stable. On the positive side it has 100% linearity until the threshold and is stable about zero.

Some sort of "soft" hard clip is actually the next best thing although you'll find sigmoid functions are cheaper. Most sigmoids share a lot of the advantageous properties of a hard clip with less linearity and more gradual onset, which is a trade-off.

Ideally if you're modelling a common diode clamp you'll want a high-pass filter (single capacitor) leading into a resistor and diode pair. There are various ways to model this, all of them are horrifyingly complicated and expensive.
Free plug-ins for Windows, MacOS and Linux. Xhip Synthesizer v8.0 and Xhip Effects Bundle v6.7.
The coder's credo: We believe our work is neither clever nor difficult; it is done because we thought it would be easy.
Work less; get more done.

Post Reply

Return to “DSP and Plugin Development”