/// <summary>
        /// Calculates the Meyer capacitors.
        /// </summary>
        /// <param name="vgs">The VGS.</param>
        /// <param name="vgd">The VGD.</param>
        protected void CalculateMeyerCharges(double vgs, double vgd)
        {
            var von      = ModelParameters.MosfetType * Von;
            var vdsat    = ModelParameters.MosfetType * SaturationVoltageDs;
            var oxideCap = ModelParameters.OxideCapFactor * EffectiveLength * BaseParameters.Width;

            /*
             * calculate meyer's capacitors
             */
            double icapgs, icapgd, icapgb;

            if (Mode > 0)
            {
                Transistor.MeyerCharges(vgs, vgd, von, vdsat,
                                        out icapgs, out icapgd, out icapgb, TempPhi, oxideCap);
            }
            else
            {
                Transistor.MeyerCharges(vgd, vgs, von, vdsat,
                                        out icapgd, out icapgs, out icapgb, TempPhi, oxideCap);
            }
            CapGs = icapgs;
            CapGd = icapgd;
            CapGb = icapgb;
        }
Exemplo n.º 2
0
        public void TransistorConstructor()
        {
            Transistor transistor = new Transistor();

            Assert.IsNotNull(transistor.Base);
            Assert.IsNotNull(transistor.Collector);
            Assert.IsNotNull(transistor.Emitter);
            Assert.AreEqual(transistor.Base.Listeners.Count, 1);
            Assert.AreEqual(transistor.Collector.Listeners.Count, 1);
            Assert.AreEqual(transistor.Emitter.Listeners.Count, 0);

            Assert.AreEqual(transistor.Base.Value, false);
            Assert.AreEqual(transistor.Collector.Value, false);
            Assert.AreEqual(transistor.Emitter.Value, false);

            transistor.Base.Value = true;
            Assert.AreEqual(transistor.Base.Value, true);
            Assert.AreEqual(transistor.Collector.Value, false);
            Assert.AreEqual(transistor.Emitter.Value, false);

            transistor.Base.Value      = false;
            transistor.Collector.Value = true;
            Assert.AreEqual(transistor.Base.Value, false);
            Assert.AreEqual(transistor.Collector.Value, true);
            Assert.AreEqual(transistor.Emitter.Value, false);

            transistor.Base.Value      = true;
            transistor.Collector.Value = true;
            Assert.AreEqual(transistor.Base.Value, true);
            Assert.AreEqual(transistor.Collector.Value, true);
            Assert.AreEqual(transistor.Emitter.Value, true);
        }
Exemplo n.º 3
0
        public override Exception Run(CancellationToken token)
        {
            LoadConfig("~/.config/taa/config.yml");

            // SiUnitを考慮してオプションをパース
            var sigmaRange = SigmaRange.Split(",", StringSplitOptions.RemoveEmptyEntries)
                             .Select(x => (double)x.ParseDecimalWithSiUnit()).ToArray();
            var sweepRange = SweepRange.Split(",", StringSplitOptions.RemoveEmptyEntries)
                             .Select(x => (long)x.ParseDecimalWithSiUnit()).ToArray();
            var seedRange = SeedRange.Split(",", StringSplitOptions.RemoveEmptyEntries)
                            .Select(x => (long)x.ParseDecimalWithSiUnit()).ToArray();

            // 数え上げ用のFilterをBuild
            Logger.Info("Start build filter");
            var filter = new Filter(Config.Config.GetInstance().Conditions, Config.Config.GetInstance().Expressions);

            Logger.Info("Finished build filter");

            var result = new Map <string, Map <decimal, long> >();

            foreach (var s in filter.Delegates)
            {
                result[s.Name] = new Map <decimal, long>();
            }

            var sweepStart = sweepRange[0];
            var sweepEnd   = sweepRange[1];
            var seedStart  = seedRange[0];
            var seedEnd    = seedRange[1];


            Logger.Info("Vtn:");
            Logger.Info($"\tVoltage: {VtnVoltage}");
            Logger.Info($"\tSigma: {VtnSigma}");
            Logger.Info($"\tDeviation: {VtnDeviation}");
            Logger.Info("Vtp:");
            Logger.Info($"\tVoltage: {VtpVoltage}");
            Logger.Info($"\tSigma: {VtpSigma}");
            Logger.Info($"\tDeviation: {VtpDeviation}");

            Logger.Info($"Sweeps: start: {sweepStart}, end: {sweepEnd}");
            Logger.Info($"Seed: start: {seedStart}, end: {seedEnd}");

            var sigmaList = new List <double>();

            if (sigmaRange.Length == 0)
            {
                Spinner.Start("Aggregating...", () => {
                    // Sigmaが固定
                    var vtn = new Transistor(VtnVoltage, VtnSigma, VtnDeviation);
                    var vtp = new Transistor(VtpVoltage, VtpSigma, VtpDeviation);

                    sigmaList.Add(VtnSigma);

                    var res = Do(vtn, vtp, filter, sweepStart, sweepEnd, seedStart, seedEnd);
                    foreach (var(key, value) in res)
                    {
                        result[key][vtn.Sigma] = value;
                    }
                });
Exemplo n.º 4
0
        public void ToStringTest()
        {
            var expect = $"t_{0.6M:E5}_s_{0.046M:E5}_d_{1.0M:E5}";
            var actual = new Transistor(0.6M, 0.046M, 1.0M).ToString();

            Assert.Equal(expect, actual);
        }
Exemplo n.º 5
0
        private static void MediatorPatternExample()
        {
            IPart board = new Board
            {
                Price = 4.5m,
                Name  = "Motherboard"
            };

            IPart cpu = new Transistor
            {
                Price = 50.1m,
                Name  = "Cpu"
            };
            Client client = new Client {
                NameOfClient = "Rui"
            };

            client.SubscribePart(board);
            Client c2 = new Client {
                NameOfClient = "Sara"
            };

            client.SubscribePart(board);
            c2.SubscribePart(board);
            c2.SubscribePart(cpu);
            board.Price = 5.5m;
            cpu.Price   = 10m;
        }
Exemplo n.º 6
0
        public void ConstructTest()
        {
            var actual = new Transistor(0.6, 0.046, 1.0);

            Assert.Equal(0.6M, actual.Voltage);
            Assert.Equal(0.046M, actual.Sigma);
            Assert.Equal(1.0M, actual.Deviation);
        }
Exemplo n.º 7
0
        public void ConstructorTest2()
        {
            var(t, s, d) = (0.6M, 0.046M, 1.0M);
            var transistor = new Transistor(t, s, d);

            Assert.Equal(t, transistor.Threshold);
            Assert.Equal(s, transistor.Sigma);
            Assert.Equal(d, transistor.NumberOfSigma);
        }
Exemplo n.º 8
0
        public void ConstructorTest1()
        {
            var(t, s, d) = (0.6, 0.046, 1.0);
            var transistor = new Transistor(t, s, d);

            Assert.Equal((decimal)t, transistor.Threshold);
            Assert.Equal((decimal)s, transistor.Sigma);
            Assert.Equal((decimal)d, transistor.NumberOfSigma);
        }
Exemplo n.º 9
0
        private static IEnumerable <Tuple <string, long> > Do(Transistor vtn, Transistor vtp, Filter filter, long sweepStart, long sweepEnd,
                                                              long seedStart, long seedEnd)
        {
            var dn = Transistor.ToTableName(vtn, vtp);

            var repo = new MssqlRepository();

            repo.Use(dn);
            return(repo.Count(r => r.Sweep.Within(sweepStart, sweepEnd) && r.Seed.Within(seedStart, seedEnd),
                              filter));
        }
Exemplo n.º 10
0
    public override void SetSimulationProp(Circuit sim)
    {
        Debug.Log("activeItem inserted");

        Transistor transistor = sim.Create <Transistor>();

        transistor.IsPNP = true;

        Connectors[0].DllConnector = transistor.leadCollector;
        Connectors[1].DllConnector = transistor.leadEmitter;
        Connectors[2].DllConnector = transistor.leadBase;
    }
Exemplo n.º 11
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;
                }
            }
Exemplo n.º 12
0
        public void GetParametersString()
        {
            var t      = new Transistor(0.6M, 0.046M, 1.0M);
            var expect = new[] {
                $"Threshold: {0.6M}",
                $"Sigma: {0.046M}",
                $"NumberOfSigma: {1.0M}"
            };

            foreach (var item in t.GetParameterStrings().Zip(expect, (s, k) => new{ s, k }))
            {
                Assert.Equal(item.k, item.s);
            }
        }
Exemplo n.º 13
0
 public TransistorPair(Transistor vtn, Transistor vtp) => (Vtn, Vtp) = (vtn, vtp);
Exemplo n.º 14
0
        public override void Draw(MicroWorld.Graphics.Renderer renderer)
        {
            if (texture0cw == null)
            {
                return;
            }
            if (!CanDraw())
            {
                return;
            }
            Components.Logics.TransistorLogics l = (Components.Logics.TransistorLogics)parent.Logics;
            Transistor p = parent as Transistor;
            Color      c = Color.Red * (float)l.FlowPercentage;

            switch (parent.ComponentRotation)
            {
            case Component.Rotation.cw0:
                renderer.Draw(texture0cw,
                              new Rectangle((int)Position.X, (int)Position.Y,
                                            (int)GetSizeRotated(parent.ComponentRotation).X, (int)GetSizeRotated(parent.ComponentRotation).Y), null,
                              Color.White);
                renderer.Draw(textureBase0cw,
                              new Rectangle((int)Position.X, (int)Position.Y,
                                            (int)GetSizeRotated(parent.ComponentRotation).X, (int)GetSizeRotated(parent.ComponentRotation).Y), null,
                              c);
                renderer.Draw(textureEmitter0cw,
                              new Rectangle((int)Position.X, (int)Position.Y,
                                            (int)GetSizeRotated(parent.ComponentRotation).X, (int)GetSizeRotated(parent.ComponentRotation).Y), null,
                              p.W3.VoltageDropAbs == 0 ? Color.Transparent : c);
                break;

            case Component.Rotation.cw90:
                renderer.Draw(texture90cw,
                              new Rectangle((int)Position.X, (int)Position.Y,
                                            (int)GetSizeRotated(parent.ComponentRotation).X, (int)GetSizeRotated(parent.ComponentRotation).Y), null,
                              Color.White);
                renderer.Draw(textureBase90cw,
                              new Rectangle((int)Position.X, (int)Position.Y,
                                            (int)GetSizeRotated(parent.ComponentRotation).X, (int)GetSizeRotated(parent.ComponentRotation).Y), null,
                              c);
                renderer.Draw(textureEmitter90cw,
                              new Rectangle((int)Position.X, (int)Position.Y,
                                            (int)GetSizeRotated(parent.ComponentRotation).X, (int)GetSizeRotated(parent.ComponentRotation).Y), null,
                              p.W3.VoltageDropAbs == 0 ? Color.Transparent : c);
                break;

            case Component.Rotation.cw180:
                renderer.Draw(texture180cw,
                              new Rectangle((int)Position.X, (int)Position.Y,
                                            (int)GetSizeRotated(parent.ComponentRotation).X, (int)GetSizeRotated(parent.ComponentRotation).Y), null,
                              Color.White);
                renderer.Draw(textureBase180cw,
                              new Rectangle((int)Position.X, (int)Position.Y,
                                            (int)GetSizeRotated(parent.ComponentRotation).X, (int)GetSizeRotated(parent.ComponentRotation).Y), null,
                              c);
                renderer.Draw(textureEmitter180cw,
                              new Rectangle((int)Position.X, (int)Position.Y,
                                            (int)GetSizeRotated(parent.ComponentRotation).X, (int)GetSizeRotated(parent.ComponentRotation).Y), null,
                              p.W3.VoltageDropAbs == 0 ? Color.Transparent : c);
                break;

            case Component.Rotation.cw270:
                renderer.Draw(texture270cw,
                              new Rectangle((int)Position.X, (int)Position.Y,
                                            (int)GetSizeRotated(parent.ComponentRotation).X, (int)GetSizeRotated(parent.ComponentRotation).Y), null,
                              Color.White);
                renderer.Draw(textureBase270cw,
                              new Rectangle((int)Position.X, (int)Position.Y,
                                            (int)GetSizeRotated(parent.ComponentRotation).X, (int)GetSizeRotated(parent.ComponentRotation).Y), null,
                              c);
                renderer.Draw(textureEmitter270cw,
                              new Rectangle((int)Position.X, (int)Position.Y,
                                            (int)GetSizeRotated(parent.ComponentRotation).X, (int)GetSizeRotated(parent.ComponentRotation).Y), null,
                              p.W3.VoltageDropAbs == 0 ? Color.Transparent : c);
                break;

            default:
                break;
            }
        }
Exemplo n.º 15
0
        /// <summary>
        /// Transient behavior
        /// </summary>
        /// <param name="simulation"></param>
        public override void Transient(TimeSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            var    state = simulation.RealState;
            double sargsw;

            var vbs   = _load.VoltageBs;
            var vbd   = _load.VoltageBd;
            var vgs   = _load.VoltageGs;
            var vgd   = _load.VoltageGs - _load.VoltageDs;
            var vgb   = _load.VoltageGs - _load.VoltageBs;
            var von   = _mbp.MosfetType * _load.Von;
            var vdsat = _mbp.MosfetType * _load.SaturationVoltageDs;

            VoltageDs.Current = _load.VoltageDs;
            VoltageBs.Current = vbs;
            VoltageGs.Current = vgs;

            double gbd = 0.0;
            double cbd = 0.0;
            double gbs = 0.0;
            double cbs = 0.0;

            var effectiveLength      = _bp.Length - 2 * _mbp.LateralDiffusion;
            var gateSourceOverlapCap = _mbp.GateSourceOverlapCapFactor * _bp.Width;
            var gateDrainOverlapCap  = _mbp.GateDrainOverlapCapFactor * _bp.Width;
            var gateBulkOverlapCap   = _mbp.GateBulkOverlapCapFactor * effectiveLength;
            var oxideCap             = _modeltemp.OxideCapFactor * effectiveLength * _bp.Width;

            /*
             * now we do the hard part of the bulk - drain and bulk - source
             * diode - we evaluate the non - linear capacitance and
             * charge
             *
             * the basic equations are not hard, but the implementation
             * is somewhat long in an attempt to avoid log / exponential
             * evaluations
             */
            /*
             * charge storage elements
             *
             * .. bulk - drain and bulk - source depletion capacitances
             */
            if (vbs < _temp.TempDepletionCap)
            {
                double arg = 1 - vbs / _temp.TempBulkPotential, sarg;

                /*
                 * the following block looks somewhat long and messy,
                 * but since most users use the default grading
                 * coefficients of .5, and sqrt is MUCH faster than an
                 * Math.Exp(Math.Log()) we use this special case code to buy time.
                 * (as much as 10% of total job time!)
                 */
                if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(_mbp.BulkJunctionSideGradingCoefficient.Value))
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        sarg = sargsw = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                }
                else
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sarg = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                    if (_mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                    {
                        sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));
                    }
                }
                // NOSQRT
                ChargeBs.Current = _temp.TempBulkPotential * (_temp.CapBs * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) +
                                                              _temp.CapBsSidewall * (1 - arg * sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient));
                CapBs = _temp.CapBs * sarg + _temp.CapBsSidewall * sargsw;
            }
            else
            {
                ChargeBs.Current = _temp.F4S + vbs * (_temp.F2S + vbs * (_temp.F3S / 2));
                CapBs            = _temp.F2S + _temp.F3S * vbs;
            }

            if (vbd < _temp.TempDepletionCap)
            {
                double arg = 1 - vbd / _temp.TempBulkPotential, sarg;

                /*
                 * the following block looks somewhat long and messy,
                 * but since most users use the default grading
                 * coefficients of .5, and sqrt is MUCH faster than an
                 * Math.Exp(Math.Log()) we use this special case code to buy time.
                 * (as much as 10% of total job time!)
                 */
                if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5) && _mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                {
                    sarg = sargsw = 1 / Math.Sqrt(arg);
                }
                else
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sarg = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                    if (_mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                    {
                        sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));
                    }
                }
                /* NOSQRT */
                ChargeBd.Current = _temp.TempBulkPotential * (_temp.CapBd * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) +
                                                              _temp.CapBdSidewall * (1 - arg * sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient));
                CapBd = _temp.CapBd * sarg + _temp.CapBdSidewall * sargsw;
            }
            else
            {
                ChargeBd.Current = _temp.F4D + vbd * (_temp.F2D + vbd * _temp.F3D / 2);
                CapBd            = _temp.F2D + vbd * _temp.F3D;
            }

            /* (above only excludes tranop, since we're only at this
             * point if tran or tranop)
             */
            /*
             * calculate equivalent conductances and currents for
             * depletion capacitors
             */

            // integrate the capacitors and save results
            ChargeBd.Integrate();
            gbd += ChargeBd.Jacobian(CapBd);
            cbd += ChargeBd.Derivative;
            ChargeBs.Integrate();
            gbs += ChargeBs.Jacobian(CapBs);
            cbs += ChargeBs.Derivative;

            /*
             * calculate meyer's capacitors
             */
            double icapgs, icapgd, icapgb;

            if (_load.Mode > 0)
            {
                Transistor.MeyerCharges(vgs, vgd, von, vdsat,
                                        out icapgs, out icapgd, out icapgb, _temp.TempPhi, oxideCap);
            }
            else
            {
                Transistor.MeyerCharges(vgd, vgs, von, vdsat,
                                        out icapgd, out icapgs, out icapgb, _temp.TempPhi, oxideCap);
            }
            CapGs.Current = icapgs;
            CapGd.Current = icapgd;
            CapGb.Current = icapgb;

            var vgs1  = VoltageGs[1];
            var vgd1  = vgs1 - VoltageDs[1];
            var vgb1  = vgs1 - VoltageBs[1];
            var capgs = CapGs.Current + CapGs[1] + gateSourceOverlapCap;
            var capgd = CapGd.Current + CapGd[1] + gateDrainOverlapCap;
            var capgb = CapGb.Current + CapGb[1] + gateBulkOverlapCap;

            /*
             * store small - signal parameters (for meyer's model)
             * all parameters already stored, so done...
             */

            ChargeGs.Current = (vgs - vgs1) * capgs + ChargeGs[1];
            ChargeGd.Current = (vgd - vgd1) * capgd + ChargeGd[1];
            ChargeGb.Current = (vgb - vgb1) * capgb + ChargeGb[1];

            /*
             * calculate equivalent conductances and currents for
             * meyer"s capacitors
             */
            ChargeGs.Integrate();
            var gcgs  = ChargeGs.Jacobian(capgs);
            var ceqgs = ChargeGs.RhsCurrent(gcgs, vgs);

            ChargeGd.Integrate();
            var gcgd  = ChargeGd.Jacobian(capgd);
            var ceqgd = ChargeGd.RhsCurrent(gcgd, vgd);

            ChargeGb.Integrate();
            var gcgb  = ChargeGb.Jacobian(capgb);
            var ceqgb = ChargeGb.RhsCurrent(gcgb, vgb);

            /*
             * store charge storage info for meyer's cap in lx table
             */

            // Load current vector
            var ceqbs = _mbp.MosfetType * (cbs - (gbs - state.Gmin) * vbs);
            var ceqbd = _mbp.MosfetType * (cbd - (gbd - state.Gmin) * vbd);

            GatePtr.Value        -= _mbp.MosfetType * (ceqgs + ceqgb + ceqgd);
            BulkPtr.Value        -= ceqbs + ceqbd - _mbp.MosfetType * ceqgb;
            DrainPrimePtr.Value  += ceqbd + _mbp.MosfetType * ceqgd;
            SourcePrimePtr.Value += ceqbs + _mbp.MosfetType * ceqgs;

            // load Y-matrix
            GateGatePtr.Value               += gcgd + gcgs + gcgb;
            BulkBulkPtr.Value               += gbd + gbs + gcgb;
            DrainPrimeDrainPrimePtr.Value   += gbd + gcgd;
            SourcePrimeSourcePrimePtr.Value += gbs + gcgs;
            GateBulkPtr.Value               -= gcgb;
            GateDrainPrimePtr.Value         -= gcgd;
            GateSourcePrimePtr.Value        -= gcgs;
            BulkGatePtr.Value               -= gcgb;
            BulkDrainPrimePtr.Value         -= gbd;
            BulkSourcePrimePtr.Value        -= gbs;
            DrainPrimeGatePtr.Value         += -gcgd;
            DrainPrimeBulkPtr.Value         += -gbd;
            SourcePrimeGatePtr.Value        += -gcgs;
            SourcePrimeBulkPtr.Value        += -gbs;
        }
Exemplo n.º 16
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 :;
        }
Exemplo n.º 17
0
        /// <summary>
        /// Transient behavior
        /// </summary>
        /// <param name="simulation">Time-based simulation</param>
        public override void Transient(TimeSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            double sargsw;

            var vbs   = _load.VoltageBs;
            var vbd   = _load.VoltageBd;
            var vgs   = _load.VoltageGs;
            var vds   = _load.VoltageDs;
            var vgd   = _load.VoltageGs - _load.VoltageDs;
            var vgb   = _load.VoltageGs - _load.VoltageBs;
            var von   = _mbp.MosfetType * _load.Von;
            var vdsat = _mbp.MosfetType * _load.SaturationVoltageDs;

            _vds.Current = vds;
            _vbs.Current = vbs;
            _vgs.Current = vgs;

            var gbd = 0.0;
            var cbd = 0.0;
            var gbs = 0.0;
            var cbs = 0.0;

            var effectiveLength      = _bp.Length - 2 * _mbp.LateralDiffusion;
            var gateSourceOverlapCap = _mbp.GateSourceOverlapCapFactor * _bp.Width;
            var gateDrainOverlapCap  = _mbp.GateDrainOverlapCapFactor * _bp.Width;
            var gateBulkOverlapCap   = _mbp.GateBulkOverlapCapFactor * effectiveLength;
            var oxideCap             = _mbp.OxideCapFactor * effectiveLength * _bp.Width;

            /*
             * now we do the hard part of the bulk - drain and bulk - source
             * diode - we evaluate the non - linear capacitance and
             * charge
             *
             * the basic equations are not hard, but the implementation
             * is somewhat long in an attempt to avoid log / exponential
             * evaluations
             */
            /*
             * charge storage elements
             *
             * .. bulk - drain and bulk - source depletion capacitances
             */

            if (vbs < _temp.TempDepletionCap)
            {
                double arg = 1 - vbs / _temp.TempBulkPotential, sarg;

                /*
                 * the following block looks somewhat long and messy,
                 * but since most users use the default grading
                 * coefficients of .5, and sqrt is MUCH faster than an
                 * Math.Exp(Math.Log()) we use this special case code to buy time.
                 * (as much as 10% of total job time!)
                 */
                if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(_mbp.BulkJunctionSideGradingCoefficient))
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        sarg = sargsw = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                }
                else
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sarg = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                    if (_mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                    {
                        sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));
                    }
                }
                /* NOSQRT */
                _qbs.Current = _temp.TempBulkPotential * (_temp.CapBs * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) +
                                                          _temp.CapBsSidewall * (1 - arg * sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient));
                CapBs = _temp.CapBs * sarg + _temp.CapBsSidewall * sargsw;
            }
            else
            {
                _qbs.Current = _temp.F4S + vbs * (_temp.F2S + vbs * (_temp.F3S / 2));
                CapBs        = _temp.F2S + _temp.F3S * vbs;
            }

            if (vbd < _temp.TempDepletionCap)
            {
                double arg = 1 - vbd / _temp.TempBulkPotential, sarg;

                /*
                 * the following block looks somewhat long and messy,
                 * but since most users use the default grading
                 * coefficients of .5, and sqrt is MUCH faster than an
                 * Math.Exp(Math.Log()) we use this special case code to buy time.
                 * (as much as 10% of total job time!)
                 */
                if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5) && _mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                {
                    sarg = sargsw = 1 / Math.Sqrt(arg);
                }
                else
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sarg = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                    if (_mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                    {
                        sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));
                    }
                }
                /* NOSQRT */
                _qbd.Current = _temp.TempBulkPotential * (_temp.CapBd * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) +
                                                          _temp.CapBdSidewall * (1 - arg * sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient));
                CapBd = _temp.CapBd * sarg + _temp.CapBdSidewall * sargsw;
            }
            else
            {
                _qbd.Current = _temp.F4D + vbd * (_temp.F2D + vbd * _temp.F3D / 2);
                CapBd        = _temp.F2D + vbd * _temp.F3D;
            }
            /* CAPZEROBYPASS */

            /* (above only excludes tranop, since we're only at this
             * point if tran or tranop)
             */

            /*
             * calculate equivalent conductances and currents for
             * depletion capacitors
             */

            /* integrate the capacitors and save results */
            _qbd.Integrate();
            gbd += _qbd.Jacobian(CapBd);
            cbd += _qbd.Derivative;
            _qbs.Integrate();
            gbs += _qbs.Jacobian(CapBs);
            cbs += _qbs.Derivative;

            /*
             * calculate meyer's capacitors
             */
            /*
             * new cmeyer - this just evaluates at the current time,
             * expects you to remember values from previous time
             * returns 1 / 2 of non - constant portion of capacitance
             * you must add in the other half from previous time
             * and the constant part
             */
            double icapgs, icapgd, icapgb;

            if (_load.Mode > 0)
            {
                Transistor.MeyerCharges(vgs, vgd, von, vdsat,
                                        out icapgs, out icapgd, out icapgb, _temp.TempPhi, oxideCap);
            }
            else
            {
                Transistor.MeyerCharges(vgd, vgs, von, vdsat,
                                        out icapgd, out icapgs, out icapgb, _temp.TempPhi, oxideCap);
            }
            _capgs.Current = icapgs;
            _capgd.Current = icapgd;
            _capgb.Current = icapgb;

            var vgs1  = _vgs[1];
            var vgd1  = vgs1 - _vds[1];
            var vgb1  = vgs1 - _vbs[1];
            var capgs = _capgs.Current + _capgs[1] + gateSourceOverlapCap;
            var capgd = _capgd.Current + _capgd[1] + gateDrainOverlapCap;
            var capgb = _capgb.Current + _capgb[1] + gateBulkOverlapCap;

            _qgs.Current = (vgs - vgs1) * capgs + _qgs[1];
            _qgd.Current = (vgd - vgd1) * capgd + _qgd[1];
            _qgb.Current = (vgb - vgb1) * capgb + _qgb[1];

            /*
             * calculate equivalent conductances and currents for
             * meyer"s capacitors
             */
            _qgs.Integrate();
            var gcgs  = _qgs.Jacobian(capgs);
            var ceqgs = _qgs.RhsCurrent(gcgs, vgs);

            _qgd.Integrate();
            var gcgd  = _qgd.Jacobian(capgd);
            var ceqgd = _qgd.RhsCurrent(gcgd, vgd);

            _qgb.Integrate();
            var gcgb  = _qgb.Jacobian(capgb);
            var ceqgb = _qgb.RhsCurrent(gcgb, vgb);

            // Load current vector
            var ceqbs = _mbp.MosfetType * (cbs - gbs * vbs);
            var ceqbd = _mbp.MosfetType * (cbd - gbd * vbd);

            GatePtr.Value        -= _mbp.MosfetType * (ceqgs + ceqgb + ceqgd);
            BulkPtr.Value        -= ceqbs + ceqbd - _mbp.MosfetType * ceqgb;
            DrainPrimePtr.Value  += ceqbd + _mbp.MosfetType * ceqgd;
            SourcePrimePtr.Value += ceqbs + _mbp.MosfetType * ceqgs;

            // Load y matrix
            GateGatePtr.Value               += gcgd + gcgs + gcgb;
            BulkBulkPtr.Value               += gbd + gbs + gcgb;
            DrainPrimeDrainPrimePtr.Value   += gbd + gcgd;
            SourcePrimeSourcePrimePtr.Value += gbs + gcgs;
            GateBulkPtr.Value               -= gcgb;
            GateDrainPrimePtr.Value         -= gcgd;
            GateSourcePrimePtr.Value        -= gcgs;
            BulkGatePtr.Value               -= gcgb;
            BulkDrainPrimePtr.Value         -= gbd;
            BulkSourcePrimePtr.Value        -= gbs;
            DrainPrimeGatePtr.Value         += -gcgd;
            DrainPrimeBulkPtr.Value         += -gbd;
            SourcePrimeGatePtr.Value        += -gcgs;
            SourcePrimeBulkPtr.Value        += -gbs;
        }
Exemplo n.º 18
0
        /// <summary>
        /// Calculate initial states
        /// </summary>
        /// <param name="simulation">Simulation</param>
        public override void GetDcState(TimeSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            double sargsw;

            var vbs   = _load.VoltageBs;
            var vbd   = _load.VoltageBd;
            var vgs   = _load.VoltageGs;
            var vgd   = _load.VoltageGs - _load.VoltageDs;
            var vgb   = _load.VoltageGs - _load.VoltageBs;
            var von   = _mbp.MosfetType * _load.Von;
            var vdsat = _mbp.MosfetType * _load.SaturationVoltageDs;

            VoltageDs.Current = _load.VoltageDs;
            VoltageBs.Current = vbs;
            VoltageGs.Current = vgs;

            var effectiveLength      = _bp.Length - 2 * _mbp.LateralDiffusion;
            var gateSourceOverlapCap = _mbp.GateSourceOverlapCapFactor * _bp.Width;
            var gateDrainOverlapCap  = _mbp.GateDrainOverlapCapFactor * _bp.Width;
            var gateBulkOverlapCap   = _mbp.GateBulkOverlapCapFactor * effectiveLength;
            var oxideCap             = _modeltemp.OxideCapFactor * effectiveLength * _bp.Width;

            /*
             * now we do the hard part of the bulk - drain and bulk - source
             * diode - we evaluate the non - linear capacitance and
             * charge
             *
             * the basic equations are not hard, but the implementation
             * is somewhat long in an attempt to avoid log / exponential
             * evaluations
             */
            /*
             * charge storage elements
             *
             * .. bulk - drain and bulk - source depletion capacitances
             */
            if (vbs < _temp.TempDepletionCap)
            {
                double arg = 1 - vbs / _temp.TempBulkPotential, sarg;

                /*
                 * the following block looks somewhat long and messy,
                 * but since most users use the default grading
                 * coefficients of .5, and sqrt is MUCH faster than an
                 * Math.Exp(Math.Log()) we use this special case code to buy time.
                 * (as much as 10% of total job time!)
                 */
                if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(_mbp.BulkJunctionSideGradingCoefficient))
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        sarg = sargsw = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                }
                else
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sarg = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                    if (_mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                    {
                        sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));
                    }
                }
                // NOSQRT
                ChargeBs.Current = _temp.TempBulkPotential * (_temp.CapBs * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) +
                                                              _temp.CapBsSidewall * (1 - arg * sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient));
            }
            else
            {
                ChargeBs.Current = _temp.F4S + vbs * (_temp.F2S + vbs * (_temp.F3S / 2));
            }

            if (vbd < _temp.TempDepletionCap)
            {
                double arg = 1 - vbd / _temp.TempBulkPotential, sarg;

                /*
                 * the following block looks somewhat long and messy,
                 * but since most users use the default grading
                 * coefficients of .5, and sqrt is MUCH faster than an
                 * Math.Exp(Math.Log()) we use this special case code to buy time.
                 * (as much as 10% of total job time!)
                 */
                if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5) && _mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                {
                    sarg = sargsw = 1 / Math.Sqrt(arg);
                }
                else
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sarg = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                    if (_mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                    {
                        sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));
                    }
                }
                /* NOSQRT */
                ChargeBd.Current = _temp.TempBulkPotential * (_temp.CapBd * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) +
                                                              _temp.CapBdSidewall * (1 - arg * sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient));
            }
            else
            {
                ChargeBd.Current = _temp.F4D + vbd * (_temp.F2D + vbd * _temp.F3D / 2);
            }

            /*
             * calculate meyer's capacitors
             */
            double icapgs, icapgd, icapgb;

            if (_load.Mode > 0)
            {
                Transistor.MeyerCharges(vgs, vgd, von, vdsat,
                                        out icapgs, out icapgd, out icapgb, _temp.TempPhi, oxideCap);
            }
            else
            {
                Transistor.MeyerCharges(vgd, vgs, von, vdsat,
                                        out icapgd, out icapgs, out icapgb, _temp.TempPhi, oxideCap);
            }
            CapGs.Current = icapgs;
            CapGd.Current = icapgd;
            CapGb.Current = icapgb;

            var capgs = 2 * CapGs.Current + gateSourceOverlapCap;
            var capgd = 2 * CapGd.Current + gateDrainOverlapCap;
            var capgb = 2 * CapGb.Current + gateBulkOverlapCap;

            /* TRANOP */
            ChargeGs.Current = capgs * vgs;
            ChargeGd.Current = capgd * vgd;
            ChargeGb.Current = capgb * vgb;
        }
Exemplo n.º 19
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;
                }
            }
        /// <summary>
        /// Initialize AC parameters
        /// </summary>
        /// <param name="simulation"></param>
        public override void InitializeParameters(FrequencySimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            double arg, sarg, sargsw;

            // Get voltages
            var vbd = _load.VoltageBd;
            var vbs = _load.VoltageBs;
            var vgs = _load.VoltageGs;
            var vds = _load.VoltageDs;
            var vgd = vgs - vds;

            var effectiveLength = _bp.Length - 2 * _mbp.LateralDiffusion;
            var oxideCap        = _modeltemp.OxideCapFactor * effectiveLength * _bp.Width;

            /*
             * now we do the hard part of the bulk - drain and bulk - source
             * diode - we evaluate the non - linear capacitance and
             * charge
             *
             * the basic equations are not hard, but the implementation
             * is somewhat long in an attempt to avoid log / exponential
             * evaluations
             */
            /*
             * charge storage elements
             *
             * .. bulk - drain and bulk - source depletion capacitances
             */
            /* CAPBYPASS */

            /* can't bypass the diode capacitance calculations */
            /* CAPZEROBYPASS */
            if (vbs < _temp.TempDepletionCap)
            {
                arg = 1 - vbs / _temp.TempBulkPotential;

                /*
                 * the following block looks somewhat long and messy,
                 * but since most users use the default grading
                 * coefficients of .5, and sqrt is MUCH faster than an
                 * Math.Exp(Math.Log()) we use this special case code to buy time.
                 * (as much as 10% of total job time!)
                 */
                if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(_mbp.BulkJunctionSideGradingCoefficient.Value))
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        sarg = sargsw = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                }
                else
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sarg = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                    if (_mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                    {
                        sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));
                    }
                }

                CapBs = _temp.CapBs * sarg + _temp.CapBsSidewall * sargsw;
            }
            else
            {
                CapBs = _temp.F2S + _temp.F3S * vbs;
            }

            /* can't bypass the diode capacitance calculations */

            /* CAPZEROBYPASS */
            if (vbd < _temp.TempDepletionCap)
            {
                arg = 1 - vbd / _temp.TempBulkPotential;

                /*
                 * the following block looks somewhat long and messy,
                 * but since most users use the default grading
                 * coefficients of .5, and sqrt is MUCH faster than an
                 * Math.Exp(Math.Log()) we use this special case code to buy time.
                 * (as much as 10% of total job time!)
                 */
                if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5) && _mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                {
                    sarg = sargsw = 1 / Math.Sqrt(arg);
                }
                else
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sarg = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                    if (_mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                    {
                        sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));
                    }
                }
                /* NOSQRT */
                CapBd = _temp.CapBd * sarg + _temp.CapBdSidewall * sargsw;
            }
            else
            {
                CapBd = _temp.F2D + vbd * _temp.F3D;
            }

            /*
             * calculate meyer's capacitors
             */
            /*
             * new cmeyer - this just evaluates at the current time,
             * expects you to remember values from previous time
             * returns 1 / 2 of non-constant portion of capacitance
             * you must add in the other half from previous time
             * and the constant part
             */
            double icapgs, icapgd, icapgb;

            if (_load.Mode > 0)
            {
                Transistor.MeyerCharges(vgs, vgd, _mbp.MosfetType * _load.Von, _mbp.MosfetType * _load.SaturationVoltageDs,
                                        out icapgs, out icapgd, out icapgb,
                                        _temp.TempPhi, oxideCap);
            }
            else
            {
                Transistor.MeyerCharges(vgd, vgs, _mbp.MosfetType * _load.Von, _mbp.MosfetType * _load.SaturationVoltageDs,
                                        out icapgd, out icapgs, out icapgb,
                                        _temp.TempPhi, oxideCap);
            }
            CapGs = icapgs;
            CapGd = icapgd;
            CapGb = icapgb;
        }
Exemplo n.º 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;

            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 = _modeltemp.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 == 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 */
                /* 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 */
            }
            else
            {
                /* DETAILPROF */

                /* 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;

                    // TODO: 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;
                }
            }

            /* 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 */
            {
                /*
                 * subroutine moseq3(vds, vbs, vgs, gm, gds, gmbs,
                 * qg, qc, qb, cggb, cgdb, cgsb, cbgb, cbdb, cbsb)
                 */

                /*
                 * this routine evaluates the drain current, its derivatives and
                 * the charges associated with the gate, channel and bulk
                 * for mosfets based on semi - empirical equations
                 */

                /*
                 *              common / mosarg / vto, beta, gamma, phi, phib, cox, xnsub, xnfs, xd, xj, xld,
                 *              1   xlamda, uo, uexp, vbp, utra, vmax, xneff, xl, xw, vbi, von, vdsat, qspof,
                 *              2   beta0, beta1, cdrain, xqco, xqc, fnarrw, fshort, lev
                 *              common / status / omega, time, delta, delold(7), ag(7), vt, xni, egfet,
                 *              1   xmu, sfactr, mode, modedc, icalc, initf, method, iord, maxord, noncon,
                 *              2   iterno, itemno, nosolv, modac, ipiv, ivmflg, ipostp, iscrch, iofile
                 *              common / knstnt / twopi, xlog2, xlog10, root2, rad, boltz, charge, ctok,
                 *              1   gmin, reltol, abstol, vntol, trtol, chgtol, eps0, epssil, epsox,
                 *              2   pivtol, pivrel
                 */

                /* equivalence (xlamda, alpha), (vbp, theta), (uexp, eta), (utra, xkappa) */

                double coeff0 = 0.0631353e0;
                double coeff1 = 0.8013292e0;
                double coeff2 = -0.01110777e0;
                double phibs;  /* phi - vbs */
                double sqphbs; /* square root of phibs */
                double dsqdvb; /*  */
                double arga, argb, argc;
                double dfsdvb;
                double dxndvb = 0.0, dvodvb = 0.0, dvodvd = 0.0,
                       dvsdvg, dvsdvb, dvsdvd, xn = 0.0;
                double onvdsc = 0.0;
                double fdrain = 0.0;
                double dfddvg = 0.0, dfddvb = 0.0,
                       dfddvd = 0.0,
                       delxl, dldvd,
                       ddldvg, ddldvd, ddldvb,
                       gds0 = 0.0;
                double fshort;

                /*
                 * bypasses the computation of charges
                 */

                /*
                 * reference cdrain equations to source and
                 * charge equations to bulk
                 */
                vdsat = 0.0;
                var oneoverxl = 1.0 / effectiveLength;
                var eta       = _mbp.Eta * 8.15e-22 / (_modeltemp.OxideCapFactor * effectiveLength * effectiveLength * effectiveLength);

                /*
                 * .....square root term
                 */
                if ((Mode == 1 ? vbs : vbd) <= 0.0)
                {
                    phibs  = _temp.TempPhi - (Mode == 1 ? vbs : vbd);
                    sqphbs = Math.Sqrt(phibs);
                    dsqdvb = -0.5 / sqphbs;
                }
                else
                {
                    var sqphis = Math.Sqrt(_temp.TempPhi); /* square root of phi */
                    var sqphs3 = _temp.TempPhi * sqphis;   /* square root of phi cubed */
                    sqphbs = sqphis / (1.0 + (Mode == 1 ? vbs : vbd) / (_temp.TempPhi + _temp.TempPhi));
                    phibs  = sqphbs * sqphbs;
                    dsqdvb = -phibs / (sqphs3 + sqphs3);
                }

                /*
                 * .....short channel effect factor
                 */
                if (_mbp.JunctionDepth > 0 && _modeltemp.CoefficientDepletionLayerWidth > 0.0)
                {
                    var wps       = _modeltemp.CoefficientDepletionLayerWidth * sqphbs;
                    var oneoverxj = 1.0 / _mbp.JunctionDepth;       /* 1 / junction depth */
                    var xjonxl    = _mbp.JunctionDepth * oneoverxl; /* junction depth / effective length */
                    var djonxj    = _mbp.LateralDiffusion * oneoverxj;
                    var wponxj    = wps * oneoverxj;
                    var wconxj    = coeff0 + coeff1 * wponxj + coeff2 * wponxj * wponxj;
                    arga   = wconxj + djonxj;
                    argc   = wponxj / (1.0 + wponxj);
                    argb   = Math.Sqrt(1.0 - argc * argc);
                    fshort = 1.0 - xjonxl * (arga * argb - djonxj);
                    var dwpdvb = _modeltemp.CoefficientDepletionLayerWidth * dsqdvb;
                    var dadvb  = (coeff1 + coeff2 * (wponxj + wponxj)) * dwpdvb * oneoverxj;
                    var dbdvb  = -argc * argc * (1.0 - argc) * dwpdvb / (argb * wps);
                    dfsdvb = -xjonxl * (dadvb * argb + arga * dbdvb);
                }
                else
                {
                    fshort = 1.0;
                    dfsdvb = 0.0;
                }

                /*
                 * .....body effect
                 */
                var gammas = _mbp.Gamma * fshort;
                var fbodys = 0.5 * gammas / (sqphbs + sqphbs);
                var fbody  = fbodys + _mbp.NarrowFactor / _bp.Width;
                var onfbdy = 1.0 / (1.0 + fbody);
                var dfbdvb = -fbodys * dsqdvb / sqphbs + fbodys * dfsdvb / fshort;
                var qbonco = gammas * sqphbs + _mbp.NarrowFactor * phibs / _bp.Width;
                var dqbdvb = gammas * dsqdvb + _mbp.Gamma * dfsdvb * sqphbs - _mbp.NarrowFactor / _bp.Width;

                /*
                 * .....static feedback effect
                 */
                var vbix = _temp.TempVoltageBi * _mbp.MosfetType - eta * (Mode * vds);

                /*
                 * .....threshold voltage
                 */
                var vth    = vbix + qbonco;
                var dvtdvd = -eta;
                var dvtdvb = dqbdvb;

                /*
                 * .....joint weak inversion and strong inversion
                 */
                von = vth;
                if (_mbp.FastSurfaceStateDensity > 0.0)
                {
                    var csonco = Circuit.Charge * _mbp.FastSurfaceStateDensity * 1e4 /* (cm *  * 2 / m *  * 2) */ * effectiveLength * _bp.Width /
                                 oxideCap;
                    var cdonco = qbonco / (phibs + phibs);
                    xn     = 1.0 + csonco + cdonco;
                    von    = vth + vt * xn;
                    dxndvb = dqbdvb / (phibs + phibs) - qbonco * dsqdvb / (phibs * sqphbs);
                    dvodvd = dvtdvd;
                    dvodvb = dvtdvb + vt * dxndvb;
                }
                else
                {
                    /*
                     * .....cutoff region
                     */
                    if ((Mode == 1 ? vgs : vgd) <= von)
                    {
                        cdrain             = 0.0;
                        Transconductance   = 0.0;
                        CondDs             = 0.0;
                        TransconductanceBs = 0.0;
                        goto innerline1000;
                    }
                }

                /*
                 * .....device is on
                 */
                var vgsx = Math.Max(Mode == 1 ? vgs : vgd, von);

                /*
                 * .....mobility modulation by gate voltage
                 */
                var onfg   = 1.0 + _mbp.Theta * (vgsx - vth);
                var fgate  = 1.0 / onfg;
                var us     = _temp.TempSurfaceMobility * 1e-4 /*(m**2/cm**2)*/ * fgate;
                var dfgdvg = -_mbp.Theta * fgate * fgate;
                var dfgdvd = -dfgdvg * dvtdvd;
                var dfgdvb = -dfgdvg * dvtdvb;

                /*
                 * .....saturation voltage
                 */
                vdsat = (vgsx - vth) * onfbdy;
                if (_mbp.MaxDriftVelocity <= 0.0)
                {
                    dvsdvg = onfbdy;
                    dvsdvd = -dvsdvg * dvtdvd;
                    dvsdvb = -dvsdvg * dvtdvb - vdsat * dfbdvb * onfbdy;
                }
                else
                {
                    var vdsc = effectiveLength * _mbp.MaxDriftVelocity / us;
                    onvdsc = 1.0 / vdsc;
                    arga   = (vgsx - vth) * onfbdy;
                    argb   = Math.Sqrt(arga * arga + vdsc * vdsc);
                    vdsat  = arga + vdsc - argb;
                    var dvsdga = (1.0 - arga / argb) * onfbdy;
                    dvsdvg = dvsdga - (1.0 - vdsc / argb) * vdsc * dfgdvg * onfg;
                    dvsdvd = -dvsdvg * dvtdvd;
                    dvsdvb = -dvsdvg * dvtdvb - arga * dvsdga * dfbdvb;
                }

                /*
                 * .....current factors in linear region
                 */
                var vdsx = Math.Min(Mode * vds, vdsat);
                if (vdsx.Equals(0.0))
                {
                    goto line900;
                }
                var cdo    = vgsx - vth - 0.5 * (1.0 + fbody) * vdsx;
                var dcodvb = -dvtdvb - 0.5 * dfbdvb * vdsx;

                /*
                 * .....normalized drain current
                 */
                var cdnorm = cdo * vdsx;
                Transconductance   = vdsx;
                CondDs             = vgsx - vth - (1.0 + fbody + dvtdvd) * vdsx;
                TransconductanceBs = dcodvb * vdsx;

                /*
                 * .....drain current without velocity saturation effect
                 */
                var cd1 = beta * cdnorm;
                beta               = beta * fgate;
                cdrain             = beta * cdnorm;
                Transconductance   = beta * Transconductance + dfgdvg * cd1;
                CondDs             = beta * CondDs + dfgdvd * cd1;
                TransconductanceBs = beta * TransconductanceBs;

                /*
                 * .....velocity saturation factor
                 */
                if (_mbp.MaxDriftVelocity > 0.0)
                {
                    fdrain = 1.0 / (1.0 + vdsx * onvdsc);
                    var fd2 = fdrain * fdrain;
                    arga   = fd2 * vdsx * onvdsc * onfg;
                    dfddvg = -dfgdvg * arga;
                    dfddvd = -dfgdvd * arga - fd2 * onvdsc;
                    dfddvb = -dfgdvb * arga;

                    /*
                     * .....drain current
                     */
                    Transconductance   = fdrain * Transconductance + dfddvg * cdrain;
                    CondDs             = fdrain * CondDs + dfddvd * cdrain;
                    TransconductanceBs = fdrain * TransconductanceBs + dfddvb * cdrain;
                    cdrain             = fdrain * cdrain;
                }

                /*
                 * .....channel length modulation
                 */
                if (Mode * vds <= vdsat)
                {
                    goto line700;
                }
                if (_mbp.MaxDriftVelocity <= 0.0)
                {
                    goto line510;
                }
                if (_modeltemp.Alpha.Equals(0.0))
                {
                    goto line700;
                }
                var cdsat = cdrain;
                var gdsat = cdsat * (1.0 - fdrain) * onvdsc;
                gdsat = Math.Max(1.0e-12, gdsat);
                var gdoncd = gdsat / cdsat;
                var gdonfd = gdsat / (1.0 - fdrain);
                var gdonfg = gdsat * onfg;
                var dgdvg  = gdoncd * Transconductance - gdonfd * dfddvg + gdonfg * dfgdvg;
                var dgdvd  = gdoncd * CondDs - gdonfd * dfddvd + gdonfg * dfgdvd;
                var dgdvb  = gdoncd * TransconductanceBs - gdonfd * dfddvb + gdonfg * dfgdvb;

                var emax   = _mbp.Kappa * cdsat * oneoverxl / gdsat;
                var emoncd = emax / cdsat;
                var emongd = emax / gdsat;
                var demdvg = emoncd * Transconductance - emongd * dgdvg;
                var demdvd = emoncd * CondDs - emongd * dgdvd;
                var demdvb = emoncd * TransconductanceBs - emongd * dgdvb;

                arga  = 0.5 * emax * _modeltemp.Alpha;
                argc  = _mbp.Kappa * _modeltemp.Alpha;
                argb  = Math.Sqrt(arga * arga + argc * (Mode * vds - vdsat));
                delxl = argb - arga;
                dldvd = argc / (argb + argb);
                var dldem = 0.5 * (arga / argb - 1.0) * _modeltemp.Alpha;
                ddldvg = dldem * demdvg;
                ddldvd = dldem * demdvd - dldvd;
                ddldvb = dldem * demdvb;
                goto line520;
line510:
                delxl  = Math.Sqrt(_mbp.Kappa * (Mode * vds - vdsat) * _modeltemp.Alpha);
                dldvd  = 0.5 * delxl / (Mode * vds - vdsat);
                ddldvg = 0.0;
                ddldvd = -dldvd;
                ddldvb = 0.0;

                /*
                 * .....punch through approximation
                 */
line520:
                if (delxl > 0.5 * effectiveLength)
                {
                    delxl  = effectiveLength - effectiveLength * effectiveLength / (4.0 * delxl);
                    arga   = 4.0 * (effectiveLength - delxl) * (effectiveLength - delxl) / (effectiveLength * effectiveLength);
                    ddldvg = ddldvg * arga;
                    ddldvd = ddldvd * arga;
                    ddldvb = ddldvb * arga;
                    dldvd  = dldvd * arga;
                }

                /*
                 * .....saturation region
                 */
                var dlonxl = delxl * oneoverxl;
                var xlfact = 1.0 / (1.0 - dlonxl);
                cdrain = cdrain * xlfact;
                var diddl = cdrain / (effectiveLength - delxl);
                Transconductance   = Transconductance * xlfact + diddl * ddldvg;
                gds0               = CondDs * xlfact + diddl * ddldvd;
                TransconductanceBs = TransconductanceBs * xlfact + diddl * ddldvb;
                Transconductance   = Transconductance + gds0 * dvsdvg;
                TransconductanceBs = TransconductanceBs + gds0 * dvsdvb;
                CondDs             = gds0 * dvsdvd + diddl * dldvd;

                /*
                 * .....finish strong inversion case
                 */
line700:
                if ((Mode == 1 ? vgs : vgd) < von)
                {
                    /*
                     * .....weak inversion
                     */
                    var onxn  = 1.0 / xn;
                    var ondvt = onxn / vt;
                    var wfact = Math.Exp(((Mode == 1 ? vgs : vgd) - von) * ondvt);
                    cdrain = cdrain * wfact;
                    var gms = Transconductance * wfact;
                    var gmw = cdrain * ondvt;
                    Transconductance = gmw;
                    if (Mode * vds > vdsat)
                    {
                        Transconductance = Transconductance + gds0 * dvsdvg * wfact;
                    }
                    CondDs             = CondDs * wfact + (gms - gmw) * dvodvd;
                    TransconductanceBs = TransconductanceBs * wfact + (gms - gmw) * dvodvb - gmw * ((Mode == 1 ? vgs : vgd) - von) * onxn * dxndvb;
                }

                /*
                 * .....charge computation
                 */
                goto innerline1000;

                /*
                 * .....special case of vds = 0.0d0 */
line900:
                beta               = beta * fgate;
                cdrain             = 0.0;
                Transconductance   = 0.0;
                CondDs             = beta * (vgsx - vth);
                TransconductanceBs = 0.0;
                if (_mbp.FastSurfaceStateDensity > 0.0 && (Mode == 1 ? vgs : vgd) < von)
                {
                    CondDs *= Math.Exp(((Mode == 1 ? vgs : vgd) - von) / (vt * xn));
                }
                innerline1000 :;

                /*
                 * .....done
                 */
            }

            /* DETAILPROF */

            /* 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;
            /* DETAILPROF */

            /*
             * meyer's capacitor model
             */


            /* DETAILPROF */

            /*
             * 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);
        }
Exemplo n.º 22
0
        /// <summary>
        /// Execute the behaviour
        /// </summary>
        /// <param name="ckt">Circuit</param>
        public override void Load(Circuit ckt)
        {
            var    bsim2 = ComponentTyped <BSIM2>();
            var    model = bsim2.Model as BSIM2Model;
            var    state = ckt.State;
            var    rstate = state;
            var    method = ckt.Method;
            double EffectiveLength, DrainArea, SourceArea, DrainPerimeter, SourcePerimeter, DrainSatCurrent, SourceSatCurrent, GateSourceOverlapCap, GateDrainOverlapCap,
                   GateBulkOverlapCap, von, vdsat, vt0;
            int    Check;
            double vbs, vgs, vds, vbd, vgd, vgdo, delvbs, delvbd, delvgs, delvds, delvgd, cdhat, cbhat, vcrit, vgb, gbs, cbs, evbs, gbd, cbd,
                   evbd, cd, czbd, czbs, czbdsw, czbssw, PhiB, PhiBSW, MJ, MJSW, arg, argsw, sarg, sargsw, capbs = 0.0, capbd = 0.0;
            double ceqqg, gcdgb, gcsgb, gcggb, gcbgb, cqgate, cqbulk, cqdrn, ceqqb, ceqqd, ceqbs, ceqbd, xnrm, xrev, cdreq;
            double gm, gds, gmbs, qgate, qbulk, qdrn = 0.0, cggb, cgdb, cgsb, cbgb, cbdb, cbsb, cdgb = 0.0,
                   cddb = 0.0, cdsb = 0.0, cdrain, qsrc = 0.0, csgb = 0.0, cssb = 0.0, csdb = 0.0;
            double gcgdb, gcgsb, gcbdb, gcbsb, gcddb, gcdsb, gcsdb, gcssb;

            EffectiveLength = bsim2.B2l - model.B2deltaL * 1.0e-6; /* m */
            DrainArea       = bsim2.B2drainArea;
            SourceArea      = bsim2.B2sourceArea;
            DrainPerimeter  = bsim2.B2drainPerimeter;
            SourcePerimeter = bsim2.B2sourcePerimeter;
            if ((DrainSatCurrent = DrainArea * model.B2jctSatCurDensity) < 1e-15)
            {
                DrainSatCurrent = 1.0e-15;
            }
            if ((SourceSatCurrent = SourceArea * model.B2jctSatCurDensity) < 1.0e-15)
            {
                SourceSatCurrent = 1.0e-15;
            }
            GateSourceOverlapCap = model.B2gateSourceOverlapCap * bsim2.B2w;
            GateDrainOverlapCap  = model.B2gateDrainOverlapCap * bsim2.B2w;
            GateBulkOverlapCap   = model.B2gateBulkOverlapCap * EffectiveLength;
            von   = model.B2type * bsim2.B2von;
            vdsat = model.B2type * bsim2.B2vdsat;
            vt0   = model.B2type * bsim2.pParam.B2vt0;

            Check = 1;
            if (state.UseSmallSignal)
            {
                vbs = state.States[0][bsim2.B2states + BSIM2.B2vbs];
                vgs = state.States[0][bsim2.B2states + BSIM2.B2vgs];
                vds = state.States[0][bsim2.B2states + BSIM2.B2vds];
            }
            else if (state.Init == State.InitFlags.InitTransient)
            {
                vbs = state.States[1][bsim2.B2states + BSIM2.B2vbs];
                vgs = state.States[1][bsim2.B2states + BSIM2.B2vgs];
                vds = state.States[1][bsim2.B2states + BSIM2.B2vds];
            }
            else if (state.Init == State.InitFlags.InitJct && !bsim2.B2off)
            {
                vds = model.B2type * bsim2.B2icVDS;
                vgs = model.B2type * bsim2.B2icVGS;
                vbs = model.B2type * bsim2.B2icVBS;
                if ((vds == 0) && (vgs == 0) && (vbs == 0) &&
                    (method != null || state.UseDC || state.Domain == State.DomainTypes.None || !state.UseIC))
                {
                    vbs = -1;
                    vgs = vt0;
                    vds = 0;
                }
            }
            else if ((state.Init == State.InitFlags.InitJct || state.Init == State.InitFlags.InitFix) && bsim2.B2off)
            {
                vbs = vgs = vds = 0;
            }
            else
            {
                /* PREDICTOR */
                vbs = model.B2type * (rstate.OldSolution[bsim2.B2bNode] - rstate.OldSolution[bsim2.B2sNodePrime]);
                vgs = model.B2type * (rstate.OldSolution[bsim2.B2gNode] - rstate.OldSolution[bsim2.B2sNodePrime]);
                vds = model.B2type * (rstate.OldSolution[bsim2.B2dNodePrime] - rstate.OldSolution[bsim2.B2sNodePrime]);
                /* PREDICTOR */
                vbd    = vbs - vds;
                vgd    = vgs - vds;
                vgdo   = state.States[0][bsim2.B2states + BSIM2.B2vgs] - state.States[0][bsim2.B2states + BSIM2.B2vds];
                delvbs = vbs - state.States[0][bsim2.B2states + BSIM2.B2vbs];
                delvbd = vbd - state.States[0][bsim2.B2states + BSIM2.B2vbd];
                delvgs = vgs - state.States[0][bsim2.B2states + BSIM2.B2vgs];
                delvds = vds - state.States[0][bsim2.B2states + BSIM2.B2vds];
                delvgd = vgd - vgdo;

                if (bsim2.B2mode >= 0)
                {
                    cdhat = state.States[0][bsim2.B2states + BSIM2.B2cd] - state.States[0][bsim2.B2states + BSIM2.B2gbd] * delvbd + state.States[0][bsim2.B2states + BSIM2.B2gmbs] *
                            delvbs + state.States[0][bsim2.B2states + BSIM2.B2gm] * delvgs + state.States[0][bsim2.B2states + BSIM2.B2gds] * delvds;
                }
                else
                {
                    cdhat = state.States[0][bsim2.B2states + BSIM2.B2cd] - (state.States[0][bsim2.B2states + BSIM2.B2gbd] - state.States[0][bsim2.B2states + BSIM2.B2gmbs]) * delvbd -
                            state.States[0][bsim2.B2states + BSIM2.B2gm] * delvgd + state.States[0][bsim2.B2states + BSIM2.B2gds] * delvds;
                }
                cbhat = state.States[0][bsim2.B2states + BSIM2.B2cbs] + state.States[0][bsim2.B2states + BSIM2.B2cbd] + state.States[0][bsim2.B2states + BSIM2.B2gbd] * delvbd +
                        state.States[0][bsim2.B2states + BSIM2.B2gbs] * delvbs;

                /* NOBYPASS */

                von = model.B2type * bsim2.B2von;
                if (state.States[0][bsim2.B2states + BSIM2.B2vds] >= 0)
                {
                    vgs = Transistor.DEVfetlim(vgs, state.States[0][bsim2.B2states + BSIM2.B2vgs], von);
                    vds = vgs - vgd;
                    vds = Transistor.DEVlimvds(vds, state.States[0][bsim2.B2states + BSIM2.B2vds]);
                    vgd = vgs - vds;
                }
                else
                {
                    vgd = Transistor.DEVfetlim(vgd, vgdo, von);
                    vds = vgs - vgd;
                    vds = -Transistor.DEVlimvds(-vds, -(state.States[0][bsim2.B2states + BSIM2.B2vds]));
                    vgs = vgd + vds;
                }
                if (vds >= 0)
                {
                    vcrit = Circuit.CONSTvt0 * Math.Log(Circuit.CONSTvt0 / (Circuit.CONSTroot2 * SourceSatCurrent));
                    vbs   = Transistor.DEVpnjlim(vbs, state.States[0][bsim2.B2states + BSIM2.B2vbs], Circuit.CONSTvt0, vcrit, ref Check); /* bsim2.B2 test */
                    vbd   = vbs - vds;
                }
                else
                {
                    vcrit = Circuit.CONSTvt0 * Math.Log(Circuit.CONSTvt0 / (Circuit.CONSTroot2 * DrainSatCurrent));
                    vbd   = Transistor.DEVpnjlim(vbd, state.States[0][bsim2.B2states + BSIM2.B2vbd], Circuit.CONSTvt0, vcrit, ref Check); /* bsim2.B2 test */
                    vbs   = vbd + vds;
                }
            }

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

            if (vbs <= 0.0)
            {
                gbs = SourceSatCurrent / Circuit.CONSTvt0 + state.Gmin;
                cbs = gbs * vbs;
            }
            else
            {
                evbs = Math.Exp(vbs / Circuit.CONSTvt0);
                gbs  = SourceSatCurrent * evbs / Circuit.CONSTvt0 + state.Gmin;
                cbs  = SourceSatCurrent * (evbs - 1) + state.Gmin * vbs;
            }
            if (vbd <= 0.0)
            {
                gbd = DrainSatCurrent / Circuit.CONSTvt0 + state.Gmin;
                cbd = gbd * vbd;
            }
            else
            {
                evbd = Math.Exp(vbd / Circuit.CONSTvt0);
                gbd  = DrainSatCurrent * evbd / Circuit.CONSTvt0 + state.Gmin;
                cbd  = DrainSatCurrent * (evbd - 1) + state.Gmin * vbd;
            }
            /* line 400 */
            if (vds >= 0)
            {
                /* normal mode */
                bsim2.B2mode = 1;
            }
            else
            {
                /* inverse mode */
                bsim2.B2mode = -1;
            }

            /* call bsim2.B2evaluate to calculate drain current and its
             * derivatives and charge and capacitances related to gate
             * drain, and bulk
             */
            if (vds >= 0)
            {
                bsim2.B2evaluate(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, ckt);
            }
            else
            {
                bsim2.B2evaluate(-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, ckt);
            }

            bsim2.B2von   = model.B2type * von;
            bsim2.B2vdsat = model.B2type * vdsat;

            /*
             * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
             */
            cd = bsim2.B2mode * cdrain - cbd;
            if (method != null || state.UseSmallSignal || (state.Domain == State.DomainTypes.Time && state.UseDC && state.UseIC))
            {
                /*
                 * 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
                 */

                czbd   = model.B2unitAreaJctCap * DrainArea;
                czbs   = model.B2unitAreaJctCap * SourceArea;
                czbdsw = model.B2unitLengthSidewallJctCap * DrainPerimeter;
                czbssw = model.B2unitLengthSidewallJctCap * SourcePerimeter;
                PhiB   = model.B2bulkJctPotential;
                PhiBSW = model.B2sidewallJctPotential;
                MJ     = model.B2bulkJctBotGradingCoeff;
                MJSW   = model.B2bulkJctSideGradingCoeff;

                /* 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));
                    state.States[0][bsim2.B2states + BSIM2.B2qbs] = PhiB * czbs * (1 - arg * sarg) / (1 - MJ) + PhiBSW * czbssw * (1 - argsw * sargsw) / (1 -
                                                                                                                                                          MJSW);
                    capbs = czbs * sarg + czbssw * sargsw;
                }
                else
                {
                    state.States[0][bsim2.B2states + BSIM2.B2qbs] = 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));
                    state.States[0][bsim2.B2states + BSIM2.B2qbd] = PhiB * czbd * (1 - arg * sarg) / (1 - MJ) + PhiBSW * czbdsw * (1 - argsw * sargsw) / (1 -
                                                                                                                                                          MJSW);
                    capbd = czbd * sarg + czbdsw * sargsw;
                }
                else
                {
                    state.States[0][bsim2.B2states + BSIM2.B2qbd] = 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 (!bsim2.B2off || state.Init != State.InitFlags.InitFix)
            {
                if (Check == 1)
                {
                    state.IsCon = false;
                }
            }
            state.States[0][bsim2.B2states + BSIM2.B2vbs]  = vbs;
            state.States[0][bsim2.B2states + BSIM2.B2vbd]  = vbd;
            state.States[0][bsim2.B2states + BSIM2.B2vgs]  = vgs;
            state.States[0][bsim2.B2states + BSIM2.B2vds]  = vds;
            state.States[0][bsim2.B2states + BSIM2.B2cd]   = cd;
            state.States[0][bsim2.B2states + BSIM2.B2cbs]  = cbs;
            state.States[0][bsim2.B2states + BSIM2.B2cbd]  = cbd;
            state.States[0][bsim2.B2states + BSIM2.B2gm]   = gm;
            state.States[0][bsim2.B2states + BSIM2.B2gds]  = gds;
            state.States[0][bsim2.B2states + BSIM2.B2gmbs] = gmbs;
            state.States[0][bsim2.B2states + BSIM2.B2gbd]  = gbd;
            state.States[0][bsim2.B2states + BSIM2.B2gbs]  = gbs;

            state.States[0][bsim2.B2states + BSIM2.B2cggb] = cggb;
            state.States[0][bsim2.B2states + BSIM2.B2cgdb] = cgdb;
            state.States[0][bsim2.B2states + BSIM2.B2cgsb] = cgsb;

            state.States[0][bsim2.B2states + BSIM2.B2cbgb] = cbgb;
            state.States[0][bsim2.B2states + BSIM2.B2cbdb] = cbdb;
            state.States[0][bsim2.B2states + BSIM2.B2cbsb] = cbsb;

            state.States[0][bsim2.B2states + BSIM2.B2cdgb] = cdgb;
            state.States[0][bsim2.B2states + BSIM2.B2cddb] = cddb;
            state.States[0][bsim2.B2states + BSIM2.B2cdsb] = cdsb;

            state.States[0][bsim2.B2states + BSIM2.B2capbs] = capbs;
            state.States[0][bsim2.B2states + BSIM2.B2capbd] = capbd;

            /* bulk and channel charge plus overlaps */

            if (method == null && ((!(state.Domain == State.DomainTypes.Time && state.UseDC)) || !state.UseIC) && !state.UseSmallSignal)
            {
                goto line850;
            }

            if (bsim2.B2mode > 0)
            {
                double[] args = new double[8];
                args[0] = GateDrainOverlapCap;
                args[1] = GateSourceOverlapCap;
                args[2] = GateBulkOverlapCap;
                args[3] = capbd;
                args[4] = capbs;
                args[5] = cggb;
                args[6] = cgdb;
                args[7] = cgsb;

                B2mosCap(ckt, vgd, vgs, vgb, args, 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
            {
                double[] args = new double[8];
                args[0] = GateSourceOverlapCap;
                args[1] = GateDrainOverlapCap;
                args[2] = GateBulkOverlapCap;
                args[3] = capbs;
                args[4] = capbd;
                args[5] = cggb;
                args[6] = cgsb;
                args[7] = cgdb;

                B2mosCap(ckt, vgs, vgd, vgb, args, 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);
            }

            state.States[0][bsim2.B2states + BSIM2.B2qg] = qgate;
            state.States[0][bsim2.B2states + BSIM2.B2qd] = qdrn - state.States[0][bsim2.B2states + BSIM2.B2qbd];
            state.States[0][bsim2.B2states + BSIM2.B2qb] = qbulk + state.States[0][bsim2.B2states + BSIM2.B2qbd] + state.States[0][bsim2.B2states + BSIM2.B2qbs];

            /* store small signal parameters */
            if (method == null && (state.Domain == State.DomainTypes.Time && state.UseDC) && state.UseIC)
            {
                goto line850;
            }

            if (state.UseSmallSignal)
            {
                state.States[0][bsim2.B2states + BSIM2.B2cggb]  = cggb;
                state.States[0][bsim2.B2states + BSIM2.B2cgdb]  = cgdb;
                state.States[0][bsim2.B2states + BSIM2.B2cgsb]  = cgsb;
                state.States[0][bsim2.B2states + BSIM2.B2cbgb]  = cbgb;
                state.States[0][bsim2.B2states + BSIM2.B2cbdb]  = cbdb;
                state.States[0][bsim2.B2states + BSIM2.B2cbsb]  = cbsb;
                state.States[0][bsim2.B2states + BSIM2.B2cdgb]  = cdgb;
                state.States[0][bsim2.B2states + BSIM2.B2cddb]  = cddb;
                state.States[0][bsim2.B2states + BSIM2.B2cdsb]  = cdsb;
                state.States[0][bsim2.B2states + BSIM2.B2capbd] = capbd;
                state.States[0][bsim2.B2states + BSIM2.B2capbs] = capbs;

                goto line1000;
            }

            if (state.Init == State.InitFlags.InitTransient)
            {
                state.States[1][bsim2.B2states + BSIM2.B2qb] = state.States[0][bsim2.B2states + BSIM2.B2qb];
                state.States[1][bsim2.B2states + BSIM2.B2qg] = state.States[0][bsim2.B2states + BSIM2.B2qg];
                state.States[1][bsim2.B2states + BSIM2.B2qd] = state.States[0][bsim2.B2states + BSIM2.B2qd];
            }

            if (method != null)
            {
                method.Integrate(state, bsim2.B2states + BSIM2.B2qb, 0.0);
                method.Integrate(state, bsim2.B2states + BSIM2.B2qg, 0.0);
                method.Integrate(state, bsim2.B2states + BSIM2.B2qd, 0.0);
            }

            goto line860;

line850:
            /* initialize to zero charge conductance and current */
            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 */
            cqgate = state.States[0][bsim2.B2states + BSIM2.B2iqg];
            cqbulk = state.States[0][bsim2.B2states + BSIM2.B2iqb];
            cqdrn  = state.States[0][bsim2.B2states + BSIM2.B2iqd];
            ceqqg  = cqgate - gcggb * vgb + gcgdb * vbd + gcgsb * vbs;
            ceqqb  = cqbulk - gcbgb * vgb + gcbdb * vbd + gcbsb * vbs;
            ceqqd  = cqdrn - gcdgb * vgb + gcddb * vbd + gcdsb * vbs;

            if (state.Init == State.InitFlags.InitTransient)
            {
                state.States[1][bsim2.B2states + BSIM2.B2iqb] = state.States[0][bsim2.B2states + BSIM2.B2iqb];
                state.States[1][bsim2.B2states + BSIM2.B2iqg] = state.States[0][bsim2.B2states + BSIM2.B2iqg];
                state.States[1][bsim2.B2states + BSIM2.B2iqd] = state.States[0][bsim2.B2states + BSIM2.B2iqd];
            }

            /*
             * load current vector
             */
line900:

            ceqbs = model.B2type * (cbs - (gbs - state.Gmin) * vbs);
            ceqbd = model.B2type * (cbd - (gbd - state.Gmin) * vbd);

            ceqqg = model.B2type * ceqqg;
            ceqqb = model.B2type * ceqqb;
            ceqqd = model.B2type * ceqqd;
            if (bsim2.B2mode >= 0)
            {
                xnrm  = 1;
                xrev  = 0;
                cdreq = model.B2type * (cdrain - gds * vds - gm * vgs - gmbs * vbs);
            }
            else
            {
                xnrm  = 0;
                xrev  = 1;
                cdreq = -(model.B2type) * (cdrain + gds * vds - gm * vgd - gmbs * vbd);
            }

            // rstate.Rhs[bsim2.B2gNode] -= ceqqg;
            // rstate.Rhs[bsim2.B2bNode] -= (ceqbs + ceqbd + ceqqb);
            // rstate.Rhs[bsim2.B2dNodePrime] += (ceqbd - cdreq - ceqqd);
            // rstate.Rhs[bsim2.B2sNodePrime] += (cdreq + ceqbs + ceqqg + ceqqb + ceqqd);

            /*
             * load y matrix
             */

            // rstate.Matrix[bsim2.B2dNode, bsim2.B2dNode] += (bsim2.B2drainConductance);
            // rstate.Matrix[bsim2.B2gNode, bsim2.B2gNode] += (gcggb);
            // rstate.Matrix[bsim2.B2sNode, bsim2.B2sNode] += (bsim2.B2sourceConductance);
            // rstate.Matrix[bsim2.B2bNode, bsim2.B2bNode] += (gbd + gbs - gcbgb - gcbdb - gcbsb);
            // rstate.Matrix[bsim2.B2dNodePrime, bsim2.B2dNodePrime] += (bsim2.B2drainConductance + gds + gbd + xrev * (gm + gmbs) + gcddb);
            // rstate.Matrix[bsim2.B2sNodePrime, bsim2.B2sNodePrime] += (bsim2.B2sourceConductance + gds + gbs + xnrm * (gm + gmbs) + gcssb);
            // rstate.Matrix[bsim2.B2dNode, bsim2.B2dNodePrime] += (-bsim2.B2drainConductance);
            // rstate.Matrix[bsim2.B2gNode, bsim2.B2bNode] += (-gcggb - gcgdb - gcgsb);
            // rstate.Matrix[bsim2.B2gNode, bsim2.B2dNodePrime] += (gcgdb);
            // rstate.Matrix[bsim2.B2gNode, bsim2.B2sNodePrime] += (gcgsb);
            // rstate.Matrix[bsim2.B2sNode, bsim2.B2sNodePrime] += (-bsim2.B2sourceConductance);
            // rstate.Matrix[bsim2.B2bNode, bsim2.B2gNode] += (gcbgb);
            // rstate.Matrix[bsim2.B2bNode, bsim2.B2dNodePrime] += (-gbd + gcbdb);
            // rstate.Matrix[bsim2.B2bNode, bsim2.B2sNodePrime] += (-gbs + gcbsb);
            // rstate.Matrix[bsim2.B2dNodePrime, bsim2.B2dNode] += (-bsim2.B2drainConductance);
            // rstate.Matrix[bsim2.B2dNodePrime, bsim2.B2gNode] += ((xnrm - xrev) * gm + gcdgb);
            // rstate.Matrix[bsim2.B2dNodePrime, bsim2.B2bNode] += (-gbd + (xnrm - xrev) * gmbs - gcdgb - gcddb - gcdsb);
            // rstate.Matrix[bsim2.B2dNodePrime, bsim2.B2sNodePrime] += (-gds - xnrm * (gm + gmbs) + gcdsb);
            // rstate.Matrix[bsim2.B2sNodePrime, bsim2.B2gNode] += (-(xnrm - xrev) * gm + gcsgb);
            // rstate.Matrix[bsim2.B2sNodePrime, bsim2.B2sNode] += (-bsim2.B2sourceConductance);
            // rstate.Matrix[bsim2.B2sNodePrime, bsim2.B2bNode] += (-gbs - (xnrm - xrev) * gmbs - gcsgb - gcsdb - gcssb);
            // rstate.Matrix[bsim2.B2sNodePrime, bsim2.B2dNodePrime] += (-gds - xrev * (gm + gmbs) + gcsdb);

            line1000 :;
        }
Exemplo n.º 23
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);
        }
Exemplo n.º 24
0
        private Exception PushFiles(CancellationToken token, ProgressBarBase parentBar, ProgressBarBase parseBar, ProgressBarBase pushBar)
        {
            try {
                var repo = new MssqlRepository();
                var name = Transistor.ToTableName(
                    new Transistor(VtnVoltage, VtnSigma, VtnDeviation),
                    new Transistor(VtpVoltage, VtpSigma, VtpDeviation)
                    );
                repo.Use(name);

                using (var pipeline = new PipeLine.PipeLine(token)) {
                    var first = pipeline.AddSelectMany(Parallel, QueueBuffer, InputFiles, RecordFactory.BuildFromCsv);
                    first.OnInterval += s => parseBar?.Tick($"parsed: {s}");

                    first.OnFinish += () => parentBar?.Tick($"Finished parse csv files. {first.TotalResultsCount} records were parsed");

                    pipeline.Invoke(() => {
                        var list = new List <Record>();
                        var sum  = 0;

                        foreach (var r in first.Results.GetConsumingEnumerable())
                        {
                            list.Add(r);
                            pushBar.MaxTicks++;

                            if (list.Count != QueueBuffer)
                            {
                                continue;
                            }
                            sum += list.Count;
                            repo.BulkUpsert(list);
                            foreach (var record in list)
                            {
                                pushBar.Tick($"{record}");
                            }
                            pushBar.Message = $"{sum} records pushed";

                            list = new List <Record>();
                        }

                        if (!list.Any())
                        {
                            return;
                        }

                        sum += list.Count;
                        repo.BulkUpsert(list);
                        foreach (var record in list)
                        {
                            pushBar.Tick($"{record}");
                        }

                        pushBar.Message = $"{sum} records pushed";
                    });

                    parentBar.Tick("Finished push");
                }
            }
            catch (OperationCanceledException e) {
                return(e);
            }
            catch (Exception e) {
                return(e);
            }

            return(null);
        }
Exemplo n.º 25
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);
        }
        /// <summary>
        /// Calculate DC state variables
        /// </summary>
        /// <param name="simulation">Time-based simulation</param>
        public override void GetDcState(TimeSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            double arg, sarg, sargsw;

            // Get voltages
            var vbd = _load.VoltageBd;
            var vbs = _load.VoltageBs;
            var vgs = _load.VoltageGs;
            var vds = _load.VoltageDs;
            var vgd = vgs - vds;
            var vgb = vgs - vbs;

            var effectiveLength      = _bp.Length - 2 * _mbp.LateralDiffusion;
            var gateSourceOverlapCap = _mbp.GateSourceOverlapCapFactor * _bp.Width;
            var gateDrainOverlapCap  = _mbp.GateDrainOverlapCapFactor * _bp.Width;
            var gateBulkOverlapCap   = _mbp.GateBulkOverlapCapFactor * effectiveLength;
            var oxideCap             = _modeltemp.OxideCapFactor * effectiveLength * _bp.Width;

            if (vbs < _temp.TempDepletionCap)
            {
                arg = 1 - vbs / _temp.TempBulkPotential;
                if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(_mbp.BulkJunctionSideGradingCoefficient.Value))
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        sarg = sargsw = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                }
                else
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        sarg = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                    if (_mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                    {
                        sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));
                    }
                }
                ChargeBs.Current = _temp.TempBulkPotential * (_temp.CapBs * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) +
                                                              _temp.CapBsSidewall * (1 - arg * sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient));
            }
            else
            {
                ChargeBs.Current = _temp.F4S + vbs * (_temp.F2S + vbs * (_temp.F3S / 2));
            }

            if (vbd < _temp.TempDepletionCap)
            {
                arg = 1 - vbd / _temp.TempBulkPotential;
                if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5) && _mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                {
                    sarg = sargsw = 1 / Math.Sqrt(arg);
                }
                else
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        sarg = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                    if (_mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                    {
                        sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));
                    }
                }
                ChargeBd.Current = _temp.TempBulkPotential * (_temp.CapBd * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) +
                                                              _temp.CapBdSidewall * (1 - arg * sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient));
            }
            else
            {
                ChargeBd.Current = _temp.F4D + vbd * (_temp.F2D + vbd * _temp.F3D / 2);
            }

            /*
             * calculate meyer's capacitors
             */
            double icapgs, icapgd, icapgb;

            if (_load.Mode > 0)
            {
                Transistor.MeyerCharges(vgs, vgd, _mbp.MosfetType * _load.Von, _mbp.MosfetType * _load.SaturationVoltageDs,
                                        out icapgs, out icapgd, out icapgb,
                                        _temp.TempPhi, oxideCap);
            }
            else
            {
                Transistor.MeyerCharges(vgd, vgs, _mbp.MosfetType * _load.Von, _mbp.MosfetType * _load.SaturationVoltageDs,
                                        out icapgd, out icapgs, out icapgb,
                                        _temp.TempPhi, oxideCap);
            }
            CapGs.Current = icapgs;
            CapGd.Current = icapgd;
            CapGb.Current = icapgb;
            var capgs = 2 * CapGs.Current + gateSourceOverlapCap;
            var capgd = 2 * CapGd.Current + gateDrainOverlapCap;
            var capgb = 2 * CapGb.Current + gateBulkOverlapCap;

            /* TRANOP only */
            ChargeGs.Current = vgs * capgs;
            ChargeGd.Current = vgd * capgd;
            ChargeGb.Current = vgb * capgb;

            // Store these voltages
            VoltageGs.Current = vgs;
            VoltageDs.Current = vds;
            VoltageBs.Current = vbs;
        }
        /// <summary>
        /// Transient behavior
        /// </summary>
        /// <param name="simulation">Time-based simulation</param>
        public override void Transient(TimeSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            double arg, sarg, sargsw;

            // Get voltages
            var vbd = _load.VoltageBd;
            var vbs = _load.VoltageBs;
            var vgs = _load.VoltageGs;
            var vds = _load.VoltageDs;
            var vgd = vgs - vds;
            var vgb = vgs - vbs;

            var effectiveLength      = _bp.Length - 2 * _mbp.LateralDiffusion;
            var gateSourceOverlapCap = _mbp.GateSourceOverlapCapFactor * _bp.Width;
            var gateDrainOverlapCap  = _mbp.GateDrainOverlapCapFactor * _bp.Width;
            var gateBulkOverlapCap   = _mbp.GateBulkOverlapCapFactor * effectiveLength;
            var oxideCap             = _modeltemp.OxideCapFactor * effectiveLength * _bp.Width;

            var gbd = 0.0;
            var cbd = 0.0;
            var gbs = 0.0;
            var cbs = 0.0;

            // Store these voltages
            VoltageGs.Current = vgs;
            VoltageDs.Current = vds;
            VoltageBs.Current = vbs;

            /*
             * now we do the hard part of the bulk - drain and bulk - source
             * diode - we evaluate the non - linear capacitance and
             * charge
             *
             * the basic equations are not hard, but the implementation
             * is somewhat long in an attempt to avoid log / exponential
             * evaluations
             */
            /*
             * charge storage elements
             *
             * .. bulk - drain and bulk - source depletion capacitances
             */
            /* CAPBYPASS */

            /* can't bypass the diode capacitance calculations */
            /* CAPZEROBYPASS */
            if (vbs < _temp.TempDepletionCap)
            {
                arg = 1 - vbs / _temp.TempBulkPotential;

                /*
                 * the following block looks somewhat long and messy,
                 * but since most users use the default grading
                 * coefficients of .5, and sqrt is MUCH faster than an
                 * Math.Exp(Math.Log()) we use this special case code to buy time.
                 * (as much as 10% of total job time!)
                 */
                if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(_mbp.BulkJunctionSideGradingCoefficient.Value))
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        sarg = sargsw = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                }
                else
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sarg = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                    if (_mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                    {
                        sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));
                    }
                }

                /* NOSQRT */
                ChargeBs.Current = _temp.TempBulkPotential * (_temp.CapBs * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) +
                                                              _temp.CapBsSidewall * (1 - arg * sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient));
                CapBs = _temp.CapBs * sarg + _temp.CapBsSidewall * sargsw;
            }
            else
            {
                ChargeBs.Current = _temp.F4S + vbs * (_temp.F2S + vbs * (_temp.F3S / 2));
                CapBs            = _temp.F2S + _temp.F3S * vbs;
            }

            /* can't bypass the diode capacitance calculations */

            /* CAPZEROBYPASS */
            if (vbd < _temp.TempDepletionCap)
            {
                arg = 1 - vbd / _temp.TempBulkPotential;

                /*
                 * the following block looks somewhat long and messy,
                 * but since most users use the default grading
                 * coefficients of .5, and sqrt is MUCH faster than an
                 * Math.Exp(Math.Log()) we use this special case code to buy time.
                 * (as much as 10% of total job time!)
                 */
                if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5) && _mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                {
                    sarg = sargsw = 1 / Math.Sqrt(arg);
                }
                else
                {
                    if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5))
                    {
                        sarg = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sarg = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
                    }
                    if (_mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5))
                    {
                        sargsw = 1 / Math.Sqrt(arg);
                    }
                    else
                    {
                        /* NOSQRT */
                        sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));
                    }
                }
                /* NOSQRT */
                ChargeBd.Current = _temp.TempBulkPotential * (_temp.CapBd * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) +
                                                              _temp.CapBdSidewall * (1 - arg * sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient));
                CapBd = _temp.CapBd * sarg + _temp.CapBdSidewall * sargsw;
            }
            else
            {
                ChargeBd.Current = _temp.F4D + vbd * (_temp.F2D + vbd * _temp.F3D / 2);
                CapBd            = _temp.F2D + vbd * _temp.F3D;
            }

            // integrate the capacitors and save results
            ChargeBd.Integrate();
            gbd += ChargeBd.Jacobian(CapBd);
            cbd += ChargeBd.Derivative;
            // NOTE: The derivative of Qbd should be added to Cd (drain current). Figure out a way later.
            ChargeBs.Integrate();
            gbs += ChargeBs.Jacobian(CapBs);
            cbs += ChargeBs.Derivative;

            /*
             * calculate meyer's capacitors
             */
            /*
             * new cmeyer - this just evaluates at the current time,
             * expects you to remember values from previous time
             * returns 1 / 2 of non-constant portion of capacitance
             * you must add in the other half from previous time
             * and the constant part
             */
            double icapgs, icapgd, icapgb;

            if (_load.Mode > 0)
            {
                Transistor.MeyerCharges(vgs, vgd, _mbp.MosfetType * _load.Von, _mbp.MosfetType * _load.SaturationVoltageDs,
                                        out icapgs, out icapgd, out icapgb,
                                        _temp.TempPhi, oxideCap);
            }
            else
            {
                Transistor.MeyerCharges(vgd, vgs, _mbp.MosfetType * _load.Von, _mbp.MosfetType * _load.SaturationVoltageDs,
                                        out icapgd, out icapgs, out icapgb,
                                        _temp.TempPhi, oxideCap);
            }
            CapGs.Current = icapgs;
            CapGd.Current = icapgd;
            CapGb.Current = icapgb;
            var vgs1  = VoltageGs[1];
            var vgd1  = vgs1 - VoltageDs[1];
            var vgb1  = vgs1 - VoltageBs[1];
            var capgs = CapGs.Current + CapGs[1] + gateSourceOverlapCap;
            var capgd = CapGd.Current + CapGd[1] + gateDrainOverlapCap;
            var capgb = CapGb.Current + CapGb[1] + gateBulkOverlapCap;

            ChargeGs.Current = (vgs - vgs1) * capgs + ChargeGs[1];
            ChargeGd.Current = (vgd - vgd1) * capgd + ChargeGd[1];
            ChargeGb.Current = (vgb - vgb1) * capgb + ChargeGb[1];


            /* NOTE: We can't reset derivatives!
             * if (capgs == 0)
             *  state.States[0][States + Cqgs] = 0;
             * if (capgd == 0)
             *  state.States[0][States + Cqgd] = 0;
             * if (capgb == 0)
             *  state.States[0][States + Cqgb] = 0;
             */

            /* NOTE: The formula with the method.Slope is to make it work for nonlinear capacitances!
             * The correct formula is: ceq = dQ/dt - geq * vq where geq = slope * dQ/dvq
             * The formula in Spice 3f5 is: ceq = dQ/dt - slope * Q where it assumes a linear capacitance
             * method.Integrate(state, out gcgs, out ceqgs, States + Qgs, capgs);
             * method.Integrate(state, out gcgd, out ceqgd, States + Qgd, capgd);
             * method.Integrate(state, out gcgb, out ceqgb, States + Qgb, capgb);
             * ceqgs = ceqgs - gcgs * vgs + method.Slope * state.States[0][States + Qgs];
             * ceqgd = ceqgd - gcgd * vgd + method.Slope * state.States[0][States + Qgd];
             * ceqgb = ceqgb - gcgb * vgb + method.Slope * state.States[0][States + Qgb];
             */

            ChargeGs.Integrate();
            var gcgs  = ChargeGs.Jacobian(capgs);
            var ceqgs = ChargeGs.RhsCurrent(gcgs, vgs);

            ChargeGd.Integrate();
            var gcgd  = ChargeGd.Jacobian(capgd);
            var ceqgd = ChargeGd.RhsCurrent(gcgd, vgd);

            ChargeGb.Integrate();
            var gcgb  = ChargeGb.Jacobian(capgb);
            var ceqgb = ChargeGb.RhsCurrent(gcgb, vgb);

            // Load current vector
            var ceqbs = _mbp.MosfetType * (cbs - gbs * vbs);
            var ceqbd = _mbp.MosfetType * (cbd - gbd * vbd);

            GatePtr.Value        -= _mbp.MosfetType * (ceqgs + ceqgb + ceqgd);
            BulkPtr.Value        -= ceqbs + ceqbd - _mbp.MosfetType * ceqgb;
            DrainPrimePtr.Value  += ceqbd + _mbp.MosfetType * ceqgd;
            SourcePrimePtr.Value += ceqbs + _mbp.MosfetType * ceqgs;

            // Load Y-matrix
            GateGatePtr.Value               += gcgd + gcgs + gcgb;
            BulkBulkPtr.Value               += gbd + gbs + gcgb;
            DrainPrimeDrainPrimePtr.Value   += gbd + gcgd;
            SourcePrimeSourcePrimePtr.Value += gbs + gcgs;
            GateBulkPtr.Value               -= gcgb;
            GateDrainPrimePtr.Value         -= gcgd;
            GateSourcePrimePtr.Value        -= gcgs;
            BulkGatePtr.Value               -= gcgb;
            BulkDrainPrimePtr.Value         -= gbd;
            BulkSourcePrimePtr.Value        -= gbs;
            DrainPrimeGatePtr.Value         -= gcgd;
            DrainPrimeBulkPtr.Value         -= gbd;
            SourcePrimeGatePtr.Value        -= gcgs;
            SourcePrimeBulkPtr.Value        -= gbs;
        }
Exemplo n.º 28
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 == 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 */
                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;
                }
            }
Exemplo n.º 29
0
        public override void Initialize()
        {
            base.Initialize();

            p = parent as Transistor;
        }
Exemplo n.º 30
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;
                }
            }
        }
Exemplo n.º 31
0
        public override void Initialize()
        {
            base.Initialize();

            p = parent as Transistor;
        }