kopia lustrzana https://github.com/r-burg/rbfilter
335 wiersze
8.5 KiB
C++
335 wiersze
8.5 KiB
C++
/******************************************************************************
|
|
|
|
Sallen_and_Key.cpp
|
|
|
|
Copyright (c) Roger Burghall 2014..2017
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <cmath>
|
|
#include <iostream>
|
|
#include "Calcs.h"
|
|
|
|
#if SHOW_FILE_COMPILING
|
|
#pragma message "Compiling Sallen_and_Key.cpp"
|
|
#endif
|
|
|
|
/*! \file Sallen_and_Key.cpp
|
|
This program calculates the component values for a Sallen and Key stage to give a specified T and q.
|
|
*/
|
|
|
|
using namespace std;
|
|
|
|
|
|
/*
|
|
class stage {
|
|
public:
|
|
double T, q;
|
|
double R1, R2, R3, C1, C2;
|
|
double gain;
|
|
char type;
|
|
circuit_class cct;
|
|
void low_pass(void);
|
|
void high_pass(void);
|
|
void band_pass(void);
|
|
void synthesise_SK_low(void);
|
|
void synthesise_SK_high(void);
|
|
void synthesise_SK_band(void);
|
|
};
|
|
*/
|
|
|
|
extern double e24[ ];
|
|
extern double e12[ ];
|
|
extern double e6[ ];
|
|
enum ee { _e6, _e12, _e24 };
|
|
|
|
extern double nearest(double v, ee e1);
|
|
|
|
double Fn_e6(double c)
|
|
{
|
|
int i = 0;
|
|
double temp;
|
|
float e6[] = { 10.0, 6.8, 4.7, 3.3, 2.2, 1.5, 1.0, 0.68 };
|
|
double exponent = exp10(int(log10(c)));
|
|
double mantissa = c / exponent;
|
|
cout << "mantissa = " << mantissa << " exponent = " << exponent << "\n";
|
|
do {
|
|
temp = sqrt(e6[i] * e6[i+1]) / 10.0;
|
|
if(temp <= mantissa) break;
|
|
i++;
|
|
if(i > 7) { cout << "i Error!\n"; return(0); }
|
|
} while(1);
|
|
return(e6[i] * exponent);
|
|
}
|
|
|
|
|
|
|
|
double Fn_e12(double c)
|
|
{
|
|
int i = 0;
|
|
double temp;
|
|
float e12[] = { 10.0, 8.2, 6.8, 5.6, 4.7, 3.9, 3.3, 2.7, 2.2, 1.8, 1.5, 1.2, 1.0, 0.82 };
|
|
double exponent = exp10(int(log10(c)));
|
|
double mantissa = c / exponent;
|
|
do {
|
|
temp = sqrt(e12[i] * e12[i+1]) / 10.0;
|
|
if(temp <= mantissa) break;
|
|
i++;
|
|
if(i > 13) { cout << "i Error!\n"; return(0); }
|
|
} while(1);
|
|
return(e12[i] * exponent);
|
|
}
|
|
|
|
|
|
|
|
void low( )
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void stage::synthesise_SK_low(void)
|
|
{
|
|
#if SHOW_CALC
|
|
cout << "stage::synthesise_SK_low\n";
|
|
#endif
|
|
#if true
|
|
double aa, bb, cc;
|
|
double r = 1e4;
|
|
double c = T / r;
|
|
// q = T / (C1 * R1 + C1 * R2 + (1.0 - gain) * C2 * R1);
|
|
double d = sqrt(2.0)/1.25;
|
|
do {
|
|
d *= 1.25;
|
|
C1 = c / d;
|
|
C2 = c * d;
|
|
#if SHOW_CALC
|
|
cout << "C1 = " << C1 << ", C2 = " << C2 << "\n";
|
|
#endif
|
|
// R1 = r / s;
|
|
// R2 = r * s;
|
|
// c / d * r * s^2 + c / d * r + (1.0 - gain) * c * d * r - s * T / q = 0
|
|
aa = c / d * r;
|
|
bb = -T / q;
|
|
cc = c / d * r + (1.0 - gain) * c * d * r;
|
|
} while(bb * bb < 5.0 * aa * cc);
|
|
double sq = sqrt(bb * bb - 4.0 * aa * cc);
|
|
#if SHOW_CALC
|
|
cout << "-bb = " << -bb << ", sq = " << sq << ", aa = " << aa << "\n";
|
|
#endif
|
|
double s1 = (-bb + sq) / (2.0 * aa);
|
|
double s2 = (-bb - sq) / (2.0 * aa);
|
|
|
|
// Now choose e6 preferred values of capacitor
|
|
C1 = nearest(C1, _e6);
|
|
C2 = nearest(C2, _e6);
|
|
c = sqrt(C1 * C2);
|
|
d = sqrt(C2 / C1);
|
|
r = sqrt(T*T / (C1 * C2));
|
|
aa = c / d * r;
|
|
bb = -T / q;
|
|
cc = c / d * r + (1.0 - gain) * c * d * r;
|
|
sq = sqrt(bb * bb - 4.0 * aa * cc);
|
|
s1 = (-bb + sq) / (2.0 * aa);
|
|
s2 = (-bb - sq) / (2.0 * aa);
|
|
|
|
R1 = r / s1;
|
|
R2 = r * s1;
|
|
#if SHOW_CALC
|
|
cout << "C1 = " << C1 << ", C2 = " << C2 << ", R1 = " << R1 << ", R2 = " << R2 << "\n";
|
|
cout << "T =" << sqrt(R1 * R2 * C1 * C2) << ", q =" << sqrt(R1 * R2 * C1 * C2) / (C1 * R1 + C1 * R2 + (1.0 - gain) * C2 * R1) << "\n";
|
|
#endif
|
|
R1 = r / s2;
|
|
R2 = r * s2;
|
|
#if SHOW_CALC
|
|
cout << "C1 = " << C1 << ", C2 = " << C2 << ", R1 = " << R1 << ", R2 = " << R2 << "\n";
|
|
cout << "T =" << sqrt(R1 * R2 * C1 * C2) << ", q =" << sqrt(R1 * R2 * C1 * C2) / (C1 * R1 + C1 * R2 + (1.0 - gain) * C2 * R1) << "\n";
|
|
#endif
|
|
|
|
#else
|
|
// double k = 1.0;
|
|
double aa, bb, cc;
|
|
double r = 1e4;
|
|
double c = T / r;
|
|
// q = T / (C1 * R1 + C1 * R2 + (1.0 - gain) * C2 * R1);
|
|
double d = sqrt(2.0)/1.25;
|
|
do {
|
|
d *= 1.25;
|
|
C1 = c / d;
|
|
C2 = c * d;
|
|
cout << "C1 = " << C1 << ", C2 = " << C2 << "\n";
|
|
// R1 = r / s;
|
|
// R2 = r * s;
|
|
// c / d * r * s^2 + c / d * r + (1.0 - gain) * c * d * r - s * T / q = 0
|
|
aa = c / d * r;
|
|
bb = -T / q;
|
|
cc = c / d * r + (1.0 - gain) * c * d * r;
|
|
} while(bb * bb < 5.0 * aa * cc);
|
|
double sq = sqrt(bb * bb - 4.0 * aa * cc);
|
|
cout << "-bb = " << -bb << ", sq = " << sq << ", aa = " << aa << "\n";
|
|
double s1 = (-bb + sq) / (2.0 * aa);
|
|
double s2 = (-bb - sq) / (2.0 * aa);
|
|
|
|
R1 = r / s1;
|
|
R2 = r * s1;
|
|
cout << "C1 = " << C1 << ", C2 = " << C2 << ", R1 = " << R1 << ", R2 = " << R2 << "\n";
|
|
// R1 = R1, R2 = R2, C1 = C1, C2 = C2, R3 = 0.0;
|
|
|
|
R1 = r / s2;
|
|
R2 = r * s2;
|
|
cout << "C1 = " << C1 << ", C2 = " << C2 << ", R1 = " << R1 << ", R2 = " << R2 << "\n";
|
|
#endif
|
|
|
|
#if SHOW_CALC
|
|
cout << "End stage::synthesise_SK_low\n";
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
void stage::synthesise_SK_high(void)
|
|
{
|
|
double cf;
|
|
R1 = 47.0E3;
|
|
R2 = R1 * (1.0 / (4.0 * q * q) + (gain - 1.0) * R1);
|
|
C1 = T / (2.0 * R2 * q);
|
|
cf = Fn_e6(C1) / C1;
|
|
C1 = C1 * cf; C2 = C1;
|
|
R1 = R1 / cf; R2 = R2 / cf;
|
|
}
|
|
|
|
|
|
|
|
/** Synthesize Sallen and Key bandpass stage.
|
|
Let R1 = R3 = R, R2 = 2R, C1 = C2 = C.
|
|
Then set q = 1 / (3 - k) i.e. k = 3.0 - 1/q
|
|
w0 = 1 / (R * C)
|
|
[The maximum gain of the filter stage will be k / (3 - k)]
|
|
*/
|
|
void stage::synthesise_SK_band(void)
|
|
{
|
|
double c, r;
|
|
gain = 3.0 - 1.0 / q;
|
|
r = 1e4;
|
|
c = T / r;
|
|
C1 = C2 = nearest(c, _e6);
|
|
r = T / C1;
|
|
R1 = R3 = r;
|
|
R2 = 2.0 * r;
|
|
|
|
/* cout << "Gain = " << gain;
|
|
cout << "\nR1 = " << R1 << ", R2 = " << R2 << ", R3 = " << R3 << "\n";
|
|
cout << "C1 =" << C1 << ", C2 =" << C2 /* << "v =" << v << " b =" << b* / << "\n";
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
void TFilter::Synth_SallKey(void)
|
|
{
|
|
int i;
|
|
ofstream file;
|
|
file.open("./Circuit.txt");
|
|
file << "Order = " << poles << "\n";
|
|
for(i=0; i<poles/2; i++) {
|
|
st[i].fclass = fclass;
|
|
// st[i].T = st[i].T;
|
|
st[i].q = st[i].q;
|
|
st[i].gain = 1.0;
|
|
switch(st[i].fclass) {
|
|
case Lowpass: st[i].synthesise_SK_low( ); file << "Lowpass\n"; break;
|
|
case Highpass: st[i].synthesise_SK_high( ); file << "Highpass\n";break;
|
|
case Bandpass: st[i].synthesise_SK_band( ); file << "Bandpass\n";break;
|
|
default: cout << "Unknown fclass\n"; exit(-1);
|
|
}
|
|
|
|
cout << "\n*************************************\nSecond order stage: Sallen and Key\n";
|
|
cout << "Stage " << i+1 << "\n";
|
|
file << "Stage = " << i << "\n";
|
|
file << "Sallen and Key\n";
|
|
cout << "Gain = " << st[i].gain << "\n"; file << "Gain = " << st[i].gain << "\n";
|
|
cout << "R1: " << st[i].R1; file << "R1 = " << st[i].R1;
|
|
cout << ", R2: " << st[i].R2; file << "\nR2 = " << st[i].R2;
|
|
if(st[i].fclass == Bandpass) { cout << ", R3: " << st[i].R3; file << "\nR3 = " << st[i].R3;}
|
|
cout << "\nC1: " << st[i].C1; file << "\nC1 = " << st[i].C1;
|
|
cout << ", C2: " << st[i].C2; file << "\nC2 = " << st[i].C2;
|
|
// if(st[i].fclass == Highpass) { cout << ", C3: " << st[i].C3; file << "\nC3 = " << st[i].C3; }
|
|
// cout << "\nAmplifier gain = " << st[i].gain; file << "\nAmplifier gain = " << st[i].gain;
|
|
cout << "\n"; file << "\n";
|
|
}
|
|
// Now for the odd pole if there is one.
|
|
if(poles%2) {
|
|
st[i].fclass = fclass;
|
|
// st[i].T = st[i].T;
|
|
st[i].R1 = 1E4;
|
|
st[i].C1 = abs(st[i].T) / st[i].R1;
|
|
st[i].C1 = nearest(st[i].C1, _e6);
|
|
st[i].R1 = abs(st[i].T) / st[i].C1;
|
|
switch(st[i].fclass) {
|
|
case Lowpass: break;
|
|
case Highpass: break;
|
|
case Bandpass: cout << "Impossible! order of bandpass filter cannot be odd.\n"; return;
|
|
default: cout << "Unknown fclass\n"; exit(-1);
|
|
}
|
|
cout << "\n*************************************\nFirst order stage:\n";
|
|
file << "First order stage:\n";
|
|
cout << "R1: " << st[i].R1; file << "R1 = " << st[i].R1;
|
|
cout << "\nC1: " << st[i].C1 << "\n"; file << "\nC1 = " << st[i].C1;
|
|
}
|
|
cout << "*************************************\n";
|
|
if(file.is_open( )) file.close( );
|
|
}
|
|
|
|
|
|
|
|
|
|
#if false
|
|
stage s1;
|
|
|
|
|
|
int main( )
|
|
{
|
|
/* Tests
|
|
cout << "123.0 -> " << Fn_e12(123.0) << "\n";
|
|
cout << "99.0 -> " << Fn_e12(99.0) << "\n";
|
|
cout << "3000.0 -> " << Fn_e12(3000.0) << "\n";
|
|
cout << "1800000.0 -> " << Fn_e12(1800000.0) << "\n";
|
|
*/
|
|
|
|
/* s1.T = 1e-3;
|
|
s1.q = 0.691;
|
|
s1.gain = 2.0;
|
|
*/
|
|
cout << "L, H or B:\n"; cin >> s1.type;
|
|
if(s1.type != 'L' && s1.type != 'H' && s1.type != 'B' && s1.type != 'l' && s1.type != 'h' && s1.type != 'b') {
|
|
cout << "Not a valid option!\n"; return(-1);
|
|
}
|
|
cout << "Gain: \n"; cin >> s1.gain;
|
|
cout << "T: \n"; cin >> s1.T;
|
|
cout << "q: \n"; cin >> s1.q;
|
|
switch(s1.type) {
|
|
case 'L':
|
|
case 'l': s1.synthesise_SK_low( ); break;
|
|
case 'H':
|
|
case 'h': s1.synthesise_SK_lowh( ); break;
|
|
case 'B':
|
|
case 'b': s1.synthesise_SK_lowb( ); break;
|
|
default: cout << "\nThat shouldn't happen!\n"; exit(-1);
|
|
}
|
|
cout << "R1: " << s1.R1 << "\n";
|
|
cout << "R2: " << s1.R2 << "\n";
|
|
cout << "C1: " << s1.C1 << "\n";
|
|
cout << "C2: " << s1.C2 << "\n";
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|