Add files via upload

master
r-burg 2018-05-27 15:10:28 +01:00 zatwierdzone przez GitHub
rodzic e9ad5826d2
commit d7ae6317cc
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
21 zmienionych plików z 4892 dodań i 0 usunięć

6
Build 100644
Wyświetl plik

@ -0,0 +1,6 @@
#! /bin/bash
# I'm still using Gtk2!
g++ -g `pkg-config --cflags gtk+-2.0 gdk-2.0 libgnome-2.0 libgnomeui-2.0 gdk-pixbuf-xlib-2.0` -o rbfilter ./rbfilter.cpp ./Calcs.cpp ./Rauch.cpp ./Sallen_and_Key.cpp ./Discrete.cpp `pkg-config --libs gtk+-2.0 gdk-2.0 libgnome-2.0 libgnomeui-2.0 gdk-pixbuf-xlib-2.0`
echo "Done!"
read

1039
Calcs.cpp 100644

Plik diff jest za duży Load Diff

120
Calcs.h 100644
Wyświetl plik

@ -0,0 +1,120 @@
#ifndef CALCSH
#define CALCSH
/*! \file Calcs.h
*/
#include <string>
using std::string;
#include <complex>
#include <stdio.h>
#include <math.h>
#include <fstream>
#include <sstream>
#include "Enums.h"
#include "Discrete.h"
#define FSTEPS 1000
#define TSTEPS 1000
#define IMAX 19
#define MAXS 19
#define LOG true
#define NORMALISE
#define VERBOSE false
// Shall we show detailed response data?
// #define SHOW_STAGES
using namespace std;
/*! \class stage
Describes one stage of a cascaded continuous filter.
*/
class stage {
public:
filter_class fclass;
circuit_class cclass;
double T, q;
std::complex<double> pole, zero;
// double t, q;
double R1, R2, R3, C1, C2, C3;
double gain;
std::complex<double> z;
iir iir1;
void R_low_pass(void);
void R_high_pass(void);
void R_band_pass(void);
void synthesise_R_low(void);
void synthesise_R_band(void);
void synthesise_R_high(void);
void synthesise_SK_low(void);
void synthesise_SK_band(void);
void synthesise_SK_high(void);
void bilinear(void);
stage& operator= (stage& f1);
};
class TFilter {
// private:
public:
filter_class fclass;
circuit_class cclass;
shape_class sclass;
double frequency;
double gain;
unsigned int poles, zeroes;
// std::complex<double> pole[20], zero[20];
double /* t[10], q[10],*/ tau; // TODO: use tau for single pole.
char type;
double fmax, tmax;
double ripple;
double bandwidth;
double samplingfreq;
double freq_resp[FSTEPS];
double step_resp[TSTEPS];
stage st[10];
void Proto_normalise(void);
double fgain(double f);
double a0;
public:
TFilter( );
// ~TFilter( );
void Calculate(void);
void log(string);
void log(string, double);
void log(string, double *);
void log(string, double *, int);
void log(string, std::complex<double>);
void _pole(double a, double w);
void transform(void);
void print_T_q(void);
void ts_and_qs(void);
void show_filter(void);
void show_filter(string title);
void bessel(void);
void sort(void);
void butterworth(void);
void chebyshev(void);
void lowpass(void);
void highpass(void);
void bandpass(void);
void Synth_Rauch(void);
void Synth_SallKey(void);
void step_calc(void);
void bilinear(void);
};
double tq(std::complex<double> p, double &t, double &q);
void bode_calc(TFilter& filter);
void step_calc(TFilter& filter);
#endif

4
Debug 100644
Wyświetl plik

@ -0,0 +1,4 @@
#! /bin/bash
gdb ./rbfilter
# read

152
Discrete.cpp 100644
Wyświetl plik

@ -0,0 +1,152 @@
/** \file
'Discrete.cpp' holds the code for implementing discrete, i.e. z-transform, filters.
*/
#include <cmath>
#include "math.h"
#include "Calcs.h"
#include <iostream>
#include <fstream>
#include <complex>
#include <stdlib.h>
#include "Discrete.h"
iir iir1;
/// 'iir::step(...)' implements the Direct Form 1 realisation.
double iir::step(double in)
{
int i;
for(i=2; i>0; i--) x[i] = x[i-1], y[i] = y[i-1];
x[0] = in * k;
y[0] = -a1*y[1] - a2*y[2] + b0*x[0] + b1*x[1] + b2*x[2];
return(y[0]);
}
/** Set the iir filter objects coefficients. */
void iir::setup(double kk, double aa0, double aa1, double aa2, double bb1, double bb2)
{
k = kk;
a1 = aa1, a2 = aa2;
b1 = bb1, b2 = bb2;
}
void iir::write(int stage)
{
char str[256];
std::ofstream out;
if(stage == 0) {
out.open("./out.c", std::ofstream::trunc);
/// Write initial code to 'out.c'
}
else out.open("./out.c", std::ofstream::app);
sprintf(str, "y%1d = -a%1d1*y%1d[1] - a%1d2*y%1d[2] + b%1d0*x%1d[0] + b%1d1*x%1d[1] + b%1d2*x%1d[2];\n",
stage, stage, stage, stage, stage, stage, stage, stage, stage, stage, stage);
out << str;
if(out.is_open( )) { out.close( ); }
}
/** Pre-warp the continuous filter. */
void prewarp(void)
{
/// Not yet designed.
}
/** Transform the continuous filter into a discrete one. */
void iir::transform(filter_class fclass, double Omega_ac, double q)
{
double ro2 = 1.0 / (Omega_ac * Omega_ac);
double roq = 1.0 / (Omega_ac * q);
b0 = 1.0;
switch(fclass) {
case Lowpass:
b1 = 2.0;
b2 = 1.0;
break;
case Highpass:
b0 = ro2;
b1 = -2.0 * ro2;
b2 = ro2;
break;
case Bandpass:
b0 = 1.0;
b1 = 0.0;
b2 = -1.0;
break;
default: cout << "\nUnknown filter type.\n"; return;
}
a0 = ro2 + roq + 1.0;
std::cout << "a0 =" << a0 << "\n";
// k = 1.0 / a0;
a1 = 2.0 - 2.0 * ro2;
a2 = ro2 - roq + 1.0;
a1 /= a0;
a2 /= a0;
b0 /= a0;
b1 /= a0;
b2 /= a0;
std::cout << "(" << b0 << "+(z^-1)*" << b1 << "+(z^-2)*" << b2 << ")/(" << 1.0 << "+(z^-1)*" << a1 << "+(z^-2)*" << a2 << ")\n";
std::cout << "-->" << (b0 + b1 + b2) / (1.0 + a1 + a2) << "\n";
std::cout << "[a0 = 1.0, a1 =" << a1 << ", a2 =" << a2 << "; b0 =" << b0 << ", b1 =" << b1 << ", b2 =" << b2 << "]\n";
/* std::cout << "Direct Form 2 realisation.\n--------------------------\n";
std::cout << "y[n] = b0 * w[n] + b1 * w[n-1] + b2 * w[n-2], w[n] = x[n] - a1 * w[n-1] - a2 * w[n-2]";
*/
}
/** 'normalise(...)' sets 'omega' */
double normalise(double fc, double fs)
{
double omega = 2.0 * M_PI * fc / fs;
return(omega);
}
#if false
int main( )
{
int i;
double fc, fs, omega;
std::cout << "cut-off freq: ";
std::cin >> fc;
std::cout << "sampling freq: ";
std::cin >> fs;
if(fc >= fs/2.0) {
std::cout << "That doesn't make sense! Cut-off must be less than sampling freq / 2.\n";
exit(-1);
}
omega = normalise(fc, fs);
std::cout << "omega =" << omega << "\n";
double omega_ac = tan(omega/2.0);
std::cout << "omega_ac =" << omega_ac << "\n\n";
iir1.transform(omega_ac, 0.7);
// iir1.setup(1.384, 0.1311136, 0.2162924, 0.1311136, -0.829328, 0.307046);
iir1.step(0.0);
std::cout << "\n";
std::cout << "Direct Form 1 realisation.\n--------------------------\n";
for(i=0; i<200; i++) std::cout << iir1.step(1.0) << "\n";
return(0);
}
#endif

21
Discrete.h 100644
Wyświetl plik

@ -0,0 +1,21 @@
#ifndef DISCRETE_H
#define DISCRETE_H
#include "Enums.h"
class iir {
int i;
double a0, a1, a2, b0, b1, b2, k;
double y[3], x[3];
public:
iir(void) { k = 1.0; for(i=0; i<3; i++) x[i] = y[i] = 0.0; }
void setup(double kk, double aa0, double aa1, double aa2, double bb1, double bb2);
void transform(filter_class fclass, double T, double q);
double step(double in);
void write(int stage);
};
#endif

5
Document 100644
Wyświetl plik

@ -0,0 +1,5 @@
#! /bin/bash
doxygen Document.conf
echo "*****************"
read

1417
Document.conf 100644

Plik diff jest za duży Load Diff

11
Drawing.h 100644
Wyświetl plik

@ -0,0 +1,11 @@
#ifndef DRAWINGH
#define DRAWINGH
/*! \file Drawing.h
*/
#define SHOW_XY false
enum DrawMode { Splane, Step, Bode, Realisation } ;
#endif

10
Enums.h 100644
Wyświetl plik

@ -0,0 +1,10 @@
#ifndef ENUMSH
#define ENUMSH
enum filter_class { Lowpass, Highpass, Bandpass };
enum circuit_class { SallKey, Rauch, ZDomain };
enum shape_class { Bessel, Butterworth, Chebyshev };
#endif

31
README 100644
Wyświetl plik

@ -0,0 +1,31 @@
Copyright (c) 2018 Roger Burghall
This is a git repository for 'rbfilter'. Copyright is owned by Roger Burghall.
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
(at your option) 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 <https://www.gnu.org/licenses/>.
The contents of this repository are subject to the GPLv3.0 ("General Public Licence")
*** No responsibility is taken for the results obtained using the program contained in or created using these files. ***
It is strongly recommended that the user should verify and validate the results obtained. Component tolerances and the limitations of real amplifiers will affect the results with actual circuits, and finite time intervals used in circuit simulation software will affect results indicated by circuit simulation software such as SPICE. Similar limitations exist when creating discrete filters.
'rbfilter' is intended to design, predict and simulate the operation of active and digital filters. As of version 1.0 it can deal with low-, band- and high-pass filters, designed as "Sallen and Key", "Rauch" and Discrete forms of Bessel, Butterworth and Chebyshev types. It does not, in general, comment on the sanity or otherwise of trying to create a particular filter, even if it involves unrealistic "q" values or operates at ridiculous frequencies.
The original version of this program was written in the early 1970s, using a Digital Equipment Corporation PDP12 computer, in Fortran. The next version dates from the 1980s and was written in BASIC and run on a BBC Model B computer. This version, written in C++, was recreated using a PC running Ubuntu; while it has enhanced functionality in some areas it lacks, as yet, some of the functions of the BBC version, such as the ability to simulate the output of a filter, given a file containing a representation of the input signal.
Use 'Build' to compile and link the program, 'Run' to run it, 'Debug' to run it under the gdb debugger. (I have not used a makefile as the program isn't big or complicated enough to warrant the effort - yet.)

423
Rauch.cpp 100644
Wyświetl plik

@ -0,0 +1,423 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <iostream>
#include "Calcs.h"
#if SHOW_FILE_COMPILING
#pragma message "Compiling Rauch.cpp"
#endif
/*! \file Rauch.cpp
This program calculates the T and q values for a Rauch stage from the component values.
*/
using namespace std;
stage stage1;
double e24[ ] = { 1.0, 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.7, 3.0,\
3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1, 10.0 };
double e12[ ] = { 1.0, 1.2, 1.5, 1.8, 2.2, 2.7, 3.3, 3.9, 4.7, 5.6, 6.8, 8.2, 10.0 };
double e6[ ] = { 1.0, 1.5, 2.2, 3.3, 4.7, 6.8, 10.0 };
enum ee { _e6, _e12, _e24 };
/**
Find the nearest e6, e12 or e24 preferred value to 'v'.
*/
double nearest(double v, ee e1)
{
int i, n;
double l = log10(v);
double p = int(l); // Power of ten: i.e. exponent
double f = l - p;
double x = pow10(f+1.0); // Mantissa
double *ep;
switch(e1) {
case _e6: ep = e6; n = 6; break;
case _e12: ep = e12; n = 12; break;
case _e24: ep = e24; n = 24; break;
default: cout << "Don't understand!";
exit(-1);
};
for(i=0; i<n; i++) {
if(ep[i] > x) break;
}
if(i == 0) {
cout << "Value below 1.0\n";
return(1.0);
}
return((x/ep[i-1] < ep[i]/x)? ep[i-1] * pow10(p-1.0): ep[i] * pow10(p-1.0));
}
/** Here comes a clever bit! Design a low-pass stage, choosing e6 values only for the capacitors, keeping sensible values for resistors.
Note: gain = R2 / R1; T = sqrt(C1.C2.R2.R3); q = T / ((1 + R2/R3 + R2/R1).C2.R3)
*/
void stage::synthesise_R_low(void)
{
#if false
double R, C, r, r1;
double a, b, c;
R1 = R2 = R3 = 1E4;
// R3 /= 1.1;
r1 = 10.0 / 1.2;
do {
r1 *= 1.2;
/// Choose ideal capacitor values; T^2 = R2*R3*C1*C2 --> C1*C2 = T^2/(R2*R3)
C = sqrt((T * T) / (R2 * R3));
r = sqrt(r1) * q;
C1 = C * r;
C2 = C / r;
// If R1 = R2 = R3 then q = T/(3*C2*R3)
// R3 *= 1.1;
/// Pick the nearest e6 values for caps.
cout << "Nearest to " << C1 << " is " << nearest(C1, _e6) << "\n";
cout << "Nearest to " << C2 << " is " << nearest(C2, _e6) << "\n";
C1 = nearest(C1, _e6);
C2 = nearest(C2, _e6);
/// Restore T to correct value
R = sqrt(T * T / (C1 * C2));
/// Adjust resistors to get back to desired q, keeping T and gain unchanged
a = C2*R;
b = -T / q;
c = 2.0*C2*R;
} while(b*b <= 4.0 * a * c);
double r = (-b + sqrt(b*b - 4.0 * a * c)) / (2.0 * a);
R1 = R * r;
R2 = R1;
R3 = R / r;
#else
double R, C, r, r1;
double a, b, c;
#if SHOW_CALC
cout << "\nsynthesise_low\n";
#endif
R1 = R2 = R3 = 1E4;
r1 = 10.0 / 1.2;
do {
r1 *= 1.2;
/// Choose ideal capacitor values; T^2 = R2*R3*C1*C2 --> C1*C2 = T^2/(R2*R3)
C = sqrt((T * T) / (R2 * R3));
r = sqrt(r1) * q;
C1 = C * r;
C2 = C / r;
// If R1 = R2 = R3 then q = T/(3*C2*R3)
/// Pick the nearest e6 values for caps.
#if SHOW_CALC
cout << "Nearest to " << C1 << " is " << nearest(C1, _e6) << "\n";
cout << "Nearest to " << C2 << " is " << nearest(C2, _e6) << "\n";
#endif
C1 = nearest(C1, _e6);
C2 = nearest(C2, _e6);
/// Restore T to correct value
R = sqrt(T * T / (C1 * C2));
/// Adjust resistors to get back to desired q, keeping T and gain unchanged
a = C2*R;
b = -T / q;
c = 2.0*C2*R;
} while(b*b <= 4.0 * a * c);
r = (-b + sqrt(b*b - 4.0 * a * c)) / (2.0 * a);
R1 = R * r;
R2 = R1;
R3 = R / r;
#if SHOW_CALC
cout << "End synthesise_low\n";
#endif
#endif
}
/// Calculate gain, T and q from component values
void stage::R_low_pass(void)
{
gain = -R2 / R1;
T = sqrt(C1*C2*R2*R3);
q = T / ((1.0 + R2/R3 + R2/R1)*C2*R3);
}
/** Design a band-pass stage, choosing e6 preferred values for the capacitors. Note:
gain = 1 / ((C1.R1)*(2+R1.(C1+C2)/(C1.C2.R1.R2))); T = sqrt(C1.C2.R1.R2); T/q = R1.(C1 + C2); i.e. q = T / (R1.(C1 + C2))
*/
void stage::synthesise_R_band(void)
{
double r;
double a, b, c;
double C;
double R;
#if SHOW_CALC
cout << "\nsynthesise_band\n";
#endif
R1 = 1.0e4; R2 = 1.0e4/1.5;
do {
/// Choose ideal capacitor values; T^2 = R1*R2*C1*C2 --> C1*C2 = T^2/(R1*R2)
// Let C1 = C.r, C2 = C/r
// If R1 = R2 then q = T/(R1*(C.r+C/r))
// C.r^2 - T/(q * R1).r + C = 0
R2 *= 1.5; /// Try progressively increasing ratios of R2:R1 until a solution is possible.
C = T / sqrt(R1*R2);
R = sqrt(R1*R2);
a = C;
b = -T / (q * R1);
c = C;
} while (b*b < 5.0*a*c);
r = (-b + sqrt(b*b - 4.0 * a * c * 1.1)) / (2.0 * a);
C1 = C * r;
C2 = C / r;
/// Pick the nearest e6 values for caps.
#if SHOW_CALC
cout << "Nearest to " << C1 << " is " << nearest(C1, _e6) << "\n";
cout << "Nearest to " << C2 << " is " << nearest(C2, _e6) << "\n";
#endif
C1 = nearest(C1, _e6);
C2 = nearest(C2, _e6);
/// Adjust resistors to get back to desired q, keeping T unchanged
R = sqrt(T * T / (C1 * C2));
R1 = sqrt(C1*C2*R*R) / (q*(C1+C2));
R2 = R * R / R1;
#if SHOW_CALC
cout << "\nEnd synthesise_band\n";
#endif
}
/** Calculate gain, T and q from component values for a band-pass stage. Note
gain = -C1/C3; T = sqrt(C2.C3.R1.R2); T/q = R1.(C1+C3); i.e. q = T / (R1.(C1+C3))
*/
void stage::R_band_pass(void)
{
gain = -1.0 / ((C1*R1)*(2+R1*(C1+C2)/(C1*C2*R1*R2)));
T = sqrt(R1*R2*C1*C2);
q = T / (R1*(C1 + C2));
}
/** Design a high pass stage, choosing e6 preferred values for C2 and C3. If the gain is to be -1
the value of C1 will be identical to C2.
*/
void stage::synthesise_R_high(void)
{
#if false
double r;
double a, b, c;
double C;
double R;
#if SHOW_CALC
cout << "\nsynthesise_high\n";
#endif
R1 = 1.0e4; R2 = 1.0e4/1.5;
do {
R2 *= 1.5;
R = sqrt(R1 * R2);
// T = sqrt(R1*R2*C2*C3)
C = T / sqrt(R1 * R2);
a = -gain * C;
b = -T / (q * R1);
c = C;
} while (b*b <= 4.0 * a * c * 0.9);
r = (-b + sqrt(b*b - 4.0 * a * c)) / (2.0 * a);
// cout << "C =" << C << " r =" << r << "\n";
C2 = C * r;
C3 = C / r;
C1 = -gain * C * r;
#if SHOW_CALC
cout << "Ideal values: C1 =" << C1 << " C2 =" << C2 << " C3 =" << C3 << "\n";
cout << "R1 =" << R1 << " R2 =" << R2 << "\n";
#endif
/// Pick the nearest e6 values for caps C2 and C3.
#if SHOW_CALC
cout << "Nearest to " << C2 << " is " << nearest(C2, _e6) << "\n";
cout << "Nearest to " << C3 << " is " << nearest(C3, _e6) << "\n";
#endif
C2 = nearest(C2, _e6);
C3 = nearest(C3, _e6);
C1 = -gain * C2;
/// Adjust resistors to get back to desired q, keeping T unchanged
R1 = T / (q * (C1 + C3));
R2 = T * T / (C2 * C3 * R1);
#endif
double R, C, r, c;
/// Calculate ideal component values
R = 1e4;
C = T / R;
r = 1.0;
c = 1.0;
C2 = C * c;
C3 = C / c;
C1 = C2 / -gain;
R1 = T / (q * (C1 + C2 + C3));
R2 = R * R / R1;
cout << "\nIdeal values: C1 =" << C1 << " C2 =" << C2 << " C3 =" << C3 << "\n";
cout << "R1 =" << R1 << " R2 =" << R2 << "\n";
/// Convert to more practical components, capacitors at least!
cout << "\nPractical values:\n";
C2 = nearest(C2, _e6);
C3 = nearest(C3, _e6);
C1 = -gain * C2;
R1 = T / (q * (C1 + C2 + C3));
R2 = T * T / (R1 * C2 * C3);
#if SHOW_CALC
cout << "\nEnd synthesise_high\n";
#endif
}
/// Calculate gain, T and q from component values for a high-pass filter
void stage::R_high_pass(void)
{
gain = -C1/C2;
T = sqrt(C3*C2*R1*R2);
q = T / (R1*(C1 + C3));
}
void TFilter::Synth_Rauch(void)
{
int i;
stage *pstage;
ofstream file;
file.open("./Circuit.txt");
file << "Order = " << poles << "\n";
for(i=0, pstage=st; i<poles/2; i++) {
pstage->fclass = fclass;
pstage->T = st[i].T;
pstage->q = st[i].q;
pstage->gain = -1.0;
cout << "\n*************************************\nSecond order stage: Rauch\n";
cout << "Stage " << i+1 << "\n";
switch(pstage->fclass) {
case Lowpass: pstage->synthesise_R_low( ); file << "Lowpass\n"; break;
case Highpass: pstage->synthesise_R_high( ); file << "Highpass\n";break;
case Bandpass: pstage->synthesise_R_band( ); file << "Bandpass\n";break;
default: cout << "Unknown fclass\n"; exit(-1);
}
// cout << "\n*************************************\nSecond order stage: Rauch\n";
file << "Stage = " << i << "\n";
file << "Rauch\n";
cout << "R1: " << pstage->R1; file << "R1 = " << pstage->R1;
cout << ", R2: " << pstage->R2; file << "\nR2 = " << pstage->R2;
if((pstage->fclass == Lowpass)||(pstage->fclass == Bandpass)) { cout << ", R3: " << pstage->R3; file << "\nR3 = " << pstage->R3;}
cout << "\nC1: " << pstage->C1; file << "\nC1 = " << pstage->C1;
cout << ", C2: " << pstage->C2; file << "\nC2 = " << pstage->C2;
if(pstage->fclass == Highpass) { cout << ", C3: " << pstage->C3; file << "\nC3 = " << pstage->C3; }
cout << "\n"; file << "\n";
pstage++;
}
// Now for the odd pole if there is one.
if(poles%2) {
pstage->fclass = fclass;
pstage->T = abs(st[i].T);
pstage->R1 = 1E4;
pstage->C1 = pstage->T / pstage->R1;
pstage->C1 = nearest(pstage->C1, _e6);
pstage->R1 = pstage->T / pstage->C1;
switch(pstage->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: " << pstage->R1; file << "R1 = " << pstage->R1;
cout << "\nC1: " << pstage->C1 << "\n"; file << "\nC1 = " << pstage->C1;
}
cout << "*************************************\n";
if(file.is_open( )) file.close( );
}
#if false
int main( )
{
char c;
do {
cout << "Synthesise or Analyse?\n"; cin >> c;
if(c == 'S' || c == 's') {
do {
cout << "Lowpass, Bandpass or Highpass?\n"; cin >> c;
if(c != 'L' && c != 'l' && c != 'B' && c != 'b' && c != 'H' && c != 'h') continue;
} while(false);
do {
cout << "Gain:\n"; cin >> stage1.gain;
if(stage1.gain >= 0.0) cout << "No! Gain must be negative.\n";
} while(stage1.gain >= 0.0);
cout << "T:\n"; cin >> stage1.T;
cout << "q:\n"; cin >> stage1.q;
switch(c) {
case 'L':
case 'l': stage1.synthesise_low( ); break;
case 'B':
case 'b': stage1.synthesise_band( ); break;
case 'H':
case 'h': stage1.synthesise_high( ); break;
}
cout << "C1 =" << stage1.C1;
cout << " C2 =" << stage1.C2;
if(c == 'h' || c == 'H') cout << " C3 =" << stage1.C3;
cout << "\n";
cout << "R1 =" << stage1.R1;
cout << " R2 =" << stage1.R2;
if(c == 'l' || c == 'L') cout << " R3 =" << stage1.R3 << "\n";
switch(c) {
case 'L':
case 'l': stage1.low_pass( ); break;
case 'B':
case 'b': stage1.band_pass( ); break;
case 'H':
case 'h': stage1.high_pass( ); break;
}
cout << "Check: gain = " << stage1.gain << " T = " << stage1.T << " q = " << stage1.q << "\n";
} else {
cout << "Lowpass, Bandpass or Highpass?\n"; cin >> c;
if(c != 'L' && c != 'l' && c != 'B' && c != 'b' && c != 'H' && c != 'h') continue;
cout << "R1: \n"; cin >> stage1.R1;
cout << "R2: \n"; cin >> stage1.R2;
if(c == 'L' || c == 'l') { cout << "R3: \n"; cin >> stage1.R3; }
cout << "C1: \n"; cin >> stage1.C1;
cout << "C2: \n"; cin >> stage1.C2;
if(c == 'H' || c == 'h') { cout << "C3: \n"; cin >> stage1.C3; }
switch(c) {
case 'L':
case 'l': stage1.low_pass( ); break;
case 'B':
case 'b': stage1.band_pass( ); break;
case 'H':
case 'h': stage1.high_pass( ); break;
}
cout << "gain = " << stage1.gain << " T = " << stage1.T << " q = " << stage1.q << "\n";
}
cout << "Again?\n";
cin >> c;
} while(c == 'y' || c == 'Y');
}
#endif

5
Run 100644
Wyświetl plik

@ -0,0 +1,5 @@
#! /bin/bash
./rbfilter
echo "********************"
read

325
Sallen_and_Key.cpp 100644
Wyświetl plik

@ -0,0 +1,325 @@
#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 = pow10(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 = pow10(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

BIN
ToDo list.odt 100644

Plik binarny nie jest wyświetlany.

17
bilinear.cpp 100644
Wyświetl plik

@ -0,0 +1,17 @@
#include "math.h"
#include <complex.h>
#include "Calcs.h"
#include <ostream>
#include <iostream>
#include <string>
std::complex<double> _bilinear(std::complex<double> s, double Ts)
{
std::complex<double> z = (1.0 + s*Ts/2.0) / (1.0 - s*Ts/2.0);
return(z);
}

26
filter.h 100644
Wyświetl plik

@ -0,0 +1,26 @@
#ifndef FILTER_H
#define FILTER_H
#include <complex.h>
#include "calcs.h"
#define SHOW_FILE_COMPILING 0
class TFilter {
public:
complex pole[40];
void log(string);
void log(string, double);
void log(string, complex);
int poles;
char type;
int zeroes;
double fmax, tmax;
double step_resp[IMAX];
};
#endif

44
main.cpp 100644
Wyświetl plik

@ -0,0 +1,44 @@
//*********************************************************
#include "math.h"
#include <complex.h>
#include "calcs.h"
#include "SandK.h"
#include "preferred.h"
#include <ostream>
#include <iostream>
#include <string>
#if SHOW_FILE_COMPILING
#pragma message "Compiling " __FILE__
#endif
using std::cout;
extern TFilter filter;
void SallenAndKey1(double Tau, double q);
int main(int argc, char **argv)
{
cout << nearest(e_12, 1025.4) << "\n";
cout << nearest(e_12, 1175.4) << "\n";
filter.poles = 5;
filter.fmax = 10.0;
butterworth(filter);
lowpass(filter, 10.0);
bode_calc(filter);
cout << "\n";
bessel(filter);
cout << "\n";
chebyshev(filter);
cout << "\n";
bode_calc(filter);
SandK cct1;
cct1.SallenAndKey(t_lowpass, 1.0, 1.0e4, 1.0e4, 0.0, 1.0e-7, 2.0e-7);
cct1.SallenAndKey1(0.001, 0.707);
}

BIN
rbfilter 100644

Plik binarny nie jest wyświetlany.

1236
rbfilter.cpp 100644

Plik diff jest za duży Load Diff

BIN
using_rbfilter.odt 100644

Plik binarny nie jest wyświetlany.