Logo Search packages:      
Sourcecode: ktechlab version File versions

mosfet.cpp

/***************************************************************************
 *   Copyright (C) 2005 by David Saxton                                    *
 *   david@bluehaze.org                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

#include "mosfet.h"

#include <cmath>
using namespace std;

#ifndef MAX
# define MAX(x,y) (((x) > (y)) ? (x) : (y))
#endif


//BEGIN class MOSFETSettings
MOSFETSettings::MOSFETSettings()
{
      I_S = 1e-14;
      N = 1.0;
      K_P = 2e-5;
      L = 1e-4;
      W = 1e-4;
      
#if 0
      phi = 0.6;
      T_OX = 1e-7;
      P_b = 0.8;
      M_J = 0.5;
      F_C = 0.5;
      M_JSW = 0.33;
      U_0 = 600.0;
      N_RD = 1;
      N_RS = 1;
#endif
}
//END class MOSFETSettings



//BEGIN class MOSFETState
MOSFETState::MOSFETState()
{
      reset();
}


void MOSFETState::reset()
{
      for ( unsigned i = 0; i < 4; ++i )
      {
            for ( unsigned j = 0; j < 4; ++j )
                  A[i][j] = 0.0;
                  
            I[i] = 0.0;
      }
}


MOSFETState MOSFETState::operator-( const MOSFETState & s ) const
{
      MOSFETState newState( *this );
      
      for ( unsigned i = 0; i < 4; ++i )
      {
            for ( unsigned j = 0; j < 4; ++j )
                  newState.A[i][j] -= s.A[i][j];
                  
            newState.I[i] -= s.I[i];
      }
      
      return newState;
}
//END class MOSFETState



//BEGIN class MOSFET
const uint MOSFET::PinD = 0;
const uint MOSFET::PinG = 1;
const uint MOSFET::PinS = 2;
const uint MOSFET::PinB = 3;


MOSFET::MOSFET( MOSFET_type type )
{
      m_pol = 10;
      switch ( type )
      {
            case neMOSFET:
//          case ndMOSFET:
                  m_pol = 1;
                  break;
                  
            case peMOSFET:
//          case pdMOSFET:
                  m_pol = -1;
                  break;
      }
      
      V_GS_prev = V_GD_prev = V_BD_prev = V_DS_prev = V_BS_prev = 0.0;
      m_numCNodes = 4;
      updateLim();
}


MOSFET::~MOSFET()
{
}

00116 void MOSFET::add_initial_dc()
{
      V_GS_prev = V_GD_prev = V_BD_prev = V_DS_prev = V_BS_prev = 0.0;
      m_os.reset();
      update_dc();
}


00124 void MOSFET::updateCurrents()
{
      if (!b_status)
            return;
      
      double V_D = p_cnode[PinD]->v;
      double V_G = p_cnode[PinG]->v;
      double V_S = p_cnode[PinS]->v;
      double V_B = p_cnode[PinB]->v;

      double V_GD = (V_G - V_D) * m_pol;
      double V_GS = (V_G - V_S) * m_pol;
      double V_BS = (V_B - V_S) * m_pol;
      double V_BD = (V_B - V_D) * m_pol;
      double V_DS = (V_D - V_S) * m_pol;
      
      double I_BS, I_BD, I_DS, g_BS, g_BD, g_DS, g_M;
      calcIg( V_BS, V_BD, V_DS, V_GS, V_GD,
                  & I_BS, & I_BD, & I_DS,
                  & g_BS, & g_BD, & g_DS,
                  & g_M );
      
      m_cnodeI[PinD] = -I_DS + I_BD;
      m_cnodeI[PinB] = -I_BD - I_BS;
      m_cnodeI[PinS] = +I_DS + I_BS;
}


00152 void MOSFET::update_dc()
{
      if (!b_status)
            return;
      
      calc_eq();
      
      MOSFETState diff = m_ns - m_os;
      for ( unsigned i = 0; i < 4; ++i )
      {
            for ( unsigned j = 0 ; j < 4; ++j )
                  A_g( i, j ) += diff.A[i][j];
            
            b_i( i ) += diff.I[i];
      }
      
      m_os = m_ns;
}


00172 void MOSFET::calc_eq()
{
      double N = m_mosfetSettings.N;
      
      double V_D = p_cnode[PinD]->v;
      double V_G = p_cnode[PinG]->v;
      double V_S = p_cnode[PinS]->v;
      double V_B = p_cnode[PinB]->v;

      double V_GD = (V_G - V_D) * m_pol;
      double V_GS = (V_G - V_S) * m_pol;
      double V_BS = (V_B - V_S) * m_pol;
      double V_BD = (V_B - V_D) * m_pol;
      double V_DS = (V_D - V_S) * m_pol;

      // help convergence
      if ( V_DS >= 0 )
      {
            V_GS = fetVoltage( V_GS, V_GS_prev, m_pol );
            
            // recalculate V_DS, same for other similar lines
            V_DS = V_GS - V_GD;
            
            V_DS = fetVoltageDS( V_DS, V_DS_prev );
            V_GD = V_GS - V_DS;
            
            V_BS = diodeVoltage( V_BS, V_BS_prev, N, V_lim );
            V_BD = V_BS - V_DS;
      }
      else
      {
            V_GD = fetVoltage( V_GD, V_GD_prev, m_pol );
            V_DS = V_GS - V_GD;
            
            V_DS = -fetVoltageDS( -V_DS, -V_DS_prev );
            V_GS = V_GD + V_DS;
            
            V_BD = diodeVoltage( V_BD, V_BD_prev, N, V_lim );
            V_BS = V_BD + V_DS;
      }
      
      V_GS_prev = V_GS;
      V_GD_prev = V_GD;
      V_BD_prev = V_BD;
      V_DS_prev = V_DS;
      V_BS_prev = V_BS;
      
      double I_BS, I_BD, I_DS, g_BS, g_BD, g_DS, g_M;
      calcIg( V_BS, V_BD, V_DS, V_GS, V_GD,
                  & I_BS, & I_BD, & I_DS,
                  & g_BS, & g_BD, & g_DS,
                  & g_M );
 
      double I_BD_eq = I_BD - g_BD * V_BD;
      double I_BS_eq = I_BS - g_BS * V_BS;

      double sc = (V_DS >= 0) ? g_M : 0;
      double dc = (V_DS < 0) ? g_M : 0;
      double I_DS_eq = I_DS - (g_DS * V_DS) - (g_M * ((V_DS >= 0) ? V_GS : V_GD));
 
      m_ns.A[PinG][PinG] = 0;
      m_ns.A[PinG][PinD] = 0;
      m_ns.A[PinG][PinS] = 0;
      m_ns.A[PinG][PinB] = 0;
      
      m_ns.A[PinD][PinG] = g_M;
      m_ns.A[PinD][PinD] = g_DS + g_BD - dc;
      m_ns.A[PinD][PinS] = -g_DS - sc;
      m_ns.A[PinD][PinB] = -g_BD;
      
      m_ns.A[PinS][PinG] = -g_M;
      m_ns.A[PinS][PinD] = -g_DS + dc;
      m_ns.A[PinS][PinS] = g_BS + g_DS + sc;
      m_ns.A[PinS][PinB] = -g_BS;
      
      m_ns.A[PinB][PinG] = 0;
      m_ns.A[PinB][PinD] = -g_BD;
      m_ns.A[PinB][PinS] = -g_BS;
      m_ns.A[PinB][PinB] = g_BS + g_BD;

      m_ns.I[PinG] = 0;
      m_ns.I[PinD] = (+I_BD_eq - I_DS_eq) * m_pol;
      m_ns.I[PinS] = (+I_BS_eq + I_DS_eq) * m_pol;
      m_ns.I[PinB] = (-I_BD_eq - I_BS_eq) * m_pol;
}


void MOSFET::calcIg( double V_BS, double V_BD, double V_DS, double V_GS, double V_GD,
                        double * I_BS, double * I_BD, double * I_DS,
                        double * g_BS, double * g_BD, double * g_DS,
                        double * g_M ) const
{
      double I_S = m_mosfetSettings.I_S;
      double N = m_mosfetSettings.N;
      double beta = m_mosfetSettings.beta();
      
      // BD and BS diodes
      mosDiodeJunction( V_BS, I_S, N, I_BS, g_BS );
      mosDiodeJunction( V_BD, I_S, N, I_BD, g_BD );
 
      // bias-dependent threshold voltage
      double V_tst = ((V_DS >= 0) ? V_GS : V_GD) - m_pol;
      
      *g_DS = 0;
      *I_DS = 0;
      *g_M = 0;
      
      if ( V_tst > 0 )
      {
            double V_DS_abs = std::abs( V_DS );
            if ( V_tst <= V_DS_abs )
            {
                  // saturation region
                  *g_M  = beta * V_tst;
                  *I_DS = *g_M * V_tst / 2;
            }
            else
            {
                  // linear region
                  *g_M  = beta * V_DS_abs;
                  *I_DS = *g_M * (V_tst - V_DS_abs / 2);
                  *g_DS = beta * (V_tst - V_DS_abs);
            }
      }
      
      if ( V_DS < 0 )
            *I_DS = -*I_DS;
}


void MOSFET::setMOSFETSettings( const MOSFETSettings & settings )
{
      m_mosfetSettings = settings;
      updateLim();
      if (p_eSet)
            p_eSet->setCacheInvalidated();
}


void MOSFET::updateLim()
{
      double I_S = m_mosfetSettings.I_S;
      double N = m_mosfetSettings.N;
      V_lim = diodeLimitedVoltage( I_S, N );
}
//END class MOSFET

Generated by  Doxygen 1.6.0   Back to index