Beispiel #1
0
        /// <summary>
        /// Bind behavior.
        /// </summary>
        /// <param name="simulation">The simulation.</param>
        /// <param name="context">Data provider</param>
        public override void Bind(Simulation simulation, BindingContext context)
        {
            base.Bind(simulation, context);

            // Get parameters
            BaseParameters = context.GetParameterSet <CommonBehaviors.IndependentSourceParameters>();

            // Setup the waveform
            BaseParameters.Waveform?.Setup();

            // Give some warnings if no value is given
            if (!BaseParameters.DcValue.Given)
            {
                // no DC value - either have a transient value or none
                CircuitWarning.Warning(this,
                                       BaseParameters.Waveform != null
                        ? "{0} has no DC value, transient time 0 value used".FormatString(Name)
                        : "{0} has no value, DC 0 assumed".FormatString(Name));
            }

            if (context is ComponentBindingContext cc)
            {
                PosNode = cc.Pins[0];
                NegNode = cc.Pins[1];
            }

            _state = ((BaseSimulation)simulation).RealState;
            var solver = _state.Solver;

            PosPtr = solver.GetRhsElement(PosNode);
            NegPtr = solver.GetRhsElement(NegNode);
        }
        /// <summary>
        /// Setup the behavior
        /// </summary>
        /// <param name="simulation">Simulation</param>
        /// <param name="provider">Data provider</param>
        public override void Setup(Simulation simulation, SetupDataProvider provider)
        {
            if (provider == null)
            {
                throw new ArgumentNullException(nameof(provider));
            }

            // Get parameters
            BaseParameters = provider.GetParameterSet <CommonBehaviors.IndependentBaseParameters>();

            // Setup the waveform
            BaseParameters.Waveform?.Setup();

            if (!BaseParameters.DcValue.Given)
            {
                // No DC value: either have a transient value or none
                if (BaseParameters.Waveform != null)
                {
                    CircuitWarning.Warning(this, "{0}: No DC value, transient time 0 value used".FormatString(Name));
                    BaseParameters.DcValue.RawValue = BaseParameters.Waveform.Value;
                }
                else
                {
                    CircuitWarning.Warning(this, "{0}: No value, DC 0 assumed".FormatString(Name));
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Setup the device
        /// </summary>
        /// <param name="ckt">The circuit</param>
        public override void Setup(Circuit ckt)
        {
            var model = Model as BSIM3v30Model;

            pParam = null;

            // Allocate nodes
            var nodes = BindNodes(ckt);

            BSIM3dNode = nodes[0].Index;
            BSIM3gNode = nodes[1].Index;
            BSIM3sNode = nodes[2].Index;
            BSIM3bNode = nodes[3].Index;

            // Allocate states
            BSIM3states = ckt.State.GetState(17);

            /* allocate a chunk of the state vector */

            /* perform the parameter defaulting */
            if (!BSIM3acnqsMod.Given)
            {
                BSIM3acnqsMod.Value = model.BSIM3acnqsMod;
            }
            else if ((BSIM3acnqsMod != 0) && (BSIM3acnqsMod != 1))
            {
                BSIM3acnqsMod.Value = model.BSIM3acnqsMod;
                CircuitWarning.Warning(this, $"Warning: acnqsMod has been set to its global value {model.BSIM3acnqsMod}.");
            }

            /* process drain series resistance */
            if ((model.BSIM3sheetResistance > 0.0) && (BSIM3drainSquares > 0.0))
            {
                BSIM3dNodePrime = CreateNode(ckt, Name.Grow("#drain")).Index;
            }
            else
            {
                BSIM3dNodePrime = BSIM3dNode;
            }

            /* process source series resistance */
            if ((model.BSIM3sheetResistance > 0.0) && (BSIM3sourceSquares > 0.0))
            {
                BSIM3sNodePrime = CreateNode(ckt, Name.Grow("#source")).Index;
            }
            else
            {
                BSIM3sNodePrime = BSIM3sNode;
            }

            /* internal charge node */
            if ((BSIM3nqsMod > 0) && (BSIM3qNode == 0))
            {
                BSIM3qNode = CreateNode(ckt, Name.Grow("#charge")).Index;
            }
            else
            {
                BSIM3qNode = 0;
            }
        }
        /// <summary>
        /// Iterates to a solution slowly ramping up independent voltages and currents.
        /// </summary>
        /// <param name="maxIterations">The maximum number of iterations per step.</param>
        /// <param name="steps">The number of steps.</param>
        /// <returns></returns>
        protected bool IterateSourceStepping(int maxIterations, int steps)
        {
            var state = RealState;

            // We will slowly ramp up voltages starting at 0 to make sure it converges
            CircuitWarning.Warning(this, Properties.Resources.StartSourceStepping);

            // We could've ended up with some crazy value, so let's reset it
            for (var i = 0; i < RealState.Solution.Length; i++)
            {
                RealState.Solution[i] = 0.0;
            }

            // Start SRC stepping
            bool success = true;

            state.Init = InitializationModes.Junction;
            for (var i = 0; i <= steps; i++)
            {
                state.SourceFactor = i / (double)steps;
                if (!Iterate(maxIterations))
                {
                    state.SourceFactor = 1.0;
                    CircuitWarning.Warning(this, Properties.Resources.SourceSteppingFailed);
                    success = false;
                    break;
                }
            }

            return(success);
        }
Beispiel #5
0
        /// <summary>
        /// Sets up the convergence aid for a specific simulation.
        /// </summary>
        /// <param name="simulation">The simulation.</param>
        public virtual void Initialize(BaseSimulation simulation)
        {
            // Get the unknown variables
            Variables = simulation.Variables;

            // Get the real solver
            var state = simulation.RealState;

            Solver = state.Solver;

            // Get the node
            if (!simulation.Variables.TryGetNode(Name, out var node))
            {
                CircuitWarning.Warning(this, "Could not set convergence aid: variable {0} not found.".FormatString(Name));
                Node = null;
                return;
            }
            Node = node;

            // Get the necessary elements
            Diagonal = Solver.GetMatrixElement(node.Index, node.Index);
            Rhs      = Value.Equals(0.0) ? null : Solver.GetRhsElement(node.Index);

            // Update the current solution to reflect our convergence aid value
            state.Solution[node.Index] = Value;
        }
        /// <summary>
        /// Perform temperature-dependent calculations.
        /// </summary>
        void ITemperatureBehavior.Temperature()
        {
            if (_mbp.NominalTemperature.Given)
            {
                _mbp.NominalTemperature.RawValue = ((BaseSimulation)Simulation).RealState.NominalTemperature;
            }

            var vtnom  = Constants.KOverQ * _mbp.NominalTemperature;
            var fact1  = _mbp.NominalTemperature / Constants.ReferenceTemperature;
            var kt1    = Constants.Boltzmann * _mbp.NominalTemperature;
            var egfet1 = 1.16 - (7.02e-4 * _mbp.NominalTemperature * _mbp.NominalTemperature) /
                         (_mbp.NominalTemperature + 1108);
            var arg1    = -egfet1 / (kt1 + kt1) + 1.1150877 / (Constants.Boltzmann * 2 * Constants.ReferenceTemperature);
            var pbfact1 = -2 * vtnom * (1.5 * Math.Log(fact1) + Constants.Charge * arg1);

            Pbo = (_mbp.GatePotential - pbfact1) / fact1;
            var gmaold = (_mbp.GatePotential - Pbo) / Pbo;

            Cjfact = 1 / (1 + .5 * (4e-4 * (_mbp.NominalTemperature - Constants.ReferenceTemperature) - gmaold));

            if (_mbp.DepletionCapCoefficient > 0.95)
            {
                CircuitWarning.Warning(this,
                                       "{0}: Depletion capacitance coefficient too large, limited to 0.95".FormatString(Name));
                _mbp.DepletionCapCoefficient.Value = .95;
            }

            Xfc = Math.Log(1 - _mbp.DepletionCapCoefficient);
            F2  = Math.Exp((1 + 0.5) * Xfc);
            F3  = 1 - _mbp.DepletionCapCoefficient * (1 + 0.5);
            /* Modification for Sydney University JFET model */
            BFactor = (1 - _mbp.B) / (_mbp.GatePotential - _mbp.Threshold);
        }
Beispiel #7
0
        /// <summary>
        /// Execute behavior
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public void Temperature(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            double factor;
            double resistance = BaseParameters.Resistance;

            // Default Value Processing for Resistor Instance
            if (!BaseParameters.Temperature.Given)
            {
                BaseParameters.Temperature.RawValue = simulation.RealState.Temperature;
            }
            if (!BaseParameters.Width.Given)
            {
                BaseParameters.Width.RawValue = ModelParameters?.DefaultWidth ?? 0.0;
            }

            if (ModelParameters != null)
            {
                if (!BaseParameters.Resistance.Given)
                {
                    if (ModelParameters.SheetResistance.Given && ModelParameters.SheetResistance > 0 && BaseParameters.Length > 0)
                    {
                        resistance = ModelParameters.SheetResistance * (BaseParameters.Length - ModelParameters.Narrow) / (BaseParameters.Width - ModelParameters.Narrow);
                    }
                    else
                    {
                        CircuitWarning.Warning(this, "{0}: resistance=0, set to 1000".FormatString(Name));
                        resistance = 1000;
                    }
                }

                var difference = BaseParameters.Temperature - ModelParameters.NominalTemperature;

                if (ModelParameters.ExponentialCoefficient.Given)
                {
                    factor = Math.Pow(1.01, ModelParameters.ExponentialCoefficient * difference);
                }
                else
                {
                    factor = 1.0 + ModelParameters.TemperatureCoefficient1 * difference + ModelParameters.TemperatureCoefficient2 * difference * difference;
                }
            }
            else
            {
                factor = 1.0;
            }

            if (resistance < MinimumResistance)
            {
                resistance = MinimumResistance;
            }

            Conductance = 1.0 / (resistance * factor);
        }
        /// <summary>
        /// Specify a parameter for this object
        /// </summary>
        /// <param name="id">The parameter identifier</param>
        /// <param name="value">The value</param>
        /// <param name="ckt">The circuit if applicable</param>
        public virtual void Set(string name, object value = null, Circuit ckt = null)
        {
            // Use reflection to find the member associated with the name
            if (!parameters.ContainsKey(name))
            {
                CircuitWarning.Warning(this, $"{Name}: Parameter '{name}' does not exist");
                return;
            }

            parameters[name].Set(this, value, ckt);
        }
Beispiel #9
0
 /// <summary>
 /// Specify a parameter for this object
 /// </summary>
 /// <param name="name"></param>
 /// <param name="value"></param>
 public virtual void Set(string name, string value)
 {
     // Set the parameter
     if (ssetter.ContainsKey(name))
     {
         ssetter[name].Invoke(me, value);
     }
     else
     {
         CircuitWarning.Warning(this, $"Unrecognized parameter \"{name}\" of type string");
     }
 }
        /// <summary>
        /// Execute behavior
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Temperature(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            double factor;
            double resist = _bp.Resistance;

            // Default Value Processing for Resistor Instance
            if (!_bp.Temperature.Given)
            {
                _bp.Temperature.RawValue = simulation.RealState.Temperature;
            }
            if (!_bp.Width.Given)
            {
                _bp.Width.RawValue = _mbp?.DefaultWidth ?? 0.0;
            }

            if (_mbp != null)
            {
                if (!_bp.Resistance.Given)
                {
                    if (_mbp.SheetResistance.Given && _mbp.SheetResistance > 0 && _bp.Length > 0)
                    {
                        resist = _mbp.SheetResistance * (_bp.Length - _mbp.Narrow) / (_bp.Width - _mbp.Narrow);
                    }
                    else
                    {
                        CircuitWarning.Warning(this, "{0}: resistance=0, set to 1000".FormatString(Name));
                        resist = 1000;
                    }
                }

                var difference = _bp.Temperature - _mbp.NominalTemperature;
                factor = 1.0 + _mbp.TemperatureCoefficient1 * difference + _mbp.TemperatureCoefficient2 * difference * difference;
            }
            else
            {
                factor = 1.0;
            }

            if (resist < 1e-12)
            {
                resist = 1e-12;
            }
            Conductance = 1.0 / (resist * factor);
        }
Beispiel #11
0
        /// <summary>
        /// Iterates to a solution while adding a conductive path to ground on all nodes.
        /// </summary>
        /// <param name="maxIterations">The maximum number of iterations per step.</param>
        /// <param name="steps">The number of steps.</param>
        /// <returns></returns>
        protected bool IterateDiagonalGminStepping(int maxIterations, int steps)
        {
            var state = RealState;

            // We will add a DC path to ground to all nodes to aid convergence
            CircuitWarning.Warning(this, Properties.Resources.StartDiagonalGminStepping);

            // We'll hack into the loading algorithm to apply our diagonal contributions
            _diagonalGmin = state.Gmin;
            if (_diagonalGmin <= 0)
            {
                _diagonalGmin = 1e-12;
            }
            void ApplyGminStep(object sender, LoadStateEventArgs args) => state.Solver.ApplyDiagonalGmin(_diagonalGmin);

            AfterLoad += ApplyGminStep;

            // We could've ended up with some crazy value, so let's reset it
            for (var i = 0; i < RealState.Solution.Length; i++)
            {
                RealState.Solution[i] = 0.0;
            }

            // Let's make it a bit easier for our iterations to converge
            for (var i = 0; i < steps; i++)
            {
                _diagonalGmin *= 10.0;
            }

            // Start GMIN stepping
            state.Init = InitializationModes.Junction;
            for (var i = 0; i <= steps; i++)
            {
                state.IsConvergent = false;
                if (!Iterate(maxIterations))
                {
                    _diagonalGmin = 0.0;
                    CircuitWarning.Warning(this, Properties.Resources.GminSteppingFailed);
                    break;
                }
                _diagonalGmin /= 10.0;
                state.Init     = InitializationModes.Float;
            }

            // Try one more time without the gmin stepping
            AfterLoad    -= ApplyGminStep;
            _diagonalGmin = 0.0;
            return(Iterate(maxIterations));
        }
Beispiel #12
0
 /// <summary>
 /// Specify a parameter for this object
 /// </summary>
 /// <param name="id">The parameter identifier</param>
 /// <param name="value">The value</param>
 public virtual void Set(string name, double value)
 {
     // Set the parameter
     if (dsetter.ContainsKey(name))
     {
         dsetter[name].Invoke(me, value);
     }
     else if (pgetter.ContainsKey(name))
     {
         pgetter[name].Invoke(me).Set(value);
     }
     else
     {
         CircuitWarning.Warning(this, $"Unrecognized parameter \"{name}\" of type double");
     }
 }
Beispiel #13
0
        /// <summary>
        /// Applies the rounding operator.
        /// </summary>
        /// <param name="arguments">The arguments.</param>
        /// <returns>The rounded result.</returns>
        public static Derivatives <Func <double> > ApplyRound(Derivatives <Func <double> >[] arguments)
        {
            arguments.ThrowIfEmpty(nameof(arguments));
            var arg = arguments[0];

            if (arguments.Length == 1)
            {
                var result = new DoubleDerivatives();
                var a0     = arg[0];
                result[0] = () => Math.Round(a0());

                // The derivative of Round() is always 0 (horizontal), but doesn't exist depending on where it is rounded
                for (var i = 1; i < arg.Count; i++)
                {
                    if (arg[i] != null)
                    {
                        CircuitWarning.Warning(null, "Trying to derive Round() for which the derivative may not exist in some points");
                    }
                }
                return(result);
            }
            if (arguments.Length == 2)
            {
                var result = new DoubleDerivatives();
                var a0     = arg[0];
                var b0     = arguments[1][0];
                result[0] = () => Math.Round(a0(), (int)Math.Round(b0()));

                // The derivative of Round() is always 0 (horizontal), but doesn't exist depending on where it is rounded
                for (var i = 1; i < arg.Count; i++)
                {
                    if (arg[i] != null)
                    {
                        CircuitWarning.Warning(null, "Trying to derive Round() to the first argument for which the derivative may not exist in some points");
                    }
                }
                for (var i = 1; i < arguments[1].Count; i++)
                {
                    if (arguments[1][i] != null)
                    {
                        CircuitWarning.Warning(null, "Trying to derive Round() to the second argument for which the derivative may not exist in some points");
                    }
                }
                return(result);
            }
            throw new CircuitException("Invalid number of arguments for Round()");
        }
Beispiel #14
0
        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Temperature(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            if (!_mbp.NominalTemperature.Given)
            {
                _mbp.NominalTemperature.RawValue = simulation.RealState.NominalTemperature;
            }
            VtNominal = Circuit.KOverQ * _mbp.NominalTemperature;

            // limit grading coeff to max of 0.9
            if (_mbp.GradingCoefficient > 0.9)
            {
                _mbp.GradingCoefficient.RawValue = 0.9;
                CircuitWarning.Warning(this, "{0}: grading coefficient too large, limited to 0.9".FormatString(Name));
            }

            // limit activation energy to min of 0.1
            if (_mbp.ActivationEnergy < 0.1)
            {
                _mbp.ActivationEnergy.RawValue = 0.1;
                CircuitWarning.Warning(this, "{0}: activation energy too small, limited to 0.1".FormatString(Name));
            }

            // limit depletion cap coeff to max of .95
            if (_mbp.DepletionCapCoefficient > 0.95)
            {
                _mbp.DepletionCapCoefficient.RawValue = 0.95;
                CircuitWarning.Warning(this, "{0}: coefficient Fc too large, limited to 0.95".FormatString(Name));
            }

            if (_mbp.Resistance > 0)
            {
                Conductance = 1 / _mbp.Resistance;
            }
            else
            {
                Conductance = 0;
            }
            Xfc = Math.Log(1 - _mbp.DepletionCapCoefficient);

            F2 = Math.Exp((1 + _mbp.GradingCoefficient) * Xfc);
            F3 = 1 - _mbp.DepletionCapCoefficient * (1 + _mbp.GradingCoefficient);
        }
Beispiel #15
0
        /// <summary>
        /// Iterates to a solution while shunting PN-junctions with a conductance.
        /// </summary>
        /// <param name="maxIterations">The maximum number of iterations per step.</param>
        /// <param name="steps">The number of steps.</param>
        /// <returns></returns>
        protected bool IterateGminStepping(int maxIterations, int steps)
        {
            var state = RealState;

            // We will shunt all PN-junctions with a conductance (should be implemented by the components)
            CircuitWarning.Warning(this, Properties.Resources.StartGminStepping);

            // We could've ended up with some crazy value, so let's reset it
            for (var i = 0; i < RealState.Solution.Length; i++)
            {
                RealState.Solution[i] = 0.0;
            }

            // Let's make it a bit easier for our iterations to converge
            var original = state.Gmin;

            if (state.Gmin <= 0)
            {
                state.Gmin = 1e-12;
            }
            for (var i = 0; i < steps; i++)
            {
                state.Gmin *= 10.0;
            }

            // Start GMIN stepping
            state.Init = InitializationModes.Junction;
            for (var i = 0; i <= steps; i++)
            {
                state.IsConvergent = false;
                if (!Iterate(maxIterations))
                {
                    state.Gmin = original;
                    CircuitWarning.Warning(this, Properties.Resources.GminSteppingFailed);
                    break;
                }

                // Success! Let's try to get more accurate now
                state.Gmin /= 10.0;
                state.Init  = InitializationModes.Float;
            }

            // Try one more time with the original gmin
            state.Gmin = original;
            return(Iterate(maxIterations));
        }
Beispiel #16
0
        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="ckt">The circuit</param>
        public override void Temperature(Circuit ckt)
        {
            var state = ckt.State;

            CurrentTemperature = state.Temperature;

            if (!DIOnomTemp.Given)
            {
                DIOnomTemp.Value = state.NominalTemperature;
            }
            vtnom = Circuit.CONSTKoverQ * DIOnomTemp;

            // limit grading coeff to max of .9
            if (DIOgradingCoeff > .9)
            {
                CircuitWarning.Warning(this, string.Format("Model {0}: Grading coefficient too large, limited to 0.9", Name));
                DIOgradingCoeff.Value = 0.9;
            }

            // limit activation energy to min of .1
            if (DIOactivationEnergy < 0.1)
            {
                CircuitWarning.Warning(this, string.Format("Model {0}: Activation energy too small, limited to 0.1", Name));
                DIOactivationEnergy.Value = 0.1;
            }

            // limit depletion cap coeff to max of .95
            if (DIOdepletionCapCoeff > .95)
            {
                CircuitWarning.Warning(this, string.Format("Model {0}: Coefficient Fc too large, limited to 0.95", Name));
                DIOdepletionCapCoeff.Value = 0.95;
            }
            if (!DIOresist.Given || DIOresist == 0)
            {
                DIOconductance = 0;
            }
            else
            {
                DIOconductance = 1.0 / DIOresist;
            }
            xfc = Math.Log(1.0 - DIOdepletionCapCoeff);

            DIOf2 = Math.Exp((1.0 + DIOgradingCoeff) * xfc);
            DIOf3 = 1.0 - DIOdepletionCapCoeff *
                    (1.0 + DIOgradingCoeff);
        }
Beispiel #17
0
        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="ckt">The circuit</param>
        public override void Temperature(Circuit ckt)
        {
            double        factor;
            double        difference;
            ResistorModel model = Model as ResistorModel ?? defaultmodel;

            // Default Value Processing for Resistor Instance
            if (!REStemp.Given)
            {
                REStemp.Value = ckt.State.Temperature;
            }
            if (!RESwidth.Given)
            {
                RESwidth.Value = model?.RESdefWidth ?? 0.0;
            }
            if (!RESlength.Given)
            {
                RESlength.Value = 0;
            }
            if (!RESresist.Given)
            {
                if (model.RESsheetRes.Given && (model.RESsheetRes != 0) && (RESlength != 0))
                {
                    RESresist.Value = model.RESsheetRes * (RESlength - model.RESnarrow) / (RESwidth - model.RESnarrow);
                }
                else
                {
                    CircuitWarning.Warning(this, string.Format("{0}: resistance=0, set to 1000", Name ?? "NULL"));
                    RESresist.Value = 1000;
                }
            }

            if (model != null)
            {
                difference = REStemp - model.REStnom;
                factor     = 1.0 + (model.REStempCoeff1) * difference + (model.REStempCoeff2) * difference * difference;
            }
            else
            {
                difference = REStemp - 300.15;
                factor     = 1.0;
            }

            RESconduct = 1.0 / (RESresist * factor);
        }
Beispiel #18
0
        /// <summary>
        /// Bind the behavior.
        /// </summary>
        /// <param name="simulation">The simulation.</param>
        /// <param name="context">The context.</param>
        public override void Bind(Simulation simulation, BindingContext context)
        {
            base.Bind(simulation, context);

            // Get parameters
            BaseParameters = context.GetParameterSet <CommonBehaviors.IndependentSourceParameters>();

            // Setup the waveform
            BaseParameters.Waveform?.Setup();

            if (!BaseParameters.DcValue.Given)
            {
                // No DC value: either have a transient value or none
                if (BaseParameters.Waveform != null)
                {
                    CircuitWarning.Warning(this, "{0}: No DC value, transient time 0 value used".FormatString(Name));
                    BaseParameters.DcValue.RawValue = BaseParameters.Waveform.Value;
                }
                else
                {
                    CircuitWarning.Warning(this, "{0}: No value, DC 0 assumed".FormatString(Name));
                }
            }

            if (context is ComponentBindingContext cc)
            {
                PosNode = cc.Pins[0];
                NegNode = cc.Pins[1];
            }

            _state = ((BaseSimulation)simulation).RealState;
            var solver    = _state.Solver;
            var variables = simulation.Variables;

            BranchEq = variables.Create(Name.Combine("branch"), VariableType.Current).Index;

            // Get matrix elements
            PosBranchPtr = solver.GetMatrixElement(PosNode, BranchEq);
            BranchPosPtr = solver.GetMatrixElement(BranchEq, PosNode);
            NegBranchPtr = solver.GetMatrixElement(NegNode, BranchEq);
            BranchNegPtr = solver.GetMatrixElement(BranchEq, NegNode);

            // Get rhs elements
            BranchPtr = solver.GetRhsElement(BranchEq);
        }
Beispiel #19
0
        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="ckt"></param>
        public override void Temperature(Circuit ckt)
        {
            if (!ISRCdcValue.Given)
            {
                // no DC value - either have a transient value or none
                if (ISRCwaveform != null)
                {
                    CircuitWarning.Warning(this, $"{Name} has no DC value, transient time 0 value used");
                }
                else
                {
                    CircuitWarning.Warning(this, $"{Name} has no value, DC 0 assumed");
                }
            }
            double radians = ISRCacPhase * Circuit.CONSTPI / 180.0;

            ISRCac = new Complex(ISRCacMag * Math.Cos(radians), ISRCacMag * Math.Sin(radians));
        }
Beispiel #20
0
        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="ckt">The circuit</param>
        public override void Temperature(Circuit ckt)
        {
            // Calculate the voltage source's complex value
            if (!VSRCdcValue.Given)
            {
                // No DC value: either have a transient value or none
                if (VSRCwaveform.Given)
                {
                    CircuitWarning.Warning(this, $"{Name}: No DC value, transient time 0 value used");
                }
                else
                {
                    CircuitWarning.Warning(this, $"{Name}: No value, DC 0 assumed");
                }
            }
            double radians = VSRCacPhase * Circuit.CONSTPI / 180.0;

            VSRCac = new Complex(VSRCacMag * Math.Cos(radians), VSRCacMag * Math.Sin(radians));
        }
        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        void ITemperatureBehavior.Temperature()
        {
            if (!_mbp.NominalTemperature.Given)
            {
                _mbp.NominalTemperature.RawValue = ((BaseSimulation)Simulation).RealState.NominalTemperature;
            }
            VtNominal = Constants.KOverQ * _mbp.NominalTemperature;

            // limit grading coeff to max of 0.9
            if (_mbp.GradingCoefficient > 0.9)
            {
                _mbp.GradingCoefficient.RawValue = 0.9;
                CircuitWarning.Warning(this, "{0}: grading coefficient too large, limited to 0.9".FormatString(Name));
            }

            // limit activation energy to min of 0.1
            if (_mbp.ActivationEnergy < 0.1)
            {
                _mbp.ActivationEnergy.RawValue = 0.1;
                CircuitWarning.Warning(this, "{0}: activation energy too small, limited to 0.1".FormatString(Name));
            }

            // limit depletion cap coeff to max of .95
            if (_mbp.DepletionCapCoefficient > 0.95)
            {
                _mbp.DepletionCapCoefficient.RawValue = 0.95;
                CircuitWarning.Warning(this, "{0}: coefficient Fc too large, limited to 0.95".FormatString(Name));
            }

            if (_mbp.Resistance > 0)
            {
                Conductance = 1 / _mbp.Resistance;
            }
            else
            {
                Conductance = 0;
            }
            Xfc = Math.Log(1 - _mbp.DepletionCapCoefficient);

            F2 = Math.Exp((1 + _mbp.GradingCoefficient) * Xfc);
            F3 = 1 - _mbp.DepletionCapCoefficient * (1 + _mbp.GradingCoefficient);
        }
Beispiel #22
0
        /// <summary>
        /// Setup behavior
        /// </summary>
        /// <param name="provider">Data provider</param>
        public override void Setup(SetupDataProvider provider)
        {
            if (provider == null)
            {
                throw new ArgumentNullException(nameof(provider));
            }

            // Get parameters
            _bp = provider.GetParameterSet <BaseParameters>("entity");

            // Give some warnings if no value is given
            if (!_bp.DcValue.Given)
            {
                // no DC value - either have a transient value or none
                CircuitWarning.Warning(this,
                                       _bp.Waveform != null
                        ? "{0} has no DC value, transient time 0 value used".FormatString(Name)
                        : "{0} has no value, DC 0 assumed".FormatString(Name));
            }
        }
Beispiel #23
0
        /// <summary>
        /// Setup behavior
        /// </summary>
        /// <param name="simulation">Simulation</param>
        /// <param name="provider">Data provider</param>
        public override void Setup(Simulation simulation, SetupDataProvider provider)
        {
            provider.ThrowIfNull(nameof(provider));

            // Get parameters
            BaseParameters = provider.GetParameterSet <CommonBehaviors.IndependentSourceParameters>();

            // Setup the waveform
            BaseParameters.Waveform?.Setup();

            // Give some warnings if no value is given
            if (!BaseParameters.DcValue.Given)
            {
                // no DC value - either have a transient value or none
                CircuitWarning.Warning(this,
                                       BaseParameters.Waveform != null
                        ? "{0} has no DC value, transient time 0 value used".FormatString(Name)
                        : "{0} has no value, DC 0 assumed".FormatString(Name));
            }
        }
        /// <summary>
        /// Setup the behavior
        /// </summary>
        /// <param name="simulation">Simulation</param>
        /// <param name="provider">Data provider</param>
        public override void Setup(Simulation simulation, SetupDataProvider provider)
        {
            if (provider == null)
            {
                throw new ArgumentNullException(nameof(provider));
            }

            // Get parameters
            _bp = provider.GetParameterSet <BaseParameters>();

            // Setup the waveform
            _bp.Waveform?.Setup();

            // Calculate the voltage source's complex value
            if (!_bp.DcValue.Given)
            {
                // No DC value: either have a transient value or none
                CircuitWarning.Warning(this,
                                       _bp.Waveform != null
                        ? "{0}: No DC value, transient time 0 value used".FormatString(Name)
                        : "{0}: No value, DC 0 assumed".FormatString(Name));
            }
        }
Beispiel #25
0
        /// <summary>
        /// Applies the maximum.
        /// </summary>
        /// <param name="arguments">The arguments.</param>
        /// <returns>The maximum result.</returns>
        public static Derivatives <Expression> ApplyMax(Derivatives <Expression>[] arguments)
        {
            arguments.ThrowIfEmpty(nameof(arguments));
            var size = 1;

            for (var i = 0; i < arguments.Length; i++)
            {
                size = Math.Max(size, arguments[i].Count);
            }
            var result = new ExpressionTreeDerivatives(size);

            if (arguments.Length == 1)
            {
                result[0] = arguments[0][0];
                return(result);
            }

            {
                // First two arguments
                var a = arguments[0][0];
                var b = arguments[1][0];
                result[0] = Expression.Call(MaxMethod, a, b);
                for (var k = 1; k < size; k++)
                {
                    if (arguments[0][k] != null || arguments[1][k] != null)
                    {
                        CircuitWarning.Warning(null, "Trying to derive Min() for which the derivative may not exist in some points");
                        var tmpda = arguments[0][k];
                        var tmpdb = arguments[1][k];
                        var funca = arguments[0][0];
                        var funcb = arguments[1][0];
                        if (tmpda != null && tmpdb != null)
                        {
                            result[k] = Expression.Condition(Expression.GreaterThan(funca, funcb), tmpda, tmpdb); // Use the derivative of the function that is currently the smallest
                        }
                        else if (tmpda != null)
                        {
                            result[k] = Expression.Condition(Expression.GreaterThan(funca, funcb), tmpda, Expression.Constant(0.0));
                        }
                        else if (tmpdb != null)
                        {
                            result[k] = Expression.Condition(Expression.GreaterThan(funca, funcb), Expression.Constant(0.0), tmpdb);
                        }
                    }
                }
            }

            for (var i = 2; i < arguments.Length; i++)
            {
                // First two arguments
                var a = result[0];
                var b = arguments[i][0];
                result[0] = Expression.Call(MaxMethod, a, b);
                for (var k = 1; k < size; k++)
                {
                    if (arguments[0][k] != null || arguments[1][k] != null)
                    {
                        CircuitWarning.Warning(null, "Trying to derive Min() for which the derivative may not exist in some points");
                        var tmpda = result[k];
                        var tmpdb = arguments[i][k];
                        var funca = a;
                        var funcb = arguments[i][0];
                        if (tmpda != null && tmpdb != null)
                        {
                            result[k] = Expression.Condition(Expression.GreaterThan(funca, funcb), tmpda, tmpdb); // Use the derivative of the function that is currently the smallest
                        }
                        else if (tmpda != null)
                        {
                            result[k] = Expression.Condition(Expression.GreaterThan(funca, funcb), tmpda, Expression.Constant(0.0));
                        }
                        else if (tmpdb != null)
                        {
                            result[k] = Expression.Condition(Expression.GreaterThan(funca, funcb), Expression.Constant(0.0), tmpdb);
                        }
                    }
                }
            }
            return(result);
        }
        /// <summary>
        /// Perform temperature-dependent calculations.
        /// </summary>
        /// <param name="simulation">The base simulation.</param>
        public void Temperature(BaseSimulation simulation)
        {
            // Update the width and length if they are not given and if the model specifies them
            if (!BaseParameters.Width.Given && ModelParameters.Width.Given)
            {
                BaseParameters.Width.RawValue = ModelParameters.Width.Value;
            }
            if (!BaseParameters.Length.Given && ModelParameters.Length.Given)
            {
                BaseParameters.Length.RawValue = ModelParameters.Length.Value;
            }

            if (!BaseParameters.Temperature.Given)
            {
                BaseParameters.Temperature.RawValue = simulation.RealState.Temperature;
            }
            Vt = BaseParameters.Temperature * Circuit.KOverQ;
            var ratio  = BaseParameters.Temperature / ModelParameters.NominalTemperature;
            var fact2  = BaseParameters.Temperature / Circuit.ReferenceTemperature;
            var kt     = BaseParameters.Temperature * Circuit.Boltzmann;
            var egfet  = 1.16 - 7.02e-4 * BaseParameters.Temperature * BaseParameters.Temperature / (BaseParameters.Temperature + 1108);
            var arg    = -egfet / (kt + kt) + 1.1150877 / (Circuit.Boltzmann * (Circuit.ReferenceTemperature + Circuit.ReferenceTemperature));
            var pbfact = -2 * Vt * (1.5 * Math.Log(fact2) + Circuit.Charge * arg);

            if (ModelParameters.DrainResistance.Given)
            {
                if (!ModelParameters.DrainResistance.Value.Equals(0.0))
                {
                    DrainConductance = 1 / ModelParameters.DrainResistance;
                }
                else
                {
                    DrainConductance = 0;
                }
            }
            else if (ModelParameters.SheetResistance.Given)
            {
                if (!ModelParameters.SheetResistance.Value.Equals(0.0))
                {
                    DrainConductance = 1 / (ModelParameters.SheetResistance * BaseParameters.DrainSquares);
                }
                else
                {
                    DrainConductance = 0;
                }
            }
            else
            {
                DrainConductance = 0;
            }
            if (ModelParameters.SourceResistance.Given)
            {
                if (!ModelParameters.SourceResistance.Value.Equals(0.0))
                {
                    SourceConductance = 1 / ModelParameters.SourceResistance;
                }
                else
                {
                    SourceConductance = 0;
                }
            }
            else if (ModelParameters.SheetResistance.Given)
            {
                if (!ModelParameters.SheetResistance.Value.Equals(0.0))
                {
                    SourceConductance = 1 / (ModelParameters.SheetResistance * BaseParameters.SourceSquares);
                }
                else
                {
                    SourceConductance = 0;
                }
            }
            else
            {
                SourceConductance = 0;
            }

            if (BaseParameters.Length - 2 * ModelParameters.LateralDiffusion <= 0)
            {
                CircuitWarning.Warning(this, "{0}: effective channel length less than zero".FormatString(Name));
            }
            var ratio4 = ratio * Math.Sqrt(ratio);

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

            TempPhi       = fact2 * phio + pbfact;
            TempVoltageBi = ModelParameters.Vt0 - ModelParameters.MosfetType * (ModelParameters.Gamma * Math.Sqrt(ModelParameters.Phi)) + .5 * (ModelTemperature.EgFet1 - egfet) +
                            ModelParameters.MosfetType * .5 * (TempPhi - ModelParameters.Phi);
            TempVt0 = TempVoltageBi + ModelParameters.MosfetType * ModelParameters.Gamma * Math.Sqrt(TempPhi);
            var tempSaturationCurrent        = ModelParameters.JunctionSatCur * Math.Exp(-egfet / Vt + ModelTemperature.EgFet1 / ModelTemperature.VtNominal);
            var tempSaturationCurrentDensity = ModelParameters.JunctionSatCurDensity * Math.Exp(-egfet / Vt + ModelTemperature.EgFet1 / ModelTemperature.VtNominal);
            var pbo = (ModelParameters.BulkJunctionPotential - ModelTemperature.PbFactor1) / ModelTemperature.Factor1;

            TempBulkPotential = fact2 * pbo + pbfact;

            if (tempSaturationCurrentDensity <= 0 || BaseParameters.DrainArea.Value <= 0 || BaseParameters.SourceArea.Value <= 0)
            {
                SourceVCritical = DrainVCritical = Vt * Math.Log(Vt / (Circuit.Root2 * tempSaturationCurrent));
            }
            else
            {
                DrainVCritical  = Vt * Math.Log(Vt / (Circuit.Root2 * tempSaturationCurrentDensity * BaseParameters.DrainArea));
                SourceVCritical = Vt * Math.Log(Vt / (Circuit.Root2 * tempSaturationCurrentDensity * BaseParameters.SourceArea));
            }

            if (tempSaturationCurrentDensity.Equals(0) || BaseParameters.DrainArea.Value <= 0 || BaseParameters.SourceArea.Value <= 0)
            {
                DrainSatCurrent  = tempSaturationCurrent;
                SourceSatCurrent = tempSaturationCurrent;
            }
            else
            {
                DrainSatCurrent  = tempSaturationCurrentDensity * BaseParameters.DrainArea;
                SourceSatCurrent = tempSaturationCurrentDensity * BaseParameters.SourceArea;
            }
        }
        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public override void Temperature(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            double czbd, czbdsw,
                   czbs,
                   czbssw;

            /* perform the parameter defaulting */
            if (!_bp.Temperature.Given)
            {
                _bp.Temperature.RawValue = simulation.RealState.Temperature;
            }
            var vt     = _bp.Temperature * Circuit.KOverQ;
            var ratio  = _bp.Temperature / _mbp.NominalTemperature;
            var fact2  = _bp.Temperature / Circuit.ReferenceTemperature;
            var kt     = _bp.Temperature * Circuit.Boltzmann;
            var egfet  = 1.16 - 7.02e-4 * _bp.Temperature * _bp.Temperature / (_bp.Temperature + 1108);
            var arg    = -egfet / (kt + kt) + 1.1150877 / (Circuit.Boltzmann * (Circuit.ReferenceTemperature + Circuit.ReferenceTemperature));
            var pbfact = -2 * vt * (1.5 * Math.Log(fact2) + Circuit.Charge * arg);

            if (_bp.Length - 2 * _mbp.LateralDiffusion <= 0)
            {
                CircuitWarning.Warning(this, "{0}: effective channel length less than zero".FormatString(Name));
            }
            var ratio4 = ratio * Math.Sqrt(ratio);

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

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

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

            capfact                  = 1 + _mbp.BulkJunctionBotGradingCoefficient * (4e-4 * (_bp.Temperature - Circuit.ReferenceTemperature) - gmanew);
            TempCapBd               *= capfact;
            TempCapBs               *= capfact;
            TempJunctionCap         *= capfact;
            capfact                  = 1 + _mbp.BulkJunctionSideGradingCoefficient * (4e-4 * (_bp.Temperature - Circuit.ReferenceTemperature) - gmanew);
            TempJunctionCapSidewall *= capfact;
            TempDepletionCap         = _mbp.ForwardCapDepletionCoefficient * TempBulkPotential;
            if (TempSaturationCurrentDensity <= 0 || _bp.DrainArea.Value <= 0 || _bp.SourceArea.Value <= 0)
            {
                SourceVCritical = DrainVCritical = vt * Math.Log(vt / (Circuit.Root2 * TempSaturationCurrent));
            }
            else
            {
                DrainVCritical  = vt * Math.Log(vt / (Circuit.Root2 * TempSaturationCurrentDensity * _bp.DrainArea));
                SourceVCritical = vt * Math.Log(vt / (Circuit.Root2 * TempSaturationCurrentDensity * _bp.SourceArea));
            }

            if (_mbp.CapBd.Given)
            {
                czbd = TempCapBd;
            }
            else
            {
                if (_mbp.BulkCapFactor.Given)
                {
                    czbd = TempJunctionCap * _bp.DrainArea;
                }
                else
                {
                    czbd = 0;
                }
            }
            if (_mbp.SidewallCapFactor.Given)
            {
                czbdsw = TempJunctionCapSidewall * _bp.DrainPerimeter;
            }
            else
            {
                czbdsw = 0;
            }
            arg = 1 - _mbp.ForwardCapDepletionCoefficient;
            var sarg   = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
            var sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));

            CapBd         = czbd;
            CapBdSidewall = czbdsw;
            F2D           = czbd * (1 - _mbp.ForwardCapDepletionCoefficient * (1 + _mbp.BulkJunctionBotGradingCoefficient)) * sarg / arg + czbdsw * (1 -
                                                                                                                                                     _mbp.ForwardCapDepletionCoefficient * (1 + _mbp.BulkJunctionSideGradingCoefficient)) * sargsw / arg;
            F3D = czbd * _mbp.BulkJunctionBotGradingCoefficient * sarg / arg / TempBulkPotential + czbdsw * _mbp.BulkJunctionSideGradingCoefficient *
                  sargsw / arg / TempBulkPotential;
            F4D = czbd * TempBulkPotential * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) + czbdsw * TempBulkPotential * (1 - arg *
                                                                                                                                             sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient) - F3D / 2 * (TempDepletionCap * TempDepletionCap) - TempDepletionCap * F2D;
            if (_mbp.CapBs.Given)
            {
                czbs = TempCapBs;
            }
            else
            {
                if (_mbp.BulkCapFactor.Given)
                {
                    czbs = TempJunctionCap * _bp.SourceArea;
                }
                else
                {
                    czbs = 0;
                }
            }
            if (_mbp.SidewallCapFactor.Given)
            {
                czbssw = TempJunctionCapSidewall * _bp.SourcePerimeter;
            }
            else
            {
                czbssw = 0;
            }
            arg           = 1 - _mbp.ForwardCapDepletionCoefficient;
            sarg          = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg));
            sargsw        = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg));
            CapBs         = czbs;
            CapBsSidewall = czbssw;
            F2S           = czbs * (1 - _mbp.ForwardCapDepletionCoefficient * (1 + _mbp.BulkJunctionBotGradingCoefficient)) * sarg / arg + czbssw * (1 -
                                                                                                                                                     _mbp.ForwardCapDepletionCoefficient * (1 + _mbp.BulkJunctionSideGradingCoefficient)) * sargsw / arg;
            F3S = czbs * _mbp.BulkJunctionBotGradingCoefficient * sarg / arg / TempBulkPotential + czbssw * _mbp.BulkJunctionSideGradingCoefficient *
                  sargsw / arg / TempBulkPotential;
            F4S = czbs * TempBulkPotential * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) + czbssw * TempBulkPotential * (1 - arg *
                                                                                                                                             sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient) - F3S / 2 * (TempDepletionCap * TempDepletionCap) - TempDepletionCap * F2S;

            if (_mbp.DrainResistance.Given)
            {
                if (!_mbp.DrainResistance.Value.Equals(0.0))
                {
                    DrainConductance = 1 / _mbp.DrainResistance;
                }
                else
                {
                    DrainConductance = 0;
                }
            }
            else if (_mbp.SheetResistance.Given)
            {
                if (!_mbp.SheetResistance.Value.Equals(0.0))
                {
                    DrainConductance = 1 / (_mbp.SheetResistance * _bp.DrainSquares);
                }
                else
                {
                    DrainConductance = 0;
                }
            }
            else
            {
                DrainConductance = 0;
            }
            if (_mbp.SourceResistance.Given)
            {
                if (!_mbp.SourceResistance.Value.Equals(0.0))
                {
                    SourceConductance = 1 / _mbp.SourceResistance;
                }
                else
                {
                    SourceConductance = 0;
                }
            }
            else if (_mbp.SheetResistance.Given)
            {
                if (!_mbp.SheetResistance.Value.Equals(0.0))
                {
                    SourceConductance = 1 / (_mbp.SheetResistance * _bp.SourceSquares);
                }
                else
                {
                    SourceConductance = 0;
                }
            }
            else
            {
                SourceConductance = 0;
            }
        }
        /// <summary>
        /// Execute behaviour
        /// </summary>
        /// <param name="ckt"></param>
        public override void Noise(Circuit ckt)
        {
            var here  = ComponentTyped <BSIM3v24>();
            var model = here.Model as BSIM3v24Model;
            var state = ckt.State;
            var noise = state.Noise;

            BSIM3noise.Generators[BSIM3RDNOIZ].Set(here.BSIM3drainConductance);
            BSIM3noise.Generators[BSIM3RSNOIZ].Set(here.BSIM3sourceConductance);

            // Calculate shot noise factor
            switch (model.BSIM3noiMod.Value)
            {
            case 1.0:
            case 3.0:
                BSIM3noise.Generators[BSIM3IDNOIZ].Set(2.0 / 3.0 * Math.Abs(here.BSIM3gm + here.BSIM3gds + here.BSIM3gmbs));
                break;

            case 2.0:
            case 4.0:
                BSIM3noise.Generators[BSIM3IDNOIZ].Set(here.BSIM3ueff * Math.Abs(here.BSIM3qinv) / (here.pParam.BSIM3leff * here.pParam.BSIM3leff
                                                                                                    + here.BSIM3ueff * Math.Abs(here.BSIM3qinv) * here.BSIM3rds));
                break;

            default:
                CircuitWarning.Warning(model, $"Invalid noise model {model.BSIM3noiMod.Value}");
                break;
            }

            // Calculate flicker noise factor
            switch (model.BSIM3noiMod.Value)
            {
            case 1.0:
            case 4.0:
                BSIM3noise.Generators[BSIM3FLNOIZ].Set(model.BSIM3kf * Math.Exp(model.BSIM3af * Math.Log(Math.Max(Math.Abs(here.BSIM3cd), 1e-38)))
                                                       / (Math.Pow(noise.Freq, model.BSIM3ef) * here.pParam.BSIM3leff * here.pParam.BSIM3leff * model.BSIM3cox));
                break;

            case 2.0:
            case 3.0:
                double vds = state.States[0][here.BSIM3states + BSIM3v24.BSIM3vds];
                if (vds < 0.0)
                {
                    vds = -vds;
                }
                double Ssi = StrongInversionNoiseEval(vds, model, here, noise.Freq, state.Temperature);
                double T10 = model.BSIM3oxideTrapDensityA * 8.62e-5 * state.Temperature;
                double T11 = here.pParam.BSIM3weff * here.pParam.BSIM3leff * Math.Pow(noise.Freq, model.BSIM3ef) * 4.0e36;
                double Swi = T10 / T11 * here.BSIM3cd * here.BSIM3cd;
                double T1  = Swi + Ssi;
                if (T1 > 0.0)
                {
                    BSIM3noise.Generators[BSIM3FLNOIZ].Set((Ssi * Swi) / T1);
                }
                else
                {
                    BSIM3noise.Generators[BSIM3FLNOIZ].Set(0.0);
                }
                break;
            }

            // Evaluate noise sources
            BSIM3noise.Evaluate(ckt);
        }
        /// <summary>
        /// Do temperature-dependent calculations
        /// </summary>
        /// <param name="simulation">Base simulation</param>
        public void Temperature(BaseSimulation simulation)
        {
            if (simulation == null)
            {
                throw new ArgumentNullException(nameof(simulation));
            }

            var xcbv = 0.0;

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

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

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

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

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

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

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

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

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

            // and now to copute the breakdown voltage, again, using temperature adjusted basic parameters
            if (ModelParameters.BreakdownVoltage.Given)
            {
                double cbv = ModelParameters.BreakdownCurrent;
                double xbv;
                if (cbv < TempSaturationCurrent * ModelParameters.BreakdownVoltage / Vt)
                {
                    cbv = TempSaturationCurrent * ModelParameters.BreakdownVoltage / Vt;
                    CircuitWarning.Warning(this, "{0}: breakdown current increased to {1:g} to resolve incompatability with specified saturation current".FormatString(Name, cbv));
                    xbv = ModelParameters.BreakdownVoltage;
                }
                else
                {
                    var tol = BaseConfiguration.RelativeTolerance * cbv;
                    xbv = ModelParameters.BreakdownVoltage - Vt * Math.Log(1 + cbv / TempSaturationCurrent);
                    int iter;
                    for (iter = 0; iter < 25; iter++)
                    {
                        xbv  = ModelParameters.BreakdownVoltage - Vt * Math.Log(cbv / TempSaturationCurrent + 1 - xbv / Vt);
                        xcbv = TempSaturationCurrent * (Math.Exp((ModelParameters.BreakdownVoltage - xbv) / Vt) - 1 + xbv / Vt);
                        if (Math.Abs(xcbv - cbv) <= tol)
                        {
                            break;
                        }
                    }
                    if (iter >= 25)
                    {
                        CircuitWarning.Warning(this, "{0}: unable to match forward and reverse diode regions: bv = {1:g}, ibv = {2:g}".FormatString(Name, xbv, xcbv));
                    }
                }
                TempBreakdownVoltage = xbv;
            }
        }
Beispiel #30
0
        /// <summary>
        /// Perform parameter checking
        /// </summary>
        /// <param name="ckt"></param>
        /// <returns></returns>
        internal static bool BSIM3checkModel(this BSIM3v30 bsim3)
        {
            var  model      = bsim3.Model as BSIM3v30Model;
            bool Fatal_Flag = false;

            using (StreamWriter sw = new StreamWriter("b3v3check.log"))
            {
                sw.WriteLine("BSIM3v3.3.0 Parameter Checking.");
                if (model.BSIM3version != "3.3.0")
                {
                    sw.WriteLine("Warning: This model is BSIM3v3.3.0; you specified a wrong version number.");
                    CircuitWarning.Warning(bsim3, "Warning: This model is BSIM3v3.3.0; you specified a wrong version number.");
                }
                sw.WriteLine($"Model = {model.Name}");

                if (bsim3.pParam.BSIM3nlx < -bsim3.pParam.BSIM3leff)
                {
                    sw.WriteLine($"Fatal: Nlx = {bsim3.pParam.BSIM3nlx} is less than -Leff.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Nlx = {bsim3.pParam.BSIM3nlx} is less than -Leff.");
                    Fatal_Flag = true;
                }

                if (model.BSIM3tox <= 0.0)
                {
                    sw.WriteLine($"Fatal: Tox = {model.BSIM3tox} is not positive.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Tox = {model.BSIM3tox} is not positive.");
                    Fatal_Flag = true;
                }

                if (model.BSIM3toxm <= 0.0)
                {
                    sw.WriteLine($"Fatal: Toxm = {model.BSIM3toxm} is not positive.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Toxm = {model.BSIM3toxm} is not positive.");
                    Fatal_Flag = true;
                }

                if (model.BSIM3lintnoi > bsim3.pParam.BSIM3leff / 2)
                {
                    sw.WriteLine($"Fatal: Lintnoi = {model.BSIM3lintnoi} is too large - Leff for noise is negative.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Lintnoi = {model.BSIM3lintnoi} is too large - Leff for noise is negative.");
                    Fatal_Flag = true;
                }

                if (bsim3.pParam.BSIM3npeak <= 0.0)
                {
                    sw.WriteLine($"Fatal: Nch = {bsim3.pParam.BSIM3npeak} is not positive.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Nch = {bsim3.pParam.BSIM3npeak} is not positive.");
                    Fatal_Flag = true;
                }
                if (bsim3.pParam.BSIM3nsub <= 0.0)
                {
                    sw.WriteLine($"Fatal: Nsub = {bsim3.pParam.BSIM3nsub} is not positive.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Nsub = {bsim3.pParam.BSIM3nsub} is not positive.");
                    Fatal_Flag = true;
                }
                if (bsim3.pParam.BSIM3ngate < 0.0)
                {
                    sw.WriteLine($"Fatal: Ngate = {bsim3.pParam.BSIM3ngate} is not positive.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Ngate = {bsim3.pParam.BSIM3ngate} Ngate is not positive.");
                    Fatal_Flag = true;
                }
                if (bsim3.pParam.BSIM3ngate > 1.0e25)
                {
                    sw.WriteLine($"Fatal: Ngate = {bsim3.pParam.BSIM3ngate} is too high.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Ngate = {bsim3.pParam.BSIM3ngate} Ngate is too high");
                    Fatal_Flag = true;
                }
                if (bsim3.pParam.BSIM3xj <= 0.0)
                {
                    sw.WriteLine($"Fatal: Xj = {bsim3.pParam.BSIM3xj} is not positive.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Xj = {bsim3.pParam.BSIM3xj} is not positive.");
                    Fatal_Flag = true;
                }

                if (bsim3.pParam.BSIM3dvt1 < 0.0)
                {
                    sw.WriteLine($"Fatal: Dvt1 = {bsim3.pParam.BSIM3dvt1} is negative.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Dvt1 = {bsim3.pParam.BSIM3dvt1} is negative.");
                    Fatal_Flag = true;
                }

                if (bsim3.pParam.BSIM3dvt1w < 0.0)
                {
                    sw.WriteLine($"Fatal: Dvt1w = {bsim3.pParam.BSIM3dvt1w} is negative.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Dvt1w = {bsim3.pParam.BSIM3dvt1w} is negative.");
                    Fatal_Flag = true;
                }

                if (bsim3.pParam.BSIM3w0 == -bsim3.pParam.BSIM3weff)
                {
                    sw.WriteLine("Fatal: (W0 + Weff) = 0 causing divided-by-zero.");
                    CircuitWarning.Warning(bsim3, "Fatal: (W0 + Weff) = 0 causing divided-by-zero.");
                    Fatal_Flag = true;
                }

                if (bsim3.pParam.BSIM3dsub < 0.0)
                {
                    sw.WriteLine($"Fatal: Dsub = {bsim3.pParam.BSIM3dsub} is negative.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Dsub = {bsim3.pParam.BSIM3dsub} is negative.");
                    Fatal_Flag = true;
                }
                if (bsim3.pParam.BSIM3b1 == -bsim3.pParam.BSIM3weff)
                {
                    sw.WriteLine("Fatal: (B1 + Weff) = 0 causing divided-by-zero.");
                    CircuitWarning.Warning(bsim3, "Fatal: (B1 + Weff) = 0 causing divided-by-zero.");
                    Fatal_Flag = true;
                }
                if (bsim3.pParam.BSIM3u0temp <= 0.0)
                {
                    sw.WriteLine($"Fatal: u0 at current temperature = {bsim3.pParam.BSIM3u0temp} is not positive.");
                    CircuitWarning.Warning(bsim3, $"Fatal: u0 at current temperature = {bsim3.pParam.BSIM3u0temp} is not positive.");
                    Fatal_Flag = true;
                }

                /* Check delta parameter */
                if (bsim3.pParam.BSIM3delta < 0.0)
                {
                    sw.WriteLine($"Fatal: Delta = {bsim3.pParam.BSIM3delta} is less than zero.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Delta = {bsim3.pParam.BSIM3delta} is less than zero.");
                    Fatal_Flag = true;
                }

                if (bsim3.pParam.BSIM3vsattemp <= 0.0)
                {
                    sw.WriteLine($"Fatal: Vsat at current temperature = {bsim3.pParam.BSIM3vsattemp} is not positive.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Vsat at current temperature = {bsim3.pParam.BSIM3vsattemp} is not positive.");
                    Fatal_Flag = true;
                }
                /* Check Rout parameters */
                if (bsim3.pParam.BSIM3pclm <= 0.0)
                {
                    sw.WriteLine($"Fatal: Pclm = {bsim3.pParam.BSIM3pclm} is not positive.");

                    CircuitWarning.Warning(bsim3, $"Fatal: Pclm = {bsim3.pParam.BSIM3pclm} is not positive.");
                    Fatal_Flag = true;
                }

                if (bsim3.pParam.BSIM3drout < 0.0)
                {
                    sw.WriteLine($"Fatal: Drout = {bsim3.pParam.BSIM3drout} is negative.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Drout = {bsim3.pParam.BSIM3drout} is negative.");
                    Fatal_Flag = true;
                }

                if (bsim3.pParam.BSIM3pscbe2 <= 0.0)
                {
                    sw.WriteLine($"Warning: Pscbe2 = {bsim3.pParam.BSIM3pscbe2} is not positive.");
                    CircuitWarning.Warning(bsim3, $"Warning: Pscbe2 = {bsim3.pParam.BSIM3pscbe2} is not positive.");
                }

                if (model.BSIM3unitLengthSidewallJctCap > 0.0 ||
                    model.BSIM3unitLengthGateSidewallJctCap > 0.0)
                {
                    if (bsim3.BSIM3drainPerimeter < bsim3.pParam.BSIM3weff)
                    {
                        sw.WriteLine($"Warning: Pd = {bsim3.BSIM3drainPerimeter} is less than W.");
                        CircuitWarning.Warning(bsim3, $"Warning: Pd = {bsim3.BSIM3drainPerimeter} is less than W.");
                    }
                    if (bsim3.BSIM3sourcePerimeter < bsim3.pParam.BSIM3weff)
                    {
                        sw.WriteLine($"Warning: Ps = {bsim3.BSIM3sourcePerimeter} is less than W.");
                        CircuitWarning.Warning(bsim3, $"Warning: Ps = {bsim3.BSIM3sourcePerimeter} is less than W.");
                    }
                }

                if (bsim3.pParam.BSIM3noff < 0.1)
                {
                    sw.WriteLine($"Warning: Noff = {bsim3.pParam.BSIM3noff} is too small.");
                    CircuitWarning.Warning(bsim3, $"Warning: Noff = {bsim3.pParam.BSIM3noff} is too small.");
                }
                if (bsim3.pParam.BSIM3noff > 4.0)
                {
                    sw.WriteLine($"Warning: Noff = {bsim3.pParam.BSIM3noff} is too large.");
                    CircuitWarning.Warning(bsim3, $"Warning: Noff = {bsim3.pParam.BSIM3noff} is too large.");
                }

                if (bsim3.pParam.BSIM3voffcv < -0.5)
                {
                    sw.WriteLine($"Warning: Voffcv = {bsim3.pParam.BSIM3voffcv} is too small.");
                    CircuitWarning.Warning(bsim3, $"Warning: Voffcv = {bsim3.pParam.BSIM3voffcv} is too small.");
                }
                if (bsim3.pParam.BSIM3voffcv > 0.5)
                {
                    sw.WriteLine($"Warning: Voffcv = {bsim3.pParam.BSIM3voffcv} is too large.");
                    CircuitWarning.Warning(bsim3, $"Warning: Voffcv = {bsim3.pParam.BSIM3voffcv} is too large.");
                }

                if (model.BSIM3ijth < 0.0)
                {
                    sw.WriteLine($"Fatal: Ijth = {model.BSIM3ijth} cannot be negative.");
                    CircuitWarning.Warning(bsim3, $"Fatal: Ijth = {model.BSIM3ijth} cannot be negative.");
                    Fatal_Flag = true;
                }

                /* Check capacitance parameters */
                if (bsim3.pParam.BSIM3clc < 0.0)
                {
                    sw.WriteLine($"Fatal: Clc = {bsim3.pParam.BSIM3clc} is negative.");

                    CircuitWarning.Warning(bsim3, $"Fatal: Clc = {bsim3.pParam.BSIM3clc} is negative.");
                    Fatal_Flag = true;
                }

                if (bsim3.pParam.BSIM3moin < 5.0)
                {
                    sw.WriteLine($"Warning: Moin = {bsim3.pParam.BSIM3moin} is too small.");
                    CircuitWarning.Warning(bsim3, $"Warning: Moin = {bsim3.pParam.BSIM3moin} is too small.");
                }
                if (bsim3.pParam.BSIM3moin > 25.0)
                {
                    sw.WriteLine($"Warning: Moin = {bsim3.pParam.BSIM3moin} is too large.");
                    CircuitWarning.Warning(bsim3, $"Warning: Moin = {bsim3.pParam.BSIM3moin} is too large.");
                }

                if (model.BSIM3capMod == 3)
                {
                    if (bsim3.pParam.BSIM3acde < 0.4)
                    {
                        sw.WriteLine($"Warning:  Acde = {bsim3.pParam.BSIM3acde} is too small.");
                        CircuitWarning.Warning(bsim3, $"Warning: Acde = {bsim3.pParam.BSIM3acde} is too small.");
                    }
                    if (bsim3.pParam.BSIM3acde > 1.6)
                    {
                        sw.WriteLine($"Warning:  Acde = {bsim3.pParam.BSIM3acde} is too large.");
                        CircuitWarning.Warning(bsim3, $"Warning: Acde = {bsim3.pParam.BSIM3acde} is too large.");
                    }
                }

                if (model.BSIM3paramChk == 1)
                {
                    /* Check L and W parameters */
                    if (bsim3.pParam.BSIM3leff <= 5.0e-8)
                    {
                        sw.WriteLine($"Warning: Leff = {bsim3.pParam.BSIM3leff} may be too small.");
                        CircuitWarning.Warning(bsim3, $"Warning: Leff = {bsim3.pParam.BSIM3leff} may be too small.");
                    }

                    if (bsim3.pParam.BSIM3leffCV <= 5.0e-8)
                    {
                        sw.WriteLine($"Warning: Leff for CV = {bsim3.pParam.BSIM3leffCV} may be too small.");
                        CircuitWarning.Warning(bsim3, $"Warning: Leff for CV = {bsim3.pParam.BSIM3leffCV} may be too small.");
                    }

                    if (bsim3.pParam.BSIM3weff <= 1.0e-7)
                    {
                        sw.WriteLine($"Warning: Weff = {bsim3.pParam.BSIM3weff} may be too small.");
                        CircuitWarning.Warning(bsim3, $"Warning: Weff = {bsim3.pParam.BSIM3weff} may be too small.");
                    }

                    if (bsim3.pParam.BSIM3weffCV <= 1.0e-7)
                    {
                        sw.WriteLine($"Warning: Weff for CV = {bsim3.pParam.BSIM3weffCV} may be too small.");
                        CircuitWarning.Warning(bsim3, $"Warning: Weff for CV = {bsim3.pParam.BSIM3weffCV} may be too small.");
                    }

                    /* Check threshold voltage parameters */
                    if (bsim3.pParam.BSIM3nlx < 0.0)
                    {
                        sw.WriteLine($"Warning: Nlx = {bsim3.pParam.BSIM3nlx} is negative.");
                        CircuitWarning.Warning(bsim3, $"Warning: Nlx = {bsim3.pParam.BSIM3nlx} is negative.");
                    }
                    if (model.BSIM3tox < 1.0e-9)
                    {
                        sw.WriteLine($"Warning: Tox = {model.BSIM3tox} is less than 10A.");
                        CircuitWarning.Warning(bsim3, $"Warning: Tox = {model.BSIM3tox} is less than 10A.");
                    }

                    if (bsim3.pParam.BSIM3npeak <= 1.0e15)
                    {
                        sw.WriteLine($"Warning: Nch = {bsim3.pParam.BSIM3npeak} may be too small.");
                        CircuitWarning.Warning(bsim3, $"Warning: Nch = {bsim3.pParam.BSIM3npeak} may be too small.");
                    }
                    else if (bsim3.pParam.BSIM3npeak >= 1.0e21)
                    {
                        sw.WriteLine($"Warning: Nch = {bsim3.pParam.BSIM3npeak} may be too large.");
                        CircuitWarning.Warning(bsim3, $"Warning: Nch = {bsim3.pParam.BSIM3npeak} may be too large.");
                    }

                    if (bsim3.pParam.BSIM3nsub <= 1.0e14)
                    {
                        sw.WriteLine($"Warning: Nsub = {bsim3.pParam.BSIM3nsub} may be too small.");
                        CircuitWarning.Warning(bsim3, $"Warning: Nsub = {bsim3.pParam.BSIM3nsub} may be too small.");
                    }
                    else if (bsim3.pParam.BSIM3nsub >= 1.0e21)
                    {
                        sw.WriteLine($"Warning: Nsub = {bsim3.pParam.BSIM3nsub} may be too large.");
                        CircuitWarning.Warning(bsim3, $"Warning: Nsub = {bsim3.pParam.BSIM3nsub} may be too large.");
                    }

                    if ((bsim3.pParam.BSIM3ngate > 0.0) &&
                        (bsim3.pParam.BSIM3ngate <= 1.0e18))
                    {
                        sw.WriteLine($"Warning: Ngate = {bsim3.pParam.BSIM3ngate} is less than 1.E18cm^-3.");
                        CircuitWarning.Warning(bsim3, $"Warning: Ngate = {bsim3.pParam.BSIM3ngate} is less than 1.E18cm^-3.");
                    }

                    if (bsim3.pParam.BSIM3dvt0 < 0.0)
                    {
                        sw.WriteLine($"Warning: Dvt0 = {bsim3.pParam.BSIM3dvt0} is negative.");
                        CircuitWarning.Warning(bsim3, $"Warning: Dvt0 = {bsim3.pParam.BSIM3dvt0} is negative.");
                    }

                    if (Math.Abs(1.0e-6 / (bsim3.pParam.BSIM3w0 + bsim3.pParam.BSIM3weff)) > 10.0)
                    {
                        sw.WriteLine("Warning: (W0 + Weff) may be too small.");
                        CircuitWarning.Warning(bsim3, "Warning: (W0 + Weff) may be too small.");
                    }

                    /* Check subthreshold parameters */
                    if (bsim3.pParam.BSIM3nfactor < 0.0)
                    {
                        sw.WriteLine($"Warning: Nfactor = {bsim3.pParam.BSIM3nfactor} is negative.");
                        CircuitWarning.Warning(bsim3, $"Warning: Nfactor = {bsim3.pParam.BSIM3nfactor} is negative.");
                    }
                    if (bsim3.pParam.BSIM3cdsc < 0.0)
                    {
                        sw.WriteLine($"Warning: Cdsc = {bsim3.pParam.BSIM3cdsc} is negative.");
                        CircuitWarning.Warning(bsim3, $"Warning: Cdsc = {bsim3.pParam.BSIM3cdsc} is negative.");
                    }
                    if (bsim3.pParam.BSIM3cdscd < 0.0)
                    {
                        sw.WriteLine($"Warning: Cdscd = {bsim3.pParam.BSIM3cdscd} is negative.");
                        CircuitWarning.Warning(bsim3, $"Warning: Cdscd = {bsim3.pParam.BSIM3cdscd} is negative.");
                    }
                    /* Check DIBL parameters */
                    if (bsim3.pParam.BSIM3eta0 < 0.0)
                    {
                        sw.WriteLine($"Warning: Eta0 = {bsim3.pParam.BSIM3eta0} is negative.");
                        CircuitWarning.Warning(bsim3, $"Warning: Eta0 = {bsim3.pParam.BSIM3eta0} is negative.");
                    }

                    /* Check Abulk parameters */
                    if (Math.Abs(1.0e-6 / (bsim3.pParam.BSIM3b1 + bsim3.pParam.BSIM3weff)) > 10.0)
                    {
                        sw.WriteLine("Warning: (B1 + Weff) may be too small.");
                        CircuitWarning.Warning(bsim3, "Warning: (B1 + Weff) may be too small.");
                    }


                    /* Check Saturation parameters */
                    if (bsim3.pParam.BSIM3a2 < 0.01)
                    {
                        sw.WriteLine($"Warning: A2 = {bsim3.pParam.BSIM3a2} is too small. Set to 0.01.");
                        CircuitWarning.Warning(bsim3, $"Warning: A2 = {bsim3.pParam.BSIM3a2} is too small. Set to 0.01.");
                        bsim3.pParam.BSIM3a2 = 0.01;
                    }
                    else if (bsim3.pParam.BSIM3a2 > 1.0)
                    {
                        sw.WriteLine($"Warning: A2 = {bsim3.pParam.BSIM3a2} is larger than 1. A2 is set to 1 and A1 is set to 0.");
                        CircuitWarning.Warning(bsim3, $"Warning: A2 = {bsim3.pParam.BSIM3a2} is larger than 1. A2 is set to 1 and A1 is set to 0.");
                        bsim3.pParam.BSIM3a2 = 1.0;
                        bsim3.pParam.BSIM3a1 = 0.0;
                    }

                    if (bsim3.pParam.BSIM3rdsw < 0.0)
                    {
                        sw.WriteLine($"Warning: Rdsw = {bsim3.pParam.BSIM3rdsw} is negative. Set to zero.");
                        CircuitWarning.Warning(bsim3, $"Warning: Rdsw = {bsim3.pParam.BSIM3rdsw} is negative. Set to zero.");
                        bsim3.pParam.BSIM3rdsw = 0.0;
                        bsim3.pParam.BSIM3rds0 = 0.0;
                    }
                    if (bsim3.pParam.BSIM3rds0 < 0.0)
                    {
                        sw.WriteLine($"Warning: Rds at current temperature = {bsim3.pParam.BSIM3rds0} is negative. Set to zero.");
                        CircuitWarning.Warning(bsim3, $"Warning: Rds at current temperature = {bsim3.pParam.BSIM3rds0} is negative. Set to zero.");
                        bsim3.pParam.BSIM3rds0 = 0.0;
                    }

                    if (bsim3.pParam.BSIM3vsattemp < 1.0e3)
                    {
                        sw.WriteLine($"Warning: Vsat at current temperature = {bsim3.pParam.BSIM3vsattemp} may be too small.");
                        CircuitWarning.Warning(bsim3, $"Warning: Vsat at current temperature = {bsim3.pParam.BSIM3vsattemp} may be too small.");
                    }

                    if (bsim3.pParam.BSIM3pdibl1 < 0.0)
                    {
                        sw.WriteLine($"Warning: Pdibl1 = {bsim3.pParam.BSIM3pdibl1} is negative.");
                        CircuitWarning.Warning(bsim3, $"Warning: Pdibl1 = {bsim3.pParam.BSIM3pdibl1} is negative.");
                    }
                    if (bsim3.pParam.BSIM3pdibl2 < 0.0)
                    {
                        sw.WriteLine($"Warning: Pdibl2 = {bsim3.pParam.BSIM3pdibl2} is negative.");
                        CircuitWarning.Warning(bsim3, $"Warning: Pdibl2 = {bsim3.pParam.BSIM3pdibl2} is negative.");
                    }
                    /* Check overlap capacitance parameters */
                    if (model.BSIM3cgdo < 0.0)
                    {
                        sw.WriteLine($"Warning: cgdo = {model.BSIM3cgdo} is negative. Set to zero.");
                        CircuitWarning.Warning(bsim3, $"Warning: cgdo = {model.BSIM3cgdo} is negative. Set to zero.");
                        model.BSIM3cgdo.Value = 0.0;
                    }
                    if (model.BSIM3cgso < 0.0)
                    {
                        sw.WriteLine($"Warning: cgso = {model.BSIM3cgso} is negative. Set to zero.");
                        CircuitWarning.Warning(bsim3, $"Warning: cgso = {model.BSIM3cgso} is negative. Set to zero.");
                        model.BSIM3cgso.Value = 0.0;
                    }
                    if (model.BSIM3cgbo < 0.0)
                    {
                        sw.WriteLine($"Warning: cgbo = {model.BSIM3cgbo} is negative. Set to zero.");
                        CircuitWarning.Warning(bsim3, $"Warning: cgbo = {model.BSIM3cgbo} is negative. Set to zero.");
                        model.BSIM3cgbo.Value = 0.0;
                    }
                }/* loop for the parameter check for warning messages */
            }

            return(Fatal_Flag);
        }