Logo Search packages:      
Sourcecode: ktechlab version File versions

jfet.cpp

/***************************************************************************
 *   Copyright (C) 2005-2006 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 "jfet.h"

#include <cmath>
using namespace std;

const uint JFET::PinD = 0;
const uint JFET::PinG = 1;
const uint JFET::PinS = 2;


//BEGIN class JFETSettings
JFETSettings::JFETSettings()
{
      V_Th = -2.0;
      beta = 1e-4;            
      I_S = 1e-14;
      N = 1.0;
      N_R = 2.0;
}
//END class JFETSettings


//BEGIN class JFETState

JFETState::JFETState()
{
      reset();
}


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


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

//END class JFETState


//BEGIN class JFET
JFET::JFET( JFET_type type )
{
      switch ( type )
      {
      case nJFET:
            m_pol = 1;
            break;
                  
      case pJFET:
            m_pol = -1;
            break;
      }
      
      V_GS_prev = 0.0;
      V_GD_prev = 0.0;
      m_numCNodes = 3;
      updateLim();
}


JFET::~JFET()
{
}


00097 void JFET::add_initial_dc()
{
      V_GS_prev = 0.0;
      V_GD_prev = 0.0;
      m_os.reset();
      update_dc();
}


00106 void JFET::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_GS = V_G - V_S;
      double V_GD = V_G - V_D;
      double V_DS = V_D - V_S;
      
      double I_GS, I_GD, I_DS, g_GS, g_GD, g_DS, g_m;
      
      calcIg( V_GS, V_GD, V_DS,
            & I_GS, & I_GD, & I_DS,
            & g_GS, & g_GD, & g_DS,
            & g_m );
      
      m_cnodeI[PinD] = I_GD - I_DS;
      m_cnodeI[PinS] = I_GS + I_DS;
      m_cnodeI[PinG] = -(m_cnodeI[PinD] + m_cnodeI[PinS]);
}


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


00152 void JFET::calc_eq()
{
      double N = m_jfetSettings.N;
      
      double V_D = p_cnode[PinD]->v;
      double V_G = p_cnode[PinG]->v;
      double V_S = p_cnode[PinS]->v;
      
      // GS diode
      double V_GS = V_G - V_S;
      V_GS_prev = V_GS = diodeVoltage( V_GS, V_GS_prev, N, V_lim );

      // GD diode
      double V_GD = V_G - V_D;
      V_GD_prev = V_GD = diodeVoltage( V_GD, V_GD_prev, N, V_lim );
      
      double V_DS = V_GS - V_GD;
      
      double I_GS, I_GD, I_DS, g_GS, g_GD, g_DS, g_m;
      
      calcIg( V_GS, V_GD, V_DS,
                  & I_GS, & I_GD, & I_DS,
                  & g_GS, & g_GD, & g_DS,
                  & g_m );

      // current sources
      double IeqG = I_GS - (g_GS * V_GS);
      double IeqD = I_GD - (g_GD * V_GD);
      double IeqS = I_DS - (g_m * V_GS) - (g_DS * V_DS);
      
      m_ns.A[PinG][PinG] = +g_GS + g_GD;
      m_ns.A[PinG][PinD] = -g_GD;
      m_ns.A[PinG][PinS] = -g_GS;
      
      m_ns.A[PinD][PinG] = -g_GD + g_m;
      m_ns.A[PinD][PinD] = +g_DS + g_GD;
      m_ns.A[PinD][PinS] = -g_m - g_DS;
      
      m_ns.A[PinS][PinG] = -g_GS - g_m;
      m_ns.A[PinS][PinD] = -g_DS;
      m_ns.A[PinS][PinS] = +g_GS + g_DS + g_m;
      
      m_ns.I[PinG] = (- IeqG - IeqD) * m_pol;
      m_ns.I[PinD] = (+ IeqD - IeqS) * m_pol;
      m_ns.I[PinS] = (+ IeqG + IeqS) * m_pol;
}


void JFET::calcIg( double V_GS, double V_GD, double V_DS,
               double * I_GS, double * I_GD, double * I_DS,
               double * g_GS, double * g_GD, double * g_DS,
               double * g_m ) const
{
      double V_Th = m_jfetSettings.V_Th;
      double beta = m_jfetSettings.beta;
      double I_S = m_jfetSettings.I_S;
      double N = m_jfetSettings.N;
      double N_R = m_jfetSettings.N_R;
      
      // GS diode
      double g_tiny = (V_GS < (- 10 * V_T * N)) ? I_S : 0;
      *g_GS = diodeConductance( V_GS, I_S, N ) + diodeConductance( V_GS, 0, N_R ) + g_tiny;
      *I_GS = diodeCurrent( V_GS, I_S, N ) + diodeCurrent( V_GS, 0, N_R ) + g_tiny * V_GS;

      // GD diode
      g_tiny = (V_GD < (- 10 * V_T * N)) ? I_S : 0;
      *g_GD = diodeConductance( V_GD, I_S, N ) + diodeConductance( V_GD, 0, N_R ) + g_tiny;
      *I_GD = diodeCurrent( V_GD, I_S, N ) + diodeCurrent( V_GD, 0, N_R ) + (g_tiny * V_GD);

      double V_GST = V_GS - V_Th;
      double V_GDT = V_GD - V_Th;
      
      *I_DS = 0;
      *g_m = 0;
      *g_DS = 0;
      
      switch ( getOpRegion( V_DS, V_GST, V_GDT ) )
      {
      case NormalCutoff:
      case InverseCutoff:
            break;
                  
      case NormalSaturation:
            *I_DS = beta * V_GST * V_GST;
            *g_DS = 0;
            *g_m  = beta * 2 * V_GST;
            break;
                  
      case NormalLinear:
            *I_DS = beta * V_DS * (2 * V_GST - V_DS);
            *g_DS = beta * 2 * (V_GST - V_DS);
            *g_m  = beta * 2 * V_DS;
            break;
            
      case InverseSaturation:
            *I_DS = - beta * V_GDT * V_GDT;
            *g_DS = beta * 2 * V_GDT;
            *g_m  = - beta * 2 * V_GDT;
            break;
            
      case InverseLinear:
            *I_DS = beta * V_DS * (2 * V_GDT + V_DS);
            *g_DS = 2 * beta * V_GDT;
            *g_m  = beta * 2 * V_DS;
            break;
      }
}


JFET::OpRegion JFET::getOpRegion( double V_DS, double V_GST, double V_GDT ) const
{
      if ( V_DS > 0 )
      {
            if ( V_GST <= 0 )
                  return NormalCutoff;
            else if ( V_GST <= V_DS )
                  return NormalSaturation;
            else  return NormalLinear;
      } else {
            if ( V_GDT <= 0 )
                  return InverseCutoff;
            else if ( V_GDT <= -V_DS )
                  return InverseSaturation;
            else  return InverseLinear;
      }
}


void JFET::setJFETSettings( const JFETSettings & settings )
{
      m_jfetSettings = settings;
      updateLim();

      if (p_eSet)
            p_eSet->setCacheInvalidated();
}


void JFET::updateLim()
{
      double I_S = m_jfetSettings.I_S;
      double N = m_jfetSettings.N;
      V_lim = diodeLimitedVoltage( I_S, N );
}

//END class JFET


Generated by  Doxygen 1.6.0   Back to index