/// <summary> /// Execute behaviour /// </summary> void ITimeBehavior.Load() { // Initialize _flux.ThrowIfNotBound(this).Current = BaseParameters.Inductance * State.Solution[BranchEq]; // Allow alterations of the flux if (UpdateFlux != null) { var args = new UpdateFluxEventArgs(BaseParameters.Inductance, State.Solution[BranchEq], _flux, State); UpdateFlux.Invoke(this, args); } // Finally load the Y-matrix _flux.Integrate(); BranchPtr.Value += _flux.RhsCurrent(); BranchBranchPtr.Value -= _flux.Jacobian(BaseParameters.Inductance); }
/// <summary> /// Execute behaviour /// </summary> /// <param name="simulation">Time-based simulation</param> public override void Transient(TimeSimulation simulation) { if (simulation == null) { throw new ArgumentNullException(nameof(simulation)); } var state = simulation.RealState; // Initialize _flux.Current = _bp.Inductance * state.Solution[_branchEq]; // Allow alterations of the flux if (UpdateFlux != null) { UpdateFluxEventArgs args = new UpdateFluxEventArgs(_bp.Inductance, state.Solution[_branchEq], _flux, state); UpdateFlux.Invoke(this, args); } // Finally load the Y-matrix _flux.Integrate(); BranchPtr.Value += _flux.RhsCurrent(); BranchBranchPtr.Value -= _flux.Jacobian(_bp.Inductance); }
/// <summary> /// Transient behavior /// </summary> /// <param name="simulation">Time-based simulation</param> public override void Transient(TimeSimulation simulation) { if (simulation == null) { throw new ArgumentNullException(nameof(simulation)); } double sargsw; var vbs = _load.VoltageBs; var vbd = _load.VoltageBd; var vgs = _load.VoltageGs; var vds = _load.VoltageDs; var vgd = _load.VoltageGs - _load.VoltageDs; var vgb = _load.VoltageGs - _load.VoltageBs; var von = _mbp.MosfetType * _load.Von; var vdsat = _mbp.MosfetType * _load.SaturationVoltageDs; _vds.Current = vds; _vbs.Current = vbs; _vgs.Current = vgs; var gbd = 0.0; var cbd = 0.0; var gbs = 0.0; var cbs = 0.0; var effectiveLength = _bp.Length - 2 * _mbp.LateralDiffusion; var gateSourceOverlapCap = _mbp.GateSourceOverlapCapFactor * _bp.Width; var gateDrainOverlapCap = _mbp.GateDrainOverlapCapFactor * _bp.Width; var gateBulkOverlapCap = _mbp.GateBulkOverlapCapFactor * effectiveLength; var oxideCap = _mbp.OxideCapFactor * effectiveLength * _bp.Width; /* * now we do the hard part of the bulk - drain and bulk - source * diode - we evaluate the non - linear capacitance and * charge * * the basic equations are not hard, but the implementation * is somewhat long in an attempt to avoid log / exponential * evaluations */ /* * charge storage elements * * .. bulk - drain and bulk - source depletion capacitances */ if (vbs < _temp.TempDepletionCap) { double arg = 1 - vbs / _temp.TempBulkPotential, sarg; /* * the following block looks somewhat long and messy, * but since most users use the default grading * coefficients of .5, and sqrt is MUCH faster than an * Math.Exp(Math.Log()) we use this special case code to buy time. * (as much as 10% of total job time!) */ if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(_mbp.BulkJunctionSideGradingCoefficient)) { if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5)) { sarg = sargsw = 1 / Math.Sqrt(arg); } else { sarg = sargsw = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg)); } } else { if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5)) { sarg = 1 / Math.Sqrt(arg); } else { /* NOSQRT */ sarg = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg)); } if (_mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5)) { sargsw = 1 / Math.Sqrt(arg); } else { /* NOSQRT */ sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg)); } } /* NOSQRT */ _qbs.Current = _temp.TempBulkPotential * (_temp.CapBs * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) + _temp.CapBsSidewall * (1 - arg * sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient)); CapBs = _temp.CapBs * sarg + _temp.CapBsSidewall * sargsw; } else { _qbs.Current = _temp.F4S + vbs * (_temp.F2S + vbs * (_temp.F3S / 2)); CapBs = _temp.F2S + _temp.F3S * vbs; } if (vbd < _temp.TempDepletionCap) { double arg = 1 - vbd / _temp.TempBulkPotential, sarg; /* * the following block looks somewhat long and messy, * but since most users use the default grading * coefficients of .5, and sqrt is MUCH faster than an * Math.Exp(Math.Log()) we use this special case code to buy time. * (as much as 10% of total job time!) */ if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5) && _mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5)) { sarg = sargsw = 1 / Math.Sqrt(arg); } else { if (_mbp.BulkJunctionBotGradingCoefficient.Value.Equals(0.5)) { sarg = 1 / Math.Sqrt(arg); } else { /* NOSQRT */ sarg = Math.Exp(-_mbp.BulkJunctionBotGradingCoefficient * Math.Log(arg)); } if (_mbp.BulkJunctionSideGradingCoefficient.Value.Equals(0.5)) { sargsw = 1 / Math.Sqrt(arg); } else { /* NOSQRT */ sargsw = Math.Exp(-_mbp.BulkJunctionSideGradingCoefficient * Math.Log(arg)); } } /* NOSQRT */ _qbd.Current = _temp.TempBulkPotential * (_temp.CapBd * (1 - arg * sarg) / (1 - _mbp.BulkJunctionBotGradingCoefficient) + _temp.CapBdSidewall * (1 - arg * sargsw) / (1 - _mbp.BulkJunctionSideGradingCoefficient)); CapBd = _temp.CapBd * sarg + _temp.CapBdSidewall * sargsw; } else { _qbd.Current = _temp.F4D + vbd * (_temp.F2D + vbd * _temp.F3D / 2); CapBd = _temp.F2D + vbd * _temp.F3D; } /* CAPZEROBYPASS */ /* (above only excludes tranop, since we're only at this * point if tran or tranop) */ /* * calculate equivalent conductances and currents for * depletion capacitors */ /* integrate the capacitors and save results */ _qbd.Integrate(); gbd += _qbd.Jacobian(CapBd); cbd += _qbd.Derivative; _qbs.Integrate(); gbs += _qbs.Jacobian(CapBs); cbs += _qbs.Derivative; /* * calculate meyer's capacitors */ /* * new cmeyer - this just evaluates at the current time, * expects you to remember values from previous time * returns 1 / 2 of non - constant portion of capacitance * you must add in the other half from previous time * and the constant part */ double icapgs, icapgd, icapgb; if (_load.Mode > 0) { Transistor.MeyerCharges(vgs, vgd, von, vdsat, out icapgs, out icapgd, out icapgb, _temp.TempPhi, oxideCap); } else { Transistor.MeyerCharges(vgd, vgs, von, vdsat, out icapgd, out icapgs, out icapgb, _temp.TempPhi, oxideCap); } _capgs.Current = icapgs; _capgd.Current = icapgd; _capgb.Current = icapgb; var vgs1 = _vgs[1]; var vgd1 = vgs1 - _vds[1]; var vgb1 = vgs1 - _vbs[1]; var capgs = _capgs.Current + _capgs[1] + gateSourceOverlapCap; var capgd = _capgd.Current + _capgd[1] + gateDrainOverlapCap; var capgb = _capgb.Current + _capgb[1] + gateBulkOverlapCap; _qgs.Current = (vgs - vgs1) * capgs + _qgs[1]; _qgd.Current = (vgd - vgd1) * capgd + _qgd[1]; _qgb.Current = (vgb - vgb1) * capgb + _qgb[1]; /* * calculate equivalent conductances and currents for * meyer"s capacitors */ _qgs.Integrate(); var gcgs = _qgs.Jacobian(capgs); var ceqgs = _qgs.RhsCurrent(gcgs, vgs); _qgd.Integrate(); var gcgd = _qgd.Jacobian(capgd); var ceqgd = _qgd.RhsCurrent(gcgd, vgd); _qgb.Integrate(); var gcgb = _qgb.Jacobian(capgb); var ceqgb = _qgb.RhsCurrent(gcgb, vgb); // Load current vector var ceqbs = _mbp.MosfetType * (cbs - gbs * vbs); var ceqbd = _mbp.MosfetType * (cbd - gbd * vbd); GatePtr.Value -= _mbp.MosfetType * (ceqgs + ceqgb + ceqgd); BulkPtr.Value -= ceqbs + ceqbd - _mbp.MosfetType * ceqgb; DrainPrimePtr.Value += ceqbd + _mbp.MosfetType * ceqgd; SourcePrimePtr.Value += ceqbs + _mbp.MosfetType * ceqgs; // Load y matrix GateGatePtr.Value += gcgd + gcgs + gcgb; BulkBulkPtr.Value += gbd + gbs + gcgb; DrainPrimeDrainPrimePtr.Value += gbd + gcgd; SourcePrimeSourcePrimePtr.Value += gbs + gcgs; GateBulkPtr.Value -= gcgb; GateDrainPrimePtr.Value -= gcgd; GateSourcePrimePtr.Value -= gcgs; BulkGatePtr.Value -= gcgb; BulkDrainPrimePtr.Value -= gbd; BulkSourcePrimePtr.Value -= gbs; DrainPrimeGatePtr.Value += -gcgd; DrainPrimeBulkPtr.Value += -gbd; SourcePrimeGatePtr.Value += -gcgs; SourcePrimeBulkPtr.Value += -gbs; }