/// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public void Temperature(BaseSimulation simulation)
        {
            simulation.ThrowIfNull(nameof(simulation));

            var xcbv = 0.0;

            // loop through all the instances
            if (!BaseParameters.Temperature.Given)
            {
                BaseParameters.Temperature.RawValue = simulation.RealState.Temperature;
            }
            Vt  = Constants.KOverQ * BaseParameters.Temperature;
            Vte = ModelParameters.EmissionCoefficient * Vt;

            // this part gets really ugly - I won't even try to explain these equations
            var fact2 = BaseParameters.Temperature / Constants.ReferenceTemperature;
            var egfet = 1.16 - 7.02e-4 * BaseParameters.Temperature * BaseParameters.Temperature / (BaseParameters.Temperature + 1108);
            var arg   = -egfet / (2 * Constants.Boltzmann * BaseParameters.Temperature) + 1.1150877 / (Constants.Boltzmann * (Constants.ReferenceTemperature +
                                                                                                                              Constants.ReferenceTemperature));
            var pbfact  = -2 * Vt * (1.5 * Math.Log(fact2) + Constants.Charge * arg);
            var egfet1  = 1.16 - 7.02e-4 * ModelParameters.NominalTemperature * ModelParameters.NominalTemperature / (ModelParameters.NominalTemperature + 1108);
            var arg1    = -egfet1 / (Constants.Boltzmann * 2 * ModelParameters.NominalTemperature) + 1.1150877 / (2 * Constants.Boltzmann * Constants.ReferenceTemperature);
            var fact1   = ModelParameters.NominalTemperature / Constants.ReferenceTemperature;
            var pbfact1 = -2 * ModelTemperature.VtNominal * (1.5 * Math.Log(fact1) + Constants.Charge * arg1);
            var pbo     = (ModelParameters.JunctionPotential - pbfact1) / fact1;
            var gmaold  = (ModelParameters.JunctionPotential - pbo) / pbo;

            TempJunctionCap = ModelParameters.JunctionCap / (1 + ModelParameters.GradingCoefficient * (400e-6 * (ModelParameters.NominalTemperature - Constants.ReferenceTemperature) - gmaold));
            TempJunctionPot = pbfact + fact2 * pbo;
            var gmanew = (TempJunctionPot - pbo) / pbo;

            TempJunctionCap *= 1 + ModelParameters.GradingCoefficient * (400e-6 * (BaseParameters.Temperature - Constants.ReferenceTemperature) - gmanew);

            TempSaturationCurrent = ModelParameters.SaturationCurrent * Math.Exp((BaseParameters.Temperature / ModelParameters.NominalTemperature - 1) * ModelParameters.ActivationEnergy /
                                                                                 (ModelParameters.EmissionCoefficient * Vt) + ModelParameters.SaturationCurrentExp / ModelParameters.EmissionCoefficient * Math.Log(BaseParameters.Temperature / ModelParameters.NominalTemperature));

            // the defintion of f1, just recompute after temperature adjusting all the variables used in it
            TempFactor1 = TempJunctionPot * (1 - Math.Exp((1 - ModelParameters.GradingCoefficient) * ModelTemperature.Xfc)) / (1 - ModelParameters.GradingCoefficient);

            // same for Depletion Capacitance
            TempDepletionCap = ModelParameters.DepletionCapCoefficient * TempJunctionPot;

            // and Vcrit
            var vte = ModelParameters.EmissionCoefficient * Vt;

            TempVCritical = vte * Math.Log(vte / (Constants.Root2 * TempSaturationCurrent));

            // and now to copute the breakdown voltage, again, using temperature adjusted basic parameters
            if (ModelParameters.BreakdownVoltage.Given)
            {
                double cbv = ModelParameters.BreakdownCurrent;
                double xbv;
                if (cbv < TempSaturationCurrent * ModelParameters.BreakdownVoltage / Vt)
                {
                    cbv = TempSaturationCurrent * ModelParameters.BreakdownVoltage / Vt;
                    CircuitWarning.Warning(this, "{0}: breakdown current increased to {1:g} to resolve incompatability with specified saturation current".FormatString(Name, cbv));
                    xbv = ModelParameters.BreakdownVoltage;
                }
                else
                {
                    var tol = BaseConfiguration.RelativeTolerance * cbv;
                    xbv = ModelParameters.BreakdownVoltage - Vt * Math.Log(1 + cbv / TempSaturationCurrent);
                    int iter;
                    for (iter = 0; iter < 25; iter++)
                    {
                        xbv  = ModelParameters.BreakdownVoltage - Vt * Math.Log(cbv / TempSaturationCurrent + 1 - xbv / Vt);
                        xcbv = TempSaturationCurrent * (Math.Exp((ModelParameters.BreakdownVoltage - xbv) / Vt) - 1 + xbv / Vt);
                        if (Math.Abs(xcbv - cbv) <= tol)
                        {
                            break;
                        }
                    }
                    if (iter >= 25)
                    {
                        CircuitWarning.Warning(this, "{0}: unable to match forward and reverse diode regions: bv = {1:g}, ibv = {2:g}".FormatString(Name, xbv, xcbv));
                    }
                }
                TempBreakdownVoltage = xbv;
            }
        }
        /// <summary>
        /// Loads the Y-matrix and Rhs-vector.
        /// </summary>
        /// <param name="simulation">The base simulation.</param>
        /// <exception cref="NotImplementedException"></exception>
        public void Load(BaseSimulation simulation)
        {
            simulation.ThrowIfNull(nameof(simulation));

            bool currentState;
            var  state = simulation.RealState;

            // decide the state of the switch
            if (state.Init == InitializationModes.Fix || state.Init == InitializationModes.Junction)
            {
                if (BaseParameters.ZeroState)
                {
                    // Switch specified "on"
                    CurrentState = true;
                    currentState = true;
                }
                else
                {
                    // Switch specified "off"
                    CurrentState = false;
                    currentState = false;
                }
            }
            else
            {
                // Get the previous state
                var ctrl = Method.GetValue(state);
                if (UseOldState)
                {
                    // Calculate the current state
                    if (ctrl > ModelParameters.Threshold + ModelParameters.Hysteresis)
                    {
                        currentState = true;
                    }
                    else if (ctrl < ModelParameters.Threshold - ModelParameters.Hysteresis)
                    {
                        currentState = false;
                    }
                    else
                    {
                        currentState = PreviousState;
                    }
                    CurrentState = currentState;
                    UseOldState  = false;
                }
                else
                {
                    PreviousState = CurrentState;

                    // Calculate the current state
                    if (ctrl > ModelParameters.Threshold + ModelParameters.Hysteresis)
                    {
                        CurrentState = true;
                        currentState = true;
                    }
                    else if (ctrl < ModelParameters.Threshold - ModelParameters.Hysteresis)
                    {
                        CurrentState = false;
                        currentState = false;
                    }
                    else
                    {
                        currentState = PreviousState;
                    }

                    // Ensure one more iteration
                    if (currentState != PreviousState)
                    {
                        state.IsConvergent = false;
                    }
                }

                // Store the current state
                CurrentState = currentState;

                // If the state changed, ensure one more iteration
                if (currentState != PreviousState)
                {
                    state.IsConvergent = false;
                }
            }

            // Get the current conduction
            var gNow = currentState ? ModelParameters.OnConductance : ModelParameters.OffConductance;

            Conductance = gNow;

            // Load the Y-matrix
            PosPosPtr.Value += gNow;
            PosNegPtr.Value -= gNow;
            NegPosPtr.Value -= gNow;
            NegNegPtr.Value += gNow;
        }
 /// <summary>
 /// Loads the Y-matrix and Rhs-vector.
 /// </summary>
 /// <param name="simulation">The base simulation.</param>
 public abstract void Load(BaseSimulation simulation);
Exemple #4
0
        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Temperature(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            if (!_mbp.NominalTemperature.Given)
            {
                _mbp.NominalTemperature.RawValue = simulation.RealState.NominalTemperature;
            }
            Factor1 = _mbp.NominalTemperature / Circuit.ReferenceTemperature;

            if (!_mbp.LeakBeCurrent.Given)
            {
                if (_mbp.C2.Given)
                {
                    _mbp.LeakBeCurrent.RawValue = _mbp.C2 * _mbp.SatCur;
                }
                else
                {
                    _mbp.LeakBeCurrent.RawValue = 0;
                }
            }
            if (!_mbp.LeakBcCurrent.Given)
            {
                if (_mbp.C4.Given)
                {
                    _mbp.LeakBcCurrent.RawValue = _mbp.C4 * _mbp.SatCur;
                }
                else
                {
                    _mbp.LeakBcCurrent.RawValue = 0;
                }
            }
            if (!_mbp.MinimumBaseResistance.Given)
            {
                _mbp.MinimumBaseResistance.RawValue = _mbp.BaseResist;
            }

            /*
             * COMPATABILITY WARNING!
             * special note: for backward compatability to much older models, spice 2G
             * implemented a special case which checked if B-E leakage saturation
             * current was >1, then it was instead a the B-E leakage saturation current
             * divided by IS, and multiplied it by IS at this point. This was not
             * handled correctly in the 2G code, and there is some question on its
             * reasonability, since it is also undocumented, so it has been left out
             * here. It could easily be added with 1 line. (The same applies to the B-C
             * leakage saturation current).   TQ  6/29/84
             */

            if (_mbp.EarlyVoltageForward.Given && !_mbp.EarlyVoltageForward.Value.Equals(0.0))
            {
                InverseEarlyVoltForward = 1 / _mbp.EarlyVoltageForward;
            }
            else
            {
                InverseEarlyVoltForward = 0;
            }
            if (_mbp.RollOffForward.Given && !_mbp.RollOffForward.Value.Equals(0.0))
            {
                InverseRollOffForward = 1 / _mbp.RollOffForward;
            }
            else
            {
                InverseRollOffForward = 0;
            }
            if (_mbp.EarlyVoltageReverse.Given && !_mbp.EarlyVoltageReverse.Value.Equals(0.0))
            {
                InverseEarlyVoltReverse = 1 / _mbp.EarlyVoltageReverse;
            }
            else
            {
                InverseEarlyVoltReverse = 0;
            }
            if (_mbp.RollOffReverse.Given && !_mbp.RollOffReverse.Value.Equals(0.0))
            {
                InverseRollOffReverse = 1 / _mbp.RollOffReverse;
            }
            else
            {
                InverseRollOffReverse = 0;
            }
            if (_mbp.CollectorResistance.Given && !_mbp.CollectorResistance.Value.Equals(0.0))
            {
                CollectorConduct = 1 / _mbp.CollectorResistance;
            }
            else
            {
                CollectorConduct = 0;
            }
            if (_mbp.EmitterResistance.Given && !_mbp.EmitterResistance.Value.Equals(0.0))
            {
                EmitterConduct = 1 / _mbp.EmitterResistance;
            }
            else
            {
                EmitterConduct = 0;
            }
            if (_mbp.TransitTimeForwardVoltageBc.Given && !_mbp.TransitTimeForwardVoltageBc.Value.Equals(0.0))
            {
                TransitTimeVoltageBcFactor = 1 / (_mbp.TransitTimeForwardVoltageBc * 1.44);
            }
            else
            {
                TransitTimeVoltageBcFactor = 0;
            }
            ExcessPhaseFactor = _mbp.ExcessPhase / (180.0 / Math.PI) * _mbp.TransitTimeForward;
            if (_mbp.DepletionCapCoefficient.Given)
            {
                if (_mbp.DepletionCapCoefficient > 0.9999)
                {
                    _mbp.DepletionCapCoefficient.RawValue = 0.9999;
                    throw new CircuitException("BJT model {0}, parameter fc limited to 0.9999".FormatString(Name));
                }
            }
            else
            {
                _mbp.DepletionCapCoefficient.RawValue = 0.5;
            }
            Xfc = Math.Log(1 - _mbp.DepletionCapCoefficient);
            F2  = Math.Exp((1 + _mbp.JunctionExpBe) * Xfc);
            F3  = 1 - _mbp.DepletionCapCoefficient * (1 + _mbp.JunctionExpBe);
            F6  = Math.Exp((1 + _mbp.JunctionExpBc) * Xfc);
            F7  = 1 - _mbp.DepletionCapCoefficient * (1 + _mbp.JunctionExpBc);
        }
Exemple #5
0
 public void Load(BaseSimulation simulation)
 {
 }
        /// <summary>
        /// Execute behavior
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Load(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            var    state = simulation.RealState;
            double vd;
            double cd, gd;

            /*
             * this routine loads diodes for dc and transient analyses.
             */
            var csat = _temp.TempSaturationCurrent * _bp.Area;
            var gspr = _modeltemp.Conductance * _bp.Area;
            var vt   = Circuit.KOverQ * _bp.Temperature;
            var vte  = _mbp.EmissionCoefficient * vt;

            // Initialization
            var check = false;

            if (state.Init == InitializationModes.Junction)
            {
                vd = _bp.Off ? 0.0 : _temp.TempVCritical;
            }
            else if (state.Init == InitializationModes.Fix && _bp.Off)
            {
                vd = 0.0;
            }
            else
            {
                // Get voltage over the diode (without series resistance)
                vd = state.Solution[PosPrimeNode] - state.Solution[_negNode];

                // limit new junction voltage
                if (_mbp.BreakdownVoltage.Given && vd < Math.Min(0, -_temp.TempBreakdownVoltage + 10 * vte))
                {
                    var vdtemp = -(vd + _temp.TempBreakdownVoltage);
                    vdtemp = Semiconductor.LimitJunction(vdtemp, -(InternalVoltage + _temp.TempBreakdownVoltage), vte, _temp.TempVCritical, ref check);
                    vd     = -(vdtemp + _temp.TempBreakdownVoltage);
                }
                else
                {
                    vd = Semiconductor.LimitJunction(vd, InternalVoltage, vte, _temp.TempVCritical, ref check);
                }
            }

            // compute dc current and derivatives
            if (vd >= -3 * vte)
            {
                // Forward bias
                var evd = Math.Exp(vd / vte);
                cd = csat * (evd - 1) + _baseConfig.Gmin * vd;
                gd = csat * evd / vte + _baseConfig.Gmin;
            }
            else if (!_mbp.BreakdownVoltage.Given || vd >= -_temp.TempBreakdownVoltage)
            {
                // Reverse bias
                var arg = 3 * vte / (vd * Math.E);
                arg = arg * arg * arg;
                cd  = -csat * (1 + arg) + _baseConfig.Gmin * vd;
                gd  = csat * 3 * arg / vd + _baseConfig.Gmin;
            }
            else
            {
                // Reverse breakdown
                var evrev = Math.Exp(-(_temp.TempBreakdownVoltage + vd) / vte);
                cd = -csat * evrev + _baseConfig.Gmin * vd;
                gd = csat * evrev / vte + _baseConfig.Gmin;
            }

            // Check convergence
            if (state.Init != InitializationModes.Fix || !_bp.Off)
            {
                if (check)
                {
                    state.IsConvergent = false;
                }
            }

            // Store for next time
            InternalVoltage = vd;
            Current         = cd;
            Conduct         = gd;

            // Load Rhs vector
            var cdeq = cd - gd * vd;

            NegPtr.Value      += cdeq;
            PosPrimePtr.Value -= cdeq;

            // Load Y-matrix
            PosPosPtr.Value           += gspr;
            NegNegPtr.Value           += gd;
            PosPrimePosPrimePtr.Value += gd + gspr;
            PosPosPrimePtr.Value      -= gspr;
            PosPrimePosPtr.Value      -= gspr;
            NegPosPrimePtr.Value      -= gd;
            PosPrimeNegPtr.Value      -= gd;
        }
        protected void SetTempVariable(ICircuitContext context, double? operatingTemperatureInKelvins, BaseSimulation simulation)
        {
            double temp = 0;
            if (operatingTemperatureInKelvins.HasValue)
            {
                temp = operatingTemperatureInKelvins.Value - Constants.CelsiusKelvin;
            }
            else
            {
                temp = Constants.ReferenceTemperature - Constants.CelsiusKelvin;
            }

            simulation.BeforeTemperature += (object sender, LoadStateEventArgs e) =>
            {
                context.Evaluator.SetParameter(simulation, "TEMP", temp);
            };
        }
 /// <summary>
 /// Perform temperature-dependent calculations.
 /// </summary>
 /// <param name="simulation">The base simulation.</param>
 public abstract void Temperature(BaseSimulation simulation);
        /// <summary>
        /// Execute behavior
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Load(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            var    state = simulation.RealState;
            double drainSatCur, sourceSatCur,
                   vgs, vds, vbs, vbd, vgd;
            double von;
            double vdsat,
                   cdrain,
                   cdreq;
            int xnrm, xrev;

            var vt    = Circuit.KOverQ * _bp.Temperature;
            var check = 1;


            /* DETAILPROF */

            /* first, we compute a few useful values - these could be
             * pre - computed, but for historical reasons are still done
             * here.  They may be moved at the expense of instance size
             */

            var effectiveLength = _bp.Length - 2 * _mbp.LateralDiffusion;

            if (_temp.TempSaturationCurrentDensity.Equals(0.0) || _bp.DrainArea.Value.Equals(0.0) || _bp.SourceArea.Value.Equals(0.0))
            {
                drainSatCur  = _temp.TempSaturationCurrent;
                sourceSatCur = _temp.TempSaturationCurrent;
            }
            else
            {
                drainSatCur  = _temp.TempSaturationCurrentDensity * _bp.DrainArea;
                sourceSatCur = _temp.TempSaturationCurrentDensity * _bp.SourceArea;
            }

            var beta     = _temp.TempTransconductance * _bp.Width / effectiveLength;
            var oxideCap = _mbp.OxideCapFactor * effectiveLength * _bp.Width;

            /* DETAILPROF */

            /*
             * ok - now to do the start - up operations
             *
             * we must get values for vbs, vds, and vgs from somewhere
             * so we either predict them or recover them from last iteration
             * These are the two most common cases - either a prediction
             * step or the general iteration step and they
             * share some code, so we put them first - others later on
             */

            if (state.Init == InitializationModes.Float || (simulation is TimeSimulation tsim && tsim.Method.BaseTime.Equals(0.0)) ||
                state.Init == InitializationModes.Fix && !_bp.Off)
            {
                // General iteration
                vbs = _mbp.MosfetType * (state.Solution[_bulkNode] - state.Solution[SourceNodePrime]);
                vgs = _mbp.MosfetType * (state.Solution[_gateNode] - state.Solution[SourceNodePrime]);
                vds = _mbp.MosfetType * (state.Solution[DrainNodePrime] - state.Solution[SourceNodePrime]);

                /* now some common crunching for some more useful quantities */
                /* DETAILPROF */

                vbd = vbs - vds;
                vgd = vgs - vds;
                var vgdo = VoltageGs - VoltageDs;
                von = _mbp.MosfetType * Von;

                /*
                 * limiting
                 * we want to keep device voltages from changing
                 * so fast that the exponentials churn out overflows
                 * and similar rudeness
                 */

                // NOTE: Spice 3f5 does not write out Vgs during DC analysis, so DEVfetlim may give different results in Spice 3f5
                if (VoltageDs >= 0)
                {
                    vgs = Transistor.LimitFet(vgs, VoltageGs, von);
                    vds = vgs - vgd;
                    vds = Transistor.LimitVoltageDs(vds, VoltageDs);
                }
                else
                {
                    vgd = Transistor.LimitFet(vgd, vgdo, von);
                    vds = vgs - vgd;
                    vds = -Transistor.LimitVoltageDs(-vds, -VoltageDs);
                    vgs = vgd + vds;
                }
                if (vds >= 0)
                {
                    vbs = Transistor.LimitJunction(vbs, VoltageBs, vt, _temp.SourceVCritical, out check);
                }
                else
                {
                    vbd = Transistor.LimitJunction(vbd, VoltageBd, vt, _temp.DrainVCritical, out check);
                    vbs = vbd + vds;
                }
                /* NODELIMITING */
            }
Exemple #10
0
        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public void Temperature(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            // Perform model defaulting
            if (!ModelParameters.NominalTemperature.Given)
            {
                ModelParameters.NominalTemperature.RawValue = simulation.RealState.NominalTemperature;
            }
            Factor1   = ModelParameters.NominalTemperature / Circuit.ReferenceTemperature;
            VtNominal = ModelParameters.NominalTemperature * Circuit.KOverQ;
            var kt1 = Circuit.Boltzmann * ModelParameters.NominalTemperature;

            EgFet1 = 1.16 - 7.02e-4 * ModelParameters.NominalTemperature * ModelParameters.NominalTemperature / (ModelParameters.NominalTemperature + 1108);
            var arg1 = -EgFet1 / (kt1 + kt1) + 1.1150877 / (Circuit.Boltzmann * (Circuit.ReferenceTemperature + Circuit.ReferenceTemperature));

            PbFactor1 = -2 * VtNominal * (1.5 * Math.Log(Factor1) + Circuit.Charge * arg1);

            if (ModelParameters.OxideThickness.Given && ModelParameters.OxideThickness > 0.0)
            {
                if (ModelParameters.SubstrateDoping.Given)
                {
                    if (ModelParameters.SubstrateDoping * 1e6 > 1.45e16)
                    {
                        if (!ModelParameters.Phi.Given)
                        {
                            ModelParameters.Phi.RawValue = 2 * VtNominal * Math.Log(ModelParameters.SubstrateDoping * 1e6 / 1.45e16);
                            ModelParameters.Phi.RawValue = Math.Max(.1, ModelParameters.Phi);
                        }

                        var fermis = ModelParameters.MosfetType * .5 * ModelParameters.Phi;
                        var wkfng  = 3.2;
                        if (!ModelParameters.GateType.Given)
                        {
                            ModelParameters.GateType.RawValue = 1;
                        }
                        if (!ModelParameters.GateType.RawValue.Equals(0))
                        {
                            var fermig = ModelParameters.MosfetType * ModelParameters.GateType * .5 * EgFet1;
                            wkfng = 3.25 + .5 * EgFet1 - fermig;
                        }

                        var wkfngs = wkfng - (3.25 + .5 * EgFet1 + fermis);
                        if (!ModelParameters.Gamma.Given)
                        {
                            ModelParameters.Gamma.RawValue =
                                Math.Sqrt(2 * 11.70 * 8.854214871e-12 * Circuit.Charge * ModelParameters.SubstrateDoping * 1e6) /
                                ModelParameters.OxideCapFactor;
                        }

                        if (!ModelParameters.Vt0.Given)
                        {
                            if (!ModelParameters.SurfaceStateDensity.Given)
                            {
                                ModelParameters.SurfaceStateDensity.RawValue = 0;
                            }
                            var vfb = wkfngs - ModelParameters.SurfaceStateDensity * 1e4 * Circuit.Charge / ModelParameters.OxideCapFactor;
                            ModelParameters.Vt0.RawValue = vfb + ModelParameters.MosfetType * (ModelParameters.Gamma * Math.Sqrt(ModelParameters.Phi) + ModelParameters.Phi);
                        }
                    }
                    else
                    {
                        ModelParameters.SubstrateDoping.RawValue = 0;
                        throw new CircuitException("{0}: Nsub < Ni".FormatString(Name));
                    }
                }
            }
        }
Exemple #11
0
 /// <summary>
 /// Execute behavior
 /// </summary>
 /// <param name="simulation">Base simulation</param>
 public override void Load(BaseSimulation simulation)
 {
     PosControlBranchPtr.Value += _bp.Coefficient.Value;
     NegControlBranchPtr.Value -= _bp.Coefficient.Value;
 }
Exemple #12
0
        /// <summary>
        /// Execute behavior
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public void Load(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            var    state = simulation.RealState;
            double cd, gd;

            // Get the current voltages
            Initialize(simulation, out double vd, out bool check);

            /*
             * this routine loads diodes for dc and transient analyses.
             */
            var csat = TempSaturationCurrent * BaseParameters.Area;
            var gspr = ModelTemperature.Conductance * BaseParameters.Area;

            // compute dc current and derivatives
            if (vd >= -3 * Vte)
            {
                // Forward bias
                var evd = Math.Exp(vd / Vte);
                cd = csat * (evd - 1) + BaseConfiguration.Gmin * vd;
                gd = csat * evd / Vte + BaseConfiguration.Gmin;
            }
            else if (!ModelParameters.BreakdownVoltage.Given || vd >= -TempBreakdownVoltage)
            {
                // Reverse bias
                var arg = 3 * Vte / (vd * Math.E);
                arg = arg * arg * arg;
                cd  = -csat * (1 + arg) + BaseConfiguration.Gmin * vd;
                gd  = csat * 3 * arg / vd + BaseConfiguration.Gmin;
            }
            else
            {
                // Reverse breakdown
                var evrev = Math.Exp(-(TempBreakdownVoltage + vd) / Vte);
                cd = -csat * evrev + BaseConfiguration.Gmin * vd;
                gd = csat * evrev / Vte + BaseConfiguration.Gmin;
            }

            // Check convergence
            if (state.Init != InitializationModes.Fix || !BaseParameters.Off)
            {
                if (check)
                {
                    state.IsConvergent = false;
                }
            }

            // Store for next time
            Voltage     = vd;
            Current     = cd;
            Conductance = gd;

            // Load Rhs vector
            var cdeq = cd - gd * vd;

            NegPtr.Value      += cdeq;
            PosPrimePtr.Value -= cdeq;

            // Load Y-matrix
            PosPosPtr.Value           += gspr;
            NegNegPtr.Value           += gd;
            PosPrimePosPrimePtr.Value += gd + gspr;
            PosPosPrimePtr.Value      -= gspr;
            PosPrimePosPtr.Value      -= gspr;
            NegPosPrimePtr.Value      -= gd;
            PosPrimeNegPtr.Value      -= gd;
        }
Exemple #13
0
        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Temperature(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            if (!_mbp.NominalTemperature.Given)
            {
                _mbp.NominalTemperature.RawValue = simulation.RealState.NominalTemperature;
            }
            Fact1     = _mbp.NominalTemperature / Circuit.ReferenceTemperature;
            VtNominal = _mbp.NominalTemperature * Circuit.KOverQ;
            var kt1 = Circuit.Boltzmann * _mbp.NominalTemperature;

            EgFet1 = 1.16 - 7.02e-4 * _mbp.NominalTemperature * _mbp.NominalTemperature / (_mbp.NominalTemperature + 1108);
            var arg1 = -EgFet1 / (kt1 + kt1) + 1.1150877 / (Circuit.Boltzmann * (Circuit.ReferenceTemperature + Circuit.ReferenceTemperature));

            PbFactor1 = -2 * VtNominal * (1.5 * Math.Log(Fact1) + Circuit.Charge * arg1);

            OxideCapFactor = 3.9 * 8.854214871e-12 / _mbp.OxideThickness;
            if (!_mbp.SurfaceMobility.Given)
            {
                _mbp.SurfaceMobility.RawValue = 600;
            }
            if (!_mbp.Transconductance.Given)
            {
                _mbp.Transconductance.RawValue = _mbp.SurfaceMobility * OxideCapFactor * 1e-4;
            }
            if (_mbp.SubstrateDoping.Given)
            {
                if (_mbp.SubstrateDoping * 1e6 /* (cm**3 / m**3) */ > 1.45e16)
                {
                    if (!_mbp.Phi.Given)
                    {
                        _mbp.Phi.RawValue = 2 * VtNominal * Math.Log(_mbp.SubstrateDoping * 1e6 /* (cm *  * 3 / m *  * 3) */ / 1.45e16);
                        _mbp.Phi.RawValue = Math.Max(.1, _mbp.Phi);
                    }
                    var fermis = _mbp.MosfetType * .5 * _mbp.Phi;
                    var wkfng  = 3.2;
                    if (!_mbp.GateType.Given)
                    {
                        _mbp.GateType.RawValue = 1;
                    }
                    if (!_mbp.GateType.RawValue.Equals(0.0))
                    {
                        var fermig = _mbp.MosfetType * _mbp.GateType * .5 * EgFet1;
                        wkfng = 3.25 + .5 * EgFet1 - fermig;
                    }
                    var wkfngs = wkfng - (3.25 + .5 * EgFet1 + fermis);
                    if (!_mbp.Gamma.Given)
                    {
                        _mbp.Gamma.RawValue = Math.Sqrt(2 * Transistor.EpsilonSilicon * Circuit.Charge * _mbp.SubstrateDoping * 1e6 /* (cm**3 / m**3) */) /
                                              OxideCapFactor;
                    }
                    if (!_mbp.Vt0.Given)
                    {
                        if (!_mbp.SurfaceStateDensity.Given)
                        {
                            _mbp.SurfaceStateDensity.RawValue = 0;
                        }
                        var vfb = wkfngs - _mbp.SurfaceStateDensity * 1e4 * Circuit.Charge / OxideCapFactor;
                        _mbp.Vt0.RawValue = vfb + _mbp.MosfetType * (_mbp.Gamma * Math.Sqrt(_mbp.Phi) + _mbp.Phi);
                    }

                    Alpha = (Transistor.EpsilonSilicon + Transistor.EpsilonSilicon) / (Circuit.Charge * _mbp.SubstrateDoping * 1e6 /* (cm**3 / m**3) */);
                    CoefficientDepletionLayerWidth = Math.Sqrt(Alpha);
                }
                else
                {
                    _mbp.SubstrateDoping.RawValue = 0;
                    throw new CircuitException("{0}: Nsub < Ni".FormatString(Name));
                }
            }
            /* now model parameter preprocessing */
            _mbp.NarrowFactor = _mbp.Delta * 0.5 * Math.PI * Transistor.EpsilonSilicon / OxideCapFactor;
        }
        /// <summary>
        /// Execute behavior
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Load(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            var    state = simulation.RealState;
            double vbe;
            double vbc;
            double gben;
            double cben;
            double gbcn;
            double cbcn;

            var vt = _bp.Temperature * Circuit.KOverQ;

            // DC model parameters
            var csat = _temp.TempSaturationCurrent * _bp.Area;
            var rbpr = _mbp.MinimumBaseResistance / _bp.Area;
            var rbpi = _mbp.BaseResist / _bp.Area - rbpr;
            var gcpr = _modeltemp.CollectorConduct * _bp.Area;
            var gepr = _modeltemp.EmitterConduct * _bp.Area;
            var oik  = _modeltemp.InverseRollOffForward / _bp.Area;
            var c2   = _temp.TempBeLeakageCurrent * _bp.Area;
            var vte  = _mbp.LeakBeEmissionCoefficient * vt;
            var oikr = _modeltemp.InverseRollOffReverse / _bp.Area;
            var c4   = _temp.TempBcLeakageCurrent * _bp.Area;
            var vtc  = _mbp.LeakBcEmissionCoefficient * vt;
            var xjrb = _mbp.BaseCurrentHalfResist * _bp.Area;

            // Initialization
            if (state.Init == InitializationModes.Junction && (simulation is TimeSimulation) && state.UseDc && state.UseIc)
            {
                vbe = _mbp.BipolarType * _bp.InitialVoltageBe;
                var vce = _mbp.BipolarType * _bp.InitialVoltageCe;
                vbc = vbe - vce;
            }
            else if (state.Init == InitializationModes.Junction && !_bp.Off)
            {
                vbe = _temp.TempVCritical;
                vbc = 0;
            }
            else if (state.Init == InitializationModes.Junction || state.Init == InitializationModes.Fix && _bp.Off)
            {
                vbe = 0;
                vbc = 0;
            }
            else
            {
                // Compute new nonlinear branch voltages
                vbe = _mbp.BipolarType * (state.Solution[BasePrimeNode] - state.Solution[EmitterPrimeNode]);
                vbc = _mbp.BipolarType * (state.Solution[BasePrimeNode] - state.Solution[CollectorPrimeNode]);

                // Limit nonlinear branch voltages
                var limited = false;
                vbe = Semiconductor.LimitJunction(vbe, VoltageBe, vt, _temp.TempVCritical, ref limited);
                vbc = Semiconductor.LimitJunction(vbc, VoltageBc, vt, _temp.TempVCritical, ref limited);
                if (limited)
                {
                    state.IsConvergent = false;
                }
            }

            // Determine dc current and derivitives
            var vtn = vt * _mbp.EmissionCoefficientForward;

            if (vbe > -5 * vtn)
            {
                var evbe = Math.Exp(vbe / vtn);
                CurrentBe = csat * (evbe - 1) + _baseConfig.Gmin * vbe;
                CondBe    = csat * evbe / vtn + _baseConfig.Gmin;
                if (c2.Equals(0)) // Avoid Exp()
                {
                    cben = 0;
                    gben = 0;
                }
                else
                {
                    var evben = Math.Exp(vbe / vte);
                    cben = c2 * (evben - 1);
                    gben = c2 * evben / vte;
                }
            }
            else
            {
                CondBe    = -csat / vbe + _baseConfig.Gmin;
                CurrentBe = CondBe * vbe;
                gben      = -c2 / vbe;
                cben      = gben * vbe;
            }

            vtn = vt * _mbp.EmissionCoefficientReverse;
            if (vbc > -5 * vtn)
            {
                var evbc = Math.Exp(vbc / vtn);
                CurrentBc = csat * (evbc - 1) + _baseConfig.Gmin * vbc;
                CondBc    = csat * evbc / vtn + _baseConfig.Gmin;
                if (c4.Equals(0)) // Avoid Exp()
                {
                    cbcn = 0;
                    gbcn = 0;
                }
                else
                {
                    var evbcn = Math.Exp(vbc / vtc);
                    cbcn = c4 * (evbcn - 1);
                    gbcn = c4 * evbcn / vtc;
                }
            }
            else
            {
                CondBc    = -csat / vbc + _baseConfig.Gmin;
                CurrentBc = CondBc * vbc;
                gbcn      = -c4 / vbc;
                cbcn      = gbcn * vbc;
            }

            // Determine base charge terms
            var q1 = 1 / (1 - _modeltemp.InverseEarlyVoltForward * vbc - _modeltemp.InverseEarlyVoltReverse * vbe);

            if (oik.Equals(0) && oikr.Equals(0)) // Avoid computations
            {
                BaseCharge = q1;
                Dqbdve     = q1 * BaseCharge * _modeltemp.InverseEarlyVoltReverse;
                Dqbdvc     = q1 * BaseCharge * _modeltemp.InverseEarlyVoltForward;
            }
            else
            {
                var    q2    = oik * CurrentBe + oikr * CurrentBc;
                var    arg   = Math.Max(0, 1 + 4 * q2);
                double sqarg = 1;
                if (!arg.Equals(0)) // Avoid Sqrt()
                {
                    sqarg = Math.Sqrt(arg);
                }
                BaseCharge = q1 * (1 + sqarg) / 2;
                Dqbdve     = q1 * (BaseCharge * _modeltemp.InverseEarlyVoltReverse + oik * CondBe / sqarg);
                Dqbdvc     = q1 * (BaseCharge * _modeltemp.InverseEarlyVoltForward + oikr * CondBc / sqarg);
            }

            // Excess phase calculation
            var ep = new ExcessPhaseEventArgs
            {
                CollectorCurrent   = 0.0,
                ExcessPhaseCurrent = CurrentBe,
                ExcessPhaseConduct = CondBe,
                BaseCharge         = BaseCharge
            };

            ExcessPhaseCalculation?.Invoke(this, ep);
            var cc  = ep.CollectorCurrent;
            var cex = ep.ExcessPhaseCurrent;
            var gex = ep.ExcessPhaseConduct;

            // Determine dc incremental conductances
            cc = cc + (cex - CurrentBc) / BaseCharge - CurrentBc / _temp.TempBetaReverse - cbcn;
            var cb = CurrentBe / _temp.TempBetaForward + cben + CurrentBc / _temp.TempBetaReverse + cbcn;
            var gx = rbpr + rbpi / BaseCharge;

            if (!xjrb.Equals(0)) // Avoid calculations
            {
                var arg1 = Math.Max(cb / xjrb, 1e-9);
                var arg2 = (-1 + Math.Sqrt(1 + 14.59025 * arg1)) / 2.4317 / Math.Sqrt(arg1);
                arg1 = Math.Tan(arg2);
                gx   = rbpr + 3 * rbpi * (arg1 - arg2) / arg2 / arg1 / arg1;
            }
            if (!gx.Equals(0)) // Do not divide by 0
            {
                gx = 1 / gx;
            }
            var gpi = CondBe / _temp.TempBetaForward + gben;
            var gmu = CondBc / _temp.TempBetaReverse + gbcn;
            var go  = (CondBc + (cex - CurrentBc) * Dqbdvc / BaseCharge) / BaseCharge;
            var gm  = (gex - (cex - CurrentBc) * Dqbdve / BaseCharge) / BaseCharge - go;

            VoltageBe         = vbe;
            VoltageBc         = vbc;
            CollectorCurrent  = cc;
            BaseCurrent       = cb;
            ConductancePi     = gpi;
            ConductanceMu     = gmu;
            Transconductance  = gm;
            OutputConductance = go;
            ConductanceX      = gx;

            // Load current excitation vector
            var ceqbe = _mbp.BipolarType * (cc + cb - vbe * (gm + go + gpi) + vbc * go);
            var ceqbc = _mbp.BipolarType * (-cc + vbe * (gm + go) - vbc * (gmu + go));

            CollectorPrimePtr.Value += ceqbc;
            BasePrimePtr.Value      += -ceqbe - ceqbc;
            EmitterPrimePtr.Value   += ceqbe;

            // Load y matrix
            CollectorCollectorPtr.Value           += gcpr;
            BaseBasePtr.Value                     += gx;
            EmitterEmitterPtr.Value               += gepr;
            CollectorPrimeCollectorPrimePtr.Value += gmu + go + gcpr;
            BasePrimeBasePrimePtr.Value           += gx + gpi + gmu;
            EmitterPrimeEmitterPrimePtr.Value     += gpi + gepr + gm + go;
            CollectorCollectorPrimePtr.Value      += -gcpr;
            BaseBasePrimePtr.Value                += -gx;
            EmitterEmitterPrimePtr.Value          += -gepr;
            CollectorPrimeCollectorPtr.Value      += -gcpr;
            CollectorPrimeBasePrimePtr.Value      += -gmu + gm;
            CollectorPrimeEmitterPrimePtr.Value   += -gm - go;
            BasePrimeBasePtr.Value                += -gx;
            BasePrimeCollectorPrimePtr.Value      += -gmu;
            BasePrimeEmitterPrimePtr.Value        += -gpi;
            EmitterPrimeEmitterPtr.Value          += -gepr;
            EmitterPrimeCollectorPrimePtr.Value   += -go;
            EmitterPrimeBasePrimePtr.Value        += -gpi - gm;
        }
Exemple #15
0
        /// <summary>
        /// Loads the Y-matrix and Rhs-vector.
        /// </summary>
        /// <param name="simulation">The base simulation.</param>
        public void Load(BaseSimulation simulation)
        {
            simulation.ThrowIfNull(nameof(simulation));
            var state = simulation.RealState;

            // DC model parameters
            var beta = ModelParameters.Beta * BaseParameters.Area;
            var gdpr = ModelParameters.DrainConductance * BaseParameters.Area;
            var gspr = ModelParameters.SourceConductance * BaseParameters.Area;
            var csat = TempSaturationCurrent * BaseParameters.Area;

            double ggs, cg;
            double ggd, cgd;
            double cdrain, gm, gds, betap, bfac;

            // Get the current voltages
            Initialize(simulation, out double vgs, out double vgd, out bool check);
            var vds = vgs - vgd;

            // Determine dc current and derivatives
            if (vgs <= -5 * BaseParameters.Temperature * Constants.KOverQ)
            {
                ggs = -csat / vgs + BaseConfiguration.Gmin;
                cg  = ggs * vgs;
            }
            else
            {
                var evgs = Math.Exp(vgs / (BaseParameters.Temperature * Constants.KOverQ));
                ggs = csat * evgs / (BaseParameters.Temperature * Constants.KOverQ) + BaseConfiguration.Gmin;
                cg  = csat * (evgs - 1) + BaseConfiguration.Gmin * vgs;
            }

            if (vgd <= -5 * (BaseParameters.Temperature * Constants.KOverQ))
            {
                ggd = -csat / vgd + BaseConfiguration.Gmin;
                cgd = ggd * vgd;
            }
            else
            {
                var evgd = Math.Exp(vgd / (BaseParameters.Temperature * Constants.KOverQ));
                ggd = csat * evgd / (BaseParameters.Temperature * Constants.KOverQ) + BaseConfiguration.Gmin;
                cgd = csat * (evgd - 1) + BaseConfiguration.Gmin * vgd;
            }

            cg += cgd;

            // Modification for Sydney University JFET model
            var vto = ModelParameters.Threshold;

            if (vds >= 0)
            {
                var vgst = vgs - vto;

                // Compute drain current and derivatives for normal mode
                if (vgst <= 0)
                {
                    // Normal mode, cutoff region
                    cdrain = 0;
                    gm     = 0;
                    gds    = 0;
                }
                else
                {
                    betap = beta * (1 + ModelParameters.LModulation * vds);
                    bfac  = ModelTemperature.BFactor;
                    if (vgst >= vds)
                    {
                        // Normal mode, linear region
                        var apart = 2 * ModelParameters.B + 3 * bfac * (vgst - vds);
                        var cpart = vds * (vds * (bfac * vds - ModelParameters.B) + vgst * apart);
                        cdrain = betap * cpart;
                        gm     = betap * vds * (apart + 3 * bfac * vgst);
                        gds    = betap * (vgst - vds) * apart
                                 + beta * ModelParameters.LModulation * cpart;
                    }
                    else
                    {
                        bfac = vgst * bfac;
                        gm   = betap * vgst * (2 * ModelParameters.B + 3 * bfac);

                        // Normal mode, saturation region
                        var cpart = vgst * vgst * (ModelParameters.B + bfac);
                        cdrain = betap * cpart;
                        gds    = ModelParameters.LModulation * beta * cpart;
                    }
                }
            }
            else
            {
                var vgdt = vgd - vto;

                // Compute drain current and derivatives for inverse mode
                if (vgdt <= 0)
                {
                    // Inverse mode, cutoff region
                    cdrain = 0;
                    gm     = 0;
                    gds    = 0;
                }
                else
                {
                    betap = beta * (1 - ModelParameters.LModulation * vds);
                    bfac  = ModelTemperature.BFactor;
                    if (vgdt + vds >= 0)
                    {
                        // Inverse mode, linear region
                        var apart = 2 * ModelParameters.B + 3 * bfac * (vgdt + vds);
                        var cpart = vds * (-vds * (-bfac * vds - ModelParameters.B) + vgdt * apart);
                        cdrain = betap * cpart;
                        gm     = betap * vds * (apart + 3 * bfac * vgdt);
                        gds    = betap * (vgdt + vds) * apart
                                 - beta * ModelParameters.LModulation * cpart - gm;
                    }
                    else
                    {
                        bfac = vgdt * bfac;
                        gm   = -betap * vgdt * (2 * ModelParameters.B + 3 * bfac);

                        // Inverse mode, saturation region
                        var cpart = vgdt * vgdt * (ModelParameters.B + bfac);
                        cdrain = -betap * cpart;
                        gds    = ModelParameters.LModulation * beta * cpart - gm;
                    }
                }
            }

            var cd = cdrain - cgd;

            Vgs = vgs;
            Vgd = vgd;
            Cg  = cg;
            Cd  = cd;
            Cgd = cgd;
            Gm  = gm;
            Gds = gds;
            Ggs = ggs;
            Ggd = ggd;

            // Check convergence
            if (state.Init != InitializationModes.Fix || !state.UseIc)
            {
                if (check)
                {
                    state.IsConvergent = false;
                }
            }

            // Load current vector
            var ceqgd = ModelParameters.JFETType * (cgd - ggd * vgd);
            var ceqgs = ModelParameters.JFETType * (cg - cgd - ggs * vgs);
            var cdreq = ModelParameters.JFETType * (cd + cgd - gds * vds - gm * vgs);

            GateNodePtr.Value        += -ceqgs - ceqgd;
            DrainPrimeNodePtr.Value  += -cdreq + ceqgd;
            SourcePrimeNodePtr.Value += cdreq + ceqgs;

            // Load Y-matrix
            DrainDrainPrimePtr.Value       += -gdpr;
            GateDrainPrimePtr.Value        += -ggd;
            GateSourcePrimePtr.Value       += -ggs;
            SourceSourcePrimePtr.Value     += -gspr;
            DrainPrimeDrainPtr.Value       += -gdpr;
            DrainPrimeGatePtr.Value        += gm - ggd;
            DrainPrimeSourcePrimePtr.Value += -gds - gm;
            SourcePrimeGatePtr.Value       += -ggs - gm;
            SourcePrimeSourcePtr.Value     += -gspr;
            SourcePrimeDrainPrimePtr.Value += -gds;
            DrainDrainPtr.Value            += gdpr;
            GateGatePtr.Value               += ggd + ggs;
            SourceSourcePtr.Value           += gspr;
            DrainPrimeDrainPrimePtr.Value   += gdpr + gds + ggd;
            SourcePrimeSourcePrimePtr.Value += gspr + gds + gm + ggs;
        }
Exemple #16
0
        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public void Temperature(BaseSimulation simulation)
        {
            simulation.ThrowIfNull(nameof(simulation));

            // Perform model defaulting
            if (!ModelParameters.NominalTemperature.Given)
            {
                ModelParameters.NominalTemperature.RawValue = simulation.RealState.NominalTemperature;
            }
            Factor1   = ModelParameters.NominalTemperature / Constants.ReferenceTemperature;
            VtNominal = ModelParameters.NominalTemperature * Constants.KOverQ;
            var kt1 = Constants.Boltzmann * ModelParameters.NominalTemperature;

            EgFet1 = 1.16 - 7.02e-4 * ModelParameters.NominalTemperature * ModelParameters.NominalTemperature / (ModelParameters.NominalTemperature + 1108);
            var arg1 = -EgFet1 / (kt1 + kt1) + 1.1150877 / (Constants.Boltzmann * (Constants.ReferenceTemperature + Constants.ReferenceTemperature));

            PbFactor1 = -2 * VtNominal * (1.5 * Math.Log(Factor1) + Constants.Charge * arg1);

            if (ModelParameters.SubstrateDoping.Given)
            {
                if (ModelParameters.SubstrateDoping * 1e6 /* (cm**3 / m**3) */ > 1.45e16)
                {
                    if (!ModelParameters.Phi.Given)
                    {
                        ModelParameters.Phi.RawValue = 2 * VtNominal * Math.Log(ModelParameters.SubstrateDoping * 1e6 /* (cm^3/m^3) */ / 1.45e16);
                        ModelParameters.Phi.RawValue = Math.Max(0.1, ModelParameters.Phi);
                    }
                    var fermis = ModelParameters.MosfetType * 0.5 * ModelParameters.Phi;
                    var wkfng  = 3.2;
                    if (!ModelParameters.GateType.Given)
                    {
                        ModelParameters.GateType.RawValue = 1;
                    }
                    if (!ModelParameters.GateType.RawValue.Equals(0.0))
                    {
                        var fermig = ModelParameters.MosfetType * ModelParameters.GateType * 0.5 * EgFet1;
                        wkfng = 3.25 + 0.5 * EgFet1 - fermig;
                    }
                    var wkfngs = wkfng - (3.25 + 0.5 * EgFet1 + fermis);
                    if (!ModelParameters.Gamma.Given)
                    {
                        ModelParameters.Gamma.RawValue = Math.Sqrt(2 * EpsilonSilicon * Constants.Charge * ModelParameters.SubstrateDoping * 1e6 /* (cm**3 / m**3) */) /
                                                         ModelParameters.OxideCapFactor;
                    }
                    if (!ModelParameters.Vt0.Given)
                    {
                        if (!ModelParameters.SurfaceStateDensity.Given)
                        {
                            ModelParameters.SurfaceStateDensity.RawValue = 0;
                        }
                        var vfb = wkfngs - ModelParameters.SurfaceStateDensity * 1e4 * Constants.Charge / ModelParameters.OxideCapFactor;
                        ModelParameters.Vt0.RawValue = vfb + ModelParameters.MosfetType * (ModelParameters.Gamma * Math.Sqrt(ModelParameters.Phi) + ModelParameters.Phi);
                    }

                    Alpha = (EpsilonSilicon + EpsilonSilicon) / (Constants.Charge * ModelParameters.SubstrateDoping * 1e6 /* (cm**3 / m**3) */);
                    CoefficientDepletionLayerWidth = Math.Sqrt(Alpha);
                }
                else
                {
                    ModelParameters.SubstrateDoping.RawValue = 0;
                    throw new CircuitException("{0}: Nsub < Ni".FormatString(Name));
                }
            }
        }
Exemple #17
0
        /// <summary>
        /// Execute behavior
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public void Load(BaseSimulation simulation)
        {
            simulation.ThrowIfNull(nameof(simulation));

            double gben;
            double cben;
            double gbcn;
            double cbcn;

            // DC model parameters
            var csat = TempSaturationCurrent * BaseParameters.Area;
            var rbpr = ModelParameters.MinimumBaseResistance / BaseParameters.Area;
            var rbpi = ModelParameters.BaseResist / BaseParameters.Area - rbpr;
            var gcpr = ModelTemperature.CollectorConduct * BaseParameters.Area;
            var gepr = ModelTemperature.EmitterConduct * BaseParameters.Area;
            var oik  = ModelTemperature.InverseRollOffForward / BaseParameters.Area;
            var c2   = TempBeLeakageCurrent * BaseParameters.Area;
            var vte  = ModelParameters.LeakBeEmissionCoefficient * Vt;
            var oikr = ModelTemperature.InverseRollOffReverse / BaseParameters.Area;
            var c4   = TempBcLeakageCurrent * BaseParameters.Area;
            var vtc  = ModelParameters.LeakBcEmissionCoefficient * Vt;
            var xjrb = ModelParameters.BaseCurrentHalfResist * BaseParameters.Area;

            // Get the current voltages
            Initialize(simulation, out var vbe, out var vbc);

            // Determine dc current and derivitives
            var vtn = Vt * ModelParameters.EmissionCoefficientForward;

            if (vbe > -5 * vtn)
            {
                var evbe = Math.Exp(vbe / vtn);
                CurrentBe = csat * (evbe - 1) + BaseConfiguration.Gmin * vbe;
                CondBe    = csat * evbe / vtn + BaseConfiguration.Gmin;
                if (c2.Equals(0)) // Avoid Exp()
                {
                    cben = 0;
                    gben = 0;
                }
                else
                {
                    var evben = Math.Exp(vbe / vte);
                    cben = c2 * (evben - 1);
                    gben = c2 * evben / vte;
                }
            }
            else
            {
                CondBe    = -csat / vbe + BaseConfiguration.Gmin;
                CurrentBe = CondBe * vbe;
                gben      = -c2 / vbe;
                cben      = gben * vbe;
            }

            vtn = Vt * ModelParameters.EmissionCoefficientReverse;
            if (vbc > -5 * vtn)
            {
                var evbc = Math.Exp(vbc / vtn);
                CurrentBc = csat * (evbc - 1) + BaseConfiguration.Gmin * vbc;
                CondBc    = csat * evbc / vtn + BaseConfiguration.Gmin;
                if (c4.Equals(0)) // Avoid Exp()
                {
                    cbcn = 0;
                    gbcn = 0;
                }
                else
                {
                    var evbcn = Math.Exp(vbc / vtc);
                    cbcn = c4 * (evbcn - 1);
                    gbcn = c4 * evbcn / vtc;
                }
            }
            else
            {
                CondBc    = -csat / vbc + BaseConfiguration.Gmin;
                CurrentBc = CondBc * vbc;
                gbcn      = -c4 / vbc;
                cbcn      = gbcn * vbc;
            }

            // Determine base charge terms
            var q1 = 1 / (1 - ModelTemperature.InverseEarlyVoltForward * vbc - ModelTemperature.InverseEarlyVoltReverse * vbe);

            if (oik.Equals(0) && oikr.Equals(0)) // Avoid computations
            {
                BaseCharge = q1;
                Dqbdve     = q1 * BaseCharge * ModelTemperature.InverseEarlyVoltReverse;
                Dqbdvc     = q1 * BaseCharge * ModelTemperature.InverseEarlyVoltForward;
            }
            else
            {
                var    q2    = oik * CurrentBe + oikr * CurrentBc;
                var    arg   = Math.Max(0, 1 + 4 * q2);
                double sqarg = 1;
                if (!arg.Equals(0)) // Avoid Sqrt()
                {
                    sqarg = Math.Sqrt(arg);
                }
                BaseCharge = q1 * (1 + sqarg) / 2;
                Dqbdve     = q1 * (BaseCharge * ModelTemperature.InverseEarlyVoltReverse + oik * CondBe / sqarg);
                Dqbdvc     = q1 * (BaseCharge * ModelTemperature.InverseEarlyVoltForward + oikr * CondBc / sqarg);
            }

            // Excess phase calculation
            var cc  = 0.0;
            var cex = CurrentBe;
            var gex = CondBe;

            ExcessPhaseCalculation(ref cc, ref cex, ref gex);

            // Determine dc incremental conductances
            cc = cc + (cex - CurrentBc) / BaseCharge - CurrentBc / TempBetaReverse - cbcn;
            var cb = CurrentBe / TempBetaForward + cben + CurrentBc / TempBetaReverse + cbcn;
            var gx = rbpr + rbpi / BaseCharge;

            if (!xjrb.Equals(0)) // Avoid calculations
            {
                var arg1 = Math.Max(cb / xjrb, 1e-9);
                var arg2 = (-1 + Math.Sqrt(1 + 14.59025 * arg1)) / 2.4317 / Math.Sqrt(arg1);
                arg1 = Math.Tan(arg2);
                gx   = rbpr + 3 * rbpi * (arg1 - arg2) / arg2 / arg1 / arg1;
            }
            if (!gx.Equals(0)) // Do not divide by 0
            {
                gx = 1 / gx;
            }
            var gpi = CondBe / TempBetaForward + gben;
            var gmu = CondBc / TempBetaReverse + gbcn;
            var go  = (CondBc + (cex - CurrentBc) * Dqbdvc / BaseCharge) / BaseCharge;
            var gm  = (gex - (cex - CurrentBc) * Dqbdve / BaseCharge) / BaseCharge - go;

            VoltageBe         = vbe;
            VoltageBc         = vbc;
            CollectorCurrent  = cc;
            BaseCurrent       = cb;
            ConductancePi     = gpi;
            ConductanceMu     = gmu;
            Transconductance  = gm;
            OutputConductance = go;
            ConductanceX      = gx;

            // Load current excitation vector
            var ceqbe = ModelParameters.BipolarType * (cc + cb - vbe * (gm + go + gpi) + vbc * go);
            var ceqbc = ModelParameters.BipolarType * (-cc + vbe * (gm + go) - vbc * (gmu + go));

            CollectorPrimePtr.Value += ceqbc;
            BasePrimePtr.Value      += -ceqbe - ceqbc;
            EmitterPrimePtr.Value   += ceqbe;

            // Load y matrix
            CollectorCollectorPtr.Value           += gcpr;
            BaseBasePtr.Value                     += gx;
            EmitterEmitterPtr.Value               += gepr;
            CollectorPrimeCollectorPrimePtr.Value += gmu + go + gcpr;
            BasePrimeBasePrimePtr.Value           += gx + gpi + gmu;
            EmitterPrimeEmitterPrimePtr.Value     += gpi + gepr + gm + go;
            CollectorCollectorPrimePtr.Value      += -gcpr;
            BaseBasePrimePtr.Value                += -gx;
            EmitterEmitterPrimePtr.Value          += -gepr;
            CollectorPrimeCollectorPtr.Value      += -gcpr;
            CollectorPrimeBasePrimePtr.Value      += -gmu + gm;
            CollectorPrimeEmitterPrimePtr.Value   += -gm - go;
            BasePrimeBasePtr.Value                += -gx;
            BasePrimeCollectorPrimePtr.Value      += -gmu;
            BasePrimeEmitterPrimePtr.Value        += -gpi;
            EmitterPrimeEmitterPtr.Value          += -gepr;
            EmitterPrimeCollectorPrimePtr.Value   += -go;
            EmitterPrimeBasePrimePtr.Value        += -gpi - gm;
        }
Exemple #18
0
        /// <summary>
        /// Execute behavior
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Load(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            bool currentState;
            var  state = simulation.RealState;

            // decide the state of the switch
            if (state.Init == RealState.InitializationStates.InitFix || state.Init == RealState.InitializationStates.InitJunction)
            {
                if (_bp.ZeroState)
                {
                    // Switch specified "on"
                    CurrentState = true;
                    currentState = true;
                }
                else
                {
                    // Switch specified "off"
                    CurrentState = false;
                    currentState = false;
                }
            }
            else
            {
                // Get the previous state
                var previousState = UseOldState ? PreviousState : CurrentState;
                var iCtrl         = state.Solution[ControllingBranch];
                if (UseOldState)
                {
                    // Calculate the current state
                    if (iCtrl > _mbp.Threshold + _mbp.Hysteresis)
                    {
                        currentState = true;
                    }
                    else if (iCtrl < _mbp.Threshold - _mbp.Hysteresis)
                    {
                        currentState = false;
                    }
                    else
                    {
                        currentState = previousState;
                    }
                    CurrentState = currentState;
                    UseOldState  = false;
                }
                else
                {
                    PreviousState = CurrentState;

                    // Calculate the current state
                    if (iCtrl > _mbp.Threshold + _mbp.Hysteresis)
                    {
                        CurrentState = true;
                        currentState = true;
                    }
                    else if (iCtrl < _mbp.Threshold - _mbp.Hysteresis)
                    {
                        CurrentState = false;
                        currentState = false;
                    }
                    else
                    {
                        currentState = PreviousState;
                    }

                    // Ensure one more iteration
                    if (currentState != PreviousState)
                    {
                        state.IsConvergent = false;
                    }
                }


                // Store the current state
                CurrentState = currentState;

                // If the state changed, ensure one more iteration
                if (currentState != previousState)
                {
                    state.IsConvergent = false;
                }
            }

            // Get the current conduction
            var gNow = currentState ? _modelload.OnConductance : _modelload.OffConductance;

            Cond = gNow;

            // Load the Y-matrix
            PosPosPtr.Value += gNow;
            PosNegPtr.Value -= gNow;
            NegPosPtr.Value -= gNow;
            NegNegPtr.Value += gNow;
        }
        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Temperature(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            double czbd, czbdsw,
                   czbs,
                   czbssw;

            /* perform the parameter defaulting */
            if (!_bp.Temperature.Given)
            {
                _bp.Temperature.RawValue = simulation.RealState.Temperature;
            }

            var vt     = _bp.Temperature * Circuit.KOverQ;
            var ratio  = _bp.Temperature / _mbp.NominalTemperature;
            var fact2  = _bp.Temperature / Circuit.ReferenceTemperature;
            var kt     = _bp.Temperature * Circuit.Boltzmann;
            var egfet  = 1.16 - 7.02e-4 * _bp.Temperature * _bp.Temperature / (_bp.Temperature + 1108);
            var arg    = -egfet / (kt + kt) + 1.1150877 / (Circuit.Boltzmann * (Circuit.ReferenceTemperature + Circuit.ReferenceTemperature));
            var pbfact = -2 * vt * (1.5 * Math.Log(fact2) + Circuit.Charge * arg);

            if (_mbp.DrainResistance.Given)
            {
                if (!_mbp.DrainResistance.Value.Equals(0.0))
                {
                    DrainConductance = 1 / _mbp.DrainResistance;
                }
                else
                {
                    DrainConductance = 0;
                }
            }
            else if (_mbp.SheetResistance.Given)
            {
                if (!_mbp.SheetResistance.Value.Equals(0.0))
                {
                    DrainConductance = 1 / (_mbp.SheetResistance * _bp.DrainSquares);
                }
                else
                {
                    DrainConductance = 0;
                }
            }
            else
            {
                DrainConductance = 0;
            }
            if (_mbp.SourceResistance.Given)
            {
                if (!_mbp.SourceResistance.Value.Equals(0.0))
                {
                    SourceConductance = 1 / _mbp.SourceResistance;
                }
                else
                {
                    SourceConductance = 0;
                }
            }
            else if (_mbp.SheetResistance.Given)
            {
                if (!_mbp.SheetResistance.Value.Equals(0.0))
                {
                    SourceConductance = 1 / (_mbp.SheetResistance * _bp.SourceSquares);
                }
                else
                {
                    SourceConductance = 0;
                }
            }
            else
            {
                SourceConductance = 0;
            }
            if (_bp.Length - 2 * _mbp.LateralDiffusion <= 0)
            {
                CircuitWarning.Warning(this, "{0}: effective channel length less than zero".FormatString(Name));
            }

            var ratio4 = ratio * Math.Sqrt(ratio);

            TempTransconductance = _mbp.Transconductance / ratio4;
            TempSurfaceMobility  = _mbp.SurfaceMobility / ratio4;
            var phio = (_mbp.Phi - _modeltemp.PbFactor1) / _modeltemp.Factor1;

            TempPhi       = fact2 * phio + pbfact;
            TempVoltageBi = _mbp.Vt0 - _mbp.MosfetType * (_mbp.Gamma * Math.Sqrt(_mbp.Phi)) + .5 * (_modeltemp.EgFet1 - egfet) +
                            _mbp.MosfetType * .5 * (TempPhi - _mbp.Phi);
            TempVt0 = TempVoltageBi + _mbp.MosfetType * _mbp.Gamma * Math.Sqrt(TempPhi);
            TempSaturationCurrent        = _mbp.JunctionSatCur * Math.Exp(-egfet / vt + _modeltemp.EgFet1 / _modeltemp.VtNominal);
            TempSaturationCurrentDensity = _mbp.JunctionSatCurDensity * Math.Exp(-egfet / vt + _modeltemp.EgFet1 / _modeltemp.VtNominal);
            var pbo     = (_mbp.BulkJunctionPotential - _modeltemp.PbFactor1) / _modeltemp.Factor1;
            var gmaold  = (_mbp.BulkJunctionPotential - pbo) / pbo;
            var capfact = 1 / (1 + _mbp.BulkJunctionBotGradingCoefficient * (4e-4 * (_mbp.NominalTemperature - Circuit.ReferenceTemperature) - gmaold));

            TempCapBd               = _mbp.CapBd * capfact;
            TempCapBs               = _mbp.CapBs * capfact;
            TempJunctionCap         = _mbp.BulkCapFactor * capfact;
            capfact                 = 1 / (1 + _mbp.BulkJunctionSideGradingCoefficient * (4e-4 * (_mbp.NominalTemperature - Circuit.ReferenceTemperature) - gmaold));
            TempJunctionCapSidewall = _mbp.SidewallCapFactor * capfact;
            TempBulkPotential       = fact2 * pbo + pbfact;
            var gmanew = (TempBulkPotential - pbo) / pbo;

            capfact                  = 1 + _mbp.BulkJunctionBotGradingCoefficient * (4e-4 * (_bp.Temperature - Circuit.ReferenceTemperature) - gmanew);
            TempCapBd               *= capfact;
            TempCapBs               *= capfact;
            TempJunctionCap         *= capfact;
            capfact                  = 1 + _mbp.BulkJunctionSideGradingCoefficient * (4e-4 * (_bp.Temperature - Circuit.ReferenceTemperature) - gmanew);
            TempJunctionCapSidewall *= capfact;
            TempDepletionCap         = _mbp.ForwardCapDepletionCoefficient * TempBulkPotential;

            if (TempSaturationCurrentDensity <= 0 || _bp.DrainArea.Value <= 0 || _bp.SourceArea.Value <= 0)
            {
                SourceVCritical = DrainVCritical = vt * Math.Log(vt / (Circuit.Root2 * TempSaturationCurrent));
            }
            else
            {
                DrainVCritical  = vt * Math.Log(vt / (Circuit.Root2 * TempSaturationCurrentDensity * _bp.DrainArea));
                SourceVCritical = vt * Math.Log(vt / (Circuit.Root2 * TempSaturationCurrentDensity * _bp.SourceArea));
            }
            if (_mbp.CapBd.Given)
            {
                czbd = TempCapBd;
            }
            else
            {
                if (_mbp.BulkCapFactor.Given)
                {
                    czbd = TempJunctionCap * _bp.DrainArea;
                }
                else
                {
                    czbd = 0;
                }
            }
            if (_mbp.SidewallCapFactor.Given)
            {
                czbdsw = TempJunctionCapSidewall * _bp.DrainPerimeter;
            }
            else
            {
                czbdsw = 0;
            }
            arg = 1 - _mbp.ForwardCapDepletionCoefficient;
            var sarg   = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
            var sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));

            CapBd         = czbd;
            CapBdSidewall = czbdsw;
            F2D           = czbd * (1 - _mbp.ForwardCapDepletionCoefficient * (1 + _mbp.BulkJunctionBotGradingCoefficient)) * sarg / arg + czbdsw * (1 -
                                                                                                                                                     _mbp.ForwardCapDepletionCoefficient * (1 + _mbp.BulkJunctionSideGradingCoefficient)) * sargsw / arg;
            F3D = czbd * _mbp.BulkJunctionBotGradingCoefficient * sarg / arg / TempBulkPotential + czbdsw * _mbp.BulkJunctionSideGradingCoefficient *
                  sargsw / arg / TempBulkPotential;
            F4D = czbd * TempBulkPotential * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) + czbdsw * TempBulkPotential * (1 - arg *
                                                                                                                                             sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient) - F3D / 2 * (TempDepletionCap * TempDepletionCap) - TempDepletionCap * F2D;
            if (_mbp.CapBs.Given)
            {
                czbs = TempCapBs;
            }
            else
            {
                if (_mbp.BulkCapFactor.Given)
                {
                    czbs = TempJunctionCap * _bp.SourceArea;
                }
                else
                {
                    czbs = 0;
                }
            }
            if (_mbp.SidewallCapFactor.Given)
            {
                czbssw = TempJunctionCapSidewall * _bp.SourcePerimeter;
            }
            else
            {
                czbssw = 0;
            }
            arg           = 1 - _mbp.ForwardCapDepletionCoefficient;
            sarg          = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
            sargsw        = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));
            CapBs         = czbs;
            CapBsSidewall = czbssw;
            F2S           = czbs * (1 - _mbp.ForwardCapDepletionCoefficient * (1 + _mbp.BulkJunctionBotGradingCoefficient)) * sarg / arg + czbssw * (1 -
                                                                                                                                                     _mbp.ForwardCapDepletionCoefficient * (1 + _mbp.BulkJunctionSideGradingCoefficient)) * sargsw / arg;
            F3S = czbs * _mbp.BulkJunctionBotGradingCoefficient * sarg / arg / TempBulkPotential + czbssw * _mbp.BulkJunctionSideGradingCoefficient *
                  sargsw / arg / TempBulkPotential;
            F4S = czbs * TempBulkPotential * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) + czbssw * TempBulkPotential * (1 - arg *
                                                                                                                                             sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient) - F3S / 2 * (TempDepletionCap * TempDepletionCap) - TempDepletionCap * F2S;
        }
Exemple #20
0
 /// <summary>
 /// Execute behavior
 /// </summary>
 /// <param name="simulation">Base simulation</param>
 public override void Load(BaseSimulation simulation)
 {
     OnConductance  = 1.0 / _mbp.OnResistance;
     OffConductance = 1.0 / _mbp.OffResistance;
 }
Exemple #21
0
        /// <summary>
        /// Execute behavior
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Load(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            var    state = simulation.RealState;
            double drainSatCur, sourceSatCur,
                   vgs, vds, vbs, vbd, vgd;
            double von;
            double vdsat, cdrain, cdreq;
            int    xnrm, xrev;

            var vt    = Circuit.KOverQ * _bp.Temperature;
            var check = 1;

            /* DETAILPROF */

            /* first, we compute a few useful values - these could be
             * pre - computed, but for historical reasons are still done
             * here.  They may be moved at the expense of instance size
             */
            var effectiveLength = _bp.Length - 2 * _mbp.LateralDiffusion;

            // This is how Spice 3f5 implements it... There may be better ways to check for 0.0
            if (_temp.TempSaturationCurrentDensity.Equals(0) || _bp.DrainArea.Value.Equals(0) || _bp.SourceArea.Value.Equals(0))
            {
                drainSatCur  = _temp.TempSaturationCurrent;
                sourceSatCur = _temp.TempSaturationCurrent;
            }
            else
            {
                drainSatCur  = _temp.TempSaturationCurrentDensity * _bp.DrainArea;
                sourceSatCur = _temp.TempSaturationCurrentDensity * _bp.SourceArea;
            }

            var beta = _temp.TempTransconductance * _bp.Width / effectiveLength;

            /*
             * ok - now to do the start - up operations
             *
             * we must get values for vbs, vds, and vgs from somewhere
             * so we either predict them or recover them from last iteration
             * These are the two most common cases - either a prediction
             * step or the general iteration step and they
             * share some code, so we put them first - others later on
             */
            if (state.Init == RealState.InitializationStates.InitFloat || state.Init == RealState.InitializationStates.InitTransient ||
                state.Init == RealState.InitializationStates.InitFix && !_bp.Off)
            {
                // general iteration
                vbs = _mbp.MosfetType * (state.Solution[_bulkNode] - state.Solution[SourceNodePrime]);
                vgs = _mbp.MosfetType * (state.Solution[_gateNode] - state.Solution[SourceNodePrime]);
                vds = _mbp.MosfetType * (state.Solution[DrainNodePrime] - state.Solution[SourceNodePrime]);

                /* now some common crunching for some more useful quantities */
                vbd = vbs - vds;
                vgd = vgs - vds;
                var vgdo = VoltageGs - VoltageDs;
                von = _mbp.MosfetType * Von;

                /*
                 * limiting
                 * we want to keep device voltages from changing
                 * so fast that the exponentials churn out overflows
                 * and similar rudeness
                 */

                if (VoltageDs >= 0)
                {
                    vgs = Transistor.LimitFet(vgs, VoltageGs, von);
                    vds = vgs - vgd;
                    vds = Transistor.LimitVoltageDs(vds, VoltageDs);
                }
                else
                {
                    vgd = Transistor.LimitFet(vgd, vgdo, von);
                    vds = vgs - vgd;
                    vds = -Transistor.LimitVoltageDs(-vds, -VoltageDs);
                    vgs = vgd + vds;
                }
                if (vds >= 0)
                {
                    vbs = Transistor.LimitJunction(vbs, VoltageBs, vt, _temp.SourceVCritical, out check);
                }
                else
                {
                    vbd = Transistor.LimitJunction(vbd, VoltageBd, vt, _temp.DrainVCritical, out check);
                    vbs = vbd + vds;
                }
            }
            else
            {
                /* ok - not one of the simple cases, so we have to
                 * look at all of the possibilities for why we were
                 * called.  We still just initialize the three voltages
                 */

                if (state.Init == RealState.InitializationStates.InitJunction && !_bp.Off)
                {
                    vds = _mbp.MosfetType * _bp.InitialVoltageDs;
                    vgs = _mbp.MosfetType * _bp.InitialVoltageGs;
                    vbs = _mbp.MosfetType * _bp.InitialVoltageBs;

                    // This is what Spice 3f5 does, but I'm not sure how valid this still is
                    if (vds.Equals(0) && vgs.Equals(0) && vbs.Equals(0) && (state.UseDc || state.Domain == RealState.DomainType.None || !state.UseIc))
                    {
                        vbs = -1;
                        vgs = _mbp.MosfetType * _temp.TempVt0;
                        vds = 0;
                    }
                }
                else
                {
                    vbs = vgs = vds = 0;
                }
            }

            /* DETAILPROF */

            /*
             * now all the preliminaries are over - we can start doing the
             * real work
             */
            vbd = vbs - vds;
            vgd = vgs - vds;

            /*
             * bulk - source and bulk - drain diodes
             * here we just evaluate the ideal diode current and the
             * corresponding derivative (conductance).
             */
            if (vbs <= 0)
            {
                CondBs    = sourceSatCur / vt;
                BsCurrent = CondBs * vbs;
                CondBs   += state.Gmin;
            }
            else
            {
                var evbs = Math.Exp(Math.Min(Transistor.MaximumExponentArgument, vbs / vt));
                CondBs    = sourceSatCur * evbs / vt + state.Gmin;
                BsCurrent = sourceSatCur * (evbs - 1);
            }
            if (vbd <= 0)
            {
                CondBd    = drainSatCur / vt;
                BdCurrent = CondBd * vbd;
                CondBd   += state.Gmin;
            }
            else
            {
                var evbd = Math.Exp(Math.Min(Transistor.MaximumExponentArgument, vbd / vt));
                CondBd    = drainSatCur * evbd / vt + state.Gmin;
                BdCurrent = drainSatCur * (evbd - 1);
            }

            /* now to determine whether the user was able to correctly
             * identify the source and drain of his device
             */
            if (vds >= 0)
            {
                /* normal mode */
                Mode = 1;
            }
            else
            {
                /* inverse mode */
                Mode = -1;
            }

            /* DETAILPROF */
            {
                /*
                 * this block of code evaluates the drain current and its
                 * derivatives using the shichman - hodges model and the
                 * charges associated with the gate, channel and bulk for
                 * mosfets
                 */

                /* the following 4 variables are local to this code block until
                 * it is obvious that they can be made global
                 */
                double arg;
                double sarg;

                if ((Mode > 0 ? vbs : vbd) <= 0)
                {
                    sarg = Math.Sqrt(_temp.TempPhi - (Mode > 0 ? vbs : vbd));
                }
                else
                {
                    sarg = Math.Sqrt(_temp.TempPhi);
                    sarg = sarg - (Mode > 0 ? vbs : vbd) / (sarg + sarg);
                    sarg = Math.Max(0, sarg);
                }
                von = _temp.TempVoltageBi * _mbp.MosfetType + _mbp.Gamma * sarg;
                var vgst = (Mode > 0 ? vgs : vgd) - von;
                vdsat = Math.Max(vgst, 0);
                if (sarg <= 0)
                {
                    arg = 0;
                }
                else
                {
                    arg = _mbp.Gamma / (sarg + sarg);
                }
                if (vgst <= 0)
                {
                    /*
                     * cutoff region
                     */
                    cdrain             = 0;
                    Transconductance   = 0;
                    CondDs             = 0;
                    TransconductanceBs = 0;
                }
                else
                {
                    /*
                     * saturation region
                     */
                    var betap = beta * (1 + _mbp.Lambda * (vds * Mode));
                    if (vgst <= vds * Mode)
                    {
                        cdrain             = betap * vgst * vgst * .5;
                        Transconductance   = betap * vgst;
                        CondDs             = _mbp.Lambda * beta * vgst * vgst * .5;
                        TransconductanceBs = Transconductance * arg;
                    }
                    else
                    {
                        /*
                         * linear region
                         */
                        cdrain             = betap * (vds * Mode) * (vgst - .5 * (vds * Mode));
                        Transconductance   = betap * (vds * Mode);
                        CondDs             = betap * (vgst - vds * Mode) + _mbp.Lambda * beta * (vds * Mode) * (vgst - .5 * (vds * Mode));
                        TransconductanceBs = Transconductance * arg;
                    }
                }

                /*
                 * finished
                 */
            }

            /* now deal with n vs p polarity */
            Von = _mbp.MosfetType * von;
            SaturationVoltageDs = _mbp.MosfetType * vdsat;
            /* line 490 */

            /*
             * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
             */
            DrainCurrent = Mode * cdrain - BdCurrent;

            /*
             * check convergence
             */
            if (!_bp.Off || state.Init != RealState.InitializationStates.InitFix)
            {
                if (check == 1)
                {
                    state.IsConvergent = false;
                }
            }

            /* DETAILPROF */

            /* save things away for next time */
            VoltageBs = vbs;
            VoltageBd = vbd;
            VoltageGs = vgs;
            VoltageDs = vds;

            /*
             * load current vector
             */
            var ceqbs = _mbp.MosfetType * (BsCurrent - (CondBs - state.Gmin) * vbs);
            var ceqbd = _mbp.MosfetType * (BdCurrent - (CondBd - state.Gmin) * vbd);

            if (Mode >= 0)
            {
                xnrm  = 1;
                xrev  = 0;
                cdreq = _mbp.MosfetType * (cdrain - CondDs * vds - Transconductance * vgs - TransconductanceBs * vbs);
            }
            else
            {
                xnrm  = 0;
                xrev  = 1;
                cdreq = -_mbp.MosfetType * (cdrain - CondDs * -vds - Transconductance * vgd - TransconductanceBs * vbd);
            }
            BulkPtr.Value        -= ceqbs + ceqbd;
            DrainPrimePtr.Value  += ceqbd - cdreq;
            SourcePrimePtr.Value += cdreq + ceqbs;

            /*
             * load y matrix
             */
            DrainDrainPtr.Value             += _temp.DrainConductance;
            SourceSourcePtr.Value           += _temp.SourceConductance;
            BulkBulkPtr.Value               += CondBd + CondBs;
            DrainPrimeDrainPrimePtr.Value   += _temp.DrainConductance + CondDs + CondBd + xrev * (Transconductance + TransconductanceBs);
            SourcePrimeSourcePrimePtr.Value += _temp.SourceConductance + CondDs + CondBs + xnrm * (Transconductance + TransconductanceBs);
            DrainDrainPrimePtr.Value        += -_temp.DrainConductance;
            SourceSourcePrimePtr.Value      += -_temp.SourceConductance;
            BulkDrainPrimePtr.Value         -= CondBd;
            BulkSourcePrimePtr.Value        -= CondBs;
            DrainPrimeDrainPtr.Value        += -_temp.DrainConductance;
            DrainPrimeGatePtr.Value         += (xnrm - xrev) * Transconductance;
            DrainPrimeBulkPtr.Value         += -CondBd + (xnrm - xrev) * TransconductanceBs;
            DrainPrimeSourcePrimePtr.Value  += -CondDs - xnrm * (Transconductance + TransconductanceBs);
            SourcePrimeGatePtr.Value        += -(xnrm - xrev) * Transconductance;
            SourcePrimeSourcePtr.Value      += -_temp.SourceConductance;
            SourcePrimeBulkPtr.Value        += -CondBs - (xnrm - xrev) * TransconductanceBs;
            SourcePrimeDrainPrimePtr.Value  += -CondDs - xrev * (Transconductance + TransconductanceBs);
        }
Exemple #22
0
        /// <summary>
        /// Execute behavior
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Load(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            var    state = simulation.RealState;
            var    rstate = state;
            double drainSatCur, sourceSatCur,
                   vgs, vds, vbs, vbd, vgd;
            double von;
            double vdsat, cdrain = 0.0,
                   cdreq;
            int xnrm, xrev;

            var vt    = Circuit.KOverQ * _bp.Temperature;
            var check = 1;

            var effectiveLength = _bp.Length - 2 * _mbp.LateralDiffusion;

            if (_temp.TempSaturationCurrentDensity.Equals(0) || _bp.DrainArea.Value <= 0 || _bp.SourceArea.Value <= 0)
            {
                drainSatCur  = _temp.TempSaturationCurrent;
                sourceSatCur = _temp.TempSaturationCurrent;
            }
            else
            {
                drainSatCur  = _temp.TempSaturationCurrentDensity * _bp.DrainArea;
                sourceSatCur = _temp.TempSaturationCurrentDensity * _bp.SourceArea;
            }

            var beta     = _temp.TempTransconductance * _bp.Width / effectiveLength;
            var oxideCap = _modeltemp.OxideCapFactor * effectiveLength * _bp.Width;

            if (state.Init == RealState.InitializationStates.InitFloat || state.Init == RealState.InitializationStates.InitTransient ||
                state.Init == RealState.InitializationStates.InitFix && !_bp.Off)
            {
                // general iteration
                vbs = _mbp.MosfetType * (rstate.Solution[_bulkNode] - rstate.Solution[SourceNodePrime]);
                vgs = _mbp.MosfetType * (rstate.Solution[_gateNode] - rstate.Solution[SourceNodePrime]);
                vds = _mbp.MosfetType * (rstate.Solution[DrainNodePrime] - rstate.Solution[SourceNodePrime]);

                // now some common crunching for some more useful quantities
                vbd = vbs - vds;
                vgd = vgs - vds;
                var vgdo = VoltageGs - VoltageDs;

                von = _mbp.MosfetType * Von;

                /*
                 * limiting
                 * We want to keep device voltages from changing
                 * so fast that the exponentials churn out overflows
                 * and similar rudeness
                 */
                if (VoltageDs >= 0)
                {
                    vgs = Transistor.LimitFet(vgs, VoltageGs, von);
                    vds = vgs - vgd;
                    vds = Transistor.LimitVoltageDs(vds, VoltageDs);
                }
                else
                {
                    vgd = Transistor.LimitFet(vgd, vgdo, von);
                    vds = vgs - vgd;
                    vds = -Transistor.LimitVoltageDs(-vds, -VoltageDs);
                    vgs = vgd + vds;
                }
                if (vds >= 0)
                {
                    vbs = Transistor.LimitJunction(vbs, VoltageBs, vt, _temp.SourceVCritical, out check);
                }
                else
                {
                    vbd = Transistor.LimitJunction(vbd, VoltageBd, vt, _temp.DrainVCritical, out check);
                    vbs = vbd + vds;
                }
            }
            else
            {
                /* ok - not one of the simple cases, so we have to
                 * look at other possibilities
                 */

                if (state.Init == RealState.InitializationStates.InitJunction && !_bp.Off)
                {
                    vds = _mbp.MosfetType * _bp.InitialVoltageDs;
                    vgs = _mbp.MosfetType * _bp.InitialVoltageGs;
                    vbs = _mbp.MosfetType * _bp.InitialVoltageBs;

                    // TODO: At some point, check what this is supposed to do
                    if (vds.Equals(0.0) && vgs.Equals(0.0) && vbs.Equals(0.0) && (state.UseDc || state.Domain == RealState.DomainType.None || !state.UseIc))
                    {
                        vbs = -1;
                        vgs = _mbp.MosfetType * _temp.TempVt0;
                        vds = 0;
                    }
                }
                else
                {
                    vbs = vgs = vds = 0;
                }
            }

            /* now all the preliminaries are over - we can start doing the
             * real work
             */
            vbd = vbs - vds;
            vgd = vgs - vds;

            /* bulk - source and bulk - drain doides
             * here we just evaluate the ideal diode current and the
             * correspoinding derivative (conductance).
             */

            if (vbs <= 0)
            {
                CondBs    = sourceSatCur / vt;
                BsCurrent = CondBs * vbs;
                CondBs   += state.Gmin;
            }
            else
            {
                var evbs = Math.Exp(vbs / vt);
                CondBs    = sourceSatCur * evbs / vt + state.Gmin;
                BsCurrent = sourceSatCur * (evbs - 1);
            }
            if (vbd <= 0)
            {
                CondBd    = drainSatCur / vt;
                BdCurrent = CondBd * vbd;
                CondBd   += state.Gmin;
            }
            else
            {
                var evbd = Math.Exp(vbd / vt);
                CondBd    = drainSatCur * evbd / vt + state.Gmin;
                BdCurrent = drainSatCur * (evbd - 1);
            }
            if (vds >= 0)
            {
                /* normal mode */
                Mode = 1;
            }
            else
            {
                /* inverse mode */
                Mode = -1;
            }
            {
                /* moseq2(vds, vbs, vgs, gm, gds, gmbs, qg, qc, qb,
                 * cggb, cgdb, cgsb, cbgb, cbdb, cbsb)
                 */
                /* note:  cgdb, cgsb, cbdb, cbsb never used */

                /*
                 * this routine evaluates the drain current, its derivatives and
                 * the charges associated with the gate, channel and bulk
                 * for mosfets
                 *
                 */

                double   arg;
                double   sarg;
                double[] a4 = new double[4], b4 = new double[4], x4 = new double[8], poly4 = new double[8];
                double   dsrgdb, d2Sdb2;
                double   sphi = 0.0;  /* square root of phi */
                double   sphi3 = 0.0; /* square root of phi cubed */
                double   barg, d2Bdb2,
                         dbrgdb,
                         argd = 0.0, args = 0.0;
                double argxs = 0.0, argxd = 0.0;
                double dgddb2, dgddvb, dgdvds, gamasd;
                double xn = 0.0, argg = 0.0, vgst,
                       dodvds = 0.0, dxndvd = 0.0, dxndvb = 0.0,
                       dudvgs, dudvds, dudvbs;
                double argv,
                       ufact, ueff, dsdvgs, dsdvbs;
                double xvalid = 0.0, bsarg = 0.0;
                double bodys = 0.0, gdbdvs = 0.0;
                double dldvgs = 0.0, dldvds = 0.0, dldvbs = 0.0;
                double xlamda = _mbp.Lambda;

                /* 'local' variables - these switch d & s around appropriately
                 * so that we don't have to worry about vds < 0
                 */
                double lvbs      = Mode > 0 ? vbs : vbd;
                double lvds      = Mode * vds;
                double lvgs      = Mode > 0 ? vgs : vgd;
                double phiMinVbs = _temp.TempPhi - lvbs;
                double tmp; /* a temporary variable, not used for more than */
                            /* about 10 lines at a time */

                /*
                 * compute some useful quantities
                 */

                if (lvbs <= 0.0)
                {
                    sarg   = Math.Sqrt(phiMinVbs);
                    dsrgdb = -0.5 / sarg;
                    d2Sdb2 = 0.5 * dsrgdb / phiMinVbs;
                }
                else
                {
                    sphi   = Math.Sqrt(_temp.TempPhi);
                    sphi3  = _temp.TempPhi * sphi;
                    sarg   = sphi / (1.0 + 0.5 * lvbs / _temp.TempPhi);
                    tmp    = sarg / sphi3;
                    dsrgdb = -0.5 * sarg * tmp;
                    d2Sdb2 = -dsrgdb * tmp;
                }
                if (lvds - lvbs >= 0)
                {
                    barg   = Math.Sqrt(phiMinVbs + lvds);
                    dbrgdb = -0.5 / barg;
                    d2Bdb2 = 0.5 * dbrgdb / (phiMinVbs + lvds);
                }
                else
                {
                    barg   = sphi / (1.0 + 0.5 * (lvbs - lvds) / _temp.TempPhi);
                    tmp    = barg / sphi3;
                    dbrgdb = -0.5 * barg * tmp;
                    d2Bdb2 = -dbrgdb * tmp;
                }

                /*
                 * calculate threshold voltage (von)
                 * narrow - channel effect
                 */

                /* XXX constant per device */
                var factor = 0.125 * _mbp.NarrowFactor * 2.0 * Math.PI * Transistor.EpsilonSilicon / oxideCap * effectiveLength;
                /* XXX constant per device */
                var eta  = 1.0 + factor;
                var vbin = _temp.TempVoltageBi * _mbp.MosfetType + factor * phiMinVbs;
                if (_mbp.Gamma > 0.0 || _mbp.SubstrateDoping > 0.0)
                {
                    var xwd = _modeltemp.Xd * barg;
                    var xws = _modeltemp.Xd * sarg;

                    /*
                     * short - channel effect with vds .ne. 0.0
                     */

                    var argss  = 0.0;
                    var argsd  = 0.0;
                    var dbargs = 0.0;
                    var dbargd = 0.0;
                    dgdvds = 0.0;
                    dgddb2 = 0.0;
                    if (_mbp.JunctionDepth > 0)
                    {
                        tmp   = 2.0 / _mbp.JunctionDepth;
                        argxs = 1.0 + xws * tmp;
                        argxd = 1.0 + xwd * tmp;
                        args  = Math.Sqrt(argxs);
                        argd  = Math.Sqrt(argxd);
                        tmp   = .5 * _mbp.JunctionDepth / effectiveLength;
                        argss = tmp * (args - 1.0);
                        argsd = tmp * (argd - 1.0);
                    }
                    gamasd = _mbp.Gamma * (1.0 - argss - argsd);
                    var dbxwd = _modeltemp.Xd * dbrgdb;
                    var dbxws = _modeltemp.Xd * dsrgdb;
                    if (_mbp.JunctionDepth > 0)
                    {
                        tmp    = 0.5 / effectiveLength;
                        dbargs = tmp * dbxws / args;
                        dbargd = tmp * dbxwd / argd;
                        var dasdb2 = -_modeltemp.Xd * (d2Sdb2 + dsrgdb * dsrgdb * _modeltemp.Xd / (_mbp.JunctionDepth * argxs)) / (effectiveLength *
                                                                                                                                   args);
                        var daddb2 = -_modeltemp.Xd * (d2Bdb2 + dbrgdb * dbrgdb * _modeltemp.Xd / (_mbp.JunctionDepth * argxd)) / (effectiveLength *
                                                                                                                                   argd);
                        dgddb2 = -0.5 * _mbp.Gamma * (dasdb2 + daddb2);
                    }
                    dgddvb = -_mbp.Gamma * (dbargs + dbargd);
                    if (_mbp.JunctionDepth > 0)
                    {
                        var ddxwd = -dbxwd;
                        dgdvds = -_mbp.Gamma * 0.5 * ddxwd / (effectiveLength * argd);
                    }
                }
                else
                {
                    gamasd = _mbp.Gamma;
                    dgddvb = 0.0;
                    dgdvds = 0.0;
                    dgddb2 = 0.0;
                }
                von = vbin + gamasd * sarg;
                var vth = von;
                vdsat = 0.0;
                if (!_mbp.FastSurfaceStateDensity.Value.Equals(0.0) && !oxideCap.Equals(0.0))
                {
                    /* XXX constant per model */
                    var cfs    = Circuit.Charge * _mbp.FastSurfaceStateDensity * 1e4;
                    var cdonco = -(gamasd * dsrgdb + dgddvb * sarg) + factor;
                    xn   = 1.0 + cfs / oxideCap * _bp.Width * effectiveLength + cdonco;
                    tmp  = vt * xn;
                    von  = von + tmp;
                    argg = 1.0 / tmp;
                    vgst = lvgs - von;
                }
                else
                {
                    vgst = lvgs - von;
                    if (lvgs <= von)
                    {
                        /*
                         * cutoff region
                         */
                        CondDs = 0.0;
                        goto line1050;
                    }
                }

                /*
                 * compute some more useful quantities
                 */

                var sarg3 = sarg * sarg * sarg;
                /* XXX constant per model */
                var sbiarg = Math.Sqrt(_temp.TempBulkPotential);
                var gammad = gamasd;
                var dgdvbs = dgddvb;
                var body   = barg * barg * barg - sarg3;
                var gdbdv  = 2.0 * gammad * (barg * barg * dbrgdb - sarg * sarg * dsrgdb);
                var dodvbs = -factor + dgdvbs * sarg + gammad * dsrgdb;
                if (_mbp.FastSurfaceStateDensity.Value.Equals(0.0))
                {
                    goto line400;
                }
                if (oxideCap.Equals(0.0))
                {
                    goto line410;
                }
                dxndvb = 2.0 * dgdvbs * dsrgdb + gammad * d2Sdb2 + dgddb2 * sarg;
                dodvbs = dodvbs + vt * dxndvb;
                dxndvd = dgdvds * dsrgdb;
                dodvds = dgdvds * sarg + vt * dxndvd;

                /*
                 * evaluate effective mobility and its derivatives
                 */
line400:
                if (oxideCap <= 0.0)
                {
                    goto line410;
                }
                var udenom = vgst;
                tmp = _mbp.CriticalField * 100 /* cm / m */ * Transistor.EpsilonSilicon / _modeltemp.OxideCapFactor;
                if (udenom <= tmp)
                {
                    goto line410;
                }
                ufact  = Math.Exp(_mbp.CriticalFieldExp * Math.Log(tmp / udenom));
                ueff   = _mbp.SurfaceMobility * 1e-4 /* (m *  * 2 / cm *  * 2) */ * ufact;
                dudvgs = -ufact * _mbp.CriticalFieldExp / udenom;
                dudvds = 0.0;
                dudvbs = _mbp.CriticalFieldExp * ufact * dodvbs / vgst;
                goto line500;
line410:
                ufact  = 1.0;
                ueff   = _mbp.SurfaceMobility * 1e-4 /* (m *  * 2 / cm *  * 2) */;
                dudvgs = 0.0;
                dudvds = 0.0;
                dudvbs = 0.0;

                /*
                 * evaluate saturation voltage and its derivatives according to
                 * grove - frohman equation
                 */
line500:
                var vgsx = lvgs;
                gammad   = gamasd / eta;
                dgdvbs   = dgddvb;
                if (!_mbp.FastSurfaceStateDensity.Value.Equals(0.0) && !oxideCap.Equals(0.0))
                {
                    vgsx = Math.Max(lvgs, von);
                }
                if (gammad > 0)
                {
                    var gammd2 = gammad * gammad;
                    argv = (vgsx - vbin) / eta + phiMinVbs;
                    if (argv <= 0.0)
                    {
                        vdsat  = 0.0;
                        dsdvgs = 0.0;
                        dsdvbs = 0.0;
                    }
                    else
                    {
                        arg    = Math.Sqrt(1.0 + 4.0 * argv / gammd2);
                        vdsat  = (vgsx - vbin) / eta + gammd2 * (1.0 - arg) / 2.0;
                        vdsat  = Math.Max(vdsat, 0.0);
                        dsdvgs = (1.0 - 1.0 / arg) / eta;
                        dsdvbs = (gammad * (1.0 - arg) + 2.0 * argv / (gammad * arg)) / eta * dgdvbs + 1.0 / arg + factor * dsdvgs;
                    }
                }
                else
                {
                    vdsat  = (vgsx - vbin) / eta;
                    vdsat  = Math.Max(vdsat, 0.0);
                    dsdvgs = 1.0;
                    dsdvbs = 0.0;
                }
                if (_mbp.MaxDriftVelocity > 0)
                {
                    /*
                     * evaluate saturation voltage and its derivatives
                     * according to baum's theory of scattering velocity
                     * saturation
                     */
                    var    v1 = (vgsx - vbin) / eta + phiMinVbs;
                    var    v2 = phiMinVbs;
                    var    xv = _mbp.MaxDriftVelocity * effectiveLength / ueff;
                    var    a1 = gammad / 0.75;
                    var    b1 = -2.0 * (v1 + xv);
                    var    c1 = -2.0 * gammad * xv;
                    var    d1 = 2.0 * v1 * (v2 + xv) - v2 * v2 - 4.0 / 3.0 * gammad * sarg3;
                    var    a  = -b1;
                    var    b  = a1 * c1 - 4.0 * d1;
                    var    c  = -d1 * (a1 * a1 - 4.0 * b1) - c1 * c1;
                    var    r  = -a * a / 3.0 + b;
                    var    s  = 2.0 * a * a * a / 27.0 - a * b / 3.0 + c;
                    var    r3 = r * r * r;
                    var    s2 = s * s;
                    var    p  = s2 / 4.0 + r3 / 27.0;
                    var    p0 = Math.Abs(p);
                    var    p2 = Math.Sqrt(p0);
                    double y3;
                    if (p < 0)
                    {
                        var ro = Math.Sqrt(s2 / 4.0 + p0);
                        ro = Math.Log(ro) / 3.0;
                        ro = Math.Exp(ro);
                        var fi = Math.Atan(-2.0 * p2 / s);
                        y3 = 2.0 * ro * Math.Cos(fi / 3.0) - a / 3.0;
                    }
                    else
                    {
                        var p3 = -s / 2.0 + p2;
                        p3 = Math.Exp(Math.Log(Math.Abs(p3)) / 3.0);
                        var p4 = -s / 2.0 - p2;
                        p4 = Math.Exp(Math.Log(Math.Abs(p4)) / 3.0);
                        y3 = p3 + p4 - a / 3.0;
                    }
                    var iknt = 0;
                    var a3   = Math.Sqrt(a1 * a1 / 4.0 - b1 + y3);
                    var b3   = Math.Sqrt(y3 * y3 / 4.0 - d1);
                    for (int i = 1; i <= 4; i++)
                    {
                        a4[i - 1] = a1 / 2.0 + Sig1[i - 1] * a3;
                        b4[i - 1] = y3 / 2.0 + Sig2[i - 1] * b3;
                        var delta4 = a4[i - 1] * a4[i - 1] / 4.0 - b4[i - 1];
                        if (delta4 < 0)
                        {
                            continue;
                        }
                        iknt         = iknt + 1;
                        tmp          = Math.Sqrt(delta4);
                        x4[iknt - 1] = -a4[i - 1] / 2.0 + tmp;
                        iknt         = iknt + 1;
                        x4[iknt - 1] = -a4[i - 1] / 2.0 - tmp;
                    }
                    var jknt = 0;
                    for (int j = 1; j <= iknt; j++)
                    {
                        if (x4[j - 1] <= 0)
                        {
                            continue;
                        }
                        /* XXX implement this sanely */
                        poly4[j - 1] = x4[j - 1] * x4[j - 1] * x4[j - 1] * x4[j - 1] + a1 * x4[j - 1] * x4[j - 1] * x4[j - 1];
                        poly4[j - 1] = poly4[j - 1] + b1 * x4[j - 1] * x4[j - 1] + c1 * x4[j - 1] + d1;
                        if (Math.Abs(poly4[j - 1]) > 1.0e-6)
                        {
                            continue;
                        }
                        jknt = jknt + 1;
                        if (jknt <= 1)
                        {
                            xvalid = x4[j - 1];
                        }
                        if (x4[j - 1] > xvalid)
                        {
                            continue;
                        }
                        xvalid = x4[j - 1];
                    }
                    if (jknt > 0)
                    {
                        vdsat = xvalid * xvalid - phiMinVbs;
                    }
                }

                /*
                 * evaluate effective channel length and its derivatives
                 */
                if (!lvds.Equals(0.0))
                {
                    gammad = gamasd;
                    double dbsrdb;
                    if (lvbs - vdsat <= 0)
                    {
                        bsarg  = Math.Sqrt(vdsat + phiMinVbs);
                        dbsrdb = -0.5 / bsarg;
                    }
                    else
                    {
                        bsarg  = sphi / (1.0 + 0.5 * (lvbs - vdsat) / _temp.TempPhi);
                        dbsrdb = -0.5 * bsarg * bsarg / sphi3;
                    }
                    bodys  = bsarg * bsarg * bsarg - sarg3;
                    gdbdvs = 2.0 * gammad * (bsarg * bsarg * dbsrdb - sarg * sarg * dsrgdb);
                    double xlfact;
                    double dldsat;
                    if (_mbp.MaxDriftVelocity <= 0)
                    {
                        if (_mbp.SubstrateDoping.Value.Equals(0.0))
                        {
                            goto line610;
                        }
                        if (xlamda > 0.0)
                        {
                            goto line610;
                        }
                        argv = (lvds - vdsat) / 4.0;
                        var sargv = Math.Sqrt(1.0 + argv * argv);
                        arg    = Math.Sqrt(argv + sargv);
                        xlfact = _modeltemp.Xd / (effectiveLength * lvds);
                        xlamda = xlfact * arg;
                        dldsat = lvds * xlamda / (8.0 * sargv);
                    }
                    else
                    {
                        argv = (vgsx - vbin) / eta - vdsat;
                        var xdv    = _modeltemp.Xd / Math.Sqrt(_mbp.ChannelCharge);
                        var xlv    = _mbp.MaxDriftVelocity * xdv / (2.0 * ueff);
                        var vqchan = argv - gammad * bsarg;
                        var dqdsat = -1.0 + gammad * dbsrdb;
                        var vl     = _mbp.MaxDriftVelocity * effectiveLength;
                        var dfunds = vl * dqdsat - ueff * vqchan;
                        var dfundg = (vl - ueff * vdsat) / eta;
                        var dfundb = -vl * (1.0 + dqdsat - factor / eta) + ueff * (gdbdvs - dgdvbs * bodys / 1.5) / eta;
                        dsdvgs = -dfundg / dfunds;
                        dsdvbs = -dfundb / dfunds;
                        if (_mbp.SubstrateDoping.Value.Equals(0.0))
                        {
                            goto line610;
                        }
                        if (xlamda > 0.0)
                        {
                            goto line610;
                        }
                        argv = lvds - vdsat;
                        argv = Math.Max(argv, 0.0);
                        var xls = Math.Sqrt(xlv * xlv + argv);
                        dldsat = xdv / (2.0 * xls);
                        xlfact = xdv / (effectiveLength * lvds);
                        xlamda = xlfact * (xls - xlv);
                        dldsat = dldsat / effectiveLength;
                    }
                    dldvgs = dldsat * dsdvgs;
                    dldvds = -xlamda + dldsat;
                    dldvbs = dldsat * dsdvbs;
                }

                // Edited to work
                goto line610_finish;
line610:
                dldvgs = 0.0;
                dldvds = 0.0;
                dldvbs = 0.0;
line610_finish:

                /*
                 * limit channel shortening at punch - through
                 */
                var xwb = _modeltemp.Xd * sbiarg;
                var xld    = effectiveLength - xwb;
                var clfact = 1.0 - xlamda * lvds;
                dldvds = -xlamda - dldvds;
                var xleff  = effectiveLength * clfact;
                var deltal = xlamda * lvds * effectiveLength;
                if (_mbp.SubstrateDoping.Value.Equals(0.0))
                {
                    xwb = 0.25e-6;
                }
                if (xleff < xwb)
                {
                    xleff  = xwb / (1.0 + (deltal - xld) / xwb);
                    clfact = xleff / effectiveLength;
                    var dfact = xleff * xleff / (xwb * xwb);
                    dldvgs = dfact * dldvgs;
                    dldvds = dfact * dldvds;
                    dldvbs = dfact * dldvbs;
                }

                /*
                 * evaluate effective beta (effective kp)
                 */
                var beta1 = beta * ufact / clfact;

                /*
                 * test for mode of operation and branch appropriately
                 */
                gammad = gamasd;
                dgdvbs = dgddvb;
                if (lvds <= 1.0e-10)
                {
                    if (lvgs <= von)
                    {
                        if (_mbp.FastSurfaceStateDensity.Value.Equals(0.0) || oxideCap.Equals(0.0))
                        {
                            CondDs = 0.0;
                            goto line1050;
                        }

                        CondDs = beta1 * (von - vbin - gammad * sarg) * Math.Exp(argg * (lvgs - von));
                        goto line1050;
                    }

                    CondDs = beta1 * (lvgs - vbin - gammad * sarg);
                    goto line1050;
                }

                if (lvgs > von)
                {
                    goto line900;
                }

                /*
                 * subthreshold region
                 */
                if (vdsat <= 0)
                {
                    CondDs = 0.0;
                    if (lvgs > vth)
                    {
                        goto doneval;
                    }
                    goto line1050;
                }
                var vdson = Math.Min(vdsat, lvds);
                if (lvds > vdsat)
                {
                    barg  = bsarg;
                    body  = bodys;
                    gdbdv = gdbdvs;
                }
                var cdson  = beta1 * ((von - vbin - eta * vdson * 0.5) * vdson - gammad * body / 1.5);
                var didvds = beta1 * (von - vbin - eta * vdson - gammad * barg);
                var gdson  = -cdson * dldvds / clfact - beta1 * dgdvds * body / 1.5;
                if (lvds < vdsat)
                {
                    gdson = gdson + didvds;
                }
                var gbson = -cdson * dldvbs / clfact + beta1 * (dodvbs * vdson + factor * vdson - dgdvbs * body / 1.5 - gdbdv);
                if (lvds > vdsat)
                {
                    gbson = gbson + didvds * dsdvbs;
                }
                var expg = Math.Exp(argg * (lvgs - von));
                cdrain = cdson * expg;
                var gmw = cdrain * argg;
                Transconductance = gmw;
                if (lvds > vdsat)
                {
                    Transconductance = gmw + didvds * dsdvgs * expg;
                }
                tmp                = gmw * (lvgs - von) / xn;
                CondDs             = gdson * expg - Transconductance * dodvds - tmp * dxndvd;
                TransconductanceBs = gbson * expg - Transconductance * dodvbs - tmp * dxndvb;
                goto doneval;

line900:
                if (lvds <= vdsat)
                {
                    /*
                     * linear region
                     */
                    cdrain             = beta1 * ((lvgs - vbin - eta * lvds / 2.0) * lvds - gammad * body / 1.5);
                    arg                = cdrain * (dudvgs / ufact - dldvgs / clfact);
                    Transconductance   = arg + beta1 * lvds;
                    arg                = cdrain * (dudvds / ufact - dldvds / clfact);
                    CondDs             = arg + beta1 * (lvgs - vbin - eta * lvds - gammad * barg - dgdvds * body / 1.5);
                    arg                = cdrain * (dudvbs / ufact - dldvbs / clfact);
                    TransconductanceBs = arg - beta1 * (gdbdv + dgdvbs * body / 1.5 - factor * lvds);
                }
                else
                {
                    /*
                     * saturation region
                     */
                    cdrain             = beta1 * ((lvgs - vbin - eta * vdsat / 2.0) * vdsat - gammad * bodys / 1.5);
                    arg                = cdrain * (dudvgs / ufact - dldvgs / clfact);
                    Transconductance   = arg + beta1 * vdsat + beta1 * (lvgs - vbin - eta * vdsat - gammad * bsarg) * dsdvgs;
                    CondDs             = -cdrain * dldvds / clfact - beta1 * dgdvds * bodys / 1.5;
                    arg                = cdrain * (dudvbs / ufact - dldvbs / clfact);
                    TransconductanceBs = arg - beta1 * (gdbdvs + dgdvbs * bodys / 1.5 - factor * vdsat) + beta1 * (lvgs - vbin - eta * vdsat - gammad *
                                                                                                                   bsarg) * dsdvbs;
                }

                /*
                 * compute charges for "on" region
                 */
                goto doneval;

                /*
                 * finish special cases
                 */
line1050:
                cdrain             = 0.0;
                Transconductance   = 0.0;
                TransconductanceBs = 0.0;

                /*
                 * finished
                 */
            }
doneval:
            Von = _mbp.MosfetType * von;
            SaturationVoltageDs = _mbp.MosfetType * vdsat;

            /*
             * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
             */
            DrainCurrent = Mode * cdrain - BdCurrent;

            /*
             * check convergence
             */
            if (!_bp.Off || state.Init != RealState.InitializationStates.InitFix)
            {
                if (check == 1)
                {
                    state.IsConvergent = false;
                }
            }
            VoltageBs = vbs;
            VoltageBd = vbd;
            VoltageGs = vgs;
            VoltageDs = vds;

            /*
             * load current vector
             */
            var ceqbs = _mbp.MosfetType * (BsCurrent - (CondBs - state.Gmin) * vbs);
            var ceqbd = _mbp.MosfetType * (BdCurrent - (CondBd - state.Gmin) * vbd);

            if (Mode >= 0)
            {
                xnrm  = 1;
                xrev  = 0;
                cdreq = _mbp.MosfetType * (cdrain - CondDs * vds - Transconductance * vgs - TransconductanceBs * vbs);
            }
            else
            {
                xnrm  = 0;
                xrev  = 1;
                cdreq = -_mbp.MosfetType * (cdrain - CondDs * -vds - Transconductance * vgd - TransconductanceBs * vbd);
            }
            BulkPtr.Value        -= ceqbs + ceqbd;
            DrainPrimePtr.Value  += ceqbd - cdreq;
            SourcePrimePtr.Value += cdreq + ceqbs;

            // load Y-matrix
            DrainDrainPtr.Value             += _temp.DrainConductance;
            SourceSourcePtr.Value           += _temp.SourceConductance;
            BulkBulkPtr.Value               += CondBd + CondBs;
            DrainPrimeDrainPrimePtr.Value   += _temp.DrainConductance + CondDs + CondBd + xrev * (Transconductance + TransconductanceBs);
            SourcePrimeSourcePrimePtr.Value += _temp.SourceConductance + CondDs + CondBs + xnrm * (Transconductance + TransconductanceBs);
            DrainDrainPrimePtr.Value        += -_temp.DrainConductance;
            SourceSourcePrimePtr.Value      += -_temp.SourceConductance;
            BulkDrainPrimePtr.Value         -= CondBd;
            BulkSourcePrimePtr.Value        -= CondBs;
            DrainPrimeDrainPtr.Value        += -_temp.DrainConductance;
            DrainPrimeGatePtr.Value         += (xnrm - xrev) * Transconductance;
            DrainPrimeBulkPtr.Value         += -CondBd + (xnrm - xrev) * TransconductanceBs;
            DrainPrimeSourcePrimePtr.Value  += -CondDs - xnrm * (Transconductance + TransconductanceBs);
            SourcePrimeGatePtr.Value        += -(xnrm - xrev) * Transconductance;
            SourcePrimeSourcePtr.Value      += -_temp.SourceConductance;
            SourcePrimeBulkPtr.Value        += -CondBs - (xnrm - xrev) * TransconductanceBs;
            SourcePrimeDrainPrimePtr.Value  += -CondDs - xrev * (Transconductance + TransconductanceBs);
        }
Exemple #23
0
 protected void SetSweepSimulation(ICircuitContext context, List <KeyValuePair <Parameter, double> > parameterValues, BaseSimulation simulation)
 {
     ParameterUpdater.Update(simulation, context, parameterValues);
 }
Exemple #24
0
 /// <summary>
 /// Test convergence on device-level
 /// </summary>
 /// <param name="simulation">Base simulation</param>
 /// <returns></returns>
 public virtual bool IsConvergent(BaseSimulation simulation)
 {
     return(true);
 }
Exemple #25
0
        /// <summary>
        /// Loads the Y-matrix and Rhs-vector.
        /// </summary>
        /// <param name="simulation">The base simulation.</param>
        public void Load(BaseSimulation simulation)
        {
            simulation.ThrowIfNull(nameof(simulation));
            var state = simulation.RealState;

            // Get the current voltages
            Initialize(simulation, out var vgs, out var vds, out var vbs, out var check);
            var vbd = vbs - vds;
            var vgd = vgs - vds;

            /*
             * bulk - source and bulk - drain diodes
             * here we just evaluate the ideal diode current and the
             * corresponding derivative (conductance).
             */
            if (vbs <= 0)
            {
                CondBs    = SourceSatCurrent / Vt;
                BsCurrent = CondBs * vbs;
                CondBs   += BaseConfiguration.Gmin;
            }
            else
            {
                var evbs = Math.Exp(Math.Min(MaximumExponentArgument, vbs / Vt));
                CondBs    = SourceSatCurrent * evbs / Vt + BaseConfiguration.Gmin;
                BsCurrent = SourceSatCurrent * (evbs - 1);
            }
            if (vbd <= 0)
            {
                CondBd    = DrainSatCurrent / Vt;
                BdCurrent = CondBd * vbd;
                CondBd   += BaseConfiguration.Gmin;
            }
            else
            {
                var evbd = Math.Exp(Math.Min(MaximumExponentArgument, vbd / Vt));
                CondBd    = DrainSatCurrent * evbd / Vt + BaseConfiguration.Gmin;
                BdCurrent = DrainSatCurrent * (evbd - 1);
            }

            /*
             * Now to determine whether the user was able to correctly
             * identify the source and drain of his device
             */
            if (vds >= 0)
            {
                // normal mode
                Mode = 1;
            }
            else
            {
                // inverse mode
                Mode = -1;
            }

            // Update
            VoltageBs = vbs;
            VoltageBd = vbd;
            VoltageGs = vgs;
            VoltageDs = vds;

            // Evaluate the currents and derivatives
            var cdrain = Mode > 0 ? Evaluate(vgs, vds, vbs) : Evaluate(vgd, -vds, vbd);

            DrainCurrent = Mode * cdrain - BdCurrent;

            // Check convergence
            if (!BaseParameters.Off || state.Init != InitializationModes.Fix)
            {
                if (check)
                {
                    state.IsConvergent = false;
                }
            }

            // Load current vector
            double xnrm, xrev, cdreq;
            var    ceqbs = ModelParameters.MosfetType * (BsCurrent - (CondBs - BaseConfiguration.Gmin) * vbs);
            var    ceqbd = ModelParameters.MosfetType * (BdCurrent - (CondBd - BaseConfiguration.Gmin) * vbd);

            if (Mode >= 0)
            {
                xnrm  = 1;
                xrev  = 0;
                cdreq = ModelParameters.MosfetType * (cdrain - CondDs * vds - Transconductance * vgs - TransconductanceBs * vbs);
            }
            else
            {
                xnrm  = 0;
                xrev  = 1;
                cdreq = -ModelParameters.MosfetType * (cdrain - CondDs * -vds - Transconductance * vgd - TransconductanceBs * vbd);
            }
            BulkPtr.Value        -= ceqbs + ceqbd;
            DrainPrimePtr.Value  += ceqbd - cdreq;
            SourcePrimePtr.Value += cdreq + ceqbs;

            // Load Y-matrix
            DrainDrainPtr.Value             += DrainConductance;
            SourceSourcePtr.Value           += SourceConductance;
            BulkBulkPtr.Value               += CondBd + CondBs;
            DrainPrimeDrainPrimePtr.Value   += DrainConductance + CondDs + CondBd + xrev * (Transconductance + TransconductanceBs);
            SourcePrimeSourcePrimePtr.Value += SourceConductance + CondDs + CondBs + xnrm * (Transconductance + TransconductanceBs);
            DrainDrainPrimePtr.Value        += -DrainConductance;
            SourceSourcePrimePtr.Value      += -SourceConductance;
            BulkDrainPrimePtr.Value         -= CondBd;
            BulkSourcePrimePtr.Value        -= CondBs;
            DrainPrimeDrainPtr.Value        += -DrainConductance;
            DrainPrimeGatePtr.Value         += (xnrm - xrev) * Transconductance;
            DrainPrimeBulkPtr.Value         += -CondBd + (xnrm - xrev) * TransconductanceBs;
            DrainPrimeSourcePrimePtr.Value  += -CondDs - xnrm * (Transconductance + TransconductanceBs);
            SourcePrimeGatePtr.Value        += -(xnrm - xrev) * Transconductance;
            SourcePrimeSourcePtr.Value      += -SourceConductance;
            SourcePrimeBulkPtr.Value        += -CondBs - (xnrm - xrev) * TransconductanceBs;
            SourcePrimeDrainPrimePtr.Value  += -CondDs - xrev * (Transconductance + TransconductanceBs);
        }
 /// <summary>
 /// Perform temperature-dependent calculations.
 /// </summary>
 /// <param name="simulation">The base simulation.</param>
 public void Temperature(BaseSimulation simulation)
 {
     // Calculate coupling factor
     Factor = BaseParameters.Coupling * Math.Sqrt(BaseParameters1.Inductance * BaseParameters2.Inductance);
 }
        /// <summary>
        /// Execute behavior
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Load(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            bool currentState;
            var  state = simulation.RealState;

            if (state.Init == InitializationModes.Fix || state.Init == InitializationModes.Junction)
            {
                if (_bp.ZeroState)
                {
                    // Switch specified "on"
                    CurrentState = true;
                    currentState = true;
                }
                else
                {
                    // Switch specified "off"
                    CurrentState = false;
                    currentState = false;
                }
            }
            else
            {
                // First iteration after a new timepoint!
                var vCtrl = state.Solution[_contPosourceNode] - state.Solution[_contNegateNode];
                if (UseOldState)
                {
                    // Calculate the current state
                    if (vCtrl > _mbp.Threshold + _mbp.Hysteresis)
                    {
                        currentState = true;
                    }
                    else if (vCtrl < _mbp.Threshold - _mbp.Hysteresis)
                    {
                        currentState = false;
                    }
                    else
                    {
                        currentState = PreviousState;
                    }
                    CurrentState = currentState;
                    UseOldState  = false;
                }
                else
                {
                    // Continue from last iteration
                    PreviousState = CurrentState;

                    // Calculate the current state
                    if (vCtrl > _mbp.Threshold + _mbp.Hysteresis)
                    {
                        CurrentState = true;
                        currentState = true;
                    }
                    else if (vCtrl < _mbp.Threshold - _mbp.Hysteresis)
                    {
                        CurrentState = false;
                        currentState = false;
                    }
                    else
                    {
                        currentState = PreviousState;
                    }

                    // Ensure one more iteration
                    if (currentState != PreviousState)
                    {
                        state.IsConvergent = false;
                    }
                }
            }

            var gNow = currentState ? _modelload.OnConductance : _modelload.OffConductance;

            Cond = gNow;

            // Load the Y-matrix
            PosPosPtr.Value += gNow;
            PosNegPtr.Value -= gNow;
            NegPosPtr.Value -= gNow;
            NegNegPtr.Value += gNow;
        }
Exemple #28
0
        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Temperature(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            /* now model parameter preprocessing */
            if (!_mbp.NominalTemperature.Given)
            {
                _mbp.NominalTemperature.RawValue = simulation.RealState.NominalTemperature;
            }
            Factor1   = _mbp.NominalTemperature / Circuit.ReferenceTemperature;
            VtNominal = _mbp.NominalTemperature * Circuit.KOverQ;
            var kt1 = Circuit.Boltzmann * _mbp.NominalTemperature;

            EgFet1 = 1.16 - 7.02e-4 * _mbp.NominalTemperature * _mbp.NominalTemperature / (_mbp.NominalTemperature + 1108);
            var arg1 = -EgFet1 / (kt1 + kt1) + 1.1150877 / (Circuit.Boltzmann * (Circuit.ReferenceTemperature + Circuit.ReferenceTemperature));

            PbFactor1 = -2 * VtNominal * (1.5 * Math.Log(Factor1) + Circuit.Charge * arg1);

            if (_mbp.SubstrateDoping.Given)
            {
                if (_mbp.SubstrateDoping * 1e6 > 1.45e16)
                {
                    if (!_mbp.Phi.Given)
                    {
                        _mbp.Phi.RawValue = 2 * VtNominal * Math.Log(_mbp.SubstrateDoping * 1e6 / 1.45e16);
                        _mbp.Phi.RawValue = Math.Max(.1, _mbp.Phi);
                    }
                    var fermis = _mbp.MosfetType * .5 * _mbp.Phi;
                    var wkfng  = 3.2;
                    if (!_mbp.GateType.Given)
                    {
                        _mbp.GateType.RawValue = 1;
                    }
                    if (!_mbp.GateType.RawValue.Equals(0))
                    {
                        var fermig = _mbp.MosfetType * _mbp.GateType * .5 * EgFet1;
                        wkfng = 3.25 + .5 * EgFet1 - fermig;
                    }
                    var wkfngs = wkfng - (3.25 + .5 * EgFet1 + fermis);
                    if (!_mbp.Gamma.Given)
                    {
                        _mbp.Gamma.RawValue = Math.Sqrt(2 * 11.70 * 8.854214871e-12 * Circuit.Charge * _mbp.SubstrateDoping * 1e6) / _mbp.OxideCapFactor;
                    }
                    if (!_mbp.Vt0.Given)
                    {
                        if (!_mbp.SurfaceStateDensity.Given)
                        {
                            _mbp.SurfaceStateDensity.RawValue = 0;
                        }
                        var vfb = wkfngs - _mbp.SurfaceStateDensity * 1e4 * Circuit.Charge / _mbp.OxideCapFactor;
                        _mbp.Vt0.RawValue = vfb + _mbp.MosfetType * (_mbp.Gamma * Math.Sqrt(_mbp.Phi) + _mbp.Phi);
                    }

                    Xd = Math.Sqrt((Transistor.EpsilonSilicon + Transistor.EpsilonSilicon) / (Circuit.Charge * _mbp.SubstrateDoping * 1e6));
                }
                else
                {
                    _mbp.SubstrateDoping.RawValue = 0;
                    throw new CircuitException("{0}: Nsub < Ni".FormatString(Name));
                }
            }
            if (!_mbp.BulkCapFactor.Given)
            {
                _mbp.BulkCapFactor.RawValue = Math.Sqrt(Transistor.EpsilonSilicon * Circuit.Charge * _mbp.SubstrateDoping * 1e6 /* cm**3/m**3 */ / (2 *
                                                                                                                                                    _mbp.BulkJunctionPotential));
            }
        }
Exemple #29
0
 /// <summary>
 /// Tests convergence at the device-level.
 /// </summary>
 /// <param name="simulation">The base simulation.</param>
 /// <returns>
 /// <c>true</c> if the device determines the solution converges; otherwise, <c>false</c>.
 /// </returns>
 public bool IsConvergent(BaseSimulation simulation) => true;
Exemple #30
0
        /// <summary>
        /// Execute behavior
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Load(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            var    state = simulation.RealState;
            var    rstate = state;
            double drainSatCur, sourceSatCur,
                   vgs, vds, vbs, vbd, vgd;
            double von;
            double vdsat, cdrain = 0.0,
                   cdreq;
            int xnrm, xrev;

            var vt    = Circuit.KOverQ * _bp.Temperature;
            var check = 1;

            var effectiveLength = _bp.Length - 2 * _mbp.LateralDiffusion;

            if (_temp.TempSaturationCurrentDensity.Equals(0) || _bp.DrainArea.Value <= 0 || _bp.SourceArea.Value <= 0)
            {
                drainSatCur  = _temp.TempSaturationCurrent;
                sourceSatCur = _temp.TempSaturationCurrent;
            }
            else
            {
                drainSatCur  = _temp.TempSaturationCurrentDensity * _bp.DrainArea;
                sourceSatCur = _temp.TempSaturationCurrentDensity * _bp.SourceArea;
            }

            var beta     = _temp.TempTransconductance * _bp.Width / effectiveLength;
            var oxideCap = _mbp.OxideCapFactor * effectiveLength * _bp.Width;

            if (state.Init == InitializationModes.Float || (simulation is TimeSimulation tsim && tsim.Method.BaseTime.Equals(0.0)) ||
                state.Init == InitializationModes.Fix && !_bp.Off)
            {
                // general iteration
                vbs = _mbp.MosfetType * (rstate.Solution[_bulkNode] - rstate.Solution[SourceNodePrime]);
                vgs = _mbp.MosfetType * (rstate.Solution[_gateNode] - rstate.Solution[SourceNodePrime]);
                vds = _mbp.MosfetType * (rstate.Solution[DrainNodePrime] - rstate.Solution[SourceNodePrime]);

                // now some common crunching for some more useful quantities
                vbd = vbs - vds;
                vgd = vgs - vds;
                var vgdo = VoltageGs - VoltageDs;

                von = _mbp.MosfetType * Von;

                /*
                 * limiting
                 * We want to keep device voltages from changing
                 * so fast that the exponentials churn out overflows
                 * and similar rudeness
                 */
                if (VoltageDs >= 0)
                {
                    vgs = Transistor.LimitFet(vgs, VoltageGs, von);
                    vds = vgs - vgd;
                    vds = Transistor.LimitVoltageDs(vds, VoltageDs);
                }
                else
                {
                    vgd = Transistor.LimitFet(vgd, vgdo, von);
                    vds = vgs - vgd;
                    vds = -Transistor.LimitVoltageDs(-vds, -VoltageDs);
                    vgs = vgd + vds;
                }
                if (vds >= 0)
                {
                    vbs = Transistor.LimitJunction(vbs, VoltageBs, vt, _temp.SourceVCritical, out check);
                }
                else
                {
                    vbd = Transistor.LimitJunction(vbd, VoltageBd, vt, _temp.DrainVCritical, out check);
                    vbs = vbd + vds;
                }
            }