bjt.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2003-2005 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 "bjt.h"
00012 #include "diode.h"
00013 #include "elementset.h"
00014 
00015 #include <cmath>
00016 using namespace std;
00017 
00018 //BEGIN class BJTSettings
00019 BJTSettings::BJTSettings()
00020 {
00021         I_S = 1e-16;
00022         N_F = 1.0;
00023         N_R = 1.0;
00024         B_F = 100.0;
00025         B_R = 1.0;
00026 }
00027 //END class BJTSettings
00028 
00029 //BEGIN class BJTState
00030 BJTState::BJTState() {
00031         reset();
00032 }
00033 
00034 void BJTState::reset() {
00035         for(unsigned i = 0; i < 3; ++i ) {
00036                 for(unsigned j = 0; j < 3; ++j ) A[i][j] = 0.0;
00037 
00038                 I[i] = 0.0;
00039         }
00040 }
00041 
00042 BJTState BJTState::operator-(const BJTState & s ) const {
00043         BJTState newState(*this );
00044 
00045         for(unsigned i = 0; i < 3; ++i ) {
00046                 for(unsigned j = 0; j < 3; ++j ) newState.A[i][j] -= s.A[i][j];
00047 
00048                 newState.I[i] -= s.I[i];
00049         }
00050 
00051         return newState;
00052 }
00053 //END class BJTState
00054 
00055 
00056 //BEGIN class BJT
00057 BJT::BJT(const bool isNPN )
00058         : NonLinear()
00059 {
00060         V_BE_prev = 0.0;
00061         V_BC_prev = 0.0;
00062         m_pol = isNPN ? 1 : -1;
00063         m_numCNodes = 3;
00064 }
00065 
00066 BJT::~BJT()
00067 {
00068 }
00069 
00070 void BJT::add_map()
00071 {
00072         if(!b_status) return;
00073 
00074         if(!p_cnode[0]->isGround ) {
00075                 p_A->setUse(p_cnode[0]->n(), p_cnode[0]->n(), Map::et_unstable, false );
00076         }
00077 
00078         if(!p_cnode[1]->isGround ) {
00079                 p_A->setUse(p_cnode[1]->n(), p_cnode[1]->n(), Map::et_unstable, false );
00080         }
00081 
00082         if(!p_cnode[2]->isGround ) {
00083                 p_A->setUse(p_cnode[2]->n(), p_cnode[2]->n(), Map::et_unstable, false );
00084         }
00085         
00086         if(!p_cnode[0]->isGround && !p_cnode[2]->isGround ) {
00087                 p_A->setUse(p_cnode[0]->n(), p_cnode[2]->n(), Map::et_unstable, false );
00088                 p_A->setUse(p_cnode[2]->n(), p_cnode[0]->n(), Map::et_unstable, false );
00089         }
00090 
00091         if(!p_cnode[1]->isGround && !p_cnode[2]->isGround ) {
00092                 p_A->setUse(p_cnode[2]->n(), p_cnode[1]->n(), Map::et_unstable, false );
00093                 p_A->setUse(p_cnode[1]->n(), p_cnode[2]->n(), Map::et_unstable, false );
00094         }
00095 }
00096 
00097 void BJT::add_initial_dc()
00098 {
00099         V_BE_prev = 0.0;
00100         V_BC_prev = 0.0;
00101         m_os.reset();
00102         update_dc();
00103 }
00104 
00105 void BJT::updateCurrents()
00106 {
00107         if(!b_status) return;
00108 
00109         double V_B = p_cnode[0]->v;
00110         double V_C = p_cnode[1]->v;
00111         double V_E = p_cnode[2]->v;
00112 
00113         double V_BE = (V_B - V_E) * m_pol;
00114         double V_BC = (V_B - V_C) * m_pol;
00115 
00116         double I_BE, I_BC, I_T, g_BE, g_BC, g_IF, g_IR;
00117         calcIg(V_BE, V_BC, & I_BE, &I_BC, &I_T, &g_BE, &g_BC, &g_IF, &g_IR );
00118 
00119         m_cnodeI[1] = I_BC - I_T;
00120         m_cnodeI[2] = I_BE + I_T;
00121         m_cnodeI[0] = -(m_cnodeI[1] + m_cnodeI[2]);
00122 }
00123 
00124 
00125 void BJT::update_dc()
00126 {
00127         if(!b_status) return;
00128 
00129         calc_eq();
00130 
00131         BJTState diff = m_ns - m_os;
00132         for(unsigned i = 0; i < 3; ++i ) {
00133                 for(unsigned j = 0 ; j < 3; ++j ) A_g(i, j ) += diff.A[i][j];
00134 
00135                 b_i(i ) += diff.I[i];
00136         }
00137 
00138         m_os = m_ns;
00139 }
00140 
00141 
00142 void BJT::calc_eq()
00143 {
00144         double V_B = p_cnode[0]->v;
00145         double V_C = p_cnode[1]->v;
00146         double V_E = p_cnode[2]->v;
00147 
00148         double V_BE = (V_B - V_E) * m_pol;
00149         double V_BC = (V_B - V_C) * m_pol;
00150 
00151         double I_S = m_bjtSettings.I_S;
00152         double N_F = m_bjtSettings.N_F;
00153         double N_R = m_bjtSettings.N_R;
00154 
00155         // adjust voltage to help convergence
00156         double V_BEcrit = diodeCriticalVoltage(I_S, N_F * V_T );
00157         double V_BCcrit = diodeCriticalVoltage(I_S, N_R * V_T );
00158         V_BE_prev = V_BE = diodeVoltage(V_BE, V_BE_prev, V_T * N_F, V_BEcrit );
00159         V_BC_prev = V_BC = diodeVoltage(V_BC, V_BC_prev, V_T * N_R, V_BCcrit );
00160 
00161         double I_BE, I_BC, I_T, g_BE, g_BC, g_IF, g_IR;
00162         calcIg(V_BE, V_BC, & I_BE, & I_BC, & I_T, & g_BE, & g_BC, & g_IF, & g_IR );
00163 
00164         double I_eq_B = I_BE - V_BE * g_BE;
00165         double I_eq_C = I_BC - V_BC * g_BC;
00166         double I_eq_E = I_T - V_BE * g_IF + V_BC * g_IR;
00167 
00168         m_ns.A[0][0] = g_BC + g_BE;
00169         m_ns.A[0][1] = -g_BC;
00170         m_ns.A[0][2] = -g_BE;
00171 
00172         m_ns.A[1][0] = -g_BC + (g_IF - g_IR);
00173         m_ns.A[1][1] = g_IR + g_BC;
00174         m_ns.A[1][2] = -g_IF;
00175 
00176         m_ns.A[2][0] = -g_BE - (g_IF - g_IR);
00177         m_ns.A[2][1] = -g_IR;
00178         m_ns.A[2][2] = g_BE + g_IF;
00179 
00180         m_ns.I[0] = (-I_eq_B - I_eq_C) * m_pol;
00181         m_ns.I[1] = (+I_eq_C - I_eq_E) * m_pol;
00182         m_ns.I[2] = (+I_eq_B + I_eq_E) * m_pol;
00183 }
00184 
00185 void BJT::calcIg(double V_BE, double V_BC, double *I_BE, double *I_BC, double *I_T, double *g_BE, double *g_BC, double *g_IF, double *g_IR )
00186 {
00187         double I_S = m_bjtSettings.I_S;
00188         double N_F = m_bjtSettings.N_F;
00189         double N_R = m_bjtSettings.N_R;
00190         double B_F = m_bjtSettings.B_F;
00191         double B_R = m_bjtSettings.B_R;
00192 
00193         // base-emitter diodes
00194         double g_tiny = (V_BE < (-10 * V_T * N_F)) ? I_S : 0;
00195 
00196         double I_F;
00197         diodeJunction(V_BE, I_S, V_T * N_F, & I_F, g_IF );
00198 
00199         double I_BEI = I_F / B_F;
00200         double g_BEI = *g_IF / B_F;
00201         double I_BEN = g_tiny * V_BE;
00202         double g_BEN = g_tiny;
00203         *I_BE = I_BEI + I_BEN;
00204         *g_BE = g_BEI + g_BEN;
00205 
00206         // base-collector diodes
00207         g_tiny = (V_BC < (-10 * V_T * N_R)) ? I_S : 0;
00208 
00209         double I_R;
00210         diodeJunction(V_BC, I_S, V_T * N_R, & I_R, g_IR );
00211 
00212         double I_BCI = I_R / B_R;
00213         double g_BCI = *g_IR / B_R;
00214         double I_BCN = g_tiny * V_BC;
00215         double g_BCN = g_tiny;
00216         *I_BC = I_BCI + I_BCN;
00217         *g_BC = g_BCI + g_BCN;
00218 
00219         *I_T = I_F - I_R;
00220 }
00221 
00222 void BJT::setBJTSettings(const BJTSettings & settings )
00223 {
00224         m_bjtSettings = settings;
00225 
00226         if(p_eSet) p_eSet->setCacheInvalidated();
00227 }
00228 
00229 //END class BJT
00230 
00231 

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