Login / Register  0 items | $0.00 NewWhat is KVR? Submit News Advertise
xhy3
KVRer
 
12 posts since 19 Jan, 2014

Postby xhy3; Mon Jun 12, 2017 5:34 am Aliasing suppression in filter feedback loop in a ZFD filter

Hi together

I like to suppress aliasing within a zfd filter in the feedback loop. I have found following interesting paper about the topic:

https://www.researchgate.net/publicatio ... onvolution

The solution looks promising and easy to implement. The only problem is the delay the filter kernel of this method introduces. I see fig. 9 in the paper, but i'm not sure how to implement that and had no success so far. I also want the tanh only for the feedback signal and not for the whole filter pole when possible.

Here is the filter code:
Code: Select all
m_wcD = 2.0f * fasttan(m_T * Pi * freq) * sampleRate;
float TwcD = m_T * m_wcD;
m_b0 = (TwcD / (TwcD + 2.0f));
m_a1 = ((TwcD - 2.0f) / (TwcD + 2.0f));

k = resonance * 4.0f;

oL = m_s4L + m_b0 * (m_s3L + m_b0 * (m_s2L + m_b0 * m_s1L));
const float b4 = m_b0 * m_b0 * m_b0 * m_b0;
const float divisor = 1.0f / (1.0f + b4 * k);
outputL = (b4 * inputWithoutRefL + oL) * divisor;

float clippedL = k * outputL;
antialiasedClipper.processTanh(&clippedL); // introduces delay (rect filter kernel, maybe 0.5 sample delay)
       
uL = inputWithoutRefL - clippedL;

float future1L = (m_b0 * uL + m_s1L);
m_s1L = (m_b0 * uL) - (m_a1 * future1L);

float future2L = (m_b0 * future1L + m_s2L);
m_s2L = (m_b0 * future1L) - (m_a1 * future2L);

float future3L = (m_b0 * future2L + m_s3L);
m_s3L = (m_b0 * future2L) - (m_a1 * future3L);

m_s4L = (m_b0 * future3L) - (m_a1 * outputL);


Would be great if someone can help here. Thanks!
stratum
KVRian
 
1240 posts since 29 May, 2012

Postby stratum; Tue Jun 13, 2017 4:10 am Re: Aliasing suppression in filter feedback loop in a ZFD filter

The link doesn't work
~stratum~
Miles1981
KVRian
 
1251 posts since 26 Apr, 2004, from UK

Postby Miles1981; Tue Jun 13, 2017 6:05 am Re: Aliasing suppression in filter feedback loop in a ZFD filter

stratum wrote:The link doesn't work

It works in my browser.
xhy3
KVRer
 
12 posts since 19 Jan, 2014

Postby xhy3; Sun Jul 02, 2017 4:36 am Re: Aliasing suppression in filter feedback loop in a ZFD filter

Sorry for the slow progress. I don't have much time for this at the moment...

For simplifying things i take the zdf filter posted by mystran (viewtopic.php?t=368466) without the non linearities:
Code: Select all
        float input = *inputL;
        if (cutoff > 1.0f) cutoff = 1.0f;
        if (cutoff < 0.0f) cutoff = 0.0f;
        float f = tan(M_PI * cutoff * 0.5f);
        float r = 4 * resonance;
       
        float g = 1 / (1 + f);
        float f3 = f*g, f2 = f*g*f3, f1 = f*g*f2, f0 = f*g*f1;

        float y3 = (g*s[3] + f3*g*s[2] + f2*g*s[1] + f1*g*s[0] + f0*input) / (1 + r*f0);
       
        float xx = input - r*y3;
        float y0 = g*(s[0] + f*xx);
        float y1 = g*(s[1] + f*y0);
        float y2 = g*(s[2] + f*y1);
       
        s[0] += 2*f * (xx - y0);
        s[1] += 2*f * (y0 - y1);
        s[2] += 2*f * (y1 - y2);
        s[3] += 2*f * (y2 - y3);


The paper says we can fold the antialiased non-linearity into the first pole. I get this when i do that:
Code: Select all
        float y0 = g*(log(cosh(f*(in - r*y3))) - log(cosh(s[0])))/(f*(in - r*y3) - s[0]) * 2;
        float y1 = g*(s[1] + f*y0);
        float y2 = g*(s[2] + f*y1);


The problem is that maxima shows no result for this when i try to solve it for y3.
Looks like there is no solution. Any input is welcome. I keep trying to make it work...

After that i also have to take a look into the x = x-1 case.

edit:
I can solve the equation when i move the y3 outside of the nonlinearity, but the filter resonance is unstable this way and it does not help much, because i need especially the feedback part to limit.
Code: Select all
float y0 = g*2*((log(cosh(f*input)) - log(cosh(s[1])))/(f*input - s[1]) - f*k*y3);


Not sure if i also have to modify the integrator part:

Code: Select all
        s[0] += 2*f * ((input - k*y3) - y0);
xhy3
KVRer
 
12 posts since 19 Jan, 2014

Postby xhy3; Mon Jul 03, 2017 11:47 pm Re: Aliasing suppression in filter feedback loop in a ZFD filter

I can't find any solution. Anyone an idea how to fold the antialising filter into the first filter pole and eliminate the delay?

Edit: Anyone already used a Jacobian matrix to solve non linear equations?
User avatar
Smashed Transistors
KVRist
 
100 posts since 10 Oct, 2014

Postby Smashed Transistors; Tue Jul 04, 2017 1:59 pm Re: Aliasing suppression in filter feedback loop in a ZFD filter

Maybe you can use some step invariant transform for the linear "ZDF" part and combine it with DPW (also known as 'antiderivative anti aliasing' or 'pre-integrated wavetables'). The maths should be fun to play with :wink:
See you here and there... Youtube, Google Play, SoundCloud...
xhy3
KVRer
 
12 posts since 19 Jan, 2014

Postby xhy3; Wed Jul 05, 2017 12:06 am Re: Aliasing suppression in filter feedback loop in a ZFD filter

Smashed Transistors wrote:Maybe you can use some step invariant transform for the linear "ZDF" part and combine it with DPW (also known as 'antiderivative anti aliasing' or 'pre-integrated wavetables'). The maths should be fun to play with :wink:

Interesting idea. This could work. I also think i should consider other solutions like the one you mentioned. BLAMPs maybe work too.
User avatar
Smashed Transistors
KVRist
 
100 posts since 10 Oct, 2014

Postby Smashed Transistors; Fri Jul 07, 2017 2:17 am Re: Aliasing suppression in filter feedback loop in a ZFD filter

Another idea that can limit distorsion induced by aliasing is to consider the non linearity as a non linear gain/integration factor.

I have combined it to the step invariant method in a 2 pole SVF filter JSFX plugin (for Reaper) :

post:
https://forum.cockos.com/showpost.php?s ... stcount=18

jsfx thread:
https://forum.cockos.com/showthread.php?t=166480

and it sounded nice to my ears.
See you here and there... Youtube, Google Play, SoundCloud...
xhy3
KVRer
 
12 posts since 19 Jan, 2014

Postby xhy3; Sat Jul 08, 2017 1:23 am Re: Aliasing suppression in filter feedback loop in a ZFD filter

Thanks for helping. I will have a look at the step invariant method. Looks interesting.
In the meantime i have used mystran's idea for folding in the nonlinearities and it seems to work well. It's not perfect, because i do nothing about he 0.5 sample delay of the antiderivate, but it's still stable and does a good job in antialiasing.

You maybe have to correct the instabilities the filter has with full resonance at higher frequencies and i would use it with 2x oversampling.

Code: Select all
        // tuning and feedback
        float input = *inputL;
        float f = tan(M_PI * cutoff * 0.5f);
        float r = 5.5 * resonance;
       
        // delay input
        float ih = 0.5 * (input + z); z = input;
        float ihf = ih - r * s[3];
       
        float s0 = s[0];
        float t0 = antialiasedClipper.processTanh(ihf, s0);

       // tanh(x) / x
        t0 /= 0.5 * (ihf + s0);
       
        // g# the denominators for solutions of individual stages
        float g = 1 / (1 + f);
       
        // f# are just factored out of the feedback solution
        float f3 = f*g, f2 = f*g*f3, f1 = f*g*f2, f0 = t0*f*g*f1;
       
        // solve feedback
        float y3 = (g*s[3] + f3*g*s[2] + f2*g*s[1] + f1*g*s[0] + f0*input) / (1 + r*f0);
       
        // then solve the remaining outputs (with the non-linear gains here)
        float xx = t0*(input - (r*y3));
        float y0 = g*(s[0] + f*xx);
        float y1 = g*(s[1] + f*y0);
        float y2 = g*(s[2] + f*y1);
       
        // update state
        s[0] += 2*f * (xx - y0);
        s[1] += 2*f * (y0 - y1);
        s[2] += 2*f * (y1 - y2);
        s[3] += 2*f * (y2 - y3);
       
        *inputL = y3;


Code: Select all
    float processTanh(float x, float x1)
    {
        if (fabs(x - x1) > 0.0000001f)
        {
            return (calcAntiderivate(x) - calcAntiderivate(x1)) / (x - x1);
        }
        else
        {
            return calcAntiderivateSmallValue(x, x1);
        }
    }

    float calcAntiderivate(float x)
    {
        return log(cosh(x));
    }
   
    float calcAntiderivateSmallValue(float x, float z1)
    {
        // not sure if that's correct
        return (x + z1) / 2 + ((x - z1) * (x - z1));
    }

Moderator: Moderators (Main)

Return to DSP and Plug-in Development