| 
							- //wdf.cpp
 - 
 - #include <stdio.h>
 - #include <inttypes.h>
 - #include <cmath>
 - #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 <class Port1, class Port2>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 <class Port>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 <class Port1, class Port2>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<ITER; ++i) {
 -                 vgn = *i1 - fg(*i1)*(*i1-*i2)/(fg(*i1)-fg(*i2));
 -                 *i2 = *i1;
 -                 *i1 = vgn;
 -                 if ((fabs(fg(vgn))) < EPSILON) break;
 -         }
 -         if ((fabs(fg(vgn)) >= 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<ITER; ++i) {
 -                 vgn = *i1 - fg(*i1)/fgdash(*i1);
 -                 *i1 = vgn;
 -                 if (fabs(fg(vgn)) < EPSILON) break;
 -         } 
 -         if ((fabs(fg(vgn)) >= 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<ITER; ++i) {
 -                 vpn = *i1 - fp(*i1)/fpdash(*i1);
 -                 *i1 = vpn;
 -                 if (fabs(fp(vpn)) < EPSILON) break;
 -         }
 -         if ((fabs(fp(vpn)) >= 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<ITER; ++i) {
 -                 vpn = *i1 - fp(*i1)*(*i1-*i2)/(fp(*i1)-fp(*i2));
 -                 *i2 = *i1;
 -                 *i1 = vpn;
 -                 if ((fabs(fp(vpn))) < EPSILON) break;
 -         }
 - 
 -         if ((fabs(fp(vpn)) >= 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;
 - }
 
 
  |