Cheap non-linear zero-delay filters

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

Post

andy-cytomic wrote:I have not analysed the CEM3320, but if anyone wants to point me towards a schematic I'll be happy to :)
Old thread revival:

Something like this?

CEM3320 Filter designs
CEM3320 Data sheet.pdf

Post

Without doing component-by-component modelling which is way too expensive on current hardware, most filter designs can be broken down to a series of non-linear equations applied in specific places. It turns out that modelling a CEM3320 vs. a minimoog ladder vs. BA662 vs. LM13700 you get very similar results and it is simply a matter of adjusting the coefficients and identifying which non-linear stages can be optimized away to save on processing.

In any case it certainly isn't a lack of access to schematics or anything like that, it is more an issue of it being entirely impractical to do full component models.

Note that the linked datasheet does not contain a schematic of the internals of the chip, so we are left to assume a design such as the LM13700 or similar.

Code: Select all

.SUBCKT LM13700 7 6 2 3 4 5
Q1 13 8 2 QPNP
Q3 13 6 15 QNPN
Q4 12 7 15 QNPN
Q5 15 5 10 QNPN
Q6 5 10 3 QNPN
Q7 14 11 3 QNPN
Q8 4 14 11 QNPN
Q2 14 13 8 QPNP
Q10 12 9 2 QPNP
Q9 4 12 9 QPNP
Q11 11 11 3 QNPN
Q12 10 10 3 QNPN
Q13 9 9 2 QPNP
Q14 8 8 2 QPNP
.MODEL QNPN NPN ()
.MODEL QPNP PNP ()
.ENDS LM13700
http://www.idea2ic.com/LM13600/diagram.jpg

Diodes are best modeled as transistors unless the diode/bjt models match. It is possible to build an "optimized" model using current mirrors instead of discrete transistors but I've been unable to get accurate results in combination with performance from those sorts of models.

Using a modern spice simulator like LTspice4, this "default" transistor model is more accurate than the models supplied by national, for example.

Just keep in mind that this whole circuit (this is actually only a portion, no buffer, no current source, no capacitors) needs to be processed for every stage of the filter, usually four or five with VC resonance, in addition to the feedback.

Processing such a filter using tanh+x approximations alone is already a huge processing load and the thought of accurately modelling sub-circuits for each OTA stage is insanity.

It can be done, but only barely in real-time if at all.
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:Without doing component-by-component modelling which is way too expensive on current hardware, most filter designs can be broken down to a series of non-linear equations applied in specific places. It turns out that modelling a CEM3320 vs. a minimoog ladder vs. BA662 vs. LM13700 you get very similar results and it is simply a matter of adjusting the coefficients and identifying which non-linear stages can be optimized away to save on processing.

In any case it certainly isn't a lack of access to schematics or anything like that, it is more an issue of it being entirely impractical to do full component models.

Note that the linked datasheet does not contain a schematic of the internals of the chip, so we are left to assume a design such as the LM13700 or similar.
I guess that is the curse of IC's.

I'm pretty new to circuits (I'm no coder either), but I know that I've seen the CA3080 used in a couple of designs (Oberheim SEM SVF, possibly a couple of 4-pole Cascaded OTA variants).

From what I understand the LM13700 is pretty much an "improved" CA3080 (also the LM13700 contains two OTA's afaik (reference)), which could be of significance in the analog emulation domain, as what are from an engineering viewpoint seen as faults could be that which the synth geeks call "character". Hehe

I guess myquestion is, for some of these applications it might actually be preferable to model the CA3080 over the LM13700?

Post

The CA3080 is a way more complicated design. Ultimately it'll simplify to the same type of model I posted for the lm13700.

The actual LM136/700 is also more complicated than that, but not so much as the 3080.

Their response in the audio range is what we care about and most of the more detailed issues are going to affect the high-frequency response.

If you take the two and measure their response (I've also done this with a BA662) they all come out very similar. The differences are for the most part just minor tweaks, slight biases and so on.

I haven't done this with a stage from the CEM3320, IR3109 or others because these are harder to come by, usually about $50-$100 each!

The over-all response should still be very close however.

What we really want to accomplish is to get within +/-6db the harmonics produced with a sine input with these chips configured in a non-linearized VCA compatible with the configuration they have in most filter circuits. The difference between the chips actually tends to be similar between two of the the same family BA662 vs. BA662 and different CA3080 vs. LM13700.
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

eXode wrote:
andy-cytomic wrote:I have not analysed the CEM3320, but if anyone wants to point me towards a schematic I'll be happy to :)
Old thread revival:

Something like this?

CEM3320 Filter designs
CEM3320 Data sheet.pdf
Yep, I've already got those. What I need is the internals of the triangles labelled "delta A" and "B", they are the business end of the deal. I have worked out some of how they are structured with the help of Antti, but I'm not confident until I have a chip in front of me and do some thorough investigations. The CEM3320 is not the same as a CA3080 (or LM13600/700, which are CA3080s with buffers and linearising diodes added).
Last edited by andy-cytomic on Mon Feb 24, 2014 2:10 am, edited 2 times in total.
The Glue, The Drop - www.cytomic.com

Post

aciddose wrote:...In any case it certainly isn't a lack of access to schematics or anything like that, it is more an issue of it being entirely impractical to do full component models.
It's hard enough with the schematic to get an accurate model, without one it's even harder. I like to start with a full component count circuit simulation as well as the actual chip to double check against, the the full component count circuit simulation matched as close to the chip as possible and then start simplify from there.
The Glue, The Drop - www.cytomic.com

Post

aciddose wrote:The CA3080 is a way more complicated design. Ultimately it'll simplify to the same type of model I posted for the lm13700.
A quote from the developer of the LM13600/700 take from here:
http://www.idea2ic.com/LM13600/LM13700.html
"So the development spec for the LM13600 was that it needed a schematic to train someone in IC layout. It needed to have 16 pins. And we were going to layout the 3080 anyway. The schematic part was easy. Just used the 3080 exactly."

So not only is it the the same schematic, it's the same layout for the OTA part!
The Glue, The Drop - www.cytomic.com

Post

From which manufacturer?

Yes they should be very similar as there is really only one way to accomplish the task. The differences though are in the real world layout of the chip, where one "transistor" of the schematic might actually be made up of a vastly more complicated and specific layout.

I'm not 100% sure that the BA662 and others use the same configuration of current mirrors, but the results I've had testing one showed no significant difference. So I'd guess they do.

When you're only trying to get reasonably accurate audio results, that means the model I posted is going to be accurate enough for every one of these circuits. Then it just becomes a matter of customizing different transistors to add the right amounts of bias at different parts of the circuit, assuming that even really matters. (In reality it doesn't. We're talking +/- 1db here.)
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

Thanks for all your input.

I am myself quite interested in the SSM2040, as it imho is one of the best (i.e. musical or whatever you wan't to call it) low pass filters that I know of. It suffers from a similar problem as the CEM3320 thanks to it being an integrated circuit (i.e. actual components/OTA's used is hard to know?). I have found J. Habiles take on it which should be pretty good though.

I also found the MOTM 440 which sounds pretty darn good, and it being available as DIY you get a full component list and schematics.

Post

eXode wrote:Thanks for all your input.

I am myself quite interested in the SSM2040, as it imho is one of the best (i.e. musical or whatever you wan't to call it) low pass filters that I know of. It suffers from a similar problem as the CEM3320 thanks to it being an integrated circuit (i.e. actual components/OTA's used is hard to know?). I have found J. Habiles take on it which should be pretty good though.

I also found the MOTM 440 which sounds pretty darn good, and it being available as DIY you get a full component list and schematics.
If you like the SSM2040 then also check out the CEM3372, which is similar in style but even more minimal, dispensing with the darlington buffers and feeding back the signal straight from the caps.
The Glue, The Drop - www.cytomic.com

Post

andy-cytomic wrote:If you like the SSM2040 then also check out the CEM3372, which is similar in style but even more minimal, dispensing with the darlington buffers and feeding back the signal straight from the caps.
Cheers Andy. I know of the CEM3372 from it's brilliant implementation in the Xpander/Matrix 12 as well. Really clever solution imho.

Post

Hello ! I have a question for Mystran.

I'm trying to follow his tutorial from the first page, to verify if I get the same results for the Moog filter than him (his code from the first page too). However, I'm stuck at one point...

The classic equations for the Moog Transistor Ladder are the following (without some of the additional gain terms) :

Code: Select all

dVc1/dt = tanh(Vin-R*Vc4) - tanh(Vc1)
dVc2/dt = tanh(Vc1) - tanh(Vc2)
dVc3/dt = tanh(Vc2) - tanh(Vc3)
dVc4/dt = tanh(Vc3) - tanh(Vc4)
If I do the discretization, following the same scheme than Mystran, here is what I got at first :

Code: Select all

y1[n+1] = s1[n] + f.tanh(x[n]-R*y4[n+1]) - f.tanh(y1[n+1])
y2[n+1] = s2[n] + f.tanh(y1[n+1]) - f.tanh(y2[n+1])
y3[n+1] = s3[n] + f.tanh(y2[n+1]) - f.tanh(y3[n+1])
y4[n+1] = s4[n] + f.tanh(y3[n+1]) - f.tanh(y4[n+1])
Then, using the half-sample approximations, and the function T(x) = tanh(x)/x :

Code: Select all

y1[n+1] = s1[n] + f.t0.(x[n]-R*y4[n+1]) - f.t1.(y1[n+1])
y2[n+1] = s2[n] + f.t1.y1[n+1] - f.t2.y2[n+1]
y3[n+1] = s3[n] + f.t2.y1[n+1] - f.t3.y3[n+1]
y4[n+1] = s4[n] + f.t3.y1[n+1] - f.t4.y4[n+1]
with :

Code: Select all

t0 = T(x[n-0.5]-R*s4[n])
t1 = T(s1[n])
t2 = T(s2[n])
t3 = T(s3[n])
t4 = T(s4[n])
From there, obtaining the value for each yx[n+1] is easy in theory, but the inverse matrix I got has very complicated terms, where mystran's code seems to have very short terms. So I think I made a mistake somewhere, or missed a point. Is it possible to help me here ?

Thanks in advance :wink:

PS. My first attempt for the discretization was like that :

Code: Select all

y1[n+1] = s1[n] + f.tanh(x[n]-R*y4[n+1]) - f.tanh(y1[n+1])
y2[n+1] = s2[n] + f.tanh(y1[n]) - f.tanh(y2[n+1])
y3[n+1] = s3[n] + f.tanh(y2[n]) - f.tanh(y3[n+1])
y4[n+1] = s4[n] + f.tanh(y3[n]) - f.tanh(y4[n+1])
But then, the expression for the tx wouldn't be the same than in the original code too, so I don't know...

Post

Wolfen666 wrote: From there, obtaining the value for each yx[n+1] is easy in theory, but the inverse matrix I got has very complicated terms, where mystran's code seems to have very short terms. So I think I made a mistake somewhere, or missed a point. Is it possible to help me here ?
You almost certainly don't want to invert any matrices, just solve the system using LU or similar and the code should look similar enough to what I originally wrote.

Post

I was thinking of that too, but I wasn't sure about the [n] and the [n+1] in my equations. So if nothing have shocked you in what I have written, I will be able to finish what I'm doing, and I will try to use the same method for other filter topologies, thanks ;)

Post

I have done an implementation using Mystran's techniques for an EMS VCS3 Diode Ladder filter, with the equations from the articles of Federico Fontana and Stefano Zambon, such as this one. Since I have not seen this filter here, I thought some people may be interested by my code in its simplified version.

The equations I am solving are the following :

Code: Select all

dvc1/dt = f.(tanh((vin-vout)/(2*Vt)) + tanh((vc2-vc1)/(2*gamma)))
dvc2/dt = f.(tanh((vc3-vc2)/(2*gamma)) - tanh((vc2-vc1)/(2*gamma)))
dvc3/dt = f.(tanh((vc4-vc3)/(2*gamma)) - tanh((vc3-vc2)/(2*gamma)))
dvc4/dt = f.(-tanh((vc4)/(6*gamma)) - tanh((vc4-vc3)/(2*gamma)))
vout = (K+1/2)*vc4
gamma = n*Vt
n = 1.836
The code not that much optimized is here :

Code: Select all

// initialization (the resonance factor is between 0 and 8 according to the article)
f = tan(Pi * cutoff/sampleRate);
r = (7.f * resonance + 0.5f);
Vt = 0.5f;
n = 1.836f;
gamma = Vt*n;

g0inv = 1.f/(2.f*Vt);
g1inv = 1.f/(2.f*gamma);
g2inv = 1.f/(6.f*gamma);

// the input x[n+1] is given by 'in', and x[n] by zi

// input with half delay
float ih = 0.5f * (in + zi);

// evaluate the non-linear factors
float t0 = f*tanhXdX((ih - r * s[3])*g0inv)*g0inv;
float t1 = f*tanhXdX((s[1]-s[0])*g1inv)*g1inv;
float t2 = f*tanhXdX((s[2]-s[1])*g1inv)*g1inv;
float t3 = f*tanhXdX((s[3]-s[2])*g1inv)*g1inv;
float t4 = f*tanhXdX((s[3])*g2inv)*g2inv;

// This formula gives the result for y3 thanks to MATLAB
float y3 = (s[2] + s[3] + t2*(s[1] + s[2] + s[3] + t1*(s[0] + s[1] + s[2] + s[3] + t0*in)) + t1*(2*s[2] + 2*s[3]))*t3 + s[3] + 2*s[3]*t1 + t2*(2*s[3] + 3*s[3]*t1);

y3 /= (t4 + t1*(2*t4 + 4) + t2*(t4 + t1*(t4 + r*t0 + 4) + 3) + 2)*t3 + t4 + t1*(2*t4 + 2) + t2*(2*t4 + t1*(3*t4 + 3) + 2) + 1;

// Other outputs
float y2 = (s[3] - (1+t4+t3)*y3) / (-t3);
float y1 = (s[2] - (1+t3+t2)*y2 + t3*y3) / (-t2);
float y0 = (s[1] - (1+t2+t1)*y1 + t2*y2) / (-t1);
float xx = (in - r*y3);

// update state
s[0] += 2 * (t0*xx + t1*(y1-y0));
s[1] += 2 * (t2*(y2-y1) - t1*(y1-y0));
s[2] += 2 * (t3*(y3-y2) - t2*(y2-y1));
s[3] += 2 * (-t4*(y3) - t3*(y3-y2));

zi = in;
out = y3*r;
I hope this will be useful for someone, and that I have not written too much crap :wink: I won't start again the discussion about the tanh as an approximation of the diode static NL behaviour :D

Thanks again to everybody who has contributed to this topic, allowing me to do this stuff :wink:
Last edited by Ivan_C on Mon Mar 16, 2015 12:16 pm, edited 2 times in total.

Post Reply

Return to “DSP and Plugin Development”