SynthMaker

filter design - code problem

Archive · 2011 26 old posts

From the original SynthMaker forum (2004–2014), with its members’ names and dates.

firmament ·

Im trying to implement the legendre (optimum) filter described here.

the coefficient formulae come from a z-transform of the transfer function and seem to be correct (well at least theyre returning realistic numbers 😉 )

the problem seems to be coming from the actual filter itself - it jumps directly to infinity when the feedback is introduced

streamin in; streamout out; streamin k; float k2, k3;

float z0,z1,z2,z3; float a0,a1,a2,a3; float b0,b1,b2,b3;

float c0P5=0.57735;float c1P31=1.3107; float c1P35=1.35897;float c1P7=1.73205;

//precalc k2=k*k; k3=k2*k;

//calculate coefficients a0=c0P5*k3; a1=c1P7*k3; a2=c1P7*k3; a3=c0P5*k3;

b0=c0P5*k3 + c1P35*k2 + c1P31*k + 1; b1=c1P7*k3 + c1P35*k2 - c1P31*k - 3; b2=c1P7*k3 - c1P35*k2 - c1P31*k + 3; b3=c0P5*k3 + c1P35*k2 + c1P31*k - 1;

//filter z0 = in + b1*z1 - b2*z2 - b3*z3; out= a0*z0 + a1*z1 + a2*z2 + a3*z3;

z3=z2; z2=z1; z1=z0;

MegaHurtz ·

invert the feedback?

firmament ·

MegaHurtz wrote: invert the feedback?

more specific ? i did try some switching of signs but didnt get anywhere

im starting to think it may be the coefficients, i tried it with arbitrary numbers (all 1s, all 0.5s etc) and the filter itself seems to be fine . .

MegaHurtz ·

Problem is I can recognise filters by sound,create and calculate them digitally and analog.. but i never related to filters in butterworth polynominals. To me an "optimal filter" is a LR4.

cyto ·

firmament wrote: //filter z0 = in + b1*z1 - b2*z2 - b3*z3; out= a0*z0 + a1*z1 + a2*z2 + a3*z3;

I don't have time to look at the math right now, but I can tell you just from a quick glance that your transfer function is still in the frequency domain. It needs to be transformed into the time domain to work correctly.

-cyto

ps. if you leave your "c" values rounded to such high numbers (x.xxxx), I can almost guarantee that if you do get this thing working, it will be very unstable. Use all the bits you can!

tor ·

have a look at the two pole example here: https://ccrma.stanford.edu/~jos/fp/Direct_Form_II.html if it is not compensated somewhere else in the coef calculations i guess the "in + b1*" should read "in - b1*" i know some times people switch their a and b's in biquads. i have not yet read the paper you refered to so i cant tell atm in your case.

this is how i would write a DF2 filter:

wn = in - wn1*a1 - wn2*a2 - wn3*a3; out = wn*b0 + wn1*b1 + wn2*b2 + wn3*b3; wn3 = wn2; wn2 = wn1; wn1 = wn;

kaj ·

Hello, I have scilab's s-z transform calculator, which transforms the H(s) to H(z)

8.414e-16 + 2.524e-15*z^-1 + 2.524e-15*z^-2 + 8.414e-16*z^-3 ---------------------------------------------------------------------------------------- 1 - 2.9999703*z^-1 + 2.9999406*z^-2 - 0.9999703*z^-3

where T (sample time) = 1/44100.

so,

streamin in; streamout out;

float x0, x1, x2, x3; float y0, y1, y2, y3;

x0 = in; y0 = 2.9999703*y1 - 2.9999406*y2 + 0.9999703*y3 + 8.414e-16*x0 + 2.524e-15*x1 + 2.524e-15*x2 + 8.414e-16*x3; y3 = y2; y2 = y1; y1 = y0; x3 = x2; x2 = x1; x1 = x0; out = y0;

I think that the problem is maybe that SM's code component does not provide the type of DOUBLE float...

infuzion ·

kaj wrote: I think that the problem is maybe that SM's code component does not provide the type of DOUBLE float...

Did you say you were going to vote on this thread?

+ SSE2=64bit audio, SSE3=faster FFT... please

firmament ·

thanks for the help guys!

MegaHurtz wrote: Problem is I can recognise filters by sound,create and calculate them digitally and analog.. but i never related to filters in butterworth polynominals. To me an "optimal filter" is a LR4.

this uses legendre polynomials rather than butterworth ones. theres already code around for l-r filters.

cyto wrote: I don't have time to look at the math right now, but I can tell you just from a quick glance that your transfer function is still in the frequency domain. It needs to be transformed into the time domain to work correctly.

the z values are delays, its configured like this

except with another delay in. pretty sure ive translated it to time domain - mathematically i took the H(s) transfer function and use thed bilinear transform to get discrete time H(z). i read this could be used directly for filter coefficients? or do i need a laplace transform for impulse response or something

cyto wrote: ps. if you leave your "c" values rounded to such high numbers (x.xxxx), I can almost guarantee that if you do get this thing working, it will be very unstable. Use all the bits you can!

thanks haha ive fixed this. ive also corrected one of the signs in my calculations for the b coefficients (interestingly they show some sort of symmetry) and the filter corner is now at the frequency i set. the response also looks about right - however its upside down / rotated somehow . . any ideas?

firmament ·

tor wrote: have a look at the two pole example here: https://ccrma.stanford.edu/~jos/fp/Direct_Form_II.html if it is not compensated somewhere else in the coef calculations i guess the "in + b1*" should read "in - b1*" i know some times people switch their a and b's in biquads. i have not yet read the paper you refered to so i cant tell atm in your case.

this is how i would write a DF2 filter:

wn = in - wn1*a1 - wn2*a2 - wn3*a3; out = wn*b0 + wn1*b1 + wn2*b2 + wn3*b3; wn3 = wn2; wn2 = wn1; wn1 = wn;

thanks, ive changed the "in + a1" to a - and my code matches up with yours. the link is useful as well, this stuff is making more and more sense!

kaj wrote: Hello, I have scilab's s-z transform calculator, which transforms the H(s) to H(z)

8.414e-16 + 2.524e-15*z^-1 + 2.524e-15*z^-2 + 8.414e-16*z^-3 ---------------------------------------------------------------------------------------- 1 - 2.9999703*z^-1 + 2.9999406*z^-2 - 0.9999703*z^-3

where T (sample time) = 1/44100.

no idea whether this is right or not but id say its fixed cutoff and samplerate so i cant do much with it . . what cutoff frequency did you give it? i could check whether my coeffs are giving the same results . .

kaj wrote: so,

streamin in; streamout out;

float x0, x1, x2, x3; float y0, y1, y2, y3;

x0 = in; y0 = 2.9999703*y1 - 2.9999406*y2 + 0.9999703*y3 + 8.414e-16*x0 + 2.524e-15*x1 + 2.524e-15*x2 + 8.414e-16*x3; y3 = y2; y2 = y1; y1 = y0; x3 = x2; x2 = x1; x1 = x0; out = y0;

I think that the problem is maybe that SM's code component does not provide the type of DOUBLE float...

yeah this isnt working, sm cant seem to handle the 8.414e-16 numbers.

wait isnt there a double primitive in the toolbox? does that get full 64bit precision?

kaj ·

to firmament

Let me know the transfer function H(s) that you used.

MegaHurtz ·

1/C*F*PI2

So.. its getting integrated at the plus signs?

tor ·

firmament wrote: wait isnt there a double primitive in the toolbox? does that get full 64bit precision?

you can do plus minus and multiplication in 64 bit but you can only feed them with 32 bit values. i designed a biquad that takes advantage of this. you find it in the RBJ ported thread. though it is not truly 64bit in the whole filter due to the delay part of the scematic in 32 bit, the multiplications of the feedbacked signals results in more presicion in the bass and less rounding noise in general. problem is when you want to any thing but plus, minus & multiplication you have to use the stream2double and double2stream prims. i do belive this is not so cpu friendly and it prevent you for having a end to end 64bit design 🙁

tor ·

i made a quick 3-pole version for you to test. I have not tested it myself. But im pretty sure it should work right. Now you should also do the precalculations and coeffisient calculations in double to get even bettet results. At the cost of some more cpu of cource.

If you do coef maths in double you must delete the stream2double prims for the coefs in my scematic. but i guess you would understand that 😀

firmament ·

kaj wrote: Let me know the transfer function H(s) that you used.

see what the calculator comes up with 😉

MegaHurtz wrote: 1/C*F*PI2

So.. its getting integrated at the plus signs?

sorry not really sure what you mean here ? i have a similar part in the schematic [ tan(pi*f/sr) ] to calculate the k coefficient in the code, its to do with making the frequency setting samplerate independent

tor wrote: you can do plus minus and multiplication in 64 bit but you can only feed them with 32 bit values. i designed a biquad that takes advantage of this. you find it in the RBJ ported thread. though it is not truly 64bit in the whole filter due to the delay part of the scematic in 32 bit, the multiplications of the feedbacked signals results in more presicion in the bass and less rounding noise in general. problem is when you want to any thing but plus, minus & multiplication you have to use the stream2double and double2stream prims. i do belive this is not so cpu friendly and it prevent you for having a end to end 64bit design 🙁

I'll try and find the ported rbj thread as the example you gave me isnt loading. the 64bit stuff seems . . useless? if you can only feed it 32 bit values then round them back off to 32 bit at the end . .

kaj ·

Hello. *************************** prewarped freq = 2/T*tan(2*pi*freq*T/2), where T is sample time. *************************** when cutoff freq = 5000 and T= 1/44100, then prewarped freq = 32815.591 (which is the actual input value)

H(z) =

0.0174349 + 0.0523047z^-1 + 0.0523047z^-2 + 0.0174349z^-3 ----------------------------------------------------------------------------------------- 1 - 1.8823263z^-1 + 1.4150742z^-2 - 0.3932688z^-3

MegaHurtz ·

I ment that the z transform would be differentiating, given that multiplying a differentiated result would create a filter. And multiplying an integrated signal would create gain. So i wasnt able to see where it would get integrated again. Wich would be needed somewhere..

kaj ·

I generalized the filter. Maybe It's OK.

streamin in; streamin wo; streamout out; float x0, x1, x2, x3; float y0, y1, y2, y3; float a, b, c, d, e, f, g, r; float w, ww, www;

w = 2*44100 * tan1(0.5*wo/44100); // prewarping the digital freq ww = w * w; www = ww * w;

r = (99316848847*www+20618754192943200*ww+1753981684186662000000*w+118029161812506173712000000); a = (297950546541*www+20618754192943200*ww-1753981684186662000000*w-354087485437518521136000000); b = (297950546541*www-20618754192943200*ww-1753981684186662000000*w+354087485437518521136000000); c = (99316848847*www-20618754192943200*ww+1753981684186662000000*w-118029161812506173712000000); a = a/r; b = b/r; c = c/r; d = 99316848847*www/r; e = 297950546541*www/r; f = 297950546541*www/r; g = 99316848847*www/r;

x0 = in; y0 = -1*a*y1 - b*y2 - c*y3 + d*x0 + e*x1 + f*x2 + g*x3; y3 = y2; y2 = y1; y1 = y0; x3 = x2; x2 = x1; x1 = x0; out = y0;

tor ·

firmament wrote: I'll try and find the ported rbj thread as the example you gave me isnt loading. the 64bit stuff seems . . useless? if you can only feed it 32 bit values then round them back off to 32 bit at the end . .

ok? lets just say that numbers with one decimal represent 32 bit and two decimal represent 64 bit in 64 bit with conversion after calculations: 1.2*1.2+1.2*1.2=1.44+1.44=2.88≃2.9 (0.02 in diff) in 32 bit with no conversion: 1.2*1.2+1.2*1.2=1.4+1.4=2.8 (0.08 in diff)

as you can see there is a huge difference and in a feedback structure theese errors build up quickly 😉

firmament ·

I've done a few ports of kaj's code to get them working in synthmaker. however because of precision issues, they arent accurate below ~300hz and break down completely sub-50

the explicit one is the full unoptimised code. asm optimised, it uses >20 cycles. the 64bit version is more accurate (thanks for the tip tor) but the difference isn't very significant

MegaHurtz ·

It ougta be 64 bits when it runs 64 bits 😉

tor ·

You are very welcome 🙂

Measurements I have done with the 2-pole biquads in VST Plugin Analyser shows a difference in prox -50dB for the noise floor. And in the bass area the altered frequencies sounds more clean and clear. But I totally agree that it should be possible to do all of the calculations in 64 bit. The speed of the digital revolution makes me think we soon will see plugs prosessing at 128 bit 😉

But they are probably not going to be created in SM

infuzion ·

firmament wrote: asm optimised, it uses >20 cycles.

3p Opt-L ASM2 is missing links from the green to the ASM. I assume connect in the order of the last math item?

firmament ·

infuzion wrote: firmament wrote: asm optimised, it uses >20 cycles.

3p Opt-L ASM2 is missing links from the green to the ASM. I assume connect in the order of the last math item?

yeah, theyre arranged so the column of multiplies on the far right of the green mess are in the same descending order as the coefficient inputs of the asm.

In case anyone was dying to know, the filter is the "optimum" midpoint between chebyshev and butterworth, giving the steepest cutoff possible without ripple

MegaHurtz ·

^^ Also getting a bit steeper as it drops into infinity.

firmament ·

tor wrote: ok? lets just say that numbers with one decimal represent 32 bit and two decimal represent 64 bit in 64 bit with conversion after calculations: 1.2*1.2+1.2*1.2=1.44+1.44=2.88≃2.9 (0.02 in diff) in 32 bit with no conversion: 1.2*1.2+1.2*1.2=1.4+1.4=2.8 (0.08 in diff)

as you can see there is a huge difference and in a feedback structure theese errors build up quickly 😉

haha should have thought it through before I posted really 😉 and i see how 128 bit could be useful.. not sure how to get this filter to work otherwise.

attached is a minor fix, the green stuff was missing quite a bit in the asm version so ive cleared that up

Wrote something here? To have a post removed or your name hidden, write to [email protected].

Before your first post

A few rules keep this a friendly place. You agree to them once.

Shown next to what you post, here and in the app. It doesn’t have to be your real name: 3–24 lower-case letters, digits or _ (capitals become lower case, spaces become _).

    Then your post goes up straight away.

    Delete this reply?

    Open it in SynthMaker?

    It goes on the track you’re editing there, in place of that track’s sound, and into My sounds. Your other tracks stay as they are.

    Want to keep that track’s sound? Start a new song in SynthMaker first (Song › New song), then open this.

    Report this reply?

    Only the developer reads reports. The person isn’t told who reported them.

    What’s wrong with it?

    Block this person?

    You won’t see their posts and replies here any more. They aren’t told, and you can unblock them at any time.

    People you’ve blocked

    Their posts and replies are hidden from you. Unblock someone to see them again.

    The community rules

    A few rules keep this a friendly place. Everyone agrees to them once, before their first post.