kopia lustrzana https://github.com/r-burg/rbfilter
Add files via upload
rodzic
e9ad5826d2
commit
d7ae6317cc
|
@ -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
|
||||||
|
|
Plik diff jest za duży
Load Diff
|
@ -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
|
|
@ -0,0 +1,4 @@
|
||||||
|
#! /bin/bash
|
||||||
|
gdb ./rbfilter
|
||||||
|
# read
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#! /bin/bash
|
||||||
|
doxygen Document.conf
|
||||||
|
echo "*****************"
|
||||||
|
read
|
||||||
|
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef DRAWINGH
|
||||||
|
#define DRAWINGH
|
||||||
|
|
||||||
|
/*! \file Drawing.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SHOW_XY false
|
||||||
|
|
||||||
|
enum DrawMode { Splane, Step, Bode, Realisation } ;
|
||||||
|
|
||||||
|
#endif
|
|
@ -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
|
||||||
|
|
|
@ -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.)
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#! /bin/bash
|
||||||
|
./rbfilter
|
||||||
|
echo "********************"
|
||||||
|
read
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Plik binarny nie jest wyświetlany.
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Plik binarny nie jest wyświetlany.
Plik diff jest za duży
Load Diff
Plik binarny nie jest wyświetlany.
Ładowanie…
Reference in New Issue