Skip to content

Commit f2cc2e8

Browse files
Fixes
1 parent c5252db commit f2cc2e8

6 files changed

Lines changed: 733 additions & 114 deletions

File tree

src/SpiceSharpParser.CustomComponents/IdealDiodes/Biasing.cs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ protected virtual void Load()
128128
Parameters,
129129
BiasingParameters,
130130
vd,
131-
Parameters.Area,
132131
out double cd,
133132
out double gd);
134133

@@ -196,14 +195,11 @@ bool IConvergenceBehavior.IsConvergent()
196195
/// <returns>The effective series resistance.</returns>
197196
protected double GetEffectiveSeriesResistance()
198197
{
199-
if (Parameters.Resistance <= 0.0)
200-
return 0.0;
201-
202-
double scale = Parameters.Area * Parameters.ParallelMultiplier;
203-
if (scale <= 0.0)
204-
throw new InvalidOperationException("Ideal diode area and parallel multiplier must be greater than zero when Rs is positive.");
205-
206-
return Parameters.Resistance * Parameters.SeriesMultiplier / scale;
198+
// LTspice's idealized Ron/Roff/Vfwd diode keeps Rs in the accepted
199+
// parameter set, but the idealized region-wise-linear model does not
200+
// use it electrically. Keep the internal zero-volt branch topology so
201+
// Rs can still be stepped without rebinding the component.
202+
return 0.0;
207203
}
208204

209205
/// <summary>
@@ -220,7 +216,10 @@ protected double GetTerminalConductance()
220216
return diodeConductance;
221217

222218
double seriesResistance = GetEffectiveSeriesResistance();
223-
if (diodeConductance <= 0.0 || seriesResistance <= 0.0)
219+
if (seriesResistance <= 0.0)
220+
return diodeConductance;
221+
222+
if (diodeConductance <= 0.0)
224223
return 0.0;
225224

226225
return diodeConductance / (1.0 + (diodeConductance * seriesResistance));

src/SpiceSharpParser.CustomComponents/IdealDiodes/IdealDiodeEquation.cs

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace SpiceSharpParser.CustomComponents.IdealDiodes
1010
/// <remarks>
1111
/// This helper owns only the local current law for one ideal diode cell. The
1212
/// biasing behavior that calls it handles the external branch details such as
13-
/// series resistance and the parallel/series diode multipliers.
13+
/// the parallel/series diode multipliers.
1414
///
1515
/// The current law is built from straight-line regions in slope/intercept
1616
/// form: <c>I = g * V + b</c>. The off region uses <c>Roff</c> or simulator
@@ -33,14 +33,12 @@ internal static class IdealDiodeEquation
3333
/// <param name="parameters">The effective model and instance parameters.</param>
3434
/// <param name="biasingParameters">The simulation biasing parameters, used for the default off conductance.</param>
3535
/// <param name="voltage">The local voltage across one diode cell.</param>
36-
/// <param name="area">The diode area multiplier applied after the local equation is evaluated.</param>
37-
/// <param name="current">The resulting local diode current, scaled by <paramref name="area" />.</param>
38-
/// <param name="conductance">The resulting small-signal conductance, scaled by <paramref name="area" />.</param>
36+
/// <param name="current">The resulting local diode current.</param>
37+
/// <param name="conductance">The resulting small-signal conductance.</param>
3938
public static void Evaluate(
4039
IdealDiodeParameters parameters,
4140
BiasingParameters biasingParameters,
4241
double voltage,
43-
double area,
4442
out double current,
4543
out double conductance)
4644
{
@@ -87,8 +85,8 @@ public static void Evaluate(
8785
-reverseVoltage);
8886

8987
// Evaluate the reverse-to-off knee. With revepsilon omitted or
90-
// zero this is a hard switch at the intersection; otherwise it is
91-
// smoothed symmetrically around the boundary.
88+
// zero this is a hard switch at the intersection; otherwise the
89+
// smoothing window extends from the boundary into reverse breakdown.
9290
EvaluateTransition(
9391
voltage,
9492
boundary,
@@ -97,6 +95,7 @@ public static void Evaluate(
9795
reverseIntercept,
9896
offConductance,
9997
0.0,
98+
false,
10099
out current,
101100
out conductance);
102101
}
@@ -115,12 +114,10 @@ public static void Evaluate(
115114
onIntercept,
116115
forwardVoltage);
117116

118-
// Avoid a second transition evaluation in the normal off region. For
119-
// smoothed knees, begin applying the blend at the start of the epsilon
120-
// band so the partial-conduction region is not missed.
121-
double forwardWidth = parameters.ForwardEpsilon.Given ? parameters.ForwardEpsilon.Value : 0.0;
122-
double forwardStart = forwardBoundary - (Math.Max(forwardWidth, 0.0) / 2.0);
123-
if (voltage > forwardBoundary || (forwardWidth > 0.0 && voltage >= forwardStart))
117+
// Avoid a second transition evaluation in the off or reverse regions.
118+
// LTspice-style forward epsilon starts at the boundary and extends
119+
// into forward conduction, so voltages below the boundary remain off.
120+
if (voltage >= forwardBoundary)
124121
{
125122
// Evaluate the off-to-forward knee using the same generic transition
126123
// helper used for reverse breakdown.
@@ -132,6 +129,7 @@ public static void Evaluate(
132129
0.0,
133130
onConductance,
134131
onIntercept,
132+
true,
135133
out current,
136134
out conductance);
137135
}
@@ -141,10 +139,6 @@ public static void Evaluate(
141139
// derivative by the tanh derivative.
142140
ApplyCurrentLimits(parameters, ref current, ref conductance);
143141

144-
// Area behaves like parallel identical cells: both DC current and
145-
// small-signal conductance scale linearly.
146-
current *= area;
147-
conductance *= area;
148142
}
149143

150144
/// <summary>
@@ -183,6 +177,11 @@ private static double FindIntersection(
183177
/// <param name="leftIntercept">The intercept used below the transition.</param>
184178
/// <param name="rightSlope">The slope used above the transition.</param>
185179
/// <param name="rightIntercept">The intercept used above the transition.</param>
180+
/// <param name="smoothTowardRight">
181+
/// If <c>true</c>, the smoothing window starts at <paramref name="boundary" /> and extends toward
182+
/// larger voltages. If <c>false</c>, the window ends at <paramref name="boundary" /> and extends
183+
/// toward smaller voltages.
184+
/// </param>
186185
/// <param name="current">The evaluated current.</param>
187186
/// <param name="conductance">The evaluated conductance.</param>
188187
private static void EvaluateTransition(
@@ -193,6 +192,7 @@ private static void EvaluateTransition(
193192
double leftIntercept,
194193
double rightSlope,
195194
double rightIntercept,
195+
bool smoothTowardRight,
196196
out double current,
197197
out double conductance)
198198
{
@@ -215,21 +215,33 @@ private static void EvaluateTransition(
215215
return;
216216
}
217217

218-
// The epsilon value is the full width of the blend, centered on the
219-
// natural intersection of the two lines.
220-
double start = boundary - (width / 2.0);
221-
double end = boundary + (width / 2.0);
218+
// LTspice uses epsilon as a one-sided width, not as a centered band.
219+
// Forward smoothing starts at Vfwd and moves right into the on-region;
220+
// reverse smoothing starts in the reverse region and ends at -Vrev.
221+
double start = smoothTowardRight ? boundary : boundary - width;
222+
double end = smoothTowardRight ? boundary + width : boundary;
223+
double slopeDelta = rightSlope - leftSlope;
224+
225+
// A one-sided conductance ramp shifts the fully conducting side by
226+
// half the slope change times the epsilon width. This keeps current
227+
// continuous where the ramp meets the straight-line region.
228+
double lowVoltageIntercept = smoothTowardRight
229+
? leftIntercept
230+
: leftIntercept - (slopeDelta * width / 2.0);
231+
double highVoltageIntercept = smoothTowardRight
232+
? rightIntercept - (slopeDelta * width / 2.0)
233+
: rightIntercept;
222234

223235
if (voltage <= start)
224236
{
225-
current = (leftSlope * voltage) + leftIntercept;
237+
current = (leftSlope * voltage) + lowVoltageIntercept;
226238
conductance = leftSlope;
227239
return;
228240
}
229241

230242
if (voltage >= end)
231243
{
232-
current = (rightSlope * voltage) + rightIntercept;
244+
current = (rightSlope * voltage) + highVoltageIntercept;
233245
conductance = rightSlope;
234246
return;
235247
}
@@ -243,8 +255,7 @@ private static void EvaluateTransition(
243255
//
244256
// where x is the distance from the start of the smoothing band.
245257
double distance = voltage - start;
246-
double slopeDelta = rightSlope - leftSlope;
247-
current = (leftSlope * start) + leftIntercept
258+
current = (leftSlope * start) + lowVoltageIntercept
248259
+ (leftSlope * distance)
249260
+ (slopeDelta * distance * distance / (2.0 * width));
250261
conductance = leftSlope + (slopeDelta * distance / width);

src/SpiceSharpParser.CustomComponents/IdealDiodes/IdealDiodeParameters.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public bool HasInstanceOverride(string parameterName)
9191
}
9292

9393
/// <summary>
94-
/// Gets or sets the area multiplier.
94+
/// Gets or sets the accepted diode area value. LTspice's idealized region-wise-linear diode ignores it electrically.
9595
/// </summary>
9696
[ParameterName("area"), ParameterInfo("Area factor")]
9797
[GreaterThan(0), Finite]
@@ -104,7 +104,7 @@ public bool HasInstanceOverride(string parameterName)
104104
public bool Off { get; set; }
105105

106106
/// <summary>
107-
/// Gets or sets the parasitic series resistance.
107+
/// Gets or sets the accepted series resistance value. LTspice's idealized region-wise-linear diode ignores it electrically.
108108
/// </summary>
109109
[ParameterName("rs"), ParameterInfo("Parasitic series resistance", Units = "Ohm")]
110110
[GreaterThanOrEquals(0), Finite]

0 commit comments

Comments
 (0)