Example #1
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;
        }
        /// <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;
        }