/// <inheritdoc/> void IBiasingBehavior.Load() { var y = Parameters.Admittance; if (_time.UseDc) { BiasingElements.Add( y, -y, -y, y, 1, 0, -1, -1, y, -y, -y, y, 1, 0, -1, 0, 1, -1, 1, 1, 1 ); } else { BiasingElements.Add( y, -y, -y, y, 1, 1, -1, -1, y, -y, -y, y, 1, 1, -1, -1 ); } var sol = BiasingState.Solution; // Calculate inputs var input1 = sol[_pos2] - sol[_neg2] + Parameters.Impedance * sol[_br2]; var input2 = sol[_pos1] - sol[_neg1] + Parameters.Impedance * sol[_br1]; Signals.SetProbedValues(input1, input2); // Update the branch equations _elements.Add(Signals.Values[0], Signals.Values[1]); }
/// <summary> /// Load behavior. /// </summary> void IBiasingBehavior.Load() { if (_time.UseDc) { return; } _qcap.Value = _value(); _qcap.Derive(); var current = _qcap.Derivative; // _qcap.Derivative is the current as integrated by the current integration method int i; for (i = 0; i < _derivatives.Length; i++) { var g = _derivatives[i]() * _method.Slope; _values[i * 2] = g; _values[i * 2 + 1] = -g; current -= g * _derivativeVariables[i].Value; } _values[i * 2] = -current; _values[i * 2 + 1] = current; _elements.Add(_values); }
public Element AddElement(string name) { var element = new Element(this, name); ElementSet.Add(element); return(element); }
/// <inheritdoc/> void IBiasingBehavior.Load() { double value; // Time domain analysis if (_method != null) { // Use the waveform if possible if (Waveform != null) { value = Waveform.Value; } else { value = Parameters.DcValue * _iteration.SourceFactor; } } else { // AC or DC analysis use the DC value value = Parameters.DcValue * _iteration.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 _elements.Add(-value, value); Current = value; }
/// <inheritdoc/> public override void Load() { base.Load(); if (_time.UseDc) { return; } // Initialize _flux.Value = Inductance * Branch.Value; // Allow alterations of the flux if (UpdateFlux != null) { var args = new UpdateFluxEventArgs(Inductance, Branch.Value, _flux); UpdateFlux.Invoke(this, args); } // Finally load the Y-matrix _flux.Integrate(); var info = _flux.GetContributions(Inductance); _elements.Add( -info.Jacobian, info.Rhs ); }
/// <inheritdoc/> void IFrequencyBehavior.Load() { var laplace = _complex.Laplace; var factor = Complex.Exp(-laplace * Parameters.Delay); // Load the Y-matrix and RHS-vector _elements.Add(1, -1, 1, -1, -factor, factor); }
/// <inheritdoc/> void IFrequencyBehavior.Load() { // 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 var value = Parameters.Phasor * Parameters.ParallelMultiplier; _elements.Add(-value, value); }
/// <inheritdoc/> void IFrequencyBehavior.Load() { // Get the current state var gNow = CurrentState ? ModelTemperature.OnConductance : ModelTemperature.OffConductance; // Load the Y-matrix _elements.Add(gNow, -gNow, -gNow, gNow); }
/// <summary> /// Loads the Y-matrix and right hand side vector. /// </summary> void IFrequencyBehavior.Load() { for (var i = 0; i < _derivatives.Length; i++) { _values[i] = -_derivatives[i](); } _elements.Add(_values); _coreElements.Add(1.0, -1.0, 1.0, -1.0); }
/// <inheritdoc/> void IBiasingBehavior.Load() { if (_time.UseDc) { return; } // Load Y-matrix _elements.Add(-_conductance, -_conductance); }
/// <summary> /// Loads the Y-matrix and right hand side vector. /// </summary> void IFrequencyBehavior.Load() { for (var i = 0; i < _derivatives.Length; i++) { var g = _derivatives[i](); _values[i * 2] = g; _values[i * 2 + 1] = -g; } _elements.Add(_values); }
/// <summary> /// Loads the Y-matrix and right hand side vector. /// </summary> void IFrequencyBehavior.Load() { var values = new Complex[_derivatives.Length]; for (var i = 0; i < _derivatives.Length; i++) { values[i] = -_derivatives[i](); } _elements.Add(values); _coreElements.Add(1.0, -1.0, 1.0, -1.0); }
/// <summary> /// Loads the Y-matrix and right hand side vector. /// </summary> void IFrequencyBehavior.Load() { var values = new Complex[_derivatives.Length * 2]; for (var i = 0; i < _derivatives.Length; i++) { var g = _derivatives[i](); values[i * 2] = g; values[i * 2 + 1] = -g; } _elements.Add(values); }
/// <inheritdoc/> void IFrequencyBehavior.Load() { var cstate = _complex; var gcpr = ModelTemperature.CollectorConduct * Parameters.Area; var gepr = ModelTemperature.EmitterConduct * Parameters.Area; var gpi = ConductancePi; var gmu = ConductanceMu; Complex gm = Transconductance; var go = OutputConductance; var td = ModelTemperature.ExcessPhaseFactor; if (!td.Equals(0)) // Avoid computations { var arg = td * cstate.Laplace; gm += go; gm *= Complex.Exp(-arg); gm -= go; } var gx = ConductanceX; var xcpi = CapBe * cstate.Laplace; var xcmu = CapBc * cstate.Laplace; var xcbx = CapBx * cstate.Laplace; var xccs = CapCs * cstate.Laplace; var xcmcb = Geqcb * cstate.Laplace; var m = Parameters.ParallelMultiplier; _elements.Add( gcpr * m, (gx + xcbx) * m, gepr * m, (gmu + go + gcpr + xcmu + xccs + xcbx) * m, (gx + gpi + gmu + xcpi + xcmu + xcmcb) * m, (gpi + gepr + gm + go + xcpi) * m, -gcpr * m, -gx * m, -gepr * m, -gcpr * m, (-gmu + gm - xcmu) * m, (-gm - go) * m, -gx * m, (-gmu - xcmu - xcmcb) * m, (-gpi - xcpi) * m, -gepr * m, (-go + xcmcb) * m, (-gpi - gm - xcpi - xcmcb) * m, xccs * m, -xccs * m, -xccs * m, -xcbx * m, -xcbx * m); }
/// <summary> /// Loads the Y-matrix and right hand side vector. /// </summary> void IBiasingBehavior.Load() { var total = _value(); for (var i = 0; i < _derivatives.Length; i++) { var df = _derivatives[i](); total -= _derivativeVariables[i].Value * df; _values[i] = -df; } _elements.Add(_values); _coreElements.Add(1.0, -1.0, 1.0, -1.0, total); }
/// <inheritdoc/> void IFrequencyBehavior.Load() { var laplace = _complex.Laplace; var factor = Complex.Exp(-laplace * Parameters.Delay.Value); var y = Parameters.Admittance; _elements.Add( y, -y, -1, y, -1, -y, y, 1, y, 1, -1, -factor, factor, 1, -factor * Parameters.Impedance, -factor, factor, -1, 1, -factor * Parameters.Impedance, -y, -y); }
/// <inheritdoc/> protected override void Load() { base.Load(); if (_time.UseDc) { return; } // Calculate the states var vgs = Vgs; var vgd = Vgd; CalculateStates(vgs, vgd); // Integrate and add contributions _qgs.Derive(); var ggs = _qgs.GetContributions(CapGs).Jacobian; var cg = _qgs.Derivative; _qgd.Derive(); var ggd = _qgd.GetContributions(CapGd).Jacobian; cg += _qgd.Derivative; var cd = -_qgd.Derivative; var cgd = _qgd.Derivative; var m = Parameters.ParallelMultiplier; ggd *= m; ggs *= m; var ceqgd = ModelParameters.JFETType * (cgd - ggd * vgd) * m; var ceqgs = ModelParameters.JFETType * (cg - cgd - ggs * vgs) * m; var cdreq = ModelParameters.JFETType * (cd + cgd) * m; _elements.Add( // Y-matrix -ggd, -ggs, -ggd, -ggs, (ggd + ggs), ggd, ggs, // RHS vector -ceqgs - ceqgd, -cdreq + ceqgd, cdreq + ceqgs); }
/// <summary> /// Loads the Y-matrix and right hand side vector. /// </summary> void IBiasingBehavior.Load() { double[] values = new double[_derivatives.Length]; var total = Voltage = _value(); int i; for (i = 0; i < values.Length; i++) { var df = _derivatives[i](); total -= _derivativeVariables[i].Value * df; values[i] = -df; } _elements.Add(values); _coreElements.Add(1.0, -1.0, 1.0, -1.0, total); }
/// <summary> /// Loads the Y-matrix and right hand side vector. /// </summary> void IBiasingBehavior.Load() { var total = Current = _value(); int i; for (i = 0; i < _derivatives.Length; i++) { var df = _derivatives[i](); total -= _derivativeVariables[i].Value * df; _values[i * 2] = df; _values[i * 2 + 1] = -df; } _values[i * 2] = -total; _values[i * 2 + 1] = total; _elements.Add(_values); }
/// <summary> /// Loads the Y-matrix and right-hand side vector. /// </summary> public void Load() { // Let us calculate the derivatives and the current double voltage = _variableA.Value - _variableB.Value; double current = Parameters.Iss * (Math.Exp(voltage / Vte) - 1.0); double derivative = current / Vte; // Load the Y-matrix and RHS vector double rhs = current - voltage * derivative; _elements.Add( // Y-matrix contributions derivative, -derivative, -derivative, derivative, // RHS vector contributions -rhs, rhs); }
/// <inheritdoc/> void IBiasingBehavior.Load() { var sol = _biasing.Solution; var input = sol[_contPosNode] - sol[_contNegNode]; Signal.SetProbedValues(input); if (_time.UseDc) { BiasingElements.Add(1, -1, 1, -1, -1, 1); } else { BiasingElements.Add(1, -1, 1, -1); _elements.Add(Signal.Values[0]); } }
/// <inheritdoc/> void IBiasingBehavior.Load() { // Don't matter for DC analysis if (_time.UseDc) { return; } var vcap = _variables.Positive.Value - _variables.Negative.Value; // Integrate _qcap.Value = Capacitance * vcap; _qcap.Derive(); var info = _qcap.GetContributions(Capacitance); var geq = info.Jacobian; var ceq = info.Rhs; // Load matrix and rhs vector _elements.Add(geq, -geq, -geq, geq, -ceq, ceq); }
/// <inheritdoc/> void IFrequencyBehavior.Load() { var state = _complex; var gspr = ModelTemperature.Conductance * Parameters.Area; var geq = LocalConductance; var xceq = LocalCapacitance * state.Laplace.Imaginary; // Load Y-matrix var m = Parameters.ParallelMultiplier; var n = Parameters.SeriesMultiplier; geq *= m / n; gspr *= m / n; xceq *= m / n; _elements.Add( gspr, new Complex(geq, xceq), new Complex(geq + gspr, xceq), -new Complex(geq, xceq), -new Complex(geq, xceq), -gspr, -gspr); }
/// <summary> /// Load the Y-matrix and Rhs-vector. /// </summary> void IBiasingBehavior.Load() { // First get the current iteration voltage var v = _nodeA.Value - _nodeB.Value; // Calculate the derivative w.r.t. one of the voltages var isNegative = v < 0; var c = Math.Pow(Math.Abs(v) / _bp.A, 1.0 / _bp.B); double g; // If v=0 the derivative is either 0 or infinity (avoid 0^(negative number) = not a number) if (v.Equals(0.0)) { g = _bp.B < 1.0 / _bp.A ? double.PositiveInfinity : 0.0; } else { g = Math.Pow(Math.Abs(v) / _bp.A, 1.0 / _bp.B - 1.0) / _bp.A; } // In order to avoid having a singular matrix, we want to have at least a very small value here. g = Math.Max(g, _baseConfig.Gmin); // If the voltage was reversed, reverse the current back if (isNegative) { c = -c; } // Load the RHS vector c -= g * v; _elements.Add( // Y-matrix g, -g, -g, g, // RHS-vector c, -c); }
/// <inheritdoc/> void IBiasingBehavior.Load() { var m = Parameters.ParallelMultiplier; var y = Parameters.Admittance * m; var sol = BiasingState.Solution; // Calculate inputs var z = Parameters.Impedance / m; var input1 = sol[_pos2] - sol[_neg2] + z * sol[_br2]; var input2 = sol[_pos1] - sol[_neg1] + z * sol[_br1]; Signals.SetProbedValues(input1, input2); // Apply contributions to the Y-matrix and right-hand side vector if (_time.UseDc) { BiasingElements.Add( y, -y, -y, y, 1, 0, -1, -1, y, -y, -y, y, 1, 0, -1, 0, 1, -1, 1, 1, 1 ); } else { BiasingElements.Add( y, -y, -y, y, 1, 1, -1, -1, y, -y, -y, y, 1, 1, -1, -1 ); } double c = Signals.InputDerivative; double d = -c * z; _elements.Add( -c, c, d, -c, c, d, Signals.Values[0], Signals.Values[1]); }
/// <inheritdoc/> void IBiasingBehavior.Load() { double value; if (_method != null) { // Use the waveform if possible if (Waveform != null) { value = Waveform.Value; } else { value = Parameters.DcValue * _iteration.SourceFactor; } } else { value = Parameters.DcValue * _iteration.SourceFactor; } Voltage = value; _elements.Add(1, 1, -1, -1, value); }
/// <inheritdoc/> void IBiasingBehavior.Load() { var con = _contributions; con.Reset(); var vt = Constants.KOverQ * Parameters.Temperature; double DrainSatCur, SourceSatCur; if ((Properties.TempSatCurDensity == 0) || (Parameters.DrainArea == 0) || (Parameters.SourceArea == 0)) { DrainSatCur = Parameters.ParallelMultiplier * Properties.TempSatCur; SourceSatCur = Parameters.ParallelMultiplier * Properties.TempSatCur; } else { DrainSatCur = Parameters.ParallelMultiplier * Properties.TempSatCurDensity * Parameters.DrainArea; SourceSatCur = Parameters.ParallelMultiplier * Properties.TempSatCurDensity * Parameters.SourceArea; } var Beta = Properties.TempTransconductance * Parameters.Width * Parameters.ParallelMultiplier / Properties.EffectiveLength; // Get the current voltages Initialize(out var vgs, out var vds, out var vbs, out var check); var vbd = vbs - vds; var vgd = vgs - vds; if (vbs <= -3 * vt) { con.Bs.G = _config.Gmin; con.Bs.C = con.Bs.G * vbs - SourceSatCur; } else { var evbs = Math.Exp(Math.Min(MaximumExponentArgument, vbs / vt)); con.Bs.G = SourceSatCur * evbs / vt + _config.Gmin; con.Bs.C = SourceSatCur * (evbs - 1) + _config.Gmin * vbs; } if (vbd <= -3 * vt) { con.Bd.G = _config.Gmin; con.Bd.C = con.Bd.G * vbd - DrainSatCur; } else { var evbd = Math.Exp(Math.Min(MaximumExponentArgument, vbd / vt)); con.Bd.G = DrainSatCur * evbd / vt + _config.Gmin; con.Bd.C = DrainSatCur * (evbd - 1) + _config.Gmin * vbd; } if (vds >= 0) { Mode = 1; } else { Mode = -1; } // An example out in the wild once-good, now-bad spaghetti code... Not touching this too much. { /* moseq2(vds,vbs,vgs,gm,gds,gmbs,qg,qc,qb, * cggb,cgdb,cgsb,cbgb,cbdb,cbsb) */ // Note: cgdb, cgsb, cbdb, cbsb never used /* * this routine evaluates the drain current, its derivatives and * the charges associated with the gate, channel and bulk * for mosfets * */ double arg; double sarg; double[] a4 = new double[4], b4 = new double[4], x4 = new double[8], poly4 = new double[8]; double beta1; double dsrgdb; double d2sdb2; double barg; double d2bdb2; double factor; double dbrgdb; double eta; double vbin; double argd = 0.0; double args = 0.0; double argss; double argsd; double argxs = 0.0; double argxd = 0.0; double daddb2; double dasdb2; double dbargd; double dbargs; double dbxwd; double dbxws; double dgddb2; double dgddvb; double dgdvds; double gamasd; double xwd; double xws; double ddxwd; double gammad; double vth; double cfs; double cdonco; double xn = 0.0; double argg = 0.0; double vgst; double sarg3; double sbiarg; double dgdvbs; double body; double gdbdv; double dodvbs; double dodvds = 0.0; double dxndvd = 0.0; double dxndvb = 0.0; double udenom; double dudvgs; double dudvds; double dudvbs; double gammd2; double argv; double vgsx; double ufact; double ueff; double dsdvgs; double dsdvbs; double a1; double a3; double a; double b1; double b3; double b; double c1; double c; double d1; double fi; double p0; double p2; double p3; double p4; double p; double r3; double r; double ro; double s2; double s; double v1; double v2; double xv; double y3; double delta4; double xvalid = 0; double bsarg = 0; double dbsrdb; double bodys = 0; double gdbdvs = 0; double sargv; double xlfact; double dldsat; double xdv; double xlv; double vqchan; double dqdsat; double vl; double dfundg; double dfunds; double dfundb; double xls; double dldvgs; double dldvds; double dldvbs; double dfact; double clfact; double xleff; double deltal; double xwb; double vdson; double cdson; double didvds; double gdson; double gmw; double gbson; double expg; double xld; double xlamda = ModelParameters.Lambda; /* 'local' variables - these switch d & s around appropriately * so that we don't have to worry about vds < 0 */ double lvbs = Mode == 1 ? vbs : vbd; double lvds = Mode * vds; double lvgs = Mode == 1 ? vgs : vgd; double phiMinVbs = Properties.TempPhi - lvbs; double tmp; /* a temporary variable, not used for more than */ /* about 10 lines at a time */ int iknt; int jknt; int i; int j; double sphi; double sphi3; /* * compute some useful quantities */ if (lvbs <= 0.0) { sarg = Math.Sqrt(phiMinVbs); dsrgdb = -0.5 / sarg; d2sdb2 = 0.5 * dsrgdb / phiMinVbs; } else { sphi = Math.Sqrt(Properties.TempPhi); sphi3 = Properties.TempPhi * sphi; sarg = sphi / (1.0 + 0.5 * lvbs / Properties.TempPhi); tmp = sarg / sphi3; dsrgdb = -0.5 * sarg * tmp; d2sdb2 = -dsrgdb * tmp; } if ((lvbs - lvds) <= 0) { barg = Math.Sqrt(phiMinVbs + lvds); dbrgdb = -0.5 / barg; d2bdb2 = 0.5 * dbrgdb / (phiMinVbs + lvds); } else { sphi = Math.Sqrt(Properties.TempPhi); /* added by HT 050523 */ sphi3 = Properties.TempPhi * sphi; /* added by HT 050523 */ barg = sphi / (1.0 + 0.5 * (lvbs - lvds) / Properties.TempPhi); tmp = barg / sphi3; dbrgdb = -0.5 * barg * tmp; d2bdb2 = -dbrgdb * tmp; } /* * calculate threshold voltage (von) * narrow-channel effect */ // XXX constant per device factor = 0.125 * ModelParameters.NarrowFactor * 2.0 * Math.PI * EpsilonSilicon / Properties.OxideCap * Properties.EffectiveLength; // XXX constant per device eta = 1.0 + factor; vbin = Properties.TempVbi * ModelParameters.MosfetType + factor * phiMinVbs; if ((ModelParameters.Gamma > 0.0) || (ModelParameters.SubstrateDoping > 0.0)) { xwd = ModelTemperature.Properties.Xd * barg; xws = ModelTemperature.Properties.Xd * sarg; // Short-channel effect with vds .ne. 0.0 argss = 0.0; argsd = 0.0; dbargs = 0.0; dbargd = 0.0; dgdvds = 0.0; dgddb2 = 0.0; if (ModelParameters.JunctionDepth > 0) { tmp = 2.0 / ModelParameters.JunctionDepth; argxs = 1.0 + xws * tmp; argxd = 1.0 + xwd * tmp; args = Math.Sqrt(argxs); argd = Math.Sqrt(argxd); tmp = .5 * ModelParameters.JunctionDepth / Properties.EffectiveLength; argss = tmp * (args - 1.0); argsd = tmp * (argd - 1.0); } gamasd = ModelParameters.Gamma * (1.0 - argss - argsd); dbxwd = ModelTemperature.Properties.Xd * dbrgdb; dbxws = ModelTemperature.Properties.Xd * dsrgdb; if (ModelParameters.JunctionDepth > 0) { tmp = 0.5 / Properties.EffectiveLength; dbargs = tmp * dbxws / args; dbargd = tmp * dbxwd / argd; dasdb2 = -ModelTemperature.Properties.Xd * (d2sdb2 + dsrgdb * dsrgdb * ModelTemperature.Properties.Xd / (ModelParameters.JunctionDepth * argxs)) / (Properties.EffectiveLength * args); daddb2 = -ModelTemperature.Properties.Xd * (d2bdb2 + dbrgdb * dbrgdb * ModelTemperature.Properties.Xd / (ModelParameters.JunctionDepth * argxd)) / (Properties.EffectiveLength * argd); dgddb2 = -0.5 * ModelParameters.Gamma * (dasdb2 + daddb2); } dgddvb = -ModelParameters.Gamma * (dbargs + dbargd); if (ModelParameters.JunctionDepth > 0) { ddxwd = -dbxwd; dgdvds = -ModelParameters.Gamma * 0.5 * ddxwd / (Properties.EffectiveLength * argd); } } else { gamasd = ModelParameters.Gamma; dgddvb = 0.0; dgdvds = 0.0; dgddb2 = 0.0; } var von = vbin + gamasd * sarg; vth = von; var vdsat = 0.0; if (ModelParameters.FastSurfaceStateDensity != 0.0 && Properties.OxideCap != 0.0) { // XXX constant per model cfs = Constants.Charge * ModelParameters.FastSurfaceStateDensity * 1e4 /*(cm**2/m**2)*/; cdonco = -(gamasd * dsrgdb + dgddvb * sarg) + factor; xn = 1.0 + cfs / Properties.OxideCap * Parameters.ParallelMultiplier * Parameters.Width * Properties.EffectiveLength + cdonco; tmp = vt * xn; von += tmp; argg = 1.0 / tmp; vgst = lvgs - von; } else { vgst = lvgs - von; if (lvgs <= vbin) { // Cutoff region con.Ds.G = 0.0; goto line1050; } } /* * compute some more useful quantities */ sarg3 = sarg * sarg * sarg; /* XXX constant per model */ sbiarg = Math.Sqrt(Properties.TempBulkPotential); gammad = gamasd; dgdvbs = dgddvb; body = barg * barg * barg - sarg3; gdbdv = 2.0 * gammad * (barg * barg * dbrgdb - sarg * sarg * dsrgdb); dodvbs = -factor + dgdvbs * sarg + gammad * dsrgdb; if (ModelParameters.FastSurfaceStateDensity == 0.0) { goto line400; } if (Properties.OxideCap == 0.0) { goto line410; } dxndvb = 2.0 * dgdvbs * dsrgdb + gammad * d2sdb2 + dgddb2 * sarg; dodvbs += vt * dxndvb; dxndvd = dgdvds * dsrgdb; dodvds = dgdvds * sarg + vt * dxndvd; /* * evaluate effective mobility and its derivatives */ line400: if (Properties.OxideCap <= 0.0) { goto line410; } udenom = vgst; tmp = ModelParameters.CriticalField * 100 /* cm/m */ * EpsilonSilicon / ModelTemperature.Properties.OxideCapFactor; if (udenom <= tmp) { goto line410; } ufact = Math.Exp(ModelParameters.CriticalFieldExp * Math.Log(tmp / udenom)); ueff = ModelParameters.SurfaceMobility * 1e-4 /*(m**2/cm**2) */ * ufact; dudvgs = -ufact * ModelParameters.CriticalFieldExp / udenom; dudvds = 0.0; dudvbs = ModelParameters.CriticalFieldExp * ufact * dodvbs / vgst; goto line500; line410: ufact = 1.0; ueff = ModelParameters.SurfaceMobility * 1e-4 /*(m**2/cm**2) */; dudvgs = 0.0; dudvds = 0.0; dudvbs = 0.0; /* * evaluate saturation voltage and its derivatives according to * grove-frohman equation */ line500: vgsx = lvgs; gammad = gamasd / eta; dgdvbs = dgddvb; if (ModelParameters.FastSurfaceStateDensity != 0 && Properties.OxideCap != 0) { vgsx = Math.Max(lvgs, von); } if (gammad > 0) { gammd2 = gammad * gammad; argv = (vgsx - vbin) / eta + phiMinVbs; if (argv <= 0.0) { vdsat = 0.0; dsdvgs = 0.0; dsdvbs = 0.0; } else { arg = Math.Sqrt(1.0 + 4.0 * argv / gammd2); vdsat = (vgsx - vbin) / eta + gammd2 * (1.0 - arg) / 2.0; vdsat = Math.Max(vdsat, 0.0); dsdvgs = (1.0 - 1.0 / arg) / eta; dsdvbs = (gammad * (1.0 - arg) + 2.0 * argv / (gammad * arg)) / eta * dgdvbs + 1.0 / arg + factor * dsdvgs; } } else { vdsat = (vgsx - vbin) / eta; vdsat = Math.Max(vdsat, 0.0); dsdvgs = 1.0; dsdvbs = 0.0; } if (ModelParameters.MaxDriftVelocity > 0) { /* * evaluate saturation voltage and its derivatives * according to baum's theory of scattering velocity * saturation */ v1 = (vgsx - vbin) / eta + phiMinVbs; v2 = phiMinVbs; xv = ModelParameters.MaxDriftVelocity * Properties.EffectiveLength / ueff; a1 = gammad / 0.75; b1 = -2.0 * (v1 + xv); c1 = -2.0 * gammad * xv; d1 = 2.0 * v1 * (v2 + xv) - v2 * v2 - 4.0 / 3.0 * gammad * sarg3; a = -b1; b = a1 * c1 - 4.0 * d1; c = -d1 * (a1 * a1 - 4.0 * b1) - c1 * c1; r = -a * a / 3.0 + b; s = 2.0 * a * a * a / 27.0 - a * b / 3.0 + c; r3 = r * r * r; s2 = s * s; p = s2 / 4.0 + r3 / 27.0; p0 = Math.Abs(p); p2 = Math.Sqrt(p0); if (p < 0) { ro = Math.Sqrt(s2 / 4.0 + p0); ro = Math.Log(ro) / 3.0; ro = Math.Exp(ro); fi = Math.Atan(-2.0 * p2 / s); y3 = 2.0 * ro * Math.Cos(fi / 3.0) - a / 3.0; } else { p3 = -s / 2.0 + p2; p3 = Math.Exp(Math.Log(Math.Abs(p3)) / 3.0); p4 = -s / 2.0 - p2; p4 = Math.Exp(Math.Log(Math.Abs(p4)) / 3.0); y3 = p3 + p4 - a / 3.0; } iknt = 0; a3 = Math.Sqrt(a1 * a1 / 4.0 - b1 + y3); b3 = Math.Sqrt(y3 * y3 / 4.0 - d1); for (i = 1; i <= 4; i++) { a4[i - 1] = a1 / 2.0 + _sig1[i - 1] * a3; b4[i - 1] = y3 / 2.0 + _sig2[i - 1] * b3; delta4 = a4[i - 1] * a4[i - 1] / 4.0 - b4[i - 1]; if (delta4 < 0) { continue; } iknt += 1; tmp = Math.Sqrt(delta4); x4[iknt - 1] = -a4[i - 1] / 2.0 + tmp; iknt += 1; x4[iknt - 1] = -a4[i - 1] / 2.0 - tmp; } jknt = 0; for (j = 1; j <= iknt; j++) { if (x4[j - 1] <= 0) { continue; } /* XXX implement this sanely */ poly4[j - 1] = x4[j - 1] * x4[j - 1] * x4[j - 1] * x4[j - 1] + a1 * x4[j - 1] * x4[j - 1] * x4[j - 1]; poly4[j - 1] = poly4[j - 1] + b1 * x4[j - 1] * x4[j - 1] + c1 * x4[j - 1] + d1; if (Math.Abs(poly4[j - 1]) > 1.0e-6) { continue; } jknt += 1; if (jknt <= 1) { xvalid = x4[j - 1]; } if (x4[j - 1] > xvalid) { continue; } xvalid = x4[j - 1]; } if (jknt > 0) { vdsat = xvalid * xvalid - phiMinVbs; } } // Evaluate effective channel length and its derivatives if (lvds != 0.0) { gammad = gamasd; if ((lvbs - vdsat) <= 0) { bsarg = Math.Sqrt(vdsat + phiMinVbs); dbsrdb = -0.5 / bsarg; } else { sphi = Math.Sqrt(Properties.TempPhi); /* added by HT 050523 */ sphi3 = Properties.TempPhi * sphi; /* added by HT 050523 */ bsarg = sphi / (1.0 + 0.5 * (lvbs - vdsat) / Properties.TempPhi); dbsrdb = -0.5 * bsarg * bsarg / sphi3; } bodys = bsarg * bsarg * bsarg - sarg3; gdbdvs = 2.0 * gammad * (bsarg * bsarg * dbsrdb - sarg * sarg * dsrgdb); if (ModelParameters.MaxDriftVelocity <= 0) { if (ModelParameters.SubstrateDoping == 0.0 || xlamda > 0.0) { dldvgs = 0.0; dldvds = 0.0; dldvbs = 0.0; } else { argv = (lvds - vdsat) / 4.0; sargv = Math.Sqrt(1.0 + argv * argv); arg = Math.Sqrt(argv + sargv); xlfact = ModelTemperature.Properties.Xd / (Properties.EffectiveLength * lvds); xlamda = xlfact * arg; dldsat = lvds * xlamda / (8.0 * sargv); dldvgs = dldsat * dsdvgs; dldvds = -xlamda + dldsat; dldvbs = dldsat * dsdvbs; } } else { argv = (vgsx - vbin) / eta - vdsat; xdv = ModelTemperature.Properties.Xd / Math.Sqrt(ModelParameters.ChannelCharge); xlv = ModelParameters.MaxDriftVelocity * xdv / (2.0 * ueff); vqchan = argv - gammad * bsarg; dqdsat = -1.0 + gammad * dbsrdb; vl = ModelParameters.MaxDriftVelocity * Properties.EffectiveLength; dfunds = vl * dqdsat - ueff * vqchan; dfundg = (vl - ueff * vdsat) / eta; dfundb = -vl * (1.0 + dqdsat - factor / eta) + ueff * (gdbdvs - dgdvbs * bodys / 1.5) / eta; dsdvgs = -dfundg / dfunds; dsdvbs = -dfundb / dfunds; if (ModelParameters.SubstrateDoping == 0.0 || xlamda > 0.0) { dldvgs = 0.0; dldvds = 0.0; dldvbs = 0.0; } else { argv = lvds - vdsat; argv = Math.Max(argv, 0.0); xls = Math.Sqrt(xlv * xlv + argv); dldsat = xdv / (2.0 * xls); xlfact = xdv / (Properties.EffectiveLength * lvds); xlamda = xlfact * (xls - xlv); dldsat /= Properties.EffectiveLength; dldvgs = dldsat * dsdvgs; dldvds = -xlamda + dldsat; dldvbs = dldsat * dsdvbs; } } } else { dldvgs = 0.0; dldvds = 0.0; dldvbs = 0.0; } /* * limit channel shortening at punch-through */ xwb = ModelTemperature.Properties.Xd * sbiarg; xld = Properties.EffectiveLength - xwb; clfact = 1.0 - xlamda * lvds; dldvds = -xlamda - dldvds; xleff = Properties.EffectiveLength * clfact; deltal = xlamda * lvds * Properties.EffectiveLength; if (ModelParameters.SubstrateDoping == 0.0) { xwb = 0.25e-6; } if (xleff < xwb) { xleff = xwb / (1.0 + (deltal - xld) / xwb); clfact = xleff / Properties.EffectiveLength; dfact = xleff * xleff / (xwb * xwb); dldvgs = dfact * dldvgs; dldvds = dfact * dldvds; dldvbs = dfact * dldvbs; } // Evaluate effective beta (effective kp) beta1 = Beta * ufact / clfact; // Test for mode of operation and branch appropriately gammad = gamasd; dgdvbs = dgddvb; if (lvds <= 1.0e-10) { if (lvgs <= von) { if ((ModelParameters.FastSurfaceStateDensity == 0.0) || (Properties.OxideCap == 0.0)) { con.Ds.G = 0.0; goto line1050; } con.Ds.G = beta1 * (von - vbin - gammad * sarg) * Math.Exp(argg * (lvgs - von)); goto line1050; } con.Ds.G = beta1 * (lvgs - vbin - gammad * sarg); goto line1050; } if (ModelParameters.FastSurfaceStateDensity != 0 && Properties.OxideCap != 0) { if (lvgs > von) { goto line900; } } else { if (lvgs > vbin) { goto line900; } goto doneval; } if (lvgs > von) { goto line900; } // Subthreshold region if (vdsat <= 0) { con.Ds.G = 0.0; if (lvgs > vth) { goto doneval; } goto line1050; } vdson = Math.Min(vdsat, lvds); if (lvds > vdsat) { barg = bsarg; body = bodys; gdbdv = gdbdvs; } cdson = beta1 * ((von - vbin - eta * vdson * 0.5) * vdson - gammad * body / 1.5); didvds = beta1 * (von - vbin - eta * vdson - gammad * barg); gdson = -cdson * dldvds / clfact - beta1 * dgdvds * body / 1.5; if (lvds < vdsat) { gdson += didvds; } gbson = -cdson * dldvbs / clfact + beta1 * (dodvbs * vdson + factor * vdson - dgdvbs * body / 1.5 - gdbdv); if (lvds > vdsat) { gbson += didvds * dsdvbs; } expg = Math.Exp(argg * (lvgs - von)); con.Ds.C = cdson * expg; gmw = con.Ds.C * argg; Gm = gmw; if (lvds > vdsat) { Gm = gmw + didvds * dsdvgs * expg; } tmp = gmw * (lvgs - von) / xn; con.Ds.G = gdson * expg - Gm * dodvds - tmp * dxndvd; Gmbs = gbson * expg - Gm * dodvbs - tmp * dxndvb; goto doneval; line900: if (lvds <= vdsat) { // Linear region con.Ds.C = beta1 * ((lvgs - vbin - eta * lvds / 2.0) * lvds - gammad * body / 1.5); arg = con.Ds.C * (dudvgs / ufact - dldvgs / clfact); Gm = arg + beta1 * lvds; arg = con.Ds.C * (dudvds / ufact - dldvds / clfact); con.Ds.G = arg + beta1 * (lvgs - vbin - eta * lvds - gammad * barg - dgdvds * body / 1.5); arg = con.Ds.C * (dudvbs / ufact - dldvbs / clfact); Gmbs = arg - beta1 * (gdbdv + dgdvbs * body / 1.5 - factor * lvds); } else { // Saturation region con.Ds.C = beta1 * ((lvgs - vbin - eta * vdsat / 2.0) * vdsat - gammad * bodys / 1.5); arg = con.Ds.C * (dudvgs / ufact - dldvgs / clfact); Gm = arg + beta1 * vdsat + beta1 * (lvgs - vbin - eta * vdsat - gammad * bsarg) * dsdvgs; con.Ds.G = -con.Ds.C * dldvds / clfact - beta1 * dgdvds * bodys / 1.5; arg = con.Ds.C * (dudvbs / ufact - dldvbs / clfact); Gmbs = arg - beta1 * (gdbdvs + dgdvbs * bodys / 1.5 - factor * vdsat) + beta1 * (lvgs - vbin - eta * vdsat - gammad * bsarg) * dsdvbs; } // Compute charges for "on" region goto doneval; // Finish special cases line1050: con.Ds.C = 0.0; Gm = 0.0; Gmbs = 0.0; // Finished doneval: Von = ModelParameters.MosfetType * von; Vdsat = ModelParameters.MosfetType * vdsat; } // COMPUTE EQUIVALENT DRAIN CURRENT SOURCE Gds = con.Ds.G; Id = Mode * con.Ds.C - con.Bd.C; Vbs = vbs; Vbd = vbd; Vgs = vgs; Vds = vds; // Update with time-dependent calculations UpdateContributions?.Invoke(this, _args); // Check convergence if (!Parameters.Off && _iteration.Mode != IterationModes.Fix) { if (check) { _iteration.IsConvergent = false; } } Gbs = con.Bs.G; Ibs = con.Bs.C; Gbd = con.Bd.G; Ibd = con.Bd.C; // Right hand side contributions double xnrm, xrev; con.Bs.C = ModelParameters.MosfetType * (con.Bs.C - con.Bs.G * vbs); con.Bd.C = ModelParameters.MosfetType * (con.Bd.C - con.Bd.G * vbd); if (Mode >= 0) { xnrm = 1; xrev = 0; con.Ds.C = ModelParameters.MosfetType * (con.Ds.C - con.Ds.G * vds - Gm * vgs - Gmbs * vbs); } else { xnrm = 0; xrev = 1; con.Ds.C = -ModelParameters.MosfetType * (con.Ds.C - con.Ds.G * (-vds) - Gm * vgd - Gmbs * vbd); } _elements.Add( // Y-matrix Properties.DrainConductance, con.Gd.G + con.Gs.G + con.Gb.G, Properties.SourceConductance, con.Bd.G + con.Bs.G + con.Gb.G, Properties.DrainConductance + con.Ds.G + con.Bd.G + xrev * (Gm + Gmbs) + con.Gd.G, Properties.SourceConductance + con.Ds.G + con.Bs.G + xnrm * (Gm + Gmbs) + con.Gs.G, -Properties.DrainConductance, -con.Gb.G, -con.Gd.G, -con.Gs.G, -Properties.SourceConductance, -con.Gb.G, -con.Bd.G, -con.Bs.G, -Properties.DrainConductance, (xnrm - xrev) * Gm - con.Gd.G, -con.Bd.G + (xnrm - xrev) * Gmbs, -con.Ds.G - xnrm * (Gm + Gmbs), -(xnrm - xrev) * Gm - con.Gs.G, -Properties.SourceConductance, -con.Bs.G - (xnrm - xrev) * Gmbs, -con.Ds.G - xrev * (Gm + Gmbs), // Right hand side vector -ModelParameters.MosfetType * (con.Gs.C + con.Gb.C + con.Gd.C), -(con.Bs.C + con.Bd.C - ModelParameters.MosfetType * con.Gb.C), con.Bd.C - con.Ds.C + ModelParameters.MosfetType * con.Gd.C, con.Ds.C + con.Bs.C + ModelParameters.MosfetType * con.Gs.C ); }
/// <inheritdoc/> void IFrequencyBehavior.Load() { var value = Parameters.Transconductance; _elements.Add(value, -value, -value, value); }
/// <inheritdoc/> void IBiasingBehavior.Load() { var con = _contributions; con.Reset(); var vt = Constants.KOverQ * Parameters.Temperature; double DrainSatCur, SourceSatCur; if ((Properties.TempSatCurDensity == 0) || (Parameters.DrainArea == 0) || (Parameters.SourceArea == 0)) { DrainSatCur = Parameters.ParallelMultiplier * Properties.TempSatCur; SourceSatCur = Parameters.ParallelMultiplier * Properties.TempSatCur; } else { DrainSatCur = Properties.TempSatCurDensity * Parameters.ParallelMultiplier * Parameters.DrainArea; SourceSatCur = Properties.TempSatCurDensity * Parameters.ParallelMultiplier * Parameters.SourceArea; } var Beta = Properties.TempTransconductance * Parameters.ParallelMultiplier * Parameters.Width / Properties.EffectiveLength; // Get the current voltages Initialize(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 <= -3 * vt) { con.Bs.G = _config.Gmin; con.Bs.C = con.Bs.G * vbs - SourceSatCur; } else { var evbs = Math.Exp(Math.Min(MaximumExponentArgument, vbs / vt)); con.Bs.G = SourceSatCur * evbs / vt + _config.Gmin; con.Bs.C = SourceSatCur * (evbs - 1) + _config.Gmin * vbs; } if (vbd <= -3 * vt) { con.Bd.G = _config.Gmin; con.Bd.C = con.Bd.G * vbd - DrainSatCur; } else { var evbd = Math.Exp(Math.Min(MaximumExponentArgument, vbd / vt)); con.Bd.G = DrainSatCur * evbd / vt + _config.Gmin; con.Bd.C = DrainSatCur * (evbd - 1) + _config.Gmin * vbd; } // Now to determine whether the user was able to correctly identify the source and drain of his device if (vds >= 0) { Mode = 1; } else { Mode = -1; } { /* * this block of code evaluates the drain current and its * derivatives using the shichman-hodges model and the * charges associated with the gate, channel and bulk for * mosfets * */ /* the following 4 variables are local to this code block until * it is obvious that they can be made global */ double arg; double betap; double sarg; double vgst; if ((Mode > 0 ? vbs : vbd) <= 0) { sarg = Math.Sqrt(Properties.TempPhi - (Mode > 0 ? vbs : vbd)); } else { sarg = Math.Sqrt(Properties.TempPhi); sarg -= (Mode > 0 ? vbs : vbd) / (sarg + sarg); sarg = Math.Max(0, sarg); } var von = (Properties.TempVbi * ModelParameters.MosfetType) + ModelParameters.Gamma * sarg; vgst = (Mode > 0 ? vgs : vgd) - von; var vdsat = Math.Max(vgst, 0); if (sarg <= 0) { arg = 0; } else { arg = ModelParameters.Gamma / (sarg + sarg); } if (vgst <= 0) { // Cutoff region con.Ds.C = 0; Gm = 0; con.Ds.G = 0; Gmbs = 0; } else { // Saturation region betap = Beta * (1 + ModelParameters.Lambda * (vds * Mode)); if (vgst <= (vds * Mode)) { con.Ds.C = betap * vgst * vgst * .5; Gm = betap * vgst; con.Ds.G = ModelParameters.Lambda * Beta * vgst * vgst * .5; Gmbs = Gm * arg; } else { // Linear region con.Ds.C = betap * (vds * Mode) * (vgst - .5 * (vds * Mode)); Gm = betap * (vds * Mode); con.Ds.G = betap * (vgst - (vds * Mode)) + ModelParameters.Lambda * Beta * (vds * Mode) * (vgst - .5 * (vds * Mode)); Gmbs = Gm * arg; } } // now deal with n vs p polarity Von = ModelParameters.MosfetType * von; Vdsat = ModelParameters.MosfetType * vdsat; } // COMPUTE EQUIVALENT DRAIN CURRENT SOURCE Gds = con.Ds.G; Id = Mode * con.Ds.C - con.Bd.C; Vbs = vbs; Vbd = vbd; Vgs = vgs; Vds = vds; // Update with time-dependent calculations UpdateContributions?.Invoke(this, _args); // Check convergence if (!Parameters.Off && _iteration.Mode != IterationModes.Fix) { if (check) { _iteration.IsConvergent = false; } } Gbs = con.Bs.G; Ibs = con.Bs.C; Gbd = con.Bd.G; Ibd = con.Bd.C; // Right hand side vector contributions con.Bs.C = ModelParameters.MosfetType * (con.Bs.C - con.Bs.G * vbs); con.Bd.C = ModelParameters.MosfetType * (con.Bd.C - con.Bd.G * vbd); double xnrm, xrev; if (Mode >= 0) { xnrm = 1; xrev = 0; con.Ds.C = ModelParameters.MosfetType * (con.Ds.C - con.Ds.G * vds - Gm * vgs - Gmbs * vbs); } else { xnrm = 0; xrev = 1; con.Ds.C = -ModelParameters.MosfetType * (con.Ds.C - con.Ds.G * (-vds) - Gm * vgd - Gmbs * vbd); } _elements.Add( // Y-matrix Properties.DrainConductance, con.Gd.G + con.Gs.G + con.Gb.G, Properties.SourceConductance, con.Bd.G + con.Bs.G + con.Gb.G, Properties.DrainConductance + con.Ds.G + con.Bd.G + xrev * (Gm + Gmbs) + con.Gd.G, Properties.SourceConductance + con.Ds.G + con.Bs.G + xnrm * (Gm + Gmbs) + con.Gs.G, -Properties.DrainConductance, -con.Gb.G, -con.Gd.G, -con.Gs.G, -Properties.SourceConductance, -con.Gb.G, -con.Bd.G, -con.Bs.G, -Properties.DrainConductance, (xnrm - xrev) * Gm - con.Gd.G, -con.Bd.G + (xnrm - xrev) * Gmbs, -con.Ds.G - xnrm * (Gm + Gmbs), -(xnrm - xrev) * Gm - con.Gs.G, -Properties.SourceConductance, -con.Bs.G - (xnrm - xrev) * Gmbs, -con.Ds.G - xrev * (Gm + Gmbs), // Right hand side vector -ModelParameters.MosfetType * (con.Gs.C + con.Gb.C + con.Gd.C), -(con.Bs.C + con.Bd.C - ModelParameters.MosfetType * con.Gb.C), con.Bd.C - con.Ds.C + ModelParameters.MosfetType * con.Gd.C, con.Ds.C + con.Bs.C + ModelParameters.MosfetType * con.Gs.C ); }
/// <inheritdoc/> void IBiasingBehavior.Load() { var val = Parameters.Coefficient; _elements.Add(1, -1, 1, -1, -val, val); }