Home │ Audio
Home Page |
Copyright © 2016 by Wayne Stegall
Updated March 19, 2017. See
Document History at end for
details.
|
Figure
1:
First
schematic |
(1) |
Rs = |
|VT|
IDSS |
Figure 2: SPICE deck uncompensated for buffer output impedance. |
* filter simulation for input
parameters f = 45Hz and q = 0.9 vdd1 vdd 0 dc 15 vss1 vss 0 dc -15 v1 vin 0 dc 0 ac 1 sin 0 1V 1kHz rs vin 0 100k * filter emulating speaker response c3s vin c3c4 0.1u c4s c3c4 c4r4 0.1u r3s e2out c3c4 19648.8 r4s c4r4 0 63662 e2 e2out 0 c4r4 0 1 * electonic equalizer filter c1 e2out c1c2 0.1u c2 c1c2 c2r2 0.1u r1 j1s c1c2 8138.78 r2 c2r2 0 627452 j1 vdd c2r2 j1s 2N3819 j2 j1s vss j2s 2N3819 r3 j2s vss 390 j3 vdd c2r2 j3s 2N3819 j4 j3s vss j4s 2N3819 r4 j4s vss 390 c3 j3s vout 10u r5 vout 0 100k .model 2N3819 njf vto=-3.0 beta=1.3m .end .control ac dec 30 10 100 plot db(vout) db(e2out) db(vout/e2out) .endc |
Figure 3: Bode plot uncompensated for buffer output impedance shows unequal ripple slightly over 0.5dB. |
Figure
4:
SPICE
determination
of
J1 output impedance. |
SpiceOpus (c) 1 -> tf v(j1s)
v1
SpiceOpus (c) 2 -> print all input_impedance = 1.000000e+005 output_impedance = 2.346907e+002 transfer_function = 0.000000e+000 SpiceOpus (c) 3 -> |
(2) |
R1-component = R1-calculated – rs-j1 |
Figure 5: SPICE deck subtracting buffer output impedance from R1. |
* filter simulation for input
parameters f = 45Hz and q = 0.9 vdd1 vdd 0 dc 15 vss1 vss 0 dc -15 v1 vin 0 dc 0 ac 1 sin 0 1V 1kHz rs vin 0 100k * filter emulating speaker response c3s vin c3c4 0.1u c4s c3c4 c4r4 0.1u r3s e2out c3c4 19648.8 r4s c4r4 0 63662 e2 e2out 0 c4r4 0 1 * electonic equalizer filter c1 e2out c1c2 0.1u c2 c1c2 c2r2 0.1u * r1 = 8138.78 - 234.69 r1 j1s c1c2 7904.09 r2 c2r2 0 627452 j1 vdd c2r2 j1s 2N3819 j2 j1s vss j2s 2N3819 r3 j2s vss 390 j3 vdd c2r2 j3s 2N3819 j4 j3s vss j4s 2N3819 r4 j4s vss 390 c3 j3s vout 10u r5 vout 0 100k .model 2N3819 njf vto=-3.0 beta=1.3m .end .control tran 1u 0.1 0 1u fourier 1k vout ac dec 30 10 100 plot db(vout) db(e2out) db(vout/e2out) .endc |
Figure 6: Bode plot compensated for buffer output impedance has equal ripple. |
Figure 7: Schematic of filter with input buffer added. |
Figure 8: Bode plot uncompensated for input buffer output impedance shows a small amount of unequal ripple. |
(3) |
valuenew-guess =
|
valueold-guess × | valuetarget
valuespice-result |
Figure 9: Code listing for filter program sbeqnjf.cpp: |
#include <iostream> #include <complex> #include <stdio.h> #include <math.h> //#include <mathext.h> //include inverse hyperbolic functions. using namespace std; #define ORDER 4 #define sqr(x) ((x)*(x)) #define ROJ 234.69 int main(int argc, char* argv[]) { int p, ret; double qmin,f,q,f2,f3db,fripple,q2,thetap,pi,kcheby,A,epsilon,dbripple; double fsf, c1c2, c1c2u, r1[2], r2[2]; complex <double> buttp[2], chebp[2]; double fmult, qmult; pi = acos(-1); fmult = 1.0; qmult = 1.0; // calculate first two poles of 4th order Butterworth for(p=0;p<2;p++) { thetap = (pi/2.0)+(2.0*(p+1)-1.0)*pi/(2.0*(double)ORDER); // cout << thetap*180.0/pi << endl; buttp[p] = complex<double>(cos(thetap),sin(thetap)); } qmin = abs(buttp[1])/(2.0*fabs(real(buttp[1]))); // get f and q from command line. ret = 0; if(argc == 4 || argc == 6) { ret = sscanf(argv[1],"%lg",&f); if(ret) ret = sscanf(argv[2],"%lg",&q); if(ret) ret = sscanf(argv[3],"%lg",&c1c2u); if(ret && argc == 6) { ret = sscanf(argv[4],"%lg",&fmult); if(ret) ret = sscanf(argv[5],"%lg",&qmult); } } // else get them from input. do { if(!ret) { cout << "Enter frequency, Q, and C1/C2 value in microfarads" << endl; cin >> f >> q >> c1c2u; } if(q <= qmin) { cout << "Quality factor must be greater than " << qmin << endl; // prevent command line operation from getting stuck if(argc == 3) return -1; } } // loop back until q is correct while(q <= qmin); // Calculate existing Chebychev pole chebp[1] = complex<double>(-1.0/(q*2.0),sqrt(1.0-sqr(-1.0/(q*2.0)))); chebp[1] *= complex<double>(imag(buttp[1])/imag(chebp[1])); // Calculate design constants kcheby = real(chebp[1])/real(buttp[1]); A = atanh(kcheby); epsilon = 1.0/sinh(A*ORDER); dbripple = 10.0*log10(sqr(epsilon)+1.0); f3db = f*abs(chebp[1]); fripple = f3db*cosh(A); // Calculate remaining Chebychev pole chebp[0] = complex<double>(real(buttp[0] * kcheby),imag(buttp[0])); q2 = fabs(0.5/cos(arg(chebp[0]))); f2 = f3db/abs(chebp[0]); for(p = 0; p < 2; p++) cout << "buttp[" << p << "] = (" << real(buttp[p]) << "," << imag(buttp[p]) << ")" << endl; cout << endl; for(p = 0; p < 2; p++) cout << "chebp[" << p << "] = (" << real(chebp[p]) << "," << imag(chebp[p]) << ")" << endl; cout << endl; cout << "Filter frequency = " << f2 << endl; cout << "Filter Q = " << q2 << endl; cout << "System dB ripple = " << dbripple << endl; cout << "System -3dB frequency = " << f3db << endl; cout << "System ripple frequency = " << fripple << endl << endl; // adjust filter pole if necessary if(argc == 6) { f2 *= fmult; q2 *= qmult; thetap = acos(-0.5/q2); chebp[0] = polar(f3db/f2,thetap); cout << "Request to scale filter: f by " << fmult << " and q by " << qmult << endl; cout << "Filter frequency = " << f2 << endl; cout << "Filter Q = " << q2 << endl; p = 0; cout << "chebp[" << p << "] = (" << real(chebp[p]) << "," << imag(chebp[p]) << ")" << endl << endl; } // calculate unity gain Sallen and Key hardware. c1c2 = c1c2u * 1.0e-6; fsf = 1.0/(2*pi*f3db*c1c2); for(p = 0; p < 2; p++) { r1[p] = -real(chebp[p])*fsf; r2[p] = -norm(chebp[p])/real(chebp[p])*fsf; } // output SPICE model cout << "* filter simulation for input parameters f = " << f << "Hz and q = " << q <<endl; cout << "* Filter scaled: f by " << fmult << " and q by " << qmult << endl; cout << "vdd1 vdd 0 dc 15" << endl \ << "vss1 vss 0 dc -15" << endl \ << "v1 vin 0 dc 0 ac 1 sin 0 1V 1kHz" << endl \ << "rs vin 0 100k" << endl \ << "* filter emulating speaker response" << endl \ << "c3s vin c3c4 " << c1c2u << "u" << endl \ << "c4s c3c4 c4r4 " << c1c2u << "u" << endl \ << "r3s fltrin c3c4 " << r1[1] << endl \ << "r4s c4r4 0 " << r2[1] << endl \ << "e2 fltrin 0 c4r4 0 1" << endl \ << "* electonic equalizer filter" << endl \ << "r3 fltrin 0 47k" << endl \ << "j1 vdd fltrin j1s 2N3819" << endl \ << "j2 j1s vss j2s 2N3819" << endl \ << "r4 j2s vss 390" << endl \ << "c1 j1s c1c2 " << c1c2u << "u" << endl \ << "c2 c1c2 c2r2 " << c1c2u << "u" << endl \ << "* r1 = " << r1[0] << " - " << ROJ << endl \ << "r1 j3s c1c2 " << r1[0]-ROJ << endl \ << "r2 c2r2 0 " << r2[0] << endl \ << "j3 vdd c2r2 j3s 2N3819" << endl \ << "j4 j3s vss j4s 2N3819" << endl \ << "r5 j4s vss 390" << endl \ << "j5 vdd c2r2 j5s 2N3819" << endl \ << "j6 j5s vss j6s 2N3819" << endl \ << "r6 j6s vss 390" << endl \ << "c3 j5s vout 10u" << endl \ << "r7 vout 0 100k" << endl \ << ".model 2N3819 njf vto=-3.0 beta=1.3m" << endl \ << ".end" << endl \ << ".control" << endl \ << "pz c4r4 0 c2r2 0 vol pol" << endl \ << "print all" << endl \ << "*tran 1u 0.1 0 1u" << endl \ << "*fourier 1k vout" << endl \ << "ac dec 30 10 100" << endl \ << "plot db(vout) db(fltrin) db(vout/fltrin)" << endl \ << ".endc" << endl << endl; return 0; } |
|
Figure
10:
Spreadsheet
managing
numerical
iteration
calculations. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Figure 11: Fully optimized SPICE deck from iteration 5. |
* filter simulation for input
parameters f = 45Hz and q = 0.9 * Filter scaled: f by 1.00018 and q by 1.01444 vdd1 vdd 0 dc 15 vss1 vss 0 dc -15 v1 vin 0 dc 0 ac 1 sin 0 1V 1kHz rs vin 0 100k * filter emulating speaker response c3s vin c3c4 0.1u c4s c3c4 c4r4 0.1u r3s fltrin c3c4 19648.8 r4s c4r4 0 63662 e2 fltrin 0 c4r4 0 1 * electonic equalizer filter r3 fltrin 0 47k j1 vdd fltrin j1s 2N3819 j2 j1s vss j2s 2N3819 r4 j2s vss 390 c1 j1s c1c2 0.1u c2 c1c2 c2r2 0.1u * r1 = 8021.46 - 234.69 r1 j3s c1c2 7786.77 r2 c2r2 0 636398 j3 vdd c2r2 j3s 2N3819 j4 j3s vss j4s 2N3819 r5 j4s vss 390 j5 vdd c2r2 j5s 2N3819 j6 j5s vss j6s 2N3819 r6 j6s vss 390 c3 j5s vout 10u r7 vout 0 100k .model 2N3819 njf vto=-3.0 beta=1.3m .end .control pz c4r4 0 c2r2 0 vol pol print all *tran 1u 0.1 0 1u *fourier 1k vout ac dec 30 10 100 plot db(vout) db(fltrin) db(vout/fltrin) .endc |
Figure 12: Bode plot from fully optimized SPICE deck. |
Figure 13: Fully optimized SPICE deck from iteration 5 with filter components rounded to standard 1% values. |
* filter simulation for input
parameters f = 45Hz and q = 0.9 * Filter scaled: f by 1.00018 and q by 1.01444 vdd1 vdd 0 dc 15 vss1 vss 0 dc -15 v1 vin 0 dc 0 ac 1 sin 0 1.41421V 1kHz rs vin 0 100k * filter emulating speaker response c3s vin c3c4 0.1u c4s c3c4 c4r4 0.1u r3s fltrin c3c4 19648.8 r4s c4r4 0 63662 e2 fltrin 0 c4r4 0 1 * electonic equalizer filter r3 fltrin 0 47k j1 vdd fltrin j1s 2N3819 j2 j1s vss j2s 2N3819 r4 j2s vss 390 c1 j1s c1c2 0.1u c2 c1c2 c2r2 0.1u * r1 = 8021.46 - 234.69 r1 j3s c1c2 7.87k r2 c2r2 0 634k j3 vdd c2r2 j3s 2N3819 j4 j3s vss j4s 2N3819 r5 j4s vss 390 j5 vdd c2r2 j5s 2N3819 j6 j5s vss j6s 2N3819 r6 j6s vss 390 c3 j5s vout 10u r7 vout 0 100k .model 2N3819 njf vto=-3.0 beta=1.3m .end .control pz c4r4 0 c2r2 0 vol pol print all tran 1u 0.1 0 1u fourier 1k vout ac dec 30 10 100 plot db(vout) db(fltrin) db(vout/fltrin) .endc |
Figure 14: Bode plot from fully optimized SPICE deck with filter components rounded to standard 1% values. |
Figure 15: Spice distortion results from fourier analysis for 1kHz | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Fourier analysis for vout: No. Harmonics: 10, THD: 0.00156519 %, Gridsize: 200, Interpolation Degree: 1
|
|
Figure 14: Noise analysis returns noise level of –115dB. |
SpiceOpus (c) 1 -> noise
v(vout) v1 dec 30 20 20k
SpiceOpus (c) 2 -> print all inoise_total = 2.531133e-012 onoise_total = 2.974034e-012 SpiceOpus (c) 3 -> print db(onoise_total)/2 db(onoise_total)/2 = -1.15267e+002 SpiceOpus (c) 4 -> |
|
1Authur
B. Williams and Fred J. Taylor, Electronic Filter Design Handbook,
McGraw-Hill, New York, 1988.
pp.
3-12–3-15, "Using Predistorted Designs".
Document History
March 18, 2017 Created.
March 19, 2017 Corrected incorrect filenames in program use
instructions and added a brief paragraph on buffer design.