diode.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2003-2004 by David Saxton                               *
00003  *   david@bluehaze.org                                                    *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  ***************************************************************************/
00010  
00011 #include <vector>
00012 #include "diode.h"
00013 #include "elementset.h"
00014 #include "matrix.h"
00015 
00016 #include <cmath>
00017 
00018 
00019 //BEGIN class Diode Settings
00020 DiodeSettings::DiodeSettings()
00021 {
00022         reset();
00023 }
00024 
00025 void DiodeSettings::reset()
00026 {
00027         I_S = 1e-15;
00028         N = 1.0;
00029         V_B = 4.7;
00030 }
00031 //END class Diode Settings
00032 
00033 //BEGIN class Diode
00034 Diode::Diode()
00035         : NonLinear()
00036 {
00037         m_numCNodes = 2;
00038         g_new = g_old = I_new = I_old = V_prev = 0.0;
00039 }
00040 
00041 Diode::~Diode()
00042 {
00043 }
00044 
00045 void Diode::add_map()
00046 {
00047         if (!b_status) return;
00048         
00049         if ( !p_cnode[0]->isGround ) {
00050                 p_A->setUse( p_cnode[0]->n(), p_cnode[0]->n(), Map::et_unstable, false );
00051         }
00052 
00053         if ( !p_cnode[1]->isGround ) {
00054                 p_A->setUse( p_cnode[1]->n(), p_cnode[1]->n(), Map::et_unstable, false );
00055         }
00056         
00057         if ( !p_cnode[0]->isGround && !p_cnode[1]->isGround ) {
00058                 p_A->setUse( p_cnode[0]->n(), p_cnode[1]->n(), Map::et_unstable, false );
00059                 p_A->setUse( p_cnode[1]->n(), p_cnode[0]->n(), Map::et_unstable, false );
00060         }
00061 }
00062 
00063 void Diode::add_initial_dc()
00064 {
00065         g_new = g_old = I_new = I_old = V_prev = 0.0;
00066         update_dc();
00067 }
00068 
00069 double Diode::current() const
00070 {
00071         if (!b_status) return 0.0;
00072 
00073         double I;
00074         calcIg(p_cnode[0]->v - p_cnode[1]->v, &I, 0);
00075 
00076         return I;
00077 }
00078 
00079 void Diode::updateCurrents()
00080 {
00081         if (!b_status) return;
00082 
00083         m_cnodeI[1] = current();
00084         m_cnodeI[0] = -m_cnodeI[1];
00085 }
00086 
00087 void Diode::update_dc()
00088 {
00089         if (!b_status) return;
00090 
00091         calc_eq();
00092 
00093         A_g( 0, 0 ) += g_new - g_old;
00094         A_g( 1, 1 ) += g_new - g_old;
00095         A_g( 0, 1 ) -= g_new - g_old;
00096         A_g( 1, 0 ) -= g_new - g_old;
00097 
00098         b_i( 0 ) -= I_new - I_old;
00099         b_i( 1 ) += I_new - I_old;
00100 
00101         g_old = g_new;
00102         I_old = I_new;
00103 }
00104 
00105 #ifndef MIN
00106 # define MIN(x,y) (((x) < (y)) ? (x) : (y))
00107 #endif
00108 
00109 void Diode::calc_eq()
00110 {
00111         double I_S = m_diodeSettings.I_S;
00112         double N = m_diodeSettings.N;
00113         double V_B = m_diodeSettings.V_B;
00114 
00115         double v = p_cnode[0]->v - p_cnode[1]->v;
00116 
00117         // adjust voltage to help convergence
00118         double V_crit = diodeCriticalVoltage( I_S, N * V_T );
00119         if (V_B != 0 && v < MIN (0, -V_B + 10 * N * V_T)) {
00120                 double V = -(v + V_B);
00121                 V = diodeVoltage( V, -(V_prev + V_B), V_T * N, V_crit );
00122                 v = -(V + V_B);
00123         } else  v = diodeVoltage( v, V_prev, V_T * N, V_crit );
00124 
00125         V_prev = v;
00126 
00127         double I_D;
00128         calcIg( v, & I_D, & g_new );
00129 
00130         I_new = I_D - (v * g_new);
00131 }
00132 
00133 void Diode::calcIg(double V, double *I_D, double *g) const
00134 {
00135         double I_S = m_diodeSettings.I_S;
00136         double N = m_diodeSettings.N;
00137         double V_B = m_diodeSettings.V_B;
00138 
00139         double gtiny = (V < - 10 * V_T * N && V_B != 0) ? I_S : 0;
00140 
00141         if ( V >= (-3 * N * V_T) ) {
00142                 if(g) *g = diodeConductance( V, I_S, V_T * N ) + gtiny;
00143                 *I_D = diodeCurrent( V, I_S, V_T * N ) + (gtiny * V);
00144         } else if ( V_B == 0 || V >= -V_B ) {
00145                 double a = (3 * N * V_T) / (V * M_E);
00146                 a = a * a * a;
00147                 *I_D = (-I_S * (1 + a)) + (gtiny * V);
00148                 if ( g ) *g = ((I_S * 3 * a) / V) + gtiny;
00149         } else {
00150                 double a = exp( -(V_B + V) / N / V_T );
00151                 *I_D = (-I_S * a) + (gtiny * V);
00152                 if ( g ) *g = I_S * a / V_T / N + gtiny;
00153         }
00154 }
00155 
00156 void Diode::setDiodeSettings( const DiodeSettings & settings )
00157 {
00158         m_diodeSettings = settings;
00159         if (p_eSet) p_eSet->setCacheInvalidated();
00160 }
00161 
00162 //END class Diode
00163 

Generated on Tue May 8 17:05:29 2007 for KTechLab by  doxygen 1.5.1