different structures for linear time-varying filters

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

Post

one of the filter-designs, which i use in my synth, consists of a cascade of biquad filters where the coefficients come from the cookbook-equations by RBJ. so far, i had implemented each biquad-stage as direct-form 1 and everything was fine. today i converted the structure into direct-form 2 (hoping for some (slight) efficiency improvement) and noticed strange clicks on note-ons. after experimenting a little bit, i found that this seems to be related to the filter envelope settings. it seems that these clicks occur, when the filter is rapidly time-varying. after the filter envenlope has settled to its sustain value (or when the envelope is set to neutral settings such that the filter is time-invariant) both structures sound apparently the same - as expected. did anyone here make similar experiences, or is it known that Direct-Form 1 is better suited for time-varying filters than Direct-Form 2? or should i suspect a bug somewhere in the filter-code? my per-sample functions for both filter-structures look like this:

Code: Select all

INLINE double CookbookFilter::getSample(double in)
{
 static doubleA tmp, tmp2;
 static intA    i;  // for the loop through the stages

 tmp = in;

 // calculate current output-sample (y[n]) of all the BiQuad-stages
 // (the output of one stage is the input for the next stage):
 for (i=0; i<numStages; i++)  
 {
  tmp2 = tmp; //for x_1[i]

  // calculate current output-sample (y[n]) of BiQuad-stage i:
  tmp = b0*(tmp) + b1*x1[i] + b2*x2[i]
                 - a1*y1[i] - a2*y2[i];

  // set x[n-1], x[n-2], y[n-1] and y[n-2] for the next call:
  x2[i] = x1[i];
  x1[i] = tmp2;
  y2[i] = y1[i];
  y1[i] = tmp;  
 }

 return tmp;
}

INLINE double CookbookFilter::getSample2(double in)
{
 static doubleA x, y, g;
 static intA    i;  //for the loop through the stages

 x = in;

 // calculate current output-sample (y[n]) of all the BiQuad-stages
 // (the output of one stage is the input for the next stage):
 for (i=0; i<numStages; i++)  
 {
  // calculate intermediate signal g[n] and output-signal y[n] of
  // BiQuad-stage i:
  g = x - a1*g1[i] - a2*g2[i];
  y = b0*g + b1*g1[i] + b2*g2[i];

  // set g[n-1], g[n-2] for the next call:
  g2[i] = g1[i];
  g1[i] = g;

  x = y; // output of one stage is input to the next
 }

 return y;
}
where (FYI):

Code: Select all

#define INLINE __forceinline

typedef __declspec( align(8) ) double doubleA; // doubles, aligned at 64-bit
                                               // (8 byte) boundaries

typedef __declspec( align(8) ) int intA; // integers, aligned at 64-bit
                                         // (8 byte) boundaries
Last edited by Music Engineer on Tue Jan 09, 2007 8:35 pm, edited 2 times in total.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

When the filter is being modulated are you interpolating the coefficients or calculating them on a per-sample basis? If interpolating it may be that the intermediate coefficients are unstable, and as your using direct form 2 with the feedback stage first it's more susceptable to going out of control.

Sam

Post

no interpolation. i "design" the filter per sample.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

sambean wrote:When the filter is being modulated are you interpolating the coefficients or calculating them on a per-sample basis? If interpolating it may be that the intermediate coefficients are unstable, and as your using direct form 2 with the feedback stage first it's more susceptable to going out of control.

Sam
Right. From what I've read, it's not uncommon for engineers to linearly interpolate the coefficients. Be careful the zeros (or is it the poles, I forget) can slide outside the circle when you do this.
braindoc wrote:no interpolation. i "design" the filter per sample.
Then I have no idea what it is. Glad you're listening for clicks, though. :-)

Post

mistertoast wrote: From what I've read, it's not uncommon for engineers to linearly interpolate the coefficients. Be careful the zeros (or is it the poles, I forget) can slide outside the circle when you do this.
the poles. yeah - not uncommon to interpolate coeffs, indeed. one of the compromises i do not want to make.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

braindoc wrote:
mistertoast wrote: From what I've read, it's not uncommon for engineers to linearly interpolate the coefficients. Be careful the zeros (or is it the poles, I forget) can slide outside the circle when you do this.
the poles. yeah - not uncommon to interpolate coeffs, indeed. one of the compromises i do not want to make.
I admire your dedication. Uncompromising attitude makes for a better synth.

Post

braindoc wrote:no interpolation. i "design" the filter per sample.
and therein lies the problem.

You're showing us the standard biquad filter stages, which are implemented correctly, but in this case the coefficient calculation is very likely the culprit.

just how exactly do you "design" the coefficients? Obviously too drastic changes there result to clicks, no matter if it's even oversampled coefficient calculation.

for example, even basic linear parameter smoothing (if done too fast) directly on the biquad coefficients can amount to nasty surprises, when the poles and zeroes are momentarily flying out of the circle by accident.

clicks on note on also suggests a problems with feedback. maybe it still hears the ending of the previous process. reset feedback on note on?

Post

Is the effect stronger for larger Q? Does it occur only when sweeping fast one direction, while the other direction is fine?

Is it possible that your redesign affects the energy stored in the system such that a fast enough sweep will "create" enough energy that the filter will ring during the sweep?

edit: oh and ... isn't it a bit pointless to use direct form if a redesign is forced on every sample?

Post

Kingston wrote: You're showing us the standard biquad filter stages, which are implemented correctly, but in this case the coefficient calculation is very likely the culprit.

just how exactly do you "design" the coefficients? Obviously too drastic changes there result to clicks, no matter if it's even oversampled coefficient calculation.
i calculate the coeffs via the cookbook-equations just before calling the getSample()-functions. and yes - very fast cutoff-changes can obviously cause some kind of clicks, just like (nearly) instantaneous changes of amplitude do - but those clicks, i'm talking about seem not to be of that kind. and i think it is unlikely that the coefficient-calculation is the problem, because i use exactly the same coefficient calculation for both structures. and one structure clicks, the other one doesn't.
Kingston wrote: for example, even basic linear parameter smoothing (if done too fast) directly on the biquad coefficients can amount to nasty surprises, when the poles and zeroes are momentarily flying out of the circle by accident.
but i don't do such a thing. coeffs are exact (up to double-precision roundoff) at every sample.
Kingston wrote: clicks on note on also suggests a problems with feedback. maybe it still hears the ending of the previous process. reset feedback on note on?
was my first suspect, too. but in the function which resets my y1, y2, x1, x2 variables to zero, i reset my g1, g2 to zero as well. mmmhhh
mystran wrote: Is the effect stronger for larger Q? Does it occur only when sweeping fast one direction, while the other direction is fine?

q changes the sound of the clicks (just as it would do if the input was a click) but doesn't seem to make them stronger - at least, not more than it would to in the case of a click-like input. further investigation suggests, that the clicks occur mainly for a (nearly) instantaneous upward-jump in cutoff-frequency.
mystran wrote: Is it possible that your redesign affects the energy stored in the system such that a fast enough sweep will "create" enough energy that the filter will ring during the sweep?

don't know. is it? can coefficient adaption "create" energy? ...edit: and - more importantly - will the amount of created energy be different for different implementation structures?
mystran wrote: edit: oh and ... isn't it a bit pointless to use direct form if a redesign is forced on every sample?

erm, probably yes. the reason why i turned my attention to an alternative (potentially more efficient) implementation-structure was mainly because i use similar biquad-cascades for various other purposes as well, where they are eihter time-invariant (as anti-aliasing filters for example) or varying only on user intervention (in an equalizer-plugIn)
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

Ok, first of all the word "energy" should be in quotes, I guess, since energy really only exists in physical structures.

But basicly, the point is, there is some values stored in the delays of the filter, and for a filter modelled after a physical system, this can sometimes be taken (directly or indirectly) as the energy stored in the physical counterpart.

In any case, the point is, depending on the filter structure, changing the coefficients can change the meaning of the stored values, and if this is done without modifying the values to match, it effectively changes the stored state of the system in a way which corresponds to adding or removing energy to the physical counterpart (and possibly other things).

I'm far too tired to figure out how various direct form filters react. I remember at least some of them causing trouble. And even if they didn't, most musically interesting stuff starts where LTI assumption fails, and I believe the main reason for different musical character of different (linear) filters is precisely in their different transient response when modulated.

SVF and Moog at least are well known for their nice behavior, although care should be taken with the digitization used, 'cos this can have effect not only on the frequency response of the LTI case, but also on the transient response (at least one "moog" type filter in musicdsp reacts pretty wildly to fast downward modulations). It's ofcourse possible to design other filters that behave in reasonable ways.

I don't feel like going more into the details, 'cos it hits really nasty stuff (and math) really fast, I'm really tired, and I don't have a grand unified theory yet (I bet probably nobody has).

Post

So...you're going to sleep instead of come up with a GUT?

Disappointing.

Post

did some simulations in matlab and found that the different structures (DF1 and DF2) indeed react completely different to abrupt cutoff-frequency changes. will check out the transposed forms next (TDF1 and TDF2)...what other structures are there, worth to try? lattice? SVF? how do their coefficients relate to the direct-form coeffs?...well...i guess, have to do some research...any helpful links?
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post

you could convert your filter to a lattice structure also known as kelly-lockbaum.

linearly-interpolating the lattice reflexion coefficients between 2 stable coefficient sets is always stable.

Post

O.K. after studying some books and papers and doing some experimentation, i found that the implementation structure has indeed a strong impact on the response of the filter to parameter/coefficient changes. in my experiments, i found, that the DF1 is prone to cause pops when the cutoff-frequency makes a downward-jump, and DF2 is prone to cause pops at upward-jumps of the cutoff-frequency. this is true for all the cookbook filter-types (LPF, HPF, BPF, Peak, Low-Shelf, High-Shelf, Allpass) - so i'd say, it's the direction of change of the pole-angle what matters. it seems to be a well known phenomenom (AES has several papers about that) - however it was new to me. the problem is related to the question how different the magnitudes of the internal state-variables in the filter are for different settings. In the four-multiply-normalized-ladder structure they have always the same variance regardless of the particular filter setting (under the assumption of white-noise input). this makes the normalized ladder topology particularly attractive for the implementation of time-varying filters. the plots below show the behaviour of DF1, DF2 and NLF under some instantaneous changes of the cutoff-frequency for white noise input and a sinosoid at a quite low frequency (i think it was 100 Hz). the plot became a bit messed up in the png-export, but i think they are still recognizable:

Image

Image

mmhh...for low-freqeuncy sinosoids, the DF1 seems to be superior ....but my experiments should by no means be seen as being in any way representative

ironically, i was initially looking at the topologies, because DF2 is more efficient, and now i arrived at an even more demanding topology (namely the NLF) - at least for the time varying filter in my synth.
My website: rs-met.com, My presences on: YouTube, GitHub, Facebook

Post Reply

Return to “DSP and Plugin Development”