/* Analog active filter calculator
Copyright (C) 2008 by Dale Heatherington (coded July 27 2008)
Based on formulas and tables in Electronic Filter Design Handbook by Arthur B. Williams




    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.


*/


/* 2 pole LOWPASS  
   Input  R = resistors in K Ohms    Fc = 3 dB cutoff freq in Hz
*/
/*------------------------------------------------------------*/
function lowpass2(dataform,R,Fc,type)
{
var C1;
var C2;
var fsf = 2 * Math.PI * Fc * R * 1000;

if(type == "butter"){
C1 = 1.414 / fsf;
C2 = .7071 / fsf; 
}

if(type == "cheby"){
C1 = 1.638 / fsf;
C2 = 0.6955 / fsf;
}

if(type == "bessel"){
C1 = 0.9066 / fsf;
C2 = 0.68 / fsf;
}

dataform.resistors.value = R;
dataform.C1.value = C1 * 1E6;
dataform.C2.value = C2 * 1E6;
}

/*-----------------------------------------------------------------*/

/* 3 pole  lowpass  
   Input  R = resistors in K Ohms    Fc = 3 dB cutoff freq in Hz  
   */

function lowpass3(dataform,R,Fc,type)
{
var C1;
var C2;
var C3;
var fsf = 2 * Math.PI * Fc * R * 1000;

if(type == "butter"){
C1 = 3.546 / fsf;
C2 = 1.392 / fsf;
C3 = 0.2024 / fsf; 
}

if(type == "cheby"){
C1 = 6.653 / fsf;
C2 = 1.825 / fsf;
C3 = 0.1345 / fsf;
}

if(type == "bessel"){
C1 = 1.423 / fsf;
C2 = 0.988 / fsf;
C3 = 0.2538 / fsf;
}

dataform.resistors.value = R;
dataform.C1.value = C1 * 1E6;
dataform.C2.value = C2 * 1E6;
dataform.C3.value = C3 * 1E6;
}
/*-----------------------------------------------------------------*/

/* 2 pole high pass 
   Input C = Caps in uF,   Fc = cutoff freq in hz  
*/

function highpass2(dataform,C,Fc,type)
{

var R1;
var R2;

fsf = 1 / (2 * Math.PI * Fc * C * 1E-6 )

if (type == "butter"){
R1 = fsf / 1.414;
R2 = fsf / 0.7071;
}

if(type == "cheby"){
R1 = fsf / 1.638 ;
R2 = fsf / 0.6955;
}

if (type == "bessel"){
R1 = fsf / 0.9066;
R2 = fsf / 0.68;
}



dataform.caps.value = C;
dataform.R1.value = R1 / 1000;
dataform.R2.value = R2 / 1000;


}

/*---------------------------------------------------------------*/

function highpass3(dataform,C,Fc,type)
{

var R1;
var R2;
var R3;
fsf = 1 / (2 * Math.PI * Fc * C * 1E-6 )

if (type == "butter"){
R1 = fsf / 3.546;
R2 = fsf / 1.392;
R3 = fsf / 0.2024
}

if(type == "cheby"){
R1 = fsf / 6.653 ;
R2 = fsf / 1.825;
R3 = fsf / 0.1345
}

if (type == "bessel"){
R1 = fsf / 1.423;
R2 = fsf / 0.988;
R3 = fsf / 0.2538
}



dataform.caps.value = C;
dataform.R1.value = R1 / 1000;
dataform.R2.value = R2 / 1000;
dataform.R3.value = R3 / 1000;

}

/*------------------------------------------------------------------*/
function cuberoot(N){
var T=0;
if (N < 0) {N=-N; T=1;};
var M = Math.sqrt (N);
var ctr = 1
while (ctr < 101) {
var M = M*N;
var M = Math.sqrt (Math.sqrt(M));
ctr++;
}
return M;
}

/*----------------------------------------------------------------------*/



/* Multiple-feedback bandpass filter design */


/* Page 5-38 filter design handbook*/
var C,D,E,G,Q,M,W,Fra,Frb,a0,Qr;

function computeParms(type,Fc,bw,poles){
var a,b;

var Qbp = Fc / bw ;

if(type == "butter"){  /* Pole locations from tables */
if(poles == 4){
	a = 0.7071;
	b = 0.7071;
	}
 if(poles == 6){
	a = 0.5;
	b = 0.866;
	a0 = 1.0;
	}
}

if(type == "cheby"){
if(poles == 4){
	a = 0.6104;
	b = 0.7106;
	}
if(poles == 6){
	a = 0.349;
	b = 0.8684;
	a0 = 0.6979;
	}

}

if( type == "bessel"){
if(poles == 4){
	a = 1.103;
	b = 0.6368;
	}
if(poles == 6){
	a = 1.0509;
	b = 1.0025;
	a0 = 1.327;
	}
}

/* A bunch of formulas from filter handbook */

C = (a*a)+(b*b);
D = (2*a) / Qbp;
E = (C / (Qbp*Qbp)) + 4;
G = Math.sqrt((E*E)-(4*D*D));
Q = Math.sqrt((E+G)/(2*D*D));
M = (a*Q)/Qbp;
W = M + Math.sqrt((M*M)-1);
Fra = Fc / W;  //Section 1 frequency
Frb = W*Fc;    //section 2 frequency

if(poles == 6){
	Qr = Qbp / a0 ;  //Real pole Q  (Section 3)
	}


}

/* Page 5-44 in filter handbook */
function bandpass(dataform,C,Fc,bw,g,type,poles){

var R1,R2,R3,R4,R5,R6,Ar,gs;

computeParms(type,Fc,bw,poles);  //Do a bunch of grungy math stuff

//Split gain up between all sections
 if(poles == 4) gs = Math.sqrt(g);  //Section gain
 if(poles == 6) gs = cuberoot(g);
 
//Now compute resistor values 

y = (Fc/Fra) - (Fra/Fc);
y = y * y;
Ar = gs * Math.sqrt(1 + (Q*Q*y));


R3 = Q/(Math.PI * Fra * C * 1E-6) ;
R1 = R3 / (2 * Ar);
R2 = (R3/2) / (( 2*Q*Q) - Ar);

y = (Fc/Frb) - (Frb/Fc);
y = y * y;
Ar = gs * Math.sqrt(1 + ((Q*Q)*y));


R6 = Q/(Math.PI * Frb * C * 1E-6) ;
R4 = R6 / (2 * Ar);
R5 = (R6/2) / (( 2*Q*Q) - Ar);

if(poles == 6){       //Real pole section (Section 3)
R9 = Qr/(Math.PI * Fc * C * 1E-6) ;
R7 = R9 / (2 * gs);
R8 = (R9/2) / (( 2*Qr*Qr) - gs);
}

//Output data now

/*Section 1 */
dataform.R1.value = R1 / 1000;  //K Ohms
dataform.R2.value = R2 / 1000;
dataform.R3.value = R3 / 1000;
dataform.Fo1.value = Fra;
dataform.Q1.value = Q;

/*Section 2 */
dataform.R4.value = R4 / 1000;
dataform.R5.value = R5 / 1000;
dataform.R6.value = R6 / 1000;
dataform.Fo2.value = Frb;
dataform.Q2.value = Q;

/*Section 3 */
if(poles == 6){
	dataform.R7.value = R7 / 1000;
	dataform.R8.value = R8 / 1000;
	dataform.R9.value = R9 / 1000;
	dataform.Q3.value = Qr;
	dataform.Fo3.value = Fc;
	if(R8 < 0) dataform.R8.value = "ERROR";
	}

dataform.caps.value = C;

//Error if requested gain exceeds gain available
if(R2 < 0) dataform.R2.value = "ERROR";
if(R5 < 0) dataform.R5.value = "ERROR";



}

/* end of Javascript program  */


