/// <summary> /// Execute behavior /// </summary> /// <param name="simulation">Base simulation</param> public void Load(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); var state = simulation.RealState; double value; PosBranchPtr.Value += 1; BranchPosPtr.Value += 1; NegBranchPtr.Value -= 1; BranchNegPtr.Value -= 1; if (simulation is TimeSimulation) { // Use the waveform if possible if (BaseParameters.Waveform != null) { value = BaseParameters.Waveform.Value; } else { value = BaseParameters.DcValue * state.SourceFactor; } } else { value = BaseParameters.DcValue * state.SourceFactor; } Voltage = value; BranchPtr.Value += value; }
/// <summary> /// Perform temperature-dependent calculations. /// </summary> /// <param name="simulation">The base simulation.</param> /// <exception cref="NotImplementedException"></exception> public override void Temperature(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); if (_mbp.NominalTemperature.Given) { _mbp.NominalTemperature.RawValue = 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); }
/// <summary> /// Execute behavior /// </summary> /// <param name="simulation">Base simulation</param> public void Load(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); var state = simulation.RealState; double value; // Time domain analysis if (simulation is TimeSimulation) { // Use the waveform if possible if (BaseParameters.Waveform != null) { value = BaseParameters.Waveform.Value; } else { value = BaseParameters.DcValue * state.SourceFactor; } } else { // AC or DC analysis use the DC value value = BaseParameters.DcValue * state.SourceFactor; } // NOTE: Spice 3f5's documentation is IXXXX POS NEG VALUE but in the code it is IXXXX NEG POS VALUE // I solved it by inverting the current when loading the rhs vector PosPtr.Value -= value; NegPtr.Value += value; Current = value; }
// TODO: I believe this method of checking convergence can be improved. These calculations seem to be common for multiple behaviors. /// <summary> /// Check if the BJT is convergent /// </summary> /// <param name="simulation">Base simulation</param> /// <returns></returns> public bool IsConvergent(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); var state = simulation.RealState; var vbe = ModelParameters.BipolarType * (state.Solution[BasePrimeNode] - state.Solution[EmitterPrimeNode]); var vbc = ModelParameters.BipolarType * (state.Solution[BasePrimeNode] - state.Solution[CollectorPrimeNode]); var delvbe = vbe - VoltageBe; var delvbc = vbc - VoltageBe; var cchat = CollectorCurrent + (Transconductance + OutputConductance) * delvbe - (OutputConductance + ConductanceMu) * delvbc; var cbhat = BaseCurrent + ConductancePi * delvbe + ConductanceMu * delvbc; var cc = CollectorCurrent; var cb = BaseCurrent; // Check convergence var tol = BaseConfiguration.RelativeTolerance * Math.Max(Math.Abs(cchat), Math.Abs(cc)) + BaseConfiguration.AbsoluteTolerance; if (Math.Abs(cchat - cc) > tol) { state.IsConvergent = false; return(false); } tol = BaseConfiguration.RelativeTolerance * Math.Max(Math.Abs(cbhat), Math.Abs(cb)) + BaseConfiguration.AbsoluteTolerance; if (Math.Abs(cbhat - cb) > tol) { state.IsConvergent = false; return(false); } return(true); }
/// <summary> /// Execute behavior /// </summary> /// <param name="simulation">Base simulation</param> public void Temperature(BaseSimulation simulation) { simulation.ThrowIfNull(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> /// Do temperature-dependent calculations /// </summary> /// <param name="simulation">Base simulation</param> public void Temperature(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); if (!BaseParameters.Temperature.Given) { BaseParameters.Temperature.RawValue = simulation.RealState.Temperature; } Vt = BaseParameters.Temperature * Constants.KOverQ; var fact2 = BaseParameters.Temperature / Constants.ReferenceTemperature; var egfet = 1.16 - 7.02e-4 * BaseParameters.Temperature * BaseParameters.Temperature / (BaseParameters.Temperature + 1108); var arg = -egfet / (2 * Constants.Boltzmann * BaseParameters.Temperature) + 1.1150877 / (Constants.Boltzmann * (Constants.ReferenceTemperature + Constants.ReferenceTemperature)); var pbfact = -2 * Vt * (1.5 * Math.Log(fact2) + Constants.Charge * arg); var ratlog = Math.Log(BaseParameters.Temperature / ModelParameters.NominalTemperature); var ratio1 = BaseParameters.Temperature / ModelParameters.NominalTemperature - 1; var factlog = ratio1 * ModelParameters.EnergyGap / Vt + ModelParameters.TempExpIs * ratlog; var factor = Math.Exp(factlog); TempSaturationCurrent = ModelParameters.SatCur * factor; var bfactor = Math.Exp(ratlog * ModelParameters.BetaExponent); TempBetaForward = ModelParameters.BetaF * bfactor; TempBetaReverse = ModelParameters.BetaR * bfactor; TempBeLeakageCurrent = ModelParameters.LeakBeCurrent * Math.Exp(factlog / ModelParameters.LeakBeEmissionCoefficient) / bfactor; TempBcLeakageCurrent = ModelParameters.LeakBcCurrent * Math.Exp(factlog / ModelParameters.LeakBcEmissionCoefficient) / bfactor; var pbo = (ModelParameters.PotentialBe - pbfact) / ModelTemperature.Factor1; var gmaold = (ModelParameters.PotentialBe - pbo) / pbo; TempBeCap = ModelParameters.DepletionCapBe / (1 + ModelParameters.JunctionExpBe * (4e-4 * (ModelParameters.NominalTemperature - Constants.ReferenceTemperature) - gmaold)); TempBePotential = fact2 * pbo + pbfact; var gmanew = (TempBePotential - pbo) / pbo; TempBeCap *= 1 + ModelParameters.JunctionExpBe * (4e-4 * (BaseParameters.Temperature - Constants.ReferenceTemperature) - gmanew); pbo = (ModelParameters.PotentialBc - pbfact) / ModelTemperature.Factor1; gmaold = (ModelParameters.PotentialBc - pbo) / pbo; TempBcCap = ModelParameters.DepletionCapBc / (1 + ModelParameters.JunctionExpBc * (4e-4 * (ModelParameters.NominalTemperature - Constants.ReferenceTemperature) - gmaold)); TempBcPotential = fact2 * pbo + pbfact; gmanew = (TempBcPotential - pbo) / pbo; TempBcCap *= 1 + ModelParameters.JunctionExpBc * (4e-4 * (BaseParameters.Temperature - Constants.ReferenceTemperature) - gmanew); TempDepletionCap = ModelParameters.DepletionCapCoefficient * TempBePotential; TempFactor1 = TempBePotential * (1 - Math.Exp((1 - ModelParameters.JunctionExpBe) * ModelTemperature.Xfc)) / (1 - ModelParameters.JunctionExpBe); TempFactor4 = ModelParameters.DepletionCapCoefficient * TempBcPotential; TempFactor5 = TempBcPotential * (1 - Math.Exp((1 - ModelParameters.JunctionExpBc) * ModelTemperature.Xfc)) / (1 - ModelParameters.JunctionExpBc); TempVCritical = Vt * Math.Log(Vt / (Constants.Root2 * ModelParameters.SatCur)); }
/// <summary> /// Loads the Y-matrix and Rhs-vector. /// </summary> /// <param name="simulation">The base simulation.</param> public void Load(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); var state = simulation.RealState; // Admittance between POS1 and INT1 Pos1Pos1Ptr.Value += BaseParameters.Admittance; Pos1Int1Ptr.Value -= BaseParameters.Admittance; Int1Pos1Ptr.Value -= BaseParameters.Admittance; Int1Int1Ptr.Value += BaseParameters.Admittance; // Admittance between POS2 and INT2 Pos2Pos2Ptr.Value += BaseParameters.Admittance; Pos2Int2Ptr.Value -= BaseParameters.Admittance; Int2Pos2Ptr.Value -= BaseParameters.Admittance; Int2Int2Ptr.Value += BaseParameters.Admittance; // Add the currents to the positive and negative nodes Int1Ibr1Ptr.Value += 1.0; Neg1Ibr1Ptr.Value -= 1.0; Int2Ibr2Ptr.Value += 1.0; Neg2Ibr2Ptr.Value -= 1.0; if (state.UseDc) { // Assume DC operation // VPOS1 - VNEG1 = VPOS2 - VNEG2 Ibr1Pos1Ptr.Value += 1.0; Ibr1Neg1Ptr.Value -= 1.0; Ibr1Pos2Ptr.Value -= 1.0; Ibr1Neg2Ptr.Value += 1.0; // IBR1 = -IBR2 Ibr2Ibr1Ptr.Value += 1.0; Ibr2Ibr2Ptr.Value += 1.0; } else { // INT1-NEG1 voltage source Ibr1Int1Ptr.Value += 1.0; Ibr1Neg1Ptr.Value -= 1.0; // INT2-NEG2 voltage source Ibr2Int2Ptr.Value += 1.0; Ibr2Neg2Ptr.Value -= 1.0; } }
/// <summary> /// Loads the Y-matrix and Rhs-vector. /// </summary> /// <param name="simulation">The base simulation.</param> public void Load(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); PosBranchPtr.Value += 1; BranchPosPtr.Value += 1; NegBranchPtr.Value -= 1; BranchNegPtr.Value -= 1; // In DC, the delay should just copy input to output if (simulation.RealState.UseDc) { BranchControlPosPtr.Value -= 1.0; BranchControlNegPtr.Value += 1.0; } }
/// <summary> /// Do temperature-dependent calculations /// </summary> /// <param name="simulation">Base simulation</param> public override void Temperature(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); if (!_mbp.NominalTemperature.Given) { _mbp.NominalTemperature.RawValue = 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); }
/// <summary> /// Do temperature-dependent calculations /// </summary> /// <param name="simulation">Base simulation</param> public void Temperature(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); if (!BaseParameters.Temperature.Given) { BaseParameters.Temperature.RawValue = simulation.RealState.Temperature; } double capacitance; if (!BaseParameters.Capacitance.Given) { if (ModelParameters == null) { throw new CircuitException("No model specified"); } var width = BaseParameters.Width.Given ? BaseParameters.Width.Value : ModelParameters.DefaultWidth.Value; capacitance = ModelParameters.JunctionCap * (width - ModelParameters.Narrow) * (BaseParameters.Length - ModelParameters.Narrow) + ModelParameters.JunctionCapSidewall * 2 * ( BaseParameters.Length - ModelParameters.Narrow + (width - ModelParameters.Narrow)); } else { capacitance = BaseParameters.Capacitance; } double factor = 1.0; if (ModelParameters != null) { double temperatureDiff = BaseParameters.Temperature - ModelParameters.NominalTemperature; factor = 1.0 + ModelParameters.TemperatureCoefficient1 * temperatureDiff + ModelParameters.TemperatureCoefficient2 * temperatureDiff * temperatureDiff; } Capacitance = factor * capacitance; }
/// <summary> /// Check convergence for the diode /// </summary> /// <param name="simulation">Base simulation</param> /// <returns></returns> public bool IsConvergent(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); var state = simulation.RealState; var vd = state.Solution[PosPrimeNode] - state.Solution[NegNode]; var delvd = vd - Voltage; var cdhat = Current + Conductance * delvd; var cd = Current; // check convergence var tol = BaseConfiguration.RelativeTolerance * Math.Max(Math.Abs(cdhat), Math.Abs(cd)) + BaseConfiguration.AbsoluteTolerance; if (Math.Abs(cdhat - cd) > tol) { state.IsConvergent = false; return(false); } return(true); }
/// <summary> /// Initializes the voltages for the current iteration. /// </summary> /// <param name="simulation">The simulation.</param> /// <param name="vgs">The VGS.</param> /// <param name="vgd">The VGD.</param> /// <param name="check">if set to <c>true</c> [check].</param> protected void Initialize(BaseSimulation simulation, out double vgs, out double vgd, out bool check) { simulation.ThrowIfNull(nameof(simulation)); var state = simulation.RealState; // Initialization check = true; if (state.Init == InitializationModes.Junction && simulation is TimeSimulation && state.UseDc && state.UseIc) { var vds = ModelParameters.JFETType * BaseParameters.InitialVds; vgs = ModelParameters.JFETType * BaseParameters.InitialVgs; vgd = vgs - vds; } else if (state.Init == InitializationModes.Junction && !BaseParameters.Off) { vgs = -1; vgd = -1; } else if (state.Init == InitializationModes.Junction || state.Init == InitializationModes.Fix && BaseParameters.Off) { vgs = 0; vgd = 0; } else { // Compute new nonlinear branch voltages vgs = ModelParameters.JFETType * (state.Solution[GateNode] - state.Solution[SourcePrimeNode]); vgd = ModelParameters.JFETType * (state.Solution[GateNode] - state.Solution[DrainPrimeNode]); // Limit nonlinear branch voltages check = false; vgs = Semiconductor.LimitJunction(vgs, Vgs, BaseParameters.Temperature * Constants.KOverQ, Vcrit, ref check); vgd = Semiconductor.LimitJunction(vgd, Vgd, BaseParameters.Temperature * Constants.KOverQ, Vcrit, ref check); vgs = Transistor.LimitFet(vgs, Vgs, ModelParameters.Threshold); vgd = Transistor.LimitFet(vgd, Vgd, ModelParameters.Threshold); } }
/// <summary> /// Perform temperature-dependent calculations. /// </summary> /// <param name="simulation">The base simulation.</param> /// <exception cref="ArgumentNullException">simulation</exception> public void Temperature(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); if (!BaseParameters.Temperature.Given) { BaseParameters.Temperature.RawValue = simulation.RealState.Temperature; } var vt = BaseParameters.Temperature * Constants.KOverQ; var fact2 = BaseParameters.Temperature / Constants.ReferenceTemperature; var ratio1 = BaseParameters.Temperature / ModelParameters.NominalTemperature - 1; TempSaturationCurrent = ModelParameters.GateSaturationCurrent * Math.Exp(ratio1 * 1.11 / vt); TempCapGs = ModelParameters.CapGs * ModelTemperature.Cjfact; TempCapGd = ModelParameters.CapGd * ModelTemperature.Cjfact; var kt = Constants.Boltzmann * BaseParameters.Temperature; var egfet = 1.16 - (7.02e-4 * BaseParameters.Temperature * BaseParameters.Temperature) / (BaseParameters.Temperature + 1108); var arg = -egfet / (kt + kt) + 1.1150877 / (Constants.Boltzmann * 2 * Constants.ReferenceTemperature); var pbfact = -2 * vt * (1.5 * Math.Log(fact2) + Constants.Charge * arg); TempGatePotential = fact2 * ModelTemperature.Pbo + pbfact; var gmanew = (TempGatePotential - ModelTemperature.Pbo) / ModelTemperature.Pbo; var cjfact1 = 1 + .5 * (4e-4 * (BaseParameters.Temperature - Constants.ReferenceTemperature) - gmanew); TempCapGs *= cjfact1; TempCapGd *= cjfact1; CorDepCap = ModelParameters.DepletionCapCoefficient * TempGatePotential; F1 = TempGatePotential * (1 - Math.Exp((1 - .5) * ModelTemperature.Xfc)) / (1 - .5); Vcrit = vt * Math.Log(vt / (Constants.Root2 * TempSaturationCurrent)); if (TempGatePotential.Equals(0.0)) { throw new CircuitException("Invalid parameter " + nameof(TempGatePotential)); } }
/// <summary> /// Loads the Y-matrix and Rhs-vector. /// </summary> /// <param name="simulation">The base simulation.</param> public void Load(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); var state = simulation.RealState; // DC model parameters var beta = ModelParameters.Beta * BaseParameters.Area; var gdpr = ModelParameters.DrainConductance * BaseParameters.Area; var gspr = ModelParameters.SourceConductance * BaseParameters.Area; var csat = TempSaturationCurrent * BaseParameters.Area; double ggs, cg; double ggd, cgd; double cdrain, gm, gds, betap, bfac; // Get the current voltages Initialize(simulation, out double vgs, out double vgd, out bool check); var vds = vgs - vgd; // Determine dc current and derivatives if (vgs <= -5 * BaseParameters.Temperature * Constants.KOverQ) { ggs = -csat / vgs + BaseConfiguration.Gmin; cg = ggs * vgs; } else { var evgs = Math.Exp(vgs / (BaseParameters.Temperature * Constants.KOverQ)); ggs = csat * evgs / (BaseParameters.Temperature * Constants.KOverQ) + BaseConfiguration.Gmin; cg = csat * (evgs - 1) + BaseConfiguration.Gmin * vgs; } if (vgd <= -5 * (BaseParameters.Temperature * Constants.KOverQ)) { ggd = -csat / vgd + BaseConfiguration.Gmin; cgd = ggd * vgd; } else { var evgd = Math.Exp(vgd / (BaseParameters.Temperature * Constants.KOverQ)); ggd = csat * evgd / (BaseParameters.Temperature * Constants.KOverQ) + BaseConfiguration.Gmin; cgd = csat * (evgd - 1) + BaseConfiguration.Gmin * vgd; } cg += cgd; // Modification for Sydney University JFET model var vto = ModelParameters.Threshold; if (vds >= 0) { var vgst = vgs - vto; // Compute drain current and derivatives for normal mode if (vgst <= 0) { // Normal mode, cutoff region cdrain = 0; gm = 0; gds = 0; } else { betap = beta * (1 + ModelParameters.LModulation * vds); bfac = ModelTemperature.BFactor; if (vgst >= vds) { // Normal mode, linear region var apart = 2 * ModelParameters.B + 3 * bfac * (vgst - vds); var cpart = vds * (vds * (bfac * vds - ModelParameters.B) + vgst * apart); cdrain = betap * cpart; gm = betap * vds * (apart + 3 * bfac * vgst); gds = betap * (vgst - vds) * apart + beta * ModelParameters.LModulation * cpart; } else { bfac = vgst * bfac; gm = betap * vgst * (2 * ModelParameters.B + 3 * bfac); // Normal mode, saturation region var cpart = vgst * vgst * (ModelParameters.B + bfac); cdrain = betap * cpart; gds = ModelParameters.LModulation * beta * cpart; } } } else { var vgdt = vgd - vto; // Compute drain current and derivatives for inverse mode if (vgdt <= 0) { // Inverse mode, cutoff region cdrain = 0; gm = 0; gds = 0; } else { betap = beta * (1 - ModelParameters.LModulation * vds); bfac = ModelTemperature.BFactor; if (vgdt + vds >= 0) { // Inverse mode, linear region var apart = 2 * ModelParameters.B + 3 * bfac * (vgdt + vds); var cpart = vds * (-vds * (-bfac * vds - ModelParameters.B) + vgdt * apart); cdrain = betap * cpart; gm = betap * vds * (apart + 3 * bfac * vgdt); gds = betap * (vgdt + vds) * apart - beta * ModelParameters.LModulation * cpart - gm; } else { bfac = vgdt * bfac; gm = -betap * vgdt * (2 * ModelParameters.B + 3 * bfac); // Inverse mode, saturation region var cpart = vgdt * vgdt * (ModelParameters.B + bfac); cdrain = -betap * cpart; gds = ModelParameters.LModulation * beta * cpart - gm; } } } var cd = cdrain - cgd; Vgs = vgs; Vgd = vgd; Cg = cg; Cd = cd; Cgd = cgd; Gm = gm; Gds = gds; Ggs = ggs; Ggd = ggd; // Check convergence if (state.Init != InitializationModes.Fix || !state.UseIc) { if (check) { state.IsConvergent = false; } } // Load current vector var ceqgd = ModelParameters.JFETType * (cgd - ggd * vgd); var ceqgs = ModelParameters.JFETType * (cg - cgd - ggs * vgs); var cdreq = ModelParameters.JFETType * (cd + cgd - gds * vds - gm * vgs); GateNodePtr.Value += -ceqgs - ceqgd; DrainPrimeNodePtr.Value += -cdreq + ceqgd; SourcePrimeNodePtr.Value += cdreq + ceqgs; // Load Y-matrix DrainDrainPrimePtr.Value += -gdpr; GateDrainPrimePtr.Value += -ggd; GateSourcePrimePtr.Value += -ggs; SourceSourcePrimePtr.Value += -gspr; DrainPrimeDrainPtr.Value += -gdpr; DrainPrimeGatePtr.Value += gm - ggd; DrainPrimeSourcePrimePtr.Value += -gds - gm; SourcePrimeGatePtr.Value += -ggs - gm; SourcePrimeSourcePtr.Value += -gspr; SourcePrimeDrainPrimePtr.Value += -gds; DrainDrainPtr.Value += gdpr; GateGatePtr.Value += ggd + ggs; SourceSourcePtr.Value += gspr; DrainPrimeDrainPrimePtr.Value += gdpr + gds + ggd; SourcePrimeSourcePrimePtr.Value += gspr + gds + gm + ggs; }
/// <summary> /// Do temperature-dependent calculations /// </summary> /// <param name="simulation">Base simulation</param> public void Temperature(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); // Perform model defaulting if (!ModelParameters.NominalTemperature.Given) { ModelParameters.NominalTemperature.RawValue = simulation.RealState.NominalTemperature; } Factor1 = ModelParameters.NominalTemperature / Constants.ReferenceTemperature; VtNominal = ModelParameters.NominalTemperature * Constants.KOverQ; var kt1 = Constants.Boltzmann * ModelParameters.NominalTemperature; EgFet1 = 1.16 - 7.02e-4 * ModelParameters.NominalTemperature * ModelParameters.NominalTemperature / (ModelParameters.NominalTemperature + 1108); var arg1 = -EgFet1 / (kt1 + kt1) + 1.1150877 / (Constants.Boltzmann * (Constants.ReferenceTemperature + Constants.ReferenceTemperature)); PbFactor1 = -2 * VtNominal * (1.5 * Math.Log(Factor1) + Constants.Charge * arg1); if (ModelParameters.SubstrateDoping.Given) { if (ModelParameters.SubstrateDoping * 1e6 > 1.45e16) { if (!ModelParameters.Phi.Given) { ModelParameters.Phi.RawValue = 2 * VtNominal * Math.Log(ModelParameters.SubstrateDoping * 1e6 / 1.45e16); ModelParameters.Phi.RawValue = Math.Max(.1, ModelParameters.Phi); } var fermis = ModelParameters.MosfetType * .5 * ModelParameters.Phi; var wkfng = 3.2; if (!ModelParameters.GateType.Given) { ModelParameters.GateType.RawValue = 1; } if (!ModelParameters.GateType.RawValue.Equals(0)) { var fermig = ModelParameters.MosfetType * ModelParameters.GateType * .5 * EgFet1; wkfng = 3.25 + .5 * EgFet1 - fermig; } var wkfngs = wkfng - (3.25 + .5 * EgFet1 + fermis); if (!ModelParameters.Gamma.Given) { ModelParameters.Gamma.RawValue = Math.Sqrt(2 * 11.70 * 8.854214871e-12 * Constants.Charge * ModelParameters.SubstrateDoping * 1e6) / ModelParameters.OxideCapFactor; } if (!ModelParameters.Vt0.Given) { if (!ModelParameters.SurfaceStateDensity.Given) { ModelParameters.SurfaceStateDensity.RawValue = 0; } var vfb = wkfngs - ModelParameters.SurfaceStateDensity * 1e4 * Constants.Charge / ModelParameters.OxideCapFactor; ModelParameters.Vt0.RawValue = vfb + ModelParameters.MosfetType * (ModelParameters.Gamma * Math.Sqrt(ModelParameters.Phi) + ModelParameters.Phi); } Xd = Math.Sqrt((EpsilonSilicon + EpsilonSilicon) / (Constants.Charge * ModelParameters.SubstrateDoping * 1e6)); } else { ModelParameters.SubstrateDoping.RawValue = 0; throw new CircuitException("{0}: Nsub < Ni".FormatString(Name)); } } if (!ModelParameters.BulkCapFactor.Given) { ModelParameters.BulkCapFactor.RawValue = Math.Sqrt(EpsilonSilicon * Constants.Charge * ModelParameters.SubstrateDoping * 1e6 /* cm**3/m**3 */ / (2 * ModelParameters.BulkJunctionPotential)); } }
/// <summary> /// Loads the Y-matrix and Rhs-vector. /// </summary> /// <param name="simulation">The base simulation.</param> public void Load(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); var state = simulation.RealState; // Get the current voltages Initialize(simulation, out double vgs, out var vds, out var vbs, out var check); var vbd = vbs - vds; var vgd = vgs - vds; /* * bulk-source and bulk-drain diodes * here we just evaluate the ideal diode current and the * corresponding derivative (conductance). */ if (vbs <= 0) { CondBs = SourceSatCurrent / Vt; BsCurrent = CondBs * vbs; CondBs += BaseConfiguration.Gmin; } else { var evbs = Math.Exp(Math.Min(MaximumExponentArgument, vbs / Vt)); CondBs = SourceSatCurrent * evbs / Vt + BaseConfiguration.Gmin; BsCurrent = SourceSatCurrent * (evbs - 1); } if (vbd <= 0) { CondBd = DrainSatCurrent / Vt; BdCurrent = CondBd * vbd; CondBd += BaseConfiguration.Gmin; } else { var evbd = Math.Exp(Math.Min(MaximumExponentArgument, vbd / Vt)); CondBd = DrainSatCurrent * evbd / Vt + BaseConfiguration.Gmin; BdCurrent = DrainSatCurrent * (evbd - 1); } /* * Now to determine whether the user was able to correctly * identify the source and drain of his device */ if (vds >= 0) { // normal mode Mode = 1; } else { // inverse mode Mode = -1; } // Update VoltageBs = vbs; VoltageBd = vbd; VoltageGs = vgs; VoltageDs = vds; // Evaluate the currents and derivatives var cdrain = Mode > 0 ? Evaluate(vgs, vds, vbs) : Evaluate(vgd, -vds, vbd); DrainCurrent = Mode * cdrain - BdCurrent; // Check convergence if (!BaseParameters.Off || state.Init != InitializationModes.Fix) { if (check) { state.IsConvergent = false; } } // Load current vector double xnrm, xrev, cdreq; var ceqbs = ModelParameters.MosfetType * (BsCurrent - (CondBs - BaseConfiguration.Gmin) * vbs); var ceqbd = ModelParameters.MosfetType * (BdCurrent - (CondBd - BaseConfiguration.Gmin) * vbd); if (Mode >= 0) { xnrm = 1; xrev = 0; cdreq = ModelParameters.MosfetType * (cdrain - CondDs * vds - Transconductance * vgs - TransconductanceBs * vbs); } else { xnrm = 0; xrev = 1; cdreq = -ModelParameters.MosfetType * (cdrain - CondDs * -vds - Transconductance * vgd - TransconductanceBs * vbd); } BulkPtr.Value -= ceqbs + ceqbd; DrainPrimePtr.Value += ceqbd - cdreq; SourcePrimePtr.Value += cdreq + ceqbs; // Load Y-matrix DrainDrainPtr.Value += DrainConductance; SourceSourcePtr.Value += SourceConductance; BulkBulkPtr.Value += CondBd + CondBs; DrainPrimeDrainPrimePtr.Value += DrainConductance + CondDs + CondBd + xrev * (Transconductance + TransconductanceBs); SourcePrimeSourcePrimePtr.Value += SourceConductance + CondDs + CondBs + xnrm * (Transconductance + TransconductanceBs); DrainDrainPrimePtr.Value += -DrainConductance; SourceSourcePrimePtr.Value += -SourceConductance; BulkDrainPrimePtr.Value -= CondBd; BulkSourcePrimePtr.Value -= CondBs; DrainPrimeDrainPtr.Value += -DrainConductance; DrainPrimeGatePtr.Value += (xnrm - xrev) * Transconductance; DrainPrimeBulkPtr.Value += -CondBd + (xnrm - xrev) * TransconductanceBs; DrainPrimeSourcePrimePtr.Value += -CondDs - xnrm * (Transconductance + TransconductanceBs); SourcePrimeGatePtr.Value += -(xnrm - xrev) * Transconductance; SourcePrimeSourcePtr.Value += -SourceConductance; SourcePrimeBulkPtr.Value += -CondBs - (xnrm - xrev) * TransconductanceBs; SourcePrimeDrainPrimePtr.Value += -CondDs - xrev * (Transconductance + TransconductanceBs); }
/// <summary> /// Do temperature-dependent calculations /// </summary> /// <param name="simulation">Base simulation</param> public override void Temperature(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); if (!_mbp.NominalTemperature.Given) { _mbp.NominalTemperature.RawValue = simulation.RealState.NominalTemperature; } Factor1 = _mbp.NominalTemperature / Constants.ReferenceTemperature; if (!_mbp.LeakBeCurrent.Given) { if (_mbp.C2.Given) { _mbp.LeakBeCurrent.RawValue = _mbp.C2 * _mbp.SatCur; } else { _mbp.LeakBeCurrent.RawValue = 0; } } if (!_mbp.LeakBcCurrent.Given) { if (_mbp.C4.Given) { _mbp.LeakBcCurrent.RawValue = _mbp.C4 * _mbp.SatCur; } else { _mbp.LeakBcCurrent.RawValue = 0; } } if (!_mbp.MinimumBaseResistance.Given) { _mbp.MinimumBaseResistance.RawValue = _mbp.BaseResist; } /* * COMPATABILITY WARNING! * special note: for backward compatability to much older models, spice 2G * implemented a special case which checked if B-E leakage saturation * current was >1, then it was instead a the B-E leakage saturation current * divided by IS, and multiplied it by IS at this point. This was not * handled correctly in the 2G code, and there is some question on its * reasonability, since it is also undocumented, so it has been left out * here. It could easily be added with 1 line. (The same applies to the B-C * leakage saturation current). TQ 6/29/84 */ if (_mbp.EarlyVoltageForward.Given && !_mbp.EarlyVoltageForward.Value.Equals(0.0)) { InverseEarlyVoltForward = 1 / _mbp.EarlyVoltageForward; } else { InverseEarlyVoltForward = 0; } if (_mbp.RollOffForward.Given && !_mbp.RollOffForward.Value.Equals(0.0)) { InverseRollOffForward = 1 / _mbp.RollOffForward; } else { InverseRollOffForward = 0; } if (_mbp.EarlyVoltageReverse.Given && !_mbp.EarlyVoltageReverse.Value.Equals(0.0)) { InverseEarlyVoltReverse = 1 / _mbp.EarlyVoltageReverse; } else { InverseEarlyVoltReverse = 0; } if (_mbp.RollOffReverse.Given && !_mbp.RollOffReverse.Value.Equals(0.0)) { InverseRollOffReverse = 1 / _mbp.RollOffReverse; } else { InverseRollOffReverse = 0; } if (_mbp.CollectorResistance.Given && !_mbp.CollectorResistance.Value.Equals(0.0)) { CollectorConduct = 1 / _mbp.CollectorResistance; } else { CollectorConduct = 0; } if (_mbp.EmitterResistance.Given && !_mbp.EmitterResistance.Value.Equals(0.0)) { EmitterConduct = 1 / _mbp.EmitterResistance; } else { EmitterConduct = 0; } if (_mbp.TransitTimeForwardVoltageBc.Given && !_mbp.TransitTimeForwardVoltageBc.Value.Equals(0.0)) { TransitTimeVoltageBcFactor = 1 / (_mbp.TransitTimeForwardVoltageBc * 1.44); } else { TransitTimeVoltageBcFactor = 0; } ExcessPhaseFactor = _mbp.ExcessPhase / (180.0 / Math.PI) * _mbp.TransitTimeForward; if (_mbp.DepletionCapCoefficient.Given) { if (_mbp.DepletionCapCoefficient > 0.9999) { _mbp.DepletionCapCoefficient.RawValue = 0.9999; throw new CircuitException("BJT model {0}, parameter fc limited to 0.9999".FormatString(Name)); } } else { _mbp.DepletionCapCoefficient.RawValue = 0.5; } Xfc = Math.Log(1 - _mbp.DepletionCapCoefficient); F2 = Math.Exp((1 + _mbp.JunctionExpBe) * Xfc); F3 = 1 - _mbp.DepletionCapCoefficient * (1 + _mbp.JunctionExpBe); F6 = Math.Exp((1 + _mbp.JunctionExpBc) * Xfc); F7 = 1 - _mbp.DepletionCapCoefficient * (1 + _mbp.JunctionExpBc); }
/// <summary> /// Loads the Y-matrix and Rhs-vector. /// </summary> /// <param name="simulation">The base simulation.</param> /// <exception cref="NotImplementedException"></exception> public void Load(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); bool currentState; var state = simulation.RealState; // decide the state of the switch if (state.Init == InitializationModes.Fix || state.Init == InitializationModes.Junction) { if (BaseParameters.ZeroState) { // Switch specified "on" CurrentState = true; currentState = true; } else { // Switch specified "off" CurrentState = false; currentState = false; } } else { // Get the previous state var ctrl = Method.GetValue(state); if (UseOldState) { // Calculate the current state if (ctrl > ModelParameters.Threshold + ModelParameters.Hysteresis) { currentState = true; } else if (ctrl < ModelParameters.Threshold - ModelParameters.Hysteresis) { currentState = false; } else { currentState = PreviousState; } CurrentState = currentState; UseOldState = false; } else { PreviousState = CurrentState; // Calculate the current state if (ctrl > ModelParameters.Threshold + ModelParameters.Hysteresis) { CurrentState = true; currentState = true; } else if (ctrl < ModelParameters.Threshold - ModelParameters.Hysteresis) { CurrentState = false; currentState = false; } else { currentState = PreviousState; } // Ensure one more iteration if (currentState != PreviousState) { state.IsConvergent = false; } } // Store the current state CurrentState = currentState; // If the state changed, ensure one more iteration if (currentState != PreviousState) { state.IsConvergent = false; } } // Get the current conduction var gNow = currentState ? ModelParameters.OnConductance : ModelParameters.OffConductance; Conductance = gNow; // Load the Y-matrix PosPosPtr.Value += gNow; PosNegPtr.Value -= gNow; NegPosPtr.Value -= gNow; NegNegPtr.Value += gNow; }
/// <summary> /// Do temperature-dependent calculations /// </summary> /// <param name="simulation">Base simulation</param> public void Temperature(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); var xcbv = 0.0; // loop through all the instances if (!BaseParameters.Temperature.Given) { BaseParameters.Temperature.RawValue = simulation.RealState.Temperature; } Vt = Constants.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 / Constants.ReferenceTemperature; var egfet = 1.16 - 7.02e-4 * BaseParameters.Temperature * BaseParameters.Temperature / (BaseParameters.Temperature + 1108); var arg = -egfet / (2 * Constants.Boltzmann * BaseParameters.Temperature) + 1.1150877 / (Constants.Boltzmann * (Constants.ReferenceTemperature + Constants.ReferenceTemperature)); var pbfact = -2 * Vt * (1.5 * Math.Log(fact2) + Constants.Charge * arg); var egfet1 = 1.16 - 7.02e-4 * ModelParameters.NominalTemperature * ModelParameters.NominalTemperature / (ModelParameters.NominalTemperature + 1108); var arg1 = -egfet1 / (Constants.Boltzmann * 2 * ModelParameters.NominalTemperature) + 1.1150877 / (2 * Constants.Boltzmann * Constants.ReferenceTemperature); var fact1 = ModelParameters.NominalTemperature / Constants.ReferenceTemperature; var pbfact1 = -2 * ModelTemperature.VtNominal * (1.5 * Math.Log(fact1) + Constants.Charge * arg1); var pbo = (ModelParameters.JunctionPotential - pbfact1) / fact1; var gmaold = (ModelParameters.JunctionPotential - pbo) / pbo; TempJunctionCap = ModelParameters.JunctionCap / (1 + ModelParameters.GradingCoefficient * (400e-6 * (ModelParameters.NominalTemperature - Constants.ReferenceTemperature) - gmaold)); TempJunctionPot = pbfact + fact2 * pbo; var gmanew = (TempJunctionPot - pbo) / pbo; TempJunctionCap *= 1 + ModelParameters.GradingCoefficient * (400e-6 * (BaseParameters.Temperature - Constants.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 / (Constants.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; } }
/// <summary> /// Execute behavior /// </summary> /// <param name="simulation">Base simulation</param> public void Load(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); var state = simulation.RealState; double cd, gd; // Get the current voltages Initialize(simulation, out double vd, out bool check); /* * this routine loads diodes for dc and transient analyses. */ var csat = TempSaturationCurrent * BaseParameters.Area; var gspr = ModelTemperature.Conductance * BaseParameters.Area; // compute dc current and derivatives if (vd >= -3 * Vte) { // Forward bias var evd = Math.Exp(vd / Vte); cd = csat * (evd - 1) + BaseConfiguration.Gmin * vd; gd = csat * evd / Vte + BaseConfiguration.Gmin; } else if (!ModelParameters.BreakdownVoltage.Given || vd >= -TempBreakdownVoltage) { // Reverse bias var arg = 3 * Vte / (vd * Math.E); arg = arg * arg * arg; cd = -csat * (1 + arg) + BaseConfiguration.Gmin * vd; gd = csat * 3 * arg / vd + BaseConfiguration.Gmin; } else { // Reverse breakdown var evrev = Math.Exp(-(TempBreakdownVoltage + vd) / Vte); cd = -csat * evrev + BaseConfiguration.Gmin * vd; gd = csat * evrev / Vte + BaseConfiguration.Gmin; } // Check convergence if (state.Init != InitializationModes.Fix || !BaseParameters.Off) { if (check) { state.IsConvergent = false; } } // Store for next time Voltage = vd; Current = cd; Conductance = gd; // Load Rhs vector var cdeq = cd - gd * vd; NegPtr.Value += cdeq; PosPrimePtr.Value -= cdeq; // Load Y-matrix PosPosPtr.Value += gspr; NegNegPtr.Value += gd; PosPrimePosPrimePtr.Value += gd + gspr; PosPosPrimePtr.Value -= gspr; PosPrimePosPtr.Value -= gspr; NegPosPrimePtr.Value -= gd; PosPrimeNegPtr.Value -= gd; }
/// <summary> /// Execute behavior /// </summary> /// <param name="simulation">Base simulation</param> public void Load(BaseSimulation simulation) { simulation.ThrowIfNull(nameof(simulation)); double gben; double cben; double gbcn; double cbcn; // DC model parameters var csat = TempSaturationCurrent * BaseParameters.Area; var rbpr = ModelParameters.MinimumBaseResistance / BaseParameters.Area; var rbpi = ModelParameters.BaseResist / BaseParameters.Area - rbpr; var gcpr = ModelTemperature.CollectorConduct * BaseParameters.Area; var gepr = ModelTemperature.EmitterConduct * BaseParameters.Area; var oik = ModelTemperature.InverseRollOffForward / BaseParameters.Area; var c2 = TempBeLeakageCurrent * BaseParameters.Area; var vte = ModelParameters.LeakBeEmissionCoefficient * Vt; var oikr = ModelTemperature.InverseRollOffReverse / BaseParameters.Area; var c4 = TempBcLeakageCurrent * BaseParameters.Area; var vtc = ModelParameters.LeakBcEmissionCoefficient * Vt; var xjrb = ModelParameters.BaseCurrentHalfResist * BaseParameters.Area; // Get the current voltages Initialize(simulation, out var vbe, out var vbc); // Determine dc current and derivitives var vtn = Vt * ModelParameters.EmissionCoefficientForward; if (vbe > -5 * vtn) { var evbe = Math.Exp(vbe / vtn); CurrentBe = csat * (evbe - 1) + BaseConfiguration.Gmin * vbe; CondBe = csat * evbe / vtn + BaseConfiguration.Gmin; if (c2.Equals(0)) // Avoid Exp() { cben = 0; gben = 0; } else { var evben = Math.Exp(vbe / vte); cben = c2 * (evben - 1); gben = c2 * evben / vte; } } else { CondBe = -csat / vbe + BaseConfiguration.Gmin; CurrentBe = CondBe * vbe; gben = -c2 / vbe; cben = gben * vbe; } vtn = Vt * ModelParameters.EmissionCoefficientReverse; if (vbc > -5 * vtn) { var evbc = Math.Exp(vbc / vtn); CurrentBc = csat * (evbc - 1) + BaseConfiguration.Gmin * vbc; CondBc = csat * evbc / vtn + BaseConfiguration.Gmin; if (c4.Equals(0)) // Avoid Exp() { cbcn = 0; gbcn = 0; } else { var evbcn = Math.Exp(vbc / vtc); cbcn = c4 * (evbcn - 1); gbcn = c4 * evbcn / vtc; } } else { CondBc = -csat / vbc + BaseConfiguration.Gmin; CurrentBc = CondBc * vbc; gbcn = -c4 / vbc; cbcn = gbcn * vbc; } // Determine base charge terms var q1 = 1 / (1 - ModelTemperature.InverseEarlyVoltForward * vbc - ModelTemperature.InverseEarlyVoltReverse * vbe); if (oik.Equals(0) && oikr.Equals(0)) // Avoid computations { BaseCharge = q1; Dqbdve = q1 * BaseCharge * ModelTemperature.InverseEarlyVoltReverse; Dqbdvc = q1 * BaseCharge * ModelTemperature.InverseEarlyVoltForward; } else { var q2 = oik * CurrentBe + oikr * CurrentBc; var arg = Math.Max(0, 1 + 4 * q2); double sqarg = 1; if (!arg.Equals(0)) // Avoid Sqrt() { sqarg = Math.Sqrt(arg); } BaseCharge = q1 * (1 + sqarg) / 2; Dqbdve = q1 * (BaseCharge * ModelTemperature.InverseEarlyVoltReverse + oik * CondBe / sqarg); Dqbdvc = q1 * (BaseCharge * ModelTemperature.InverseEarlyVoltForward + oikr * CondBc / sqarg); } // Excess phase calculation var cc = 0.0; var cex = CurrentBe; var gex = CondBe; ExcessPhaseCalculation(ref cc, ref cex, ref gex); // Determine dc incremental conductances cc = cc + (cex - CurrentBc) / BaseCharge - CurrentBc / TempBetaReverse - cbcn; var cb = CurrentBe / TempBetaForward + cben + CurrentBc / TempBetaReverse + cbcn; var gx = rbpr + rbpi / BaseCharge; if (!xjrb.Equals(0)) // Avoid calculations { var arg1 = Math.Max(cb / xjrb, 1e-9); var arg2 = (-1 + Math.Sqrt(1 + 14.59025 * arg1)) / 2.4317 / Math.Sqrt(arg1); arg1 = Math.Tan(arg2); gx = rbpr + 3 * rbpi * (arg1 - arg2) / arg2 / arg1 / arg1; } if (!gx.Equals(0)) // Do not divide by 0 { gx = 1 / gx; } var gpi = CondBe / TempBetaForward + gben; var gmu = CondBc / TempBetaReverse + gbcn; var go = (CondBc + (cex - CurrentBc) * Dqbdvc / BaseCharge) / BaseCharge; var gm = (gex - (cex - CurrentBc) * Dqbdve / BaseCharge) / BaseCharge - go; VoltageBe = vbe; VoltageBc = vbc; CollectorCurrent = cc; BaseCurrent = cb; ConductancePi = gpi; ConductanceMu = gmu; Transconductance = gm; OutputConductance = go; ConductanceX = gx; // Load current excitation vector var ceqbe = ModelParameters.BipolarType * (cc + cb - vbe * (gm + go + gpi) + vbc * go); var ceqbc = ModelParameters.BipolarType * (-cc + vbe * (gm + go) - vbc * (gmu + go)); CollectorPrimePtr.Value += ceqbc; BasePrimePtr.Value += -ceqbe - ceqbc; EmitterPrimePtr.Value += ceqbe; // Load y matrix CollectorCollectorPtr.Value += gcpr; BaseBasePtr.Value += gx; EmitterEmitterPtr.Value += gepr; CollectorPrimeCollectorPrimePtr.Value += gmu + go + gcpr; BasePrimeBasePrimePtr.Value += gx + gpi + gmu; EmitterPrimeEmitterPrimePtr.Value += gpi + gepr + gm + go; CollectorCollectorPrimePtr.Value += -gcpr; BaseBasePrimePtr.Value += -gx; EmitterEmitterPrimePtr.Value += -gepr; CollectorPrimeCollectorPtr.Value += -gcpr; CollectorPrimeBasePrimePtr.Value += -gmu + gm; CollectorPrimeEmitterPrimePtr.Value += -gm - go; BasePrimeBasePtr.Value += -gx; BasePrimeCollectorPrimePtr.Value += -gmu; BasePrimeEmitterPrimePtr.Value += -gpi; EmitterPrimeEmitterPtr.Value += -gepr; EmitterPrimeCollectorPrimePtr.Value += -go; EmitterPrimeBasePrimePtr.Value += -gpi - gm; }