Skip to content

Commit 2c74a1f

Browse files
Merge pull request #183 from SpiceSharp/ideal_diode
Ideal diode
2 parents f7cab37 + 609edd8 commit 2c74a1f

27 files changed

Lines changed: 4930 additions & 57 deletions

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,19 @@ Using SpiceSharpParser involves three steps:
109109
| Behavioral | B (arbitrary behavioral source with V= or I= expressions) |
110110
| Switches | S (voltage-controlled), W (current-controlled) |
111111

112+
### Custom Components
113+
114+
`SpiceSharpParser.CustomComponents` adds opt-in parser mappings for LTspice-style ideal diode models:
115+
116+
```spice
117+
.model did D(Ron=0.1 Roff=1e9 Vfwd=0.7 Ilimit=10 Epsilon=10m)
118+
D1 out 0 did
119+
```
120+
121+
Enable the mappings with `reader.Settings.UseCustomComponents()` before calling `Read()`. Ideal diode models support LTspice-style `Ron`, `Roff`, `Vfwd`, `Vrev`, `Rrev`, `Ilimit`, `RevIlimit`, `Epsilon`, `RevEpsilon`, `M`, and `N` behavior, while ordinary diode models still fall back to SpiceSharp's built-in semiconductor diode.
122+
123+
See [LTspice-Style Ideal Diode](src/docs/articles/ideal-diode.md) for syntax, scaling rules, current-law details, and the optional LTspice-backed golden tests for DC, AC, and transient parity.
124+
112125
### Behavioral Modeling
113126

114127
`VALUE={expr}`, `TABLE={expr}`, `POLY(n)`, `B` sources, source-level `E` / `G` / `F` / `H` `LAPLACE` transfer functions, function-style `LAPLACE(input, transfer)` in behavioral expressions, and a full set of built-in math functions. `LAPLACE` supports voltage-controlled and current-controlled forms with rational polynomials in `s`, including finite constant `M=`, `TD=`, and `DELAY=` options. Function-style calls also support call-local options, mixed-expression helper lowering, and arbitrary scalar input expressions.

src/SpiceSharp-Parser.sln

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ VisualStudioVersion = 18.5.11612.153 insiders
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpiceSharpParser", "SpiceSharpParser\SpiceSharpParser.csproj", "{DF3DD787-71CC-4C89-9E33-DC4536A52278}"
77
EndProject
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpiceSharpParser.CustomComponents", "SpiceSharpParser.CustomComponents\SpiceSharpParser.CustomComponents.csproj", "{BC0D188B-D27A-4870-A739-A57A61D6E497}"
9+
EndProject
810
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpiceSharpParser.IntegrationTests", "SpiceSharpParser.IntegrationTests\SpiceSharpParser.IntegrationTests.csproj", "{57920E91-873B-4E66-B0EC-4CAC45007AA9}"
911
EndProject
1012
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodeAnalysis", "CodeAnalysis", "{A98DF2D4-CFE4-44F3-AD5C-21D6A0648EFD}"
@@ -32,6 +34,12 @@ Global
3234
{DF3DD787-71CC-4C89-9E33-DC4536A52278}.ERRORS|Any CPU.Build.0 = Release|Any CPU
3335
{DF3DD787-71CC-4C89-9E33-DC4536A52278}.Release|Any CPU.ActiveCfg = Release|Any CPU
3436
{DF3DD787-71CC-4C89-9E33-DC4536A52278}.Release|Any CPU.Build.0 = Release|Any CPU
37+
{BC0D188B-D27A-4870-A739-A57A61D6E497}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38+
{BC0D188B-D27A-4870-A739-A57A61D6E497}.Debug|Any CPU.Build.0 = Debug|Any CPU
39+
{BC0D188B-D27A-4870-A739-A57A61D6E497}.ERRORS|Any CPU.ActiveCfg = Release|Any CPU
40+
{BC0D188B-D27A-4870-A739-A57A61D6E497}.ERRORS|Any CPU.Build.0 = Release|Any CPU
41+
{BC0D188B-D27A-4870-A739-A57A61D6E497}.Release|Any CPU.ActiveCfg = Release|Any CPU
42+
{BC0D188B-D27A-4870-A739-A57A61D6E497}.Release|Any CPU.Build.0 = Release|Any CPU
3543
{57920E91-873B-4E66-B0EC-4CAC45007AA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
3644
{57920E91-873B-4E66-B0EC-4CAC45007AA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
3745
{57920E91-873B-4E66-B0EC-4CAC45007AA9}.ERRORS|Any CPU.ActiveCfg = Release|Any CPU
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
using SpiceSharp.Attributes;
2+
using SpiceSharp.Behaviors;
3+
using SpiceSharp.Components;
4+
using SpiceSharp.ParameterSets;
5+
using SpiceSharp.Simulations;
6+
using SpiceSharpParser.CustomComponents.IdealDiodes;
7+
using System;
8+
using System.Collections.Concurrent;
9+
using System.Collections.Generic;
10+
11+
namespace SpiceSharpParser.CustomComponents
12+
{
13+
/// <summary>
14+
/// A standalone LTspice-style ideal diode component.
15+
/// </summary>
16+
/// <seealso cref="Component" />
17+
/// <seealso cref="IParameterized{P}" />
18+
/// <seealso cref="IdealDiodeParameters" />
19+
[Pin(0, "D+"), Pin(1, "D-")]
20+
public class IdealDiode : Component<IdealDiodeParameters>
21+
{
22+
private readonly ConcurrentDictionary<ISimulation, IdealDiodeParameters> _simulationModelParameters = new ConcurrentDictionary<ISimulation, IdealDiodeParameters>();
23+
private readonly ConcurrentDictionary<ISimulation, ConcurrentDictionary<string, double>> _simulationModelParameterOverrides =
24+
new ConcurrentDictionary<ISimulation, ConcurrentDictionary<string, double>>();
25+
26+
/// <summary>
27+
/// The pin count for ideal diodes.
28+
/// </summary>
29+
[ParameterName("pincount"), ParameterInfo("Number of pins")]
30+
public const int PinCount = 2;
31+
32+
internal IdealDiodeParameters ModelParameters { get; set; }
33+
34+
internal void SetModelParameters(ISimulation simulation, IdealDiodeParameters parameters)
35+
{
36+
if (simulation == null)
37+
{
38+
ModelParameters = parameters;
39+
return;
40+
}
41+
42+
_simulationModelParameters[simulation] = parameters;
43+
}
44+
45+
internal IdealDiodeParameters GetModelParameters(ISimulation simulation)
46+
{
47+
if (simulation != null && _simulationModelParameters.TryGetValue(simulation, out var parameters))
48+
{
49+
return parameters;
50+
}
51+
52+
return ModelParameters;
53+
}
54+
55+
internal void SetModelParameterOverride(ISimulation simulation, string parameterName, double value)
56+
{
57+
if (simulation == null)
58+
{
59+
return;
60+
}
61+
62+
var overrides = _simulationModelParameterOverrides.GetOrAdd(
63+
simulation,
64+
_ => new ConcurrentDictionary<string, double>(StringComparer.OrdinalIgnoreCase));
65+
overrides[parameterName] = value;
66+
}
67+
68+
internal IEnumerable<KeyValuePair<string, double>> GetModelParameterOverrides(ISimulation simulation)
69+
{
70+
if (simulation != null && _simulationModelParameterOverrides.TryGetValue(simulation, out var overrides))
71+
{
72+
return overrides;
73+
}
74+
75+
return Array.Empty<KeyValuePair<string, double>>();
76+
}
77+
78+
/// <summary>
79+
/// Initializes a new instance of the <see cref="IdealDiode"/> class.
80+
/// </summary>
81+
/// <param name="name">The name of the device.</param>
82+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="name"/> is <c>null</c>.</exception>
83+
public IdealDiode(string name)
84+
: base(name, PinCount)
85+
{
86+
}
87+
88+
/// <summary>
89+
/// Initializes a new instance of the <see cref="IdealDiode"/> class.
90+
/// </summary>
91+
/// <param name="name">The name of the device.</param>
92+
/// <param name="anode">The anode.</param>
93+
/// <param name="cathode">The cathode.</param>
94+
/// <exception cref="ArgumentNullException">Thrown if <paramref name="name"/> is <c>null</c>.</exception>
95+
public IdealDiode(string name, string anode, string cathode)
96+
: this(name)
97+
{
98+
Connect(anode, cathode);
99+
}
100+
101+
/// <inheritdoc />
102+
public override void CreateBehaviors(ISimulation simulation)
103+
{
104+
var behaviors = new BehaviorContainer(Name);
105+
var context = new ComponentBindingContext(this, simulation, behaviors);
106+
107+
if (simulation.UsesBehaviors<IFrequencyBehavior>())
108+
{
109+
behaviors.Add(new Frequency(context, this, simulation));
110+
}
111+
else if (simulation.UsesBehaviors<IBiasingBehavior>())
112+
{
113+
behaviors.Add(new Biasing(context, this, simulation));
114+
}
115+
116+
simulation.EntityBehaviors.Add(behaviors);
117+
}
118+
}
119+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using SpiceSharp.Behaviors;
2+
using SpiceSharp.Entities;
3+
using SpiceSharp.ParameterSets;
4+
using SpiceSharp.Simulations;
5+
using SpiceSharpParser.CustomComponents.IdealDiodes;
6+
7+
namespace SpiceSharpParser.CustomComponents
8+
{
9+
/// <summary>
10+
/// Parser-side model container for LTspice-style ideal diode parameters.
11+
/// </summary>
12+
public class IdealDiodeModel : Entity<IdealDiodeParameters>
13+
{
14+
/// <summary>
15+
/// Initializes a new instance of the <see cref="IdealDiodeModel"/> class.
16+
/// </summary>
17+
/// <param name="name">The model name.</param>
18+
public IdealDiodeModel(string name)
19+
: base(name)
20+
{
21+
}
22+
23+
/// <inheritdoc />
24+
public override void CreateBehaviors(ISimulation simulation)
25+
{
26+
var behaviors = new BehaviorContainer(Name);
27+
var context = new BindingContext(this, simulation, behaviors);
28+
behaviors.Add(new IdealDiodeModelBehavior(context));
29+
30+
simulation.EntityBehaviors.Add(behaviors);
31+
}
32+
33+
private sealed class IdealDiodeModelBehavior : Behavior, IParameterized<IdealDiodeParameters>
34+
{
35+
public IdealDiodeModelBehavior(IBindingContext context)
36+
: base(context)
37+
{
38+
Parameters = context.GetParameterSet<IdealDiodeParameters>();
39+
}
40+
41+
public IdealDiodeParameters Parameters { get; }
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)