Esempio n. 1
0
        /// <summary>
        /// Initializes the voltages to be used for calculating the current iteration.
        /// </summary>
        /// <param name="simulation">The simulation.</param>
        /// <param name="vgs">The VGS.</param>
        /// <param name="vds">The VDS.</param>
        /// <param name="vbs">The VBS.</param>
        /// <param name="check">If set to <c>true</c>, the current voltage was limited and another iteration should be calculated.</param>
        protected void Initialize(BaseSimulation simulation,
                                  out double vgs, out double vds, out double vbs, out bool check)
        {
            var state = simulation.RealState;

            check = true;

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

                // now some common crunching for some more useful quantities
                var vbd  = vbs - vds;
                var vgd  = vgs - vds;
                var vgdo = VoltageGs - VoltageDs;
                var von  = ModelParameters.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.LimitVds(vds, VoltageDs);
                }
                else
                {
                    vgd = Transistor.LimitFet(vgd, vgdo, von);
                    vds = vgs - vgd;
                    vds = -Transistor.LimitVds(-vds, -VoltageDs);
                    vgs = vgd + vds;
                }

                check = false;
                if (vds >= 0)
                {
                    vbs = Semiconductor.LimitJunction(vbs, VoltageBs, Vt, SourceVCritical, ref check);
                }
                else
                {
                    vbd = Semiconductor.LimitJunction(vbd, VoltageBd, Vt, DrainVCritical, ref check);
                    vbs = vbd + vds;
                }
            }
Esempio n. 2
0
        /// <include file='../common/docs.xml' path='docs/methods/Initialize/*'/>
        protected void Initialize(out double vgs, out double vds, out double vbs, out bool check)
        {
            check = true;

            if (_iteration.Mode == IterationModes.Float || (_method != null && _method.BaseTime.Equals(0.0)) ||
                _iteration.Mode == IterationModes.Fix && !Parameters.Off)
            {
                // General iteration
                var s = _variables.SourcePrime.Value;
                vbs = ModelParameters.MosfetType * (_variables.Bulk.Value - s);
                vgs = ModelParameters.MosfetType * (_variables.Gate.Value - s);
                vds = ModelParameters.MosfetType * (_variables.DrainPrime.Value - s);

                // now some common crunching for some more useful quantities
                var vbd  = vbs - vds;
                var vgd  = vgs - vds;
                var vgdo = Vgs - Vds;
                var von  = ModelParameters.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 (Vds >= 0)
                {
                    vgs = Transistor.LimitFet(vgs, Vgs, von);
                    vds = vgs - vgd;
                    vds = Transistor.LimitVds(vds, Vds);
                }
                else
                {
                    vgd = Transistor.LimitFet(vgd, vgdo, von);
                    vds = vgs - vgd;
                    vds = -Transistor.LimitVds(-vds, -Vds);
                    vgs = vgd + vds;
                }

                check = false;
                if (vds >= 0)
                {
                    vbs = Semiconductor.LimitJunction(vbs, Vbs, Properties.TempVt, SourceVCritical, ref check);
                }
                else
                {
                    vbd = Semiconductor.LimitJunction(vbd, Vbd, Properties.TempVt, DrainVCritical, ref 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 (_iteration.Mode == IterationModes.Junction && !Parameters.Off)
                {
                    vds = ModelParameters.MosfetType * Parameters.InitialVds;
                    vgs = ModelParameters.MosfetType * Parameters.InitialVgs;
                    vbs = ModelParameters.MosfetType * Parameters.InitialVbs;

                    // TODO: At some point, check what this is supposed to do
                    if (vds.Equals(0) && vgs.Equals(0) && vbs.Equals(0) && (_time == null || _time.UseDc || !_time.UseIc))
                    {
                        vbs = -1;
                        vgs = ModelParameters.MosfetType * Properties.TempVt0;
                        vds = 0;
                    }
                }
                else
                {
                    vbs = vgs = vds = 0;
                }
            }
        }
        /// <summary>
        /// Load the behavior
        /// </summary>
        /// <param name="simulation">Simulation</param>
        void IBiasingBehavior.Load()
        {
            var    state = _state;
            double capbd = 0.0;
            double capbs = 0.0;
            double cdgb  = 0.0;
            double cddb  = 0.0;
            double cdsb  = 0.0;
            double csgb  = 0.0;
            double cssb  = 0.0;
            double csdb  = 0.0;
            double qdrn  = 0.0;
            double qsrc  = 0.0;

            double[] args = new double[8];
            bool     chargeComputationsNeeded = TranBehavior != null;

            double EffectiveLength = BaseParameters.Length - ModelParameters.DeltaL * 1.0e-6;
            double DrainArea       = BaseParameters.DrainArea;
            double SourceArea      = BaseParameters.SourceArea;
            double DrainPerimeter  = BaseParameters.DrainPerimeter;
            double SourcePerimeter = BaseParameters.SourcePerimeter;
            double DrainSatCurrent;

            if ((DrainSatCurrent = DrainArea * ModelParameters.JctSatCurDensity)
                < 1e-15)
            {
                DrainSatCurrent = 1.0e-15;
            }

            double SourceSatCurrent;

            if ((SourceSatCurrent = SourceArea * ModelParameters.JctSatCurDensity)
                < 1.0e-15)
            {
                SourceSatCurrent = 1.0e-15;
            }

            double GateSourceOverlapCap = ModelParameters.GateSourceOverlapCap * BaseParameters.Width;
            double GateDrainOverlapCap  = ModelParameters.GateDrainOverlapCap * BaseParameters.Width;
            double GateBulkOverlapCap   = ModelParameters.GateBulkOverlapCap * EffectiveLength;
            double von   = ModelParameters.Type * Von;
            double vdsat = ModelParameters.Type * Vdsat;
            double vt0   = ModelParameters.Type * Vt0;
            bool   Check = true;
            double vbd;
            double vbs;
            double vds;
            double vgd;
            double vgs;

            if (Simulation is FrequencySimulation && !state.UseDc)
            {
                vbs = this.Vbs;
                vgs = this.Vgs;
                vds = this.Vds;
                chargeComputationsNeeded = true;
            }
            else if (state.Init == InitializationModes.Junction && !BaseParameters.Off)
            {
                vds = ModelParameters.Type * BaseParameters.IcVDS;
                vgs = ModelParameters.Type * BaseParameters.IcVGS;
                vbs = ModelParameters.Type * BaseParameters.IcVBS;
                if ((vds == 0) && (vgs == 0) && (vbs == 0) &&
                    (state.UseDc || TranBehavior != null || !state.UseIc))
                {
                    vbs = -1;
                    vgs = vt0;
                    vds = 0;
                }
            }
            else if ((state.Init == InitializationModes.Junction ||
                      state.Init == InitializationModes.Fix) && (BaseParameters.Off))
            {
                vbs = vgs = vds = 0;
            }
            else
            {
                vbs = ModelParameters.Type * (state.Solution[BulkNode] - state.Solution[SourceNodePrime]);
                vgs = ModelParameters.Type * (state.Solution[GateNode] - state.Solution[SourceNodePrime]);
                vds = ModelParameters.Type * (state.Solution[DrainNodePrime] - state.Solution[SourceNodePrime]);
                vbd = vbs - vds;
                vgd = vgs - vds;
                double vgdo = this.Vgs - this.Vds;

                von = ModelParameters.Type * base.Von;
                if (this.Vds >= 0)
                {
                    vgs = Transistor.LimitFet(vgs, this.Vgs, von);
                    vds = vgs - vgd;
                    vds = Transistor.LimitVds(vds, this.Vds);
                    vgd = vgs - vds;
                }
                else
                {
                    vgd = Transistor.LimitFet(vgd, vgdo, von);
                    vds = vgs - vgd;
                    vds = -Transistor.LimitVds(-vds, -this.Vds);
                    vgs = vgd + vds;
                }

                Check = false;
                double vcrit;
                if (vds >= 0)
                {
                    vcrit = Constants.Vt0 * Math.Log(Constants.Vt0 / (Constants.Root2 * SourceSatCurrent));
                    vbs   = Semiconductor.LimitJunction(vbs, this.Vbs, Constants.Vt0, vcrit, ref Check); /* B1 test */
                    vbd   = vbs - vds;
                }
                else
                {
                    vcrit = Constants.Vt0 * Math.Log(Constants.Vt0 / (Constants.Root2 * DrainSatCurrent));
                    vbd   = Semiconductor.LimitJunction(vbd, this.Vbd, Constants.Vt0, vcrit, ref Check); /* B1 test*/
                    vbs   = vbd + vds;
                }
            }

            /* determine DC current and derivatives */
            vbd = vbs - vds;
            vgd = vgs - vds;
            double vgb = vgs - vbs;
            double cbs;
            double gbs;

            if (vbs <= 0.0)
            {
                gbs = SourceSatCurrent / Constants.Vt0 + BaseConfiguration.Gmin;
                cbs = gbs * vbs;
            }
            else
            {
                double evbs = Math.Exp(vbs / Constants.Vt0);
                gbs = SourceSatCurrent * evbs / Constants.Vt0 + BaseConfiguration.Gmin;
                cbs = SourceSatCurrent * (evbs - 1) + BaseConfiguration.Gmin * vbs;
            }

            double cbd;
            double gbd;

            if (vbd <= 0.0)
            {
                gbd = DrainSatCurrent / Constants.Vt0 + BaseConfiguration.Gmin;
                cbd = gbd * vbd;
            }
            else
            {
                double evbd = Math.Exp(vbd / Constants.Vt0);
                gbd = DrainSatCurrent * evbd / Constants.Vt0 + BaseConfiguration.Gmin;
                cbd = DrainSatCurrent * (evbd - 1) + BaseConfiguration.Gmin * vbd;
            }

            /* line 400 */
            if (vds >= 0)
            {
                /* normal mode */
                this.Mode = 1;
            }
            else
            {
                /* inverse mode */
                this.Mode = -1;
            }

            double cdrain;
            double gds;
            double gm;
            double gmbs;
            double cgdb;
            double cgsb;
            double cbdb;
            double cggb;
            double cbgb;
            double cbsb;
            double qgate;
            double qbulk;

            /* call B1evaluate to calculate drain current and its
             * derivatives and charge and capacitances related to gate
             * drain, and bulk
             */
            if (vds >= 0)
            {
                Evaluate(chargeComputationsNeeded,
                         vds, vbs, vgs, out gm, out gds, out gmbs, out qgate,
                         out qbulk, out qdrn, out cggb, out cgdb, out cgsb, out cbgb, out cbdb, out cbsb, out cdgb,
                         out cddb, out cdsb, out cdrain, out von, out vdsat);
            }
            else
            {
                Evaluate(chargeComputationsNeeded,
                         -vds, vbd, vgd, out gm, out gds, out gmbs, out qgate,
                         out qbulk, out qsrc, out cggb, out cgsb, out cgdb, out cbgb, out cbsb, out cbdb, out csgb,
                         out cssb, out csdb, out cdrain, out von, out vdsat);
            }

            base.Von   = ModelParameters.Type * von;
            this.Vdsat = ModelParameters.Type * vdsat;

            /*
             *  COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
             */
            double cd = Mode * cdrain - cbd;

            if (chargeComputationsNeeded)
            {
                /*
                 *  charge storage elements
                 *
                 *   bulk-drain and bulk-source depletion capacitances
                 *  czbd : zero bias drain junction capacitance
                 *  czbs : zero bias source junction capacitance
                 * czbdsw:zero bias drain junction sidewall capacitance
                 * czbssw:zero bias source junction sidewall capacitance
                 */

                double czbd   = ModelParameters.UnitAreaJctCap * DrainArea;
                double czbs   = ModelParameters.UnitAreaJctCap * SourceArea;
                double czbdsw = ModelParameters.UnitLengthSidewallJctCap * DrainPerimeter;
                double czbssw = ModelParameters.UnitLengthSidewallJctCap * SourcePerimeter;
                double PhiB   = ModelParameters.BulkJctPotential;
                double PhiBSW = ModelParameters.SidewallJctPotential;
                double MJ     = ModelParameters.BulkJctBotGradingCoeff;
                double MJSW   = ModelParameters.BulkJctSideGradingCoeff;
                double arg;
                double sarg;
                double sargsw;
                double argsw;
                /* Source Bulk Junction */
                if (vbs < 0)
                {
                    arg      = 1 - vbs / PhiB;
                    argsw    = 1 - vbs / PhiBSW;
                    sarg     = Math.Exp(-MJ * Math.Log(arg));
                    sargsw   = Math.Exp(-MJSW * Math.Log(argsw));
                    this.Qbs = PhiB * czbs * (1 - arg * sarg) / (1 - MJ) +
                               PhiBSW * czbssw * (1 - argsw * sargsw) / (1 - MJSW);
                    capbs = czbs * sarg + czbssw * sargsw;
                }
                else
                {
                    this.Qbs = vbs * (czbs + czbssw) +
                               vbs * vbs * (czbs * MJ * 0.5 / PhiB + czbssw * MJSW * 0.5 / PhiBSW);
                    capbs = czbs + czbssw + vbs * (czbs * MJ / PhiB + czbssw * MJSW / PhiBSW);
                }

                /* Drain Bulk Junction */
                if (vbd < 0)
                {
                    arg    = 1 - vbd / PhiB;
                    argsw  = 1 - vbd / PhiBSW;
                    sarg   = Math.Exp(-MJ * Math.Log(arg));
                    sargsw = Math.Exp(-MJSW * Math.Log(argsw));

                    this.Qbd = PhiB * czbd * (1 - arg * sarg) / (1 - MJ) +
                               PhiBSW * czbdsw * (1 - argsw * sargsw) / (1 - MJSW);
                    capbd = czbd * sarg + czbdsw * sargsw;
                }
                else
                {
                    this.Qbd = vbd * (czbd + czbdsw) +
                               vbd * vbd * (czbd * MJ * 0.5 / PhiB + czbdsw * MJSW * 0.5 / PhiBSW);
                    capbd = czbd + czbdsw + vbd * (czbd * MJ / PhiB + czbdsw * MJSW / PhiBSW);
                }
            }

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

            this.Vbs  = vbs;
            this.Vbd  = vbd;
            this.Vgs  = vgs;
            this.Vds  = vds;
            this.Cd   = cd;
            this.Cbs  = cbs;
            this.Cbd  = cbd;
            this.Gm   = gm;
            this.Gds  = gds;
            this.Gmbs = gmbs;
            this.Gbd  = gbd;
            this.Gbs  = gbs;

            this.Cggb = cggb;
            this.Cgdb = cgdb;
            this.Cgsb = cgsb;

            this.Cbgb = cbgb;
            this.Cbdb = cbdb;
            this.Cbsb = cbsb;

            this.Cdgb = cdgb;
            this.Cddb = cddb;
            this.Cdsb = cdsb;

            this.Capbs = capbs;
            this.Capbd = capbd;

            /* bulk and channel charge plus overlaps */
            // if (!(ckt->CKTmode & (MODETRAN | MODEAC)) && (!(ckt->CKTmode & MODETRANOP) || !(ckt->CKTmode & MODEUIC)) && !(ckt->CKTmode & MODEINITSMSIG))
            if (!chargeComputationsNeeded)
            {
                goto line850;
            }
            double gcbdb;
            double gcbgb;
            double gcbsb;
            double gcddb;
            double gcdgb;
            double gcdsb;
            double gcgdb;
            double gcggb;
            double gcgsb;
            double gcsdb;
            double gcsgb;
            double gcssb;

            // line755:
            if (this.Mode > 0)
            {
                args[0] = GateDrainOverlapCap;
                args[1] = GateSourceOverlapCap;
                args[2] = GateBulkOverlapCap;
                args[3] = capbd;
                args[4] = capbs;
                args[5] = cggb;
                args[6] = cgdb;
                args[7] = cgsb;

                MosCap(vgd, vgs, vgb,
                       args,

                       /*
                        * GateDrainOverlapCap,
                        * GateSourceOverlapCap,GateBulkOverlapCap,
                        * capbd,capbs,
                        *          cggb,cgdb,cgsb,
                        */
                       cbgb, cbdb, cbsb,
                       cdgb, cddb, cdsb,
                       out gcggb, out gcgdb, out gcgsb,
                       out gcbgb, out gcbdb, out gcbsb,
                       out gcdgb, out gcddb, out gcdsb, out gcsgb, out gcsdb, out gcssb,
                       ref qgate, ref qbulk,
                       ref qdrn, out qsrc);
            }
            else
            {
                args[0] = GateSourceOverlapCap;
                args[1] = GateDrainOverlapCap;
                args[2] = GateBulkOverlapCap;
                args[3] = capbs;
                args[4] = capbd;
                args[5] = cggb;
                args[6] = cgsb;
                args[7] = cgdb;

                MosCap(vgs, vgd, vgb,
                       args,

                       /*
                        * GateSourceOverlapCap,
                        * GateDrainOverlapCap,GateBulkOverlapCap,
                        * capbs,capbd,
                        * cggb,cgsb,cgdb,
                        */
                       cbgb, cbsb, cbdb,
                       csgb, cssb, csdb,
                       out gcggb, out gcgsb, out gcgdb,
                       out gcbgb, out gcbsb, out gcbdb,
                       out gcsgb, out gcssb, out gcsdb, out gcdgb, out gcdsb, out gcddb,
                       ref qgate, ref qbulk,
                       ref qsrc, out qdrn);
            }

            // store small signal parameters
            // if ((!(ckt->CKTmode & (MODEAC | MODETRAN))) && (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))
            // goto line850;

            if (Simulation is FrequencySimulation && !state.UseDc)
            {
                this.Cggb  = cggb;
                this.Cgdb  = cgdb;
                this.Cgsb  = cgsb;
                this.Cbgb  = cbgb;
                this.Cbdb  = cbdb;
                this.Cbsb  = cbsb;
                this.Cdgb  = cdgb;
                this.Cddb  = cddb;
                this.Cdsb  = cdsb;
                this.Capbd = capbd;
                this.Capbs = capbs;
                goto line1000;
            }

            if (TranBehavior != null)
            {
                TranBehavior.Qg.Current = qgate;
                TranBehavior.Qd.Current = qdrn - this.Qbd;
                TranBehavior.Qb.Current = qbulk + this.Qbd + this.Qbs;

                if (!state.UseDc)
                {
                    TranBehavior.Qb.Integrate();
                    TranBehavior.Qg.Integrate();
                    TranBehavior.Qd.Integrate();
                }
            }

            goto line860;
line850:
            /* initialize to zero charge conductance and current */
            double ceqqd;
            double ceqqg;
            double ceqqb;

            ceqqg = ceqqb = ceqqd = 0.0;
            gcdgb = gcddb = gcdsb = 0.0;
            gcsgb = gcsdb = gcssb = 0.0;
            gcggb = gcgdb = gcgsb = 0.0;
            gcbgb = gcbdb = gcbsb = 0.0;
            goto line900;
line860:
            /* evaluate equivalent charge current */
            double cqgate = TranBehavior.Qg.Derivative;
            double cqbulk = TranBehavior.Qb.Derivative;
            double cqdrn  = TranBehavior.Qd.Derivative;

            ceqqg = cqgate - gcggb * vgb + gcgdb * vbd + gcgsb * vbs;
            ceqqb = cqbulk - gcbgb * vgb + gcbdb * vbd + gcbsb * vbs;
            ceqqd = cqdrn - gcdgb * vgb + gcddb * vbd + gcdsb * vbs;
            double ceqbs;

            /*
             *  load current vector
             */
line900:
            ceqbs = ModelParameters.Type * (cbs - (gbs - BaseConfiguration.Gmin) * vbs);
            double ceqbd = ModelParameters.Type * (cbd - (gbd - BaseConfiguration.Gmin) * vbd);

            ceqqg = ModelParameters.Type * ceqqg;
            ceqqb = ModelParameters.Type * ceqqb;
            ceqqd = ModelParameters.Type * ceqqd;
            double cdreq;
            double xnrm;
            double xrev;

            if (this.Mode >= 0)
            {
                xnrm  = 1;
                xrev  = 0;
                cdreq = ModelParameters.Type * (cdrain - gds * vds - gm * vgs - gmbs * vbs);
            }
            else
            {
                xnrm  = 0;
                xrev  = 1;
                cdreq = -(ModelParameters.Type) * (cdrain + gds * vds - gm * vgd - gmbs * vbd);
            }

            var m = BaseParameters.Multiplier;

            GateNodePtr.Value        -= m * ceqqg;
            BulkNodePtr.Value        -= m * (ceqbs + ceqbd + ceqqb);
            DrainNodePrimePtr.Value  += m * (ceqbd - cdreq - ceqqd);
            SourceNodePrimePtr.Value += m * (cdreq + ceqbs + ceqqg + ceqqb + ceqqd);

            /*
             *  load y matrix
             */
            DdPtr.Value   += m * (base.DrainConductance);
            GgPtr.Value   += m * (gcggb);
            SsPtr.Value   += m * (base.SourceConductance);
            BbPtr.Value   += m * (gbd + gbs - gcbgb - gcbdb - gcbsb);
            DPdpPtr.Value += m * (base.DrainConductance + gds + gbd + xrev * (gm + gmbs) + gcddb);
            SPspPtr.Value += m * (base.SourceConductance + gds + gbs + xnrm * (gm + gmbs) + gcssb);
            DdpPtr.Value  += m * (-base.DrainConductance);
            GbPtr.Value   += m * (-gcggb - gcgdb - gcgsb);
            GdpPtr.Value  += m * (gcgdb);
            GspPtr.Value  += m * (gcgsb);
            SspPtr.Value  += m * (-base.SourceConductance);
            BgPtr.Value   += m * (gcbgb);
            BdpPtr.Value  += m * (-gbd + gcbdb);
            BspPtr.Value  += m * (-gbs + gcbsb);
            DPdPtr.Value  += m * (-base.DrainConductance);
            DPgPtr.Value  += m * ((xnrm - xrev) * gm + gcdgb);
            DPbPtr.Value  += m * (-gbd + (xnrm - xrev) * gmbs - gcdgb - gcddb - gcdsb);
            DPspPtr.Value += m * (-gds - xnrm * (gm + gmbs) + gcdsb);
            SPgPtr.Value  += m * (-(xnrm - xrev) * gm + gcsgb);
            SPsPtr.Value  += m * (-base.SourceConductance);
            SPbPtr.Value  += m * (-gbs - (xnrm - xrev) * gmbs - gcsgb - gcsdb - gcssb);
            SPdpPtr.Value += m * (-gds - xrev * (gm + gmbs) + gcsdb);

            line1000 :;
        }