/// <summary> /// Initializes a new instance of the <see cref="Frequency"/> class. /// </summary> /// <param name="context">The binding context.</param> /// <exception cref="ArgumentNullException">Thrown if <paramref name="context"/> is <c>null</c>.</exception> public Frequency(IComponentBindingContext context) : base(context) { ModelParameters = context.ModelBehaviors.GetParameterSet <ModelParameters>(); Behavior = context.Behaviors.GetValue <IMosfetBiasingBehavior>(); _complex = context.GetState <IComplexSimulationState>(); Variables = new MosfetVariables <Complex>(context, _complex); _elements = new ElementSet <Complex>(_complex.Solver, Variables.GetMatrixLocations(_complex.Map)); }
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// <summary> /// Updates the model properties. /// </summary> /// <param name="mp">The model parameters.</param> public void Update(ModelParameters mp) { OxideCapFactor = 3.9 * 8.854214871e-12 / mp.OxideThickness; Vtnom = mp.NominalTemperature * Constants.KOverQ; Factor1 = mp.NominalTemperature / Constants.ReferenceTemperature; Kt1 = Constants.Boltzmann * mp.NominalTemperature; EgFet1 = 1.16 - (7.02e-4 * mp.NominalTemperature * mp.NominalTemperature) / (mp.NominalTemperature + 1108); var arg1 = -EgFet1 / (Kt1 + Kt1) + 1.1150877 / (Constants.Boltzmann * Constants.ReferenceTemperature * 2); PbFactor1 = -2 * Vtnom * (1.5 * Math.Log(Factor1) + Constants.Charge * arg1); }
/// <summary> /// Initializes a new instance of the <see cref="Frequency"/> class. /// </summary> /// <param name="context">The binding context.</param> /// <exception cref="ArgumentNullException">Thrown if <paramref name="context"/> is <c>null</c>.</exception> public Frequency(IComponentBindingContext context) : base(context) { ModelParameters = context.ModelBehaviors.GetParameterSet <ModelParameters>(); Behavior = context.Behaviors.GetValue <IMosfetBiasingBehavior>(); _complex = context.GetState <IComplexSimulationState>(); Variables = new MosfetVariables <Complex>(Name, _complex, context.Nodes, !ModelParameters.DrainResistance.Equals(0.0) || !ModelParameters.SheetResistance.Equals(0.0) && Behavior.Parameters.DrainSquares > 0, !ModelParameters.SourceResistance.Equals(0.0) || !ModelParameters.SheetResistance.Equals(0.0) && Behavior.Parameters.SourceSquares > 0); _elements = new ElementSet <Complex>(_complex.Solver, Variables.GetMatrixLocations(_complex.Map)); }
/// <summary> /// Initializes a new instance of the <see cref="Time"/> class. /// </summary> /// <param name="context">The binding context.</param> /// <exception cref="ArgumentNullException">Thrown if <paramref name="context"/> is <c>null</c>.</exception> public Time(IComponentBindingContext context) : base(context) { context.ThrowIfNull(nameof(context)); _time = context.GetState <ITimeSimulationState>(); _behavior = context.Behaviors.GetValue <IMosfetBiasingBehavior>(); _mp = context.ModelBehaviors.GetParameterSet <ModelParameters>(); var method = context.GetState <IIntegrationMethod>(); _vgs = new StateValue <double>(2); method.RegisterState(_vgs); _vds = new StateValue <double>(2); method.RegisterState(_vds); _vbs = new StateValue <double>(2); method.RegisterState(_vbs); _cgs = new StateValue <double>(2); method.RegisterState(_cgs); _cgd = new StateValue <double>(2); method.RegisterState(_cgd); _cgb = new StateValue <double>(2); method.RegisterState(_cgb); _qgs = method.CreateDerivative(); _qgd = method.CreateDerivative(); _qgb = method.CreateDerivative(); _qbd = method.CreateDerivative(); _qbs = method.CreateDerivative(); _behavior.UpdateContributions += UpdateTime; }
/// <summary> /// Updates the charges and capacitances.. /// </summary> /// <param name="mode">The mode.</param> /// <param name="vgs">The gate-source voltage.</param> /// <param name="vds">The drain-source voltage.</param> /// <param name="vbs">The bulk-source voltage.</param> /// <param name="von">The threshold voltage.</param> /// <param name="vdsat">The saturation voltage.</param> /// <param name="mp">The model parameters.</param> /// <param name="tp">The temperature-dependent properties.</param> public void Update(double mode, double vgs, double vds, double vbs, double von, double vdsat, ModelParameters mp, TemperatureProperties tp) { var vbd = vbs - vds; var vgd = vgs - vds; double arg, sarg, sargsw; /* * 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 */ // Can't bypass the diode capacitance calculations if (!tp.Cbs.Equals(0.0) || !tp.CbsSidewall.Equals(0.0)) { if (vbs < tp.TempDepCap) { arg = 1 - vbs / tp.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 (mp.BulkJunctionBotGradingCoefficient.Equals(mp.BulkJunctionSideGradingCoefficient)) { if (mp.BulkJunctionBotGradingCoefficient.Equals(0.5)) { sarg = sargsw = 1 / Math.Sqrt(arg); } else { sarg = sargsw = Math.Exp(-mp.BulkJunctionBotGradingCoefficient * Math.Log(arg)); } } else { if (mp.BulkJunctionBotGradingCoefficient.Equals(0.5)) { sarg = 1 / Math.Sqrt(arg); } else { sarg = Math.Exp(-mp.BulkJunctionBotGradingCoefficient * Math.Log(arg)); } if (mp.BulkJunctionSideGradingCoefficient.Equals(0.5)) { sargsw = 1 / Math.Sqrt(arg); } else { sargsw = Math.Exp(-mp.BulkJunctionSideGradingCoefficient * Math.Log(arg)); } } Qbs = tp.TempBulkPotential * (tp.Cbs * (1 - arg * sarg) / (1 - mp.BulkJunctionBotGradingCoefficient) + tp.CbsSidewall * (1 - arg * sargsw) / (1 - mp.BulkJunctionSideGradingCoefficient)); Cbs = tp.Cbs * sarg + tp.CbsSidewall * sargsw; } else { Qbs = tp.F4s + vbs * (tp.F2s + vbs * (tp.F3s / 2)); Cbs = tp.F2s + tp.F3s * vbs; } } else { Qbs = 0; Cbs = 0; } // can't bypass the diode capacitance calculations if (!tp.Cbd.Equals(0.0) || !tp.CbdSidewall.Equals(0.0)) { if (vbd < tp.TempDepCap) { arg = 1 - vbd / tp.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 (mp.BulkJunctionBotGradingCoefficient.Equals(0.5) && mp.BulkJunctionSideGradingCoefficient.Equals(0.5)) { sarg = sargsw = 1 / Math.Sqrt(arg); } else { if (mp.BulkJunctionBotGradingCoefficient == .5) { sarg = 1 / Math.Sqrt(arg); } else { sarg = Math.Exp(-mp.BulkJunctionBotGradingCoefficient * Math.Log(arg)); } if (mp.BulkJunctionSideGradingCoefficient == .5) { sargsw = 1 / Math.Sqrt(arg); } else { sargsw = Math.Exp(-mp.BulkJunctionSideGradingCoefficient * Math.Log(arg)); } } Qbd = tp.TempBulkPotential * (tp.Cbd * (1 - arg * sarg) / (1 - mp.BulkJunctionBotGradingCoefficient) + tp.CbdSidewall * (1 - arg * sargsw) / (1 - mp.BulkJunctionSideGradingCoefficient)); Cbd = tp.Cbd * sarg + tp.CbdSidewall * sargsw; } else { Qbd = tp.F4d + vbd * (tp.F2d + vbd * tp.F3d / 2); Cbd = tp.F2d + vbd * tp.F3d; } } else { Qbd = 0; Cbd = 0; } // Calculate Meyer capacitances double cgs, cgd, cgb; if (mode > 0) { Transistor.MeyerCharges(vgs, vgd, von, vdsat, out cgs, out cgd, out cgb, tp.TempPhi, tp.OxideCap); } else { Transistor.MeyerCharges(vgd, vgs, von, vdsat, out cgd, out cgs, out cgb, tp.TempPhi, tp.OxideCap); } Cgs = cgs; Cgd = cgd; Cgb = cgb; }
/// <summary> /// Calculates the charges and capacitances for the specified voltages. /// </summary> /// <param name="behavior">The biasing behavior.</param> /// <param name="mp">The model parameters.</param> public void Calculate(IMosfetBiasingBehavior behavior, ModelParameters mp) { var tp = behavior.Properties; var vgs = behavior.Vgs; var vds = behavior.Vds; var vbs = behavior.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. */ // Bulk-source depletion capacitances { /* can't bypass the diode capacitance calculations */ if (tp.Cbs != 0 || tp.CbsSidewall != 0) { if (vbs < tp.TempDepCap) { double arg = 1 - vbs / tp.TempBulkPotential; double sarg, sargsw; /* * 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 (mp.BulkJunctionBotGradingCoefficient == mp.BulkJunctionSideGradingCoefficient) { if (mp.BulkJunctionBotGradingCoefficient == .5) { sarg = sargsw = 1 / Math.Sqrt(arg); } else { sarg = sargsw = Math.Exp(-mp.BulkJunctionBotGradingCoefficient * Math.Log(arg)); } } else { if (mp.BulkJunctionBotGradingCoefficient == .5) { sarg = 1 / Math.Sqrt(arg); } else { sarg = Math.Exp(-mp.BulkJunctionBotGradingCoefficient * Math.Log(arg)); } if (mp.BulkJunctionSideGradingCoefficient == .5) { sargsw = 1 / Math.Sqrt(arg); } else { sargsw = Math.Exp(-mp.BulkJunctionSideGradingCoefficient * Math.Log(arg)); } } Qbs = tp.TempBulkPotential * (tp.Cbs * (1 - arg * sarg) / (1 - mp.BulkJunctionBotGradingCoefficient) + tp.CbsSidewall * (1 - arg * sargsw) / (1 - mp.BulkJunctionSideGradingCoefficient)); Cbs = tp.Cbs * sarg + tp.CbsSidewall * sargsw; } else { Qbs = tp.F4s + vbs * (tp.F2s + vbs * (tp.F3s / 2)); Cbs = tp.F2s + tp.F3s * vbs; } } else { Qbs = 0; Cbs = 0; } } // Bulk-drain depletion capacitances { var vbd = vbs - vds; if (tp.Cbd != 0 || tp.CbdSidewall != 0) { if (vbd < tp.TempDepCap) { double arg = 1 - vbd / tp.TempBulkPotential; double sarg, sargsw; /* * 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 (mp.BulkJunctionBotGradingCoefficient == .5 && mp.BulkJunctionSideGradingCoefficient == .5) { sarg = sargsw = 1 / Math.Sqrt(arg); } else { if (mp.BulkJunctionBotGradingCoefficient == .5) { sarg = 1 / Math.Sqrt(arg); } else { sarg = Math.Exp(-mp.BulkJunctionBotGradingCoefficient * Math.Log(arg)); } if (mp.BulkJunctionSideGradingCoefficient == .5) { sargsw = 1 / Math.Sqrt(arg); } else { sargsw = Math.Exp(-mp.BulkJunctionSideGradingCoefficient * Math.Log(arg)); } } Qbd = tp.TempBulkPotential * (tp.Cbd * (1 - arg * sarg) / (1 - mp.BulkJunctionBotGradingCoefficient) + tp.CbdSidewall * (1 - arg * sargsw) / (1 - mp.BulkJunctionSideGradingCoefficient)); Cbd = tp.Cbd * sarg + tp.CbdSidewall * sargsw; } else { Qbd = tp.F4d + vbd * (tp.F2d + vbd * tp.F3d / 2); Cbd = tp.F2d + vbd * tp.F3d; } } else { Qbd = 0; Cbd = 0; } } // Meyer capacitance calculation { /* * 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 cgs, cgd, cgb; if (behavior.Mode > 0) { Transistor.MeyerCharges(vgs, vgs - vds, mp.MosfetType * behavior.Von, mp.MosfetType * behavior.Vdsat, out cgs, out cgd, out cgb, tp.TempPhi, tp.OxideCap); } else { Transistor.MeyerCharges(vgs - vds, vgs, mp.MosfetType * behavior.Von, mp.MosfetType * behavior.Vdsat, out cgd, out cgs, out cgb, tp.TempPhi, tp.OxideCap); } Cgs = cgs; Cgd = cgd; Cgb = cgb; } }
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// <summary> /// Updates the specified properties. /// </summary> /// <param name="name">The name.</param> /// <param name="p">The parameters of the transistor.</param> /// <param name="mp">The model parameters.</param> /// <param name="mprp">The model properties.</param> public void Update(string name, Parameters p, ModelParameters mp, ModelProperties mprp) { if (!mp.Transconductance.Given) { mp.Transconductance = new GivenParameter <double>(mp.SurfaceMobility * mprp.OxideCapFactor * 1e-4, false); } TempVt = p.Temperature * Constants.KOverQ; var ratio = p.Temperature / mp.NominalTemperature; var fact2 = p.Temperature / Constants.ReferenceTemperature; var kt = p.Temperature * Constants.Boltzmann; var egfet = 1.16 - (7.02e-4 * p.Temperature * p.Temperature) / (p.Temperature + 1108); var arg = -egfet / (kt + kt) + 1.1150877 / (Constants.Boltzmann * (Constants.ReferenceTemperature + Constants.ReferenceTemperature)); var pbfact = -2 * TempVt * (1.5 * Math.Log(fact2) + Constants.Charge * arg); OxideCap = mprp.OxideCapFactor * EffectiveLength * p.ParallelMultiplier * p.Width; if (p.Length - 2 * mp.LateralDiffusion <= 0) { SpiceSharpWarning.Warning(this, "{0}: effective channel length less than zero".FormatString(name)); } var ratio4 = ratio * Math.Sqrt(ratio); TempTransconductance = mp.Transconductance / ratio4; TempSurfaceMobility = mp.SurfaceMobility / ratio4; var phio = (mp.Phi - mprp.PbFactor1) / mprp.Factor1; TempPhi = fact2 * phio + pbfact; TempVbi = mp.Vt0 - mp.MosfetType * (mp.Gamma * Math.Sqrt(mp.Phi)) + .5 * (mprp.EgFet1 - egfet) + mp.MosfetType * .5 * (TempPhi - mp.Phi); TempVt0 = TempVbi + mp.MosfetType * mp.Gamma * Math.Sqrt(TempPhi); var TempSaturationCurrent = mp.JunctionSatCur * Math.Exp(-egfet / TempVt + mprp.EgFet1 / mprp.Vtnom); var TempSaturationCurrentDensity = mp.JunctionSatCurDensity * Math.Exp(-egfet / TempVt + mprp.EgFet1 / mprp.Vtnom); var pbo = (mp.BulkJunctionPotential - mprp.PbFactor1) / mprp.Factor1; TempBulkPotential = fact2 * pbo + pbfact; if ((TempSaturationCurrentDensity == 0) || (p.DrainArea == 0) || (p.SourceArea == 0)) { SourceVCritical = DrainVCritical = TempVt * Math.Log(TempVt / (Constants.Root2 * p.ParallelMultiplier * TempSaturationCurrent)); } else { DrainVCritical = TempVt * Math.Log(TempVt / (Constants.Root2 * p.ParallelMultiplier * TempSaturationCurrentDensity * p.DrainArea)); SourceVCritical = TempVt * Math.Log(TempVt / (Constants.Root2 * p.ParallelMultiplier * TempSaturationCurrentDensity * p.SourceArea)); } if (mp.DrainResistance.Given) { if (mp.DrainResistance != 0) { DrainConductance = p.ParallelMultiplier / mp.DrainResistance; } else { DrainConductance = 0; } } else if (mp.SheetResistance.Given) { if (mp.SheetResistance != 0) { DrainConductance = p.ParallelMultiplier / (mp.SheetResistance * p.DrainSquares); } else { DrainConductance = 0; } } else { DrainConductance = 0; } if (mp.SourceResistance.Given) { if (mp.SourceResistance != 0) { SourceConductance = p.ParallelMultiplier / mp.SourceResistance; } else { SourceConductance = 0; } } else if (mp.SheetResistance.Given) { if ((mp.SheetResistance != 0) && (p.SourceSquares != 0)) { SourceConductance = p.ParallelMultiplier / (mp.SheetResistance * p.SourceSquares); } else { SourceConductance = 0; } } else { SourceConductance = 0; } EffectiveLength = p.Length - (2 * mp.LateralDiffusion); var gmaold = (mp.BulkJunctionPotential - pbo) / pbo; var capfact = 1 / (1 + (mp.BulkJunctionBotGradingCoefficient * ((4e-4 * (mp.NominalTemperature - Constants.ReferenceTemperature)) - gmaold))); TempCbd = mp.CapBd * capfact; TempCbs = mp.CapBs * capfact; TempCj = mp.BulkCapFactor * capfact; capfact = 1 / (1 + (mp.BulkJunctionSideGradingCoefficient * ((4e-4 * (mp.NominalTemperature - Constants.ReferenceTemperature)) - gmaold))); TempCjsw = mp.SidewallCapFactor * capfact; TempBulkPotential = (fact2 * pbo) + pbfact; var gmanew = (TempBulkPotential - pbo) / pbo; capfact = 1 + (mp.BulkJunctionBotGradingCoefficient * ((4e-4 * (p.Temperature - Constants.ReferenceTemperature)) - gmanew)); TempCbd *= capfact; TempCbs *= capfact; TempCj *= capfact; capfact = 1 + (mp.BulkJunctionSideGradingCoefficient * ((4e-4 * (p.Temperature - Constants.ReferenceTemperature)) - gmanew)); TempCjsw *= capfact; TempDepCap = mp.ForwardCapDepletionCoefficient * TempBulkPotential; double czbd, czbdsw; if (mp.CapBd.Given) { czbd = TempCbd * p.ParallelMultiplier; } else { if (mp.BulkCapFactor.Given) { czbd = TempCj * p.ParallelMultiplier * p.DrainArea; } else { czbd = 0; } } if (mp.SidewallCapFactor.Given) { czbdsw = TempCjsw * p.DrainPerimeter * p.ParallelMultiplier; } else { czbdsw = 0; } arg = 1 - mp.ForwardCapDepletionCoefficient; var sarg = Math.Exp((-mp.BulkJunctionBotGradingCoefficient) * Math.Log(arg)); var sargsw = Math.Exp((-mp.BulkJunctionSideGradingCoefficient) * Math.Log(arg)); Cbd = czbd; CbdSidewall = czbdsw; F2d = (czbd * (1 - (mp.ForwardCapDepletionCoefficient * (1 + mp.BulkJunctionBotGradingCoefficient))) * sarg / arg) + (czbdsw * (1 - (mp.ForwardCapDepletionCoefficient * (1 + mp.BulkJunctionSideGradingCoefficient))) * sargsw / arg); F3d = (czbd * mp.BulkJunctionBotGradingCoefficient * sarg / arg / TempBulkPotential) + (czbdsw * mp.BulkJunctionSideGradingCoefficient * sargsw / arg / TempBulkPotential); F4d = (czbd * TempBulkPotential * (1 - (arg * sarg)) / (1 - mp.BulkJunctionBotGradingCoefficient)) + (czbdsw * TempBulkPotential * (1 - (arg * sargsw)) / (1 - mp.BulkJunctionSideGradingCoefficient)) - (F3d / 2 * (TempDepCap * TempDepCap)) - (TempDepCap * F2d); double czbs, czbssw; if (mp.CapBs.Given) { czbs = TempCbs * p.ParallelMultiplier; } else { if (mp.BulkCapFactor.Given) { czbs = TempCj * p.SourceArea * p.ParallelMultiplier; } else { czbs = 0; } } if (mp.SidewallCapFactor.Given) { czbssw = TempCjsw * p.SourcePerimeter * p.ParallelMultiplier; } else { czbssw = 0; } arg = 1 - mp.ForwardCapDepletionCoefficient; sarg = Math.Exp((-mp.BulkJunctionBotGradingCoefficient) * Math.Log(arg)); sargsw = Math.Exp((-mp.BulkJunctionSideGradingCoefficient) * Math.Log(arg)); Cbs = czbs; CbsSidewall = czbssw; F2s = (czbs * (1 - (mp.ForwardCapDepletionCoefficient * (1 + mp.BulkJunctionBotGradingCoefficient))) * sarg / arg) + (czbssw * (1 - (mp.ForwardCapDepletionCoefficient * (1 + mp.BulkJunctionSideGradingCoefficient))) * sargsw / arg); F3s = (czbs * mp.BulkJunctionBotGradingCoefficient * sarg / arg / TempBulkPotential) + (czbssw * mp.BulkJunctionSideGradingCoefficient * sargsw / arg / TempBulkPotential); F4s = (czbs * TempBulkPotential * (1 - (arg * sarg)) / (1 - mp.BulkJunctionBotGradingCoefficient)) + (czbssw * TempBulkPotential * (1 - (arg * sargsw)) / (1 - mp.BulkJunctionSideGradingCoefficient)) - (F3s / 2 * (TempDepCap * TempDepCap)) - (TempDepCap * F2s); }