Avatar

Please consider registering
guest

sp_LogInOut Log In sp_Registration Register

Register | Lost password?
Advanced Search

— Forum Scope —




— Match —





— Forum Options —





Minimum search word length is 3 characters - maximum search word length is 84 characters

sp_Feed Topic RSS sp_TopicIcon
filter saturation and self oscillation?
Avatar
Member
Members
August 27, 2018 - 9:16 am
Member Since: August 27, 2018
Forum Posts: 7
sp_UserOfflineSmall Offline

Hi. I have played around with the filters, MoogLadder and K35, and have a question regarding the NLP (saturation) as described in the book.

When there is no saturation, the filters work fine and sound nice, but when turning saturation on and increasing the drive, at a certain point and when there is no input, these filters go into a self oscillation, where the output is a a straight sine (with a frequency close to cutoff). 

I havn't seen this behavior described anywhere. Even if this is intended, it doesn't seem very desirable. 

Can anyone describe what is going on and what to do about it. Or point me to place where this issue is addressed?

Avatar
Admin
August 27, 2018 - 10:54 am
Member Since: January 29, 2017
Forum Posts: 656
sp_UserOfflineSmall Offline

The NLP saturators that I use include a saturation control that allows you to change the steepness of the NLP curve, while maintaining the range of [-1, +1] for input and output. 

However, the fact that the I/O range is limited to [-1, +1] (or normalized) does not limit the amount of energy (or power) to unity. When the overall loop gain of the filter goes over the self-oscillation K value (4 for the Moog) the filter goes unstable. This should happen for non-zero inputs as well. With high saturation levels it may be possible to get the loop gain above the self-oscillation threshold, and place the poles outside the unit circle. 

One thing you can do is to monitor the output of the saturator to see what is happening. I believe that they all include under-flow protection do they should not produce de-normaled numbers (#DEN) which can have the same effect. Or that you have tiny residuals left over in storage registers that are getting amplified through the unstable loop. 

I have also recently experimented with soft-knee peak limiters as the NLP component with MUCH better results - more stable/pure self-oscillation and no chance of instability. 

This will also be in my new 2nd Edition book which hopefully will be ready around late fall 2018 - in fact, I have the "soft-knee peak limiter as the NLP component" as a homework assignment for the Virtual Analog filter chapter. 

And with the built-in sample rate conversion objects that are included with all ASPiK projects, these nonlinear filters are much better behaving and sounding than in previous versions. 

BTW - there will be a massive new set of App Notes and Documents, as well as videos on the ASPiK system. 

- Will

Avatar
Member
Members
August 27, 2018 - 12:53 pm
Member Since: August 27, 2018
Forum Posts: 7
sp_UserOfflineSmall Offline

Hi Will. Thanks for getting back to me so swiftly. Interesting. Sounds really great with a 2nd Edition! I will happily order a copy when its out! Also looking forward to the App Notes!

Yes, I forgot to mention that the problem arises at high resonance settings (around ~3.6).

I'm using doubles and clamping denormals to zero btw, so I think the problem lies in the residual in the storage registers, and the fact that the saturation amplifies the feedback, essentially pushing the resulting K equal or above self osc. 

(Interestingly, I havn't had problems when trying out the Diode ladder filter, which seems more stable in this regard. Again, I'm unsure why.)

It seems your implementation is what is also described in this paper: https://quod.lib.umich.edu/i/icmc/bbp2372.1992.009/--making-digital-filters-sound-analog?view=image

that unfortunatly doesn't address the stability nor disclose the "saturation" function, except for that it is more of a Z curve than an S curve.

However, one thing that struck me was the sentence "...Furthermore, the clipping action occurred at the input to the filter, so that the result of the clipping was itself filtered." (section 5)

So if that is the case, why don't we just do it like the hardware?

Avatar
Admin
August 27, 2018 - 1:47 pm
Member Since: January 29, 2017
Forum Posts: 656
sp_UserOfflineSmall Offline

Yes, as long as the loop gain (and resulting loop *energy*) are within the limits, it won't go unstable and yeah the residual noise in the z^-1 registers are the likely culprit.

I actually devoted a chapter to non-linear processing in the new book with lots of choices for wave-shaper functions. There are also experimental ways to come up with a particular wave-shaper - for example, you can take an analog distortion circuit and simulate it in SPICE (or probe it for real) to get a FFT of the distortion output when a sinusoid is applied. That results in a series of harmonics that follows an envelope across the spectrum. Then, you can take a waveshaper equation and manipulate (or perturb) it until its harmonic envelope matches the analog circuit. That gives a relatively easy way to match the spectral result of the nonlinearity (of course there are other attributes as well and for tubes, this is only barely a solution as the waveshaper function is dynamic). 

As far as the hardware goes, the locations of the nonlinearities are highly dependent on the structures themselves and the "clipping occurring at the input of a filter" is not the case across all filter types. At all. 

For the Moog filter in particular, the tanh( ) wave-shaping is attempting to model the tanh( ) behavior of the BJT transistors used in the design. This quote is from the Synth Plugin book:

"The analog Moog filter is nonlinear in nature due to the way the transistor ladder differential pairs conduct current. The differential voltage and current relationship uses the tanh() function. Huovilainen [2004] proposed a nonlinear model that inserted a tanh() block in each 1st order LPF stage (which were based on a biquad structure), and another in the feedback path. Zavalishin [2012] proposed an “advanced nonlinear model” by inserting two tanh() blocks in each trapezoidal integrator, one at the input and another in the feedback path. Välimäki [2006] and Zavalishin [2012] both proposed “cheap” versions with only one tanh() block; for Välimäki it was at the input x(n) while for Zavalishin it is just inside the feedback loop as shown in Figure 7.30."

Note that Huovilainen's Moog structure included five (5!) nonlinear wave-shapers. This source came from an excellent article in: 

http://arteca.mit.edu/journal/10.1162/comj.2006.30.2.19

Also note that I chose Zavalishin's model instead of Välimäki's primarily because I thought it sounded better. 

For the Korg35, the clipper circuit is not at the input, but rather at the output (this is also in the Synth Plugin book, which also includes part of the analog schematic showing the clipping circuit which is essentially a tubescreamer diode clipper inside of the positive feedback loop).

For the Oberheim SEM filter, the nonlinear block is in the same location of the diode-based "governor" that Tom designed into it, and uses Zavalishin's placement.

So I think it is more complicated than just "clipping at the input" and when the saturator is inside of a loop, then you always have to watch out for the energy level within the loop. 

- Will

Avatar
Member
Members
August 28, 2018 - 2:54 am
Member Since: August 27, 2018
Forum Posts: 7
sp_UserOfflineSmall Offline

That paper was a good read. Thanks so much, Will.

I tried to move it around. The idea was to do the saturation before the K scale. For the moog ladder the m_fK can be factored out (since the input to dU is xn=xn+xn*m_fK), so dU can be split in two, and saturation performed on e.g. only the first part:

original code:

const float fGainCompensation = 1.0;
xn *= (float)(1.0 + fGainCompensation*m_fK);
// calculate input to first filter
double dU = (xn - m_dK*dSigma)*m_dAlpha_0;
dU = fasttanh(m_dSaturation*dU);

alternative code:
double dU2 = (xn - fSigma) * m_fAlpha_0;
dU2 = fasttanh(m_dSaturation*dU2);
double dU = (xn * m_fAlpha_0)/m_fK + dU2;
dU*=m_fK;

This does not give the same result musically, but it did give me the stability I was looking for, all the way up to K=3.99.

This will do for now. I will take a look at the k35 next. Thanks.

Avatar
Admin
August 28, 2018 - 9:42 am
Member Since: January 29, 2017
Forum Posts: 656
sp_UserOfflineSmall Offline

Hey - one thing to check for is the fasttanh( ) -- the ANSI version of tanh( ) is very fast, so you might want to see if there is any difference with it.

Also be careful with the Korg35 filter - it has a positive feedback path so anything even a hair over the loop gain limit with blow it up. 

- Will

Forum Timezone: America/New_York

Most Users Ever Online: 152

Currently Online:
7 Guest(s)

Currently Browsing this Page:
1 Guest(s)

Top Posters:

Chaes: 56

Skyler: 48

Derek: 46

Frodson: 45

Peter: 43

TheSmile: 43

clau_ste: 39

Nickolai: 39

JimmyM: 33

Gwen: 32

Member Stats:

Guest Posters: 1

Members: 738

Moderators: 1

Admins: 6

Forum Stats:

Groups: 13

Forums: 42

Topics: 815

Posts: 3146

Moderators: W Pirkle: 656