//wdf.cpp #include #include #include #include "wdf.h" using std::abs; WDF::WDF() {} void WDF::setWD(T val) { WD = val; state = val; DUMP(printf("DOWN\tWDF\t%c\tWD=%f\tWU=%f\tV=%f\n",type,WD,WU,(WD+WU)/2.0)); } void OnePort::setWD(T val) { WD = val; state = val; DUMP(printf("DOWN\tOneport\t%c\tWD=%f\tWU=%f\tV=%f\n",type,WD,WU,(WD+WU)/2.0)); } T WDF::Voltage() { T Volts = (WU + WD) / 2.0; return Volts; } T WDF::Current() { T Amps = (WU - WD) / (2.0*PortRes); return Amps; } template ser::ser(Port1 *l, Port2 *r) : Adaptor(THREEPORT) { left = l; right = r; PortRes = l->PortRes + r->PortRes; type = 'S'; } ser::ser(R* l, par* r) : Adaptor(THREEPORT) { left = l; right = r; PortRes = l->PortRes + r->PortRes; type = 'S'; } ser::ser(C* l, R* r) : Adaptor(THREEPORT) { left = l; right = r; PortRes = l->PortRes + r->PortRes; type = 'S'; } ser::ser(C* l, V* r) : Adaptor(THREEPORT) { left = l; right = r; PortRes = l->PortRes + r->PortRes; type = 'S'; } template inv::inv(Port *l) : Adaptor(PASSTHROUGH) { left = l; PortRes = l->PortRes; type = 'I'; } inv::inv(ser *l) : Adaptor(PASSTHROUGH) { left = l; PortRes = l->PortRes; type = 'I'; } T ser::waveUp() { //Adaptor::WU = -left->waveUp() - right->waveUp(); WDF::WU = -left->waveUp() - right->waveUp(); DUMP(printf("UP\tser\tWU=%f\tWD=%f\tV=%f\n",WU,WD,(WD+WU)/2.0)); return WU; } template par::par(Port1 *l, Port2 *r) : Adaptor(THREEPORT) { left = l; right = r; PortRes = 1.0 / (1.0 / l->PortRes + 1.0 / r->PortRes); type = 'P'; } par::par(inv* l, R* r) : Adaptor(THREEPORT) { left = l; right = r; PortRes = 1.0 / (1.0 / l->PortRes + 1.0 / r->PortRes); type = 'P'; } par::par(inv* l, V* r) : Adaptor(THREEPORT) { left = l; right = r; PortRes = 1.0 / (1.0 / l->PortRes + 1.0 / r->PortRes); type = 'P'; } par::par(C* l, R* r) : Adaptor(THREEPORT) { left = l; right = r; PortRes = 1.0 / (1.0 / l->PortRes + 1.0 / r->PortRes); type = 'P'; } T par::waveUp() { T G23 = 1.0 / left->PortRes + 1.0 / right->PortRes; WDF::WU = (1.0 / left->PortRes)/G23*left->waveUp() + (1.0 / right->PortRes)/G23*right->waveUp(); DUMP(printf("UP\tpar\tWU=%f\tWD=%f\tV=%f\n",WU,WD,(WD+WU)/2.0)); return WU; } Adaptor::Adaptor(int flag) { WU = 0.0; WD = 0.0; switch (flag) { case ONEPORT: left = NULL; right = NULL; break; case PASSTHROUGH: right = NULL; break; default: case THREEPORT: break; } } void ser::setWD(T waveparent) { Adaptor::setWD(waveparent); DUMP(printf("SER WP=%f\n",waveparent)); left->setWD(left->WU-(2.0*left->PortRes/(PortRes+left->PortRes+right->PortRes))*(waveparent+left->WU+right->WU)); right->setWD(right->WU-(2.0*right->PortRes/(PortRes+left->PortRes+right->PortRes))*(waveparent+left->WU+right->WU)); } void par::setWD(T waveparent) { Adaptor::setWD(waveparent); DUMP(printf("PAR WP=%f\n",waveparent)); T p = 2.0*(waveparent/PortRes + left->WU/left->PortRes + right->WU/right->PortRes)/(1.0/PortRes + 1.0/left->PortRes + 1.0/right->PortRes); left->setWD((p - left->WU)); right->setWD((p - right->WU)); } T inv::waveUp() { ///////////WD = -left->WD; WU = -left->waveUp(); //- DUMP(printf("UP\tinv\tWU=%f\tWD=%f\tV=%f\n",WU,WD,(WD+WU)/2.0)); return WU; } void inv::setWD(T waveparent) { WDF::setWD(waveparent); DUMP(printf("INV WP=%f\n",waveparent)); //left->WD = -waveparent; //- ///////////left->WU = -WU; left->setWD(-waveparent); //- } R::R(T res) : Adaptor(ONEPORT) { PortRes = res; type = 'R'; } T R::waveUp() { WU = 0.0; DUMP(printf("UP\tR\tWU=%f\tWD=%f\tV=%f\n",WU, WD,(WD+WU)/2.0)); return WU; } C::C(T c, T fs) : Adaptor(ONEPORT) { PortRes = 1.0/(2.0*c*fs); state = 0.0; type = 'C'; } T C::waveUp() { WU = state; DUMP(printf("UP\tC\tWU=%f\tWD=%f\tV=%f\n",WU,WD,(WD+WU)/2.0)); return WU; } V::V(T ee, T r) : Adaptor(ONEPORT) { e = ee; PortRes = r; WD = 0.0; //always? type = 'V'; } T V::waveUp() { T watts = 100.0; WU = 2.0*e - WD; if (Voltage()*Current() > watts) WU *= 0.999;//0.9955; DUMP(printf("UP\tV\tWU=%f\tWD=%f\tV=%f\n",WU, WD,(WD+WU)/2.0)); return WU; } inline T _exp(const T x) { if(x < 10.0 && x > 10.0) return 1.0 + x + x*x/2.0 + x*x*x/6.0 + x*x*x*x/24.0 + x*x*x*x*x/120.0 + x*x*x*x*x*x/720.0 + x*x*x*x*x*x*x/5040.0; else return exp(x); } inline T _log(const T x) { if(x > 10) return log(x); const T a=(x-1)/(x+1); return 2.0*(a+a*a*a/3.0+a*a*a*a*a/5.0+a*a*a*a*a*a*a/7.0+a*a*a*a*a*a*a*a*a/9.0); } inline T _pow(const T a, const T b) { return pow(a,b); } T Triode::ffg(T VG) { return (G.WD-G.PortRes*(gg*_pow(_log(1.0+_exp(cg*VG))/cg,e)+ig0)-VG); } T Triode::fgdash(T VG) { T a1 = exp(cg*VG); T b1 = -e*pow(log(a1+1.0)/cg,e-1.0); T c1 = a1/(a1+1.0)*gg*G.PortRes; return (b1*c1); } T Triode::ffp(T VP) { static bool prepared = false; static double scale; static double coeff[4]; if(!prepared) { //go go series expansion const double L2 = log(2.0); const double scale = pow(L2,gamma-2)/(8.0*pow(c,gamma)); coeff[0] = 8.0*L2*L2*scale; coeff[1] = gamma*c*L2*4*scale; coeff[2] = (c*c*gamma*gamma+L2*c*c*gamma-c*c*gamma)*scale; coeff[3] = 0.0; prepared = true; } double A = VP/mu+vg; return (P.WD+P.PortRes*((g*(coeff[0]+coeff[1]*A+coeff[2]*A*A))+(G.WD-vg)/G.PortRes)-VP); printf("%f\n", VP/mu+vg); return (P.WD+P.PortRes*((g*_pow(_log(1.0+_exp(c*(VP/mu+vg)))/c,gamma))+(G.WD-vg)/G.PortRes)-VP); } // ^ T Triode::fpdash(T VP) { T a1 = exp(c*(vg+VP/mu)); T b1 = a1/(mu*(a1+1.0)); T c1 = g*gamma*P.PortRes*pow(log(a1+1.0)/c,gamma-1.0); return (c1*b1); } T Triode::ffk() { return (K.WD - K.PortRes*(g*pow(log(1.0+exp(c*(vp/mu+vg)))/c,gamma))); } /* T Triode::secantfg(T *i1, T *i2) { T vgn = 0.0; T init = *i1; for (int i = 0; i= EPSILON)) { DUMP(fprintf(stderr,"Vg did not converge\n")); return init; } return vgn; } T Triode::newtonfg(T *i1) { T init = *i1; if (fabs(fg(*i1)) < EPSILON || fgdash(*i1)==0.0) return *i1; T vgn = 0.0; for (int i = 0; i= EPSILON)) { // vgn = init; DUMP(fprintf(stderr,"Vg did not converge\n")); } return vgn; } T Triode::newtonfp(T *i1) { T init = *i1; if (fabs(fp(*i1)) < EPSILON || fpdash(*i1)==0.0) return *i1; T vpn = 0.0; for (int i = 0; i= EPSILON)) { // vpn = init; DUMP(fprintf(stderr,"Vp did not converge\n")); } return vpn; } T Triode::secantfp(T *i1, T *i2) { T vpn = 0.0; for (int i = 0; i= EPSILON)) DUMP(fprintf(stderr,"Vp did not converge\n")); return vpn; } */ //****************************************************************************80 // Purpose: // // Brent's method root finder. // // Licensing: // // This code below is distributed under the GNU LGPL license. // // Author: // // Original FORTRAN77 version by Richard Brent. // C++ version by John Burkardt. // Adapted for zamvalve by Damien Zammit. T Triode::r8_abs ( T x ) { T value; if ( 0.0 <= x ) { value = x; } else { value = - x; } return value; } Triode::Triode() { T r = 1.0; while ( 1.0 < ( T ) ( 1.0 + r ) ) { r = r / 2.0; } r *= 2.0; r8_epsilon = r; } T Triode::r8_max ( T x, T y ) { T value; if ( y < x ) { value = x; } else { value = y; } return value; } T Triode::r8_sign ( T x ) { T value; if ( x < 0.0 ) { value = -1.0; } else { value = 1.0; } return value; } T Triode::zeroffp ( T a, T b, T t ) { T c; T d; T e; T fa; T fb; T fc; T m; T macheps; T p; T q; T r; T s; T sa; T sb; T tol; // // Make local copies of A and B. // sa = a; sb = b; fa = ffp ( sa ); fb = ffp ( sb ); c = sa; fc = fa; e = sb - sa; d = e; macheps = r8_epsilon; for ( ; ; ) { if ( abs ( fc ) < abs ( fb ) ) { sa = sb; sb = c; c = sa; fa = fb; fb = fc; fc = fa; } tol = 2.0 * macheps * abs ( sb ) + t; m = 0.5 * ( c - sb ); if ( abs ( m ) <= tol || fb == 0.0 ) { break; } if ( abs ( e ) < tol || abs ( fa ) <= abs ( fb ) ) { e = m; d = e; } else { s = fb / fa; if ( sa == c ) { p = 2.0 * m * s; q = 1.0 - s; } else { q = fa / fc; r = fb / fc; p = s * ( 2.0 * m * q * ( q - r ) - ( sb - sa ) * ( r - 1.0 ) ); q = ( q - 1.0 ) * ( r - 1.0 ) * ( s - 1.0 ); } if ( 0.0 < p ) { q = - q; } else { p = - p; } s = e; e = d; if ( 2.0 * p < 3.0 * m * q - abs ( tol * q ) && p < abs ( 0.5 * s * q ) ) { d = p / q; } else { e = m; d = e; } } sa = sb; fa = fb; if ( tol < abs ( d ) ) { sb = sb + d; } else if ( 0.0 < m ) { sb = sb + tol; } else { sb = sb - tol; } fb = ffp ( sb ); if ( ( 0.0 < fb && 0.0 < fc ) || ( fb <= 0.0 && fc <= 0.0 ) ) { c = sa; fc = fa; e = sb - sa; d = e; } } return sb; } T Triode::zeroffg ( T a, T b, T t ) { T c; T d; T e; T fa; T fb; T fc; T m; T macheps; T p; T q; T r; T s; T sa; T sb; T tol; // // Make local copies of A and B. // sa = a; sb = b; fa = ffg ( sa ); fb = ffg ( sb ); c = sa; fc = fa; e = sb - sa; d = e; macheps = r8_epsilon; for ( ; ; ) { if ( abs ( fc ) < abs ( fb ) ) { sa = sb; sb = c; c = sa; fa = fb; fb = fc; fc = fa; } tol = 2.0 * macheps * abs ( sb ) + t; m = 0.5 * ( c - sb ); if ( abs ( m ) <= tol || fb == 0.0 ) { break; } if ( abs ( e ) < tol || abs ( fa ) <= abs ( fb ) ) { e = m; d = e; } else { s = fb / fa; if ( sa == c ) { p = 2.0 * m * s; q = 1.0 - s; } else { q = fa / fc; r = fb / fc; p = s * ( 2.0 * m * q * ( q - r ) - ( sb - sa ) * ( r - 1.0 ) ); q = ( q - 1.0 ) * ( r - 1.0 ) * ( s - 1.0 ); } if ( 0.0 < p ) { q = - q; } else { p = - p; } s = e; e = d; if ( 2.0 * p < 3.0 * m * q - abs ( tol * q ) && p < abs ( 0.5 * s * q ) ) { d = p / q; } else { e = m; d = e; } } sa = sb; fa = fb; if ( tol < abs ( d ) ) { sb = sb + d; } else if ( 0.0 < m ) { sb = sb + tol; } else { sb = sb - tol; } fb = ffg ( sb ); if ( ( 0.0 < fb && 0.0 < fc ) || ( fb <= 0.0 && fc <= 0.0 ) ) { c = sa; fc = fa; e = sb - sa; d = e; } } return sb; }