Main Archive Specials Wiki | FAQ Links Submit Forum


Another 4-pole lowpass...

Type : 4-pole LP/HP
References : Posted by fuzzpilz [AT] gmx [DOT] net

Notes :
Vaguely based on the Stilson/Smith Moog paper, but going in a rather different direction from others I've seen here.

The parameters are peak frequency and peak magnitude (g below); both are reasonably accurate for magnitudes above 1. DC gain is 1.

The filter has some undesirable properties - e.g. it's unstable for low peak freqs if implemented in single precision (haven't been able to cleanly separate it into biquads or onepoles to see if that helps), and it responds so strongly to parameter changes that it's not advisable to update the coefficients much more rarely than, say, every eight samples during sweeps, which makes it somewhat expensive.

I like the sound, however, and the accuracy is nice to have, since many filters are not very strong in that respect.

I haven't looked at the HP again for a while, but IIRC it had approximately the same good and bad sides.


Code :
double coef[9];
double d[4];
double omega; //peak freq
double g; //peak mag

// calculating coefficients:

double k,p,q,a;
double a0,a1,a2,a3,a4;

k=(4.0*g-3.0)/(g+1.0);
p=1.0-0.25*k;p*=p;

// LP:
a=1.0/(tan(0.5*omega)*(1.0+p));
p=1.0+a;
q=1.0-a;

a0=1.0/(k+p*p*p*p);
a1=4.0*(k+p*p*p*q);
a2=6.0*(k+p*p*q*q);
a3=4.0*(k+p*q*q*q);
a4= (k+q*q*q*q);
p=a0*(k+1.0);

coef[0]=p;
coef[1]=4.0*p;
coef[2]=6.0*p;
coef[3]=4.0*p;
coef[4]=p;
coef[5]=-a1*a0;
coef[6]=-a2*a0;
coef[7]=-a3*a0;
coef[8]=-a4*a0;

// or HP:
a=tan(0.5*omega)/(1.0+p);
p=a+1.0;
q=a-1.0;

a0=1.0/(p*p*p*p+k);
a1=4.0*(p*p*p*q-k);
a2=6.0*(p*p*q*q+k);
a3=4.0*(p*q*q*q-k);
a4= (q*q*q*q+k);
p=a0*(k+1.0);

coef[0]=p;
coef[1]=-4.0*p;
coef[2]=6.0*p;
coef[3]=-4.0*p;
coef[4]=p;
coef[5]=-a1*a0;
coef[6]=-a2*a0;
coef[7]=-a3*a0;
coef[8]=-a4*a0;

// per sample:

out=coef[0]*in+d[0];
d[0]=coef[1]*in+coef[5]*out+d[1];
d[1]=coef[2]*in+coef[6]*out+d[2];
d[2]=coef[3]*in+coef[7]*out+d[3];
d[3]=coef[4]*in+coef[8]*out;



Comments


Added on : 04/04/05 by Christian[ AT ]savioursofsoul[ DOT ]de
Comment :
Yet untested object pascal translation:

unit T4PoleUnit;

interface

type TFilterType=(ftLowPass, ftHighPass);
     T4Pole=class(TObject)
     private
       fGain     : Double;
       fFreq     : Double;
       fSR       : Single;
     protected
       fCoeffs     : array[0..8] of Double;
       d           : array[0..3] of Double;
       fFilterType : TFilterType;
       procedure SetGain(s:Double);
       procedure SetFrequency(s:Double);
       procedure SetFilterType(v:TFilterType);
       procedure Calc;
     public
       constructor Create;
       function Process(s:single):single;
     published
       property Gain: Double read fGain write SetGain;
       property Frequency: Double read fFreq write SetFrequency;
       property SampleRate: Single read fSR write fSR;
       property FilterType: TFilterType read fFilterType write SetFilterType;
     end;

implementation

uses math;

const kDenorm = 1.0e-25;

constructor T4Pole.Create;
begin
inherited create;
fFreq:=1000;
fSR:=44100;
Calc;
end;

procedure T4Pole.SetFrequency(s:Double);
begin
fFreq:=s;
Calc;
end;

procedure T4Pole.SetGain(s:Double);
begin
fGain:=s;
Calc;
end;

procedure T4Pole.SetFilterType(v:TFilterType);
begin
fFilterType:=v;
Calc;
end;

procedure T4Pole.Calc;
var k,p,q,b,s : Double;
    a         : array[0..4] of Double;
begin
fGain:=1;
if fFilterType=ftLowPass
  then s:=1
  else s:=-1;
// calculating coefficients:
k:=(4.0*fGain-3.0)/(fGain+1.0);
p:=1.0-0.25*k;
p:=p*p;

if fFilterType=ftLowPass
  then b:=1.0/(tan(pi*fFreq/fSR)*(1.0+p))
  else b:=tan(pi*fFreq/fSR)/(1.0+p);
p:=1.0+b;
q:=s*(1.0-b);

a[0] := 1.0/(  k+p*p*p*p);
a[1] := 4.0*(s*k+p*p*p*q);
a[2] := 6.0*(  k+p*p*q*q);
a[3] := 4.0*(s*k+p*q*q*q);
a[4] :=     (  k+q*q*q*q);
p    := a[0]*(k+1.0);

fCoeffs[0]:=p;
fCoeffs[1]:=4.0*p*s;
fCoeffs[2]:=6.0*p;
fCoeffs[3]:=4.0*p*s;
fCoeffs[4]:=p;
fCoeffs[5]:=-a[1]*a[0];
fCoeffs[6]:=-a[2]*a[0];
fCoeffs[7]:=-a[3]*a[0];
fCoeffs[8]:=-a[4]*a[0];
end;

function T4Pole.Process(s:single):single;
begin
Result:=fCoeffs[0]*s+d[0];
d[0]:=fCoeffs[1]*s+fCoeffs[5]*Result+d[1];
d[1]:=fCoeffs[2]*s+fCoeffs[6]*Result+d[2];
d[2]:=fCoeffs[3]*s+fCoeffs[7]*Result+d[3];
d[3]:=fCoeffs[4]*s+fCoeffs[8]*Result;
end;

end.              




Added on : 19/03/15 by super_peter1980[ AT ]gmx[ DOT ]de
Comment :
so bad that this filter is so unstable. i tested it and is has a really nice sound. but frequencies below 200 hz are not possible. :-(              



Add your own comment
Comments are displayed in fixed width, no HTML code allowed!
Email:

Comment:

Are you human?



Site created and maintained by Bram
Graphic design by line.out | Server sponsered by fxpansion