/// <summary> /// Calculate excess phase /// </summary> /// <param name="sender">Sender</param> /// <param name="args">Arguments</param> public void CalculateExcessPhase(object sender, ExcessPhaseEventArgs args) { if (args == null) { throw new ArgumentNullException(nameof(args)); } double td = _modeltemp.ExcessPhaseFactor; if (td.Equals(0)) { StateExcessPhaseCurrentBc.Current = args.ExcessPhaseCurrent; return; } /* * weil's approx. for excess phase applied with backward - * euler integration */ double cbe = args.ExcessPhaseCurrent; double gbe = args.ExcessPhaseConduct; double delta = StateExcessPhaseCurrentBc.Timesteps[0]; double prevdelta = StateExcessPhaseCurrentBc.Timesteps[1]; var arg1 = delta / td; var arg2 = 3 * arg1; arg1 = arg2 * arg1; var denom = 1 + arg1 + arg2; var arg3 = arg1 / denom; /* Still need a place for this... * if (state.Init == State.InitFlags.InitTransient) * { * state.States[1][State + Cexbc] = cbe / qb; * state.States[2][State + Cexbc] = state.States[1][State + Cexbc]; * } */ args.CollectorCurrent = (StateExcessPhaseCurrentBc[1] * (1 + delta / prevdelta + arg2) - StateExcessPhaseCurrentBc[2] * delta / prevdelta) / denom; args.ExcessPhaseCurrent = cbe * arg3; args.ExcessPhaseConduct = gbe * arg3; StateExcessPhaseCurrentBc.Current = args.CollectorCurrent + args.ExcessPhaseCurrent / args.BaseCharge; }
/// <summary> /// Execute behavior /// </summary> /// <param name="simulation">Base simulation</param> public override void Load(BaseSimulation simulation) { if (simulation == null) { throw new ArgumentNullException(nameof(simulation)); } var state = simulation.RealState; double vbe; double vbc; double gben; double cben; double gbcn; double cbcn; var vt = _bp.Temperature * Circuit.KOverQ; // DC model parameters var csat = _temp.TempSaturationCurrent * _bp.Area; var rbpr = _mbp.MinimumBaseResistance / _bp.Area; var rbpi = _mbp.BaseResist / _bp.Area - rbpr; var gcpr = _modeltemp.CollectorConduct * _bp.Area; var gepr = _modeltemp.EmitterConduct * _bp.Area; var oik = _modeltemp.InverseRollOffForward / _bp.Area; var c2 = _temp.TempBeLeakageCurrent * _bp.Area; var vte = _mbp.LeakBeEmissionCoefficient * vt; var oikr = _modeltemp.InverseRollOffReverse / _bp.Area; var c4 = _temp.TempBcLeakageCurrent * _bp.Area; var vtc = _mbp.LeakBcEmissionCoefficient * vt; var xjrb = _mbp.BaseCurrentHalfResist * _bp.Area; // Initialization if (state.Init == RealState.InitializationStates.InitJunction && state.Domain == RealState.DomainType.Time && state.UseDc && state.UseIc) { vbe = _mbp.BipolarType * _bp.InitialVoltageBe; var vce = _mbp.BipolarType * _bp.InitialVoltageCe; vbc = vbe - vce; } else if (state.Init == RealState.InitializationStates.InitJunction && !_bp.Off) { vbe = _temp.TempVCritical; vbc = 0; } else if (state.Init == RealState.InitializationStates.InitJunction || state.Init == RealState.InitializationStates.InitFix && _bp.Off) { vbe = 0; vbc = 0; } else { // Compute new nonlinear branch voltages vbe = _mbp.BipolarType * (state.Solution[BasePrimeNode] - state.Solution[EmitterPrimeNode]); vbc = _mbp.BipolarType * (state.Solution[BasePrimeNode] - state.Solution[CollectorPrimeNode]); // Limit nonlinear branch voltages bool limited = false; vbe = Semiconductor.LimitJunction(vbe, VoltageBe, vt, _temp.TempVCritical, ref limited); vbc = Semiconductor.LimitJunction(vbc, VoltageBc, vt, _temp.TempVCritical, ref limited); if (limited) { state.IsConvergent = false; } } // Determine dc current and derivitives var vtn = vt * _mbp.EmissionCoefficientForward; if (vbe > -5 * vtn) { var evbe = Math.Exp(vbe / vtn); CurrentBe = csat * (evbe - 1) + state.Gmin * vbe; CondBe = csat * evbe / vtn + state.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 + state.Gmin; CurrentBe = CondBe * vbe; gben = -c2 / vbe; cben = gben * vbe; } vtn = vt * _mbp.EmissionCoefficientReverse; if (vbc > -5 * vtn) { var evbc = Math.Exp(vbc / vtn); CurrentBc = csat * (evbc - 1) + state.Gmin * vbc; CondBc = csat * evbc / vtn + state.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 + state.Gmin; CurrentBc = CondBc * vbc; gbcn = -c4 / vbc; cbcn = gbcn * vbc; } // Determine base charge terms var q1 = 1 / (1 - _modeltemp.InverseEarlyVoltForward * vbc - _modeltemp.InverseEarlyVoltReverse * vbe); if (oik.Equals(0) && oikr.Equals(0)) // Avoid computations { BaseCharge = q1; Dqbdve = q1 * BaseCharge * _modeltemp.InverseEarlyVoltReverse; Dqbdvc = q1 * BaseCharge * _modeltemp.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 * _modeltemp.InverseEarlyVoltReverse + oik * CondBe / sqarg); Dqbdvc = q1 * (BaseCharge * _modeltemp.InverseEarlyVoltForward + oikr * CondBc / sqarg); } // Excess phase calculation ExcessPhaseEventArgs ep = new ExcessPhaseEventArgs { CollectorCurrent = 0.0, ExcessPhaseCurrent = CurrentBe, ExcessPhaseConduct = CondBe, BaseCharge = BaseCharge }; ExcessPhaseCalculation?.Invoke(this, ep); var cc = ep.CollectorCurrent; var cex = ep.ExcessPhaseCurrent; var gex = ep.ExcessPhaseConduct; // Determine dc incremental conductances cc = cc + (cex - CurrentBc) / BaseCharge - CurrentBc / _temp.TempBetaReverse - cbcn; var cb = CurrentBe / _temp.TempBetaForward + cben + CurrentBc / _temp.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 / _temp.TempBetaForward + gben; var gmu = CondBc / _temp.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 = _mbp.BipolarType * (cc + cb - vbe * (gm + go + gpi) + vbc * go); var ceqbc = _mbp.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; }