Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,19 @@ Using SpiceSharpParser involves three steps:
| Behavioral | B (arbitrary behavioral source with V= or I= expressions) |
| Switches | S (voltage-controlled), W (current-controlled) |

### Custom Components

`SpiceSharpParser.CustomComponents` adds opt-in parser mappings for LTspice-style ideal diode models:

```spice
.model did D(Ron=0.1 Roff=1e9 Vfwd=0.7 Ilimit=10 Epsilon=10m)
D1 out 0 did
```

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.

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.

### Behavioral Modeling

`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.
Expand Down
8 changes: 8 additions & 0 deletions src/SpiceSharp-Parser.sln
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ VisualStudioVersion = 18.5.11612.153 insiders
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpiceSharpParser", "SpiceSharpParser\SpiceSharpParser.csproj", "{DF3DD787-71CC-4C89-9E33-DC4536A52278}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpiceSharpParser.CustomComponents", "SpiceSharpParser.CustomComponents\SpiceSharpParser.CustomComponents.csproj", "{BC0D188B-D27A-4870-A739-A57A61D6E497}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpiceSharpParser.IntegrationTests", "SpiceSharpParser.IntegrationTests\SpiceSharpParser.IntegrationTests.csproj", "{57920E91-873B-4E66-B0EC-4CAC45007AA9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodeAnalysis", "CodeAnalysis", "{A98DF2D4-CFE4-44F3-AD5C-21D6A0648EFD}"
Expand Down Expand Up @@ -32,6 +34,12 @@ Global
{DF3DD787-71CC-4C89-9E33-DC4536A52278}.ERRORS|Any CPU.Build.0 = Release|Any CPU
{DF3DD787-71CC-4C89-9E33-DC4536A52278}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DF3DD787-71CC-4C89-9E33-DC4536A52278}.Release|Any CPU.Build.0 = Release|Any CPU
{BC0D188B-D27A-4870-A739-A57A61D6E497}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC0D188B-D27A-4870-A739-A57A61D6E497}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC0D188B-D27A-4870-A739-A57A61D6E497}.ERRORS|Any CPU.ActiveCfg = Release|Any CPU
{BC0D188B-D27A-4870-A739-A57A61D6E497}.ERRORS|Any CPU.Build.0 = Release|Any CPU
{BC0D188B-D27A-4870-A739-A57A61D6E497}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC0D188B-D27A-4870-A739-A57A61D6E497}.Release|Any CPU.Build.0 = Release|Any CPU
{57920E91-873B-4E66-B0EC-4CAC45007AA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{57920E91-873B-4E66-B0EC-4CAC45007AA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{57920E91-873B-4E66-B0EC-4CAC45007AA9}.ERRORS|Any CPU.ActiveCfg = Release|Any CPU
Expand Down
119 changes: 119 additions & 0 deletions src/SpiceSharpParser.CustomComponents/IdealDiode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
using SpiceSharp.Attributes;
using SpiceSharp.Behaviors;
using SpiceSharp.Components;
using SpiceSharp.ParameterSets;
using SpiceSharp.Simulations;
using SpiceSharpParser.CustomComponents.IdealDiodes;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace SpiceSharpParser.CustomComponents
{
/// <summary>
/// A standalone LTspice-style ideal diode component.
/// </summary>
/// <seealso cref="Component" />
/// <seealso cref="IParameterized{P}" />
/// <seealso cref="IdealDiodeParameters" />
[Pin(0, "D+"), Pin(1, "D-")]
public class IdealDiode : Component<IdealDiodeParameters>
{
private readonly ConcurrentDictionary<ISimulation, IdealDiodeParameters> _simulationModelParameters = new ConcurrentDictionary<ISimulation, IdealDiodeParameters>();
private readonly ConcurrentDictionary<ISimulation, ConcurrentDictionary<string, double>> _simulationModelParameterOverrides =
new ConcurrentDictionary<ISimulation, ConcurrentDictionary<string, double>>();

/// <summary>
/// The pin count for ideal diodes.
/// </summary>
[ParameterName("pincount"), ParameterInfo("Number of pins")]
public const int PinCount = 2;

internal IdealDiodeParameters ModelParameters { get; set; }

internal void SetModelParameters(ISimulation simulation, IdealDiodeParameters parameters)
{
if (simulation == null)
{
ModelParameters = parameters;
return;
}

_simulationModelParameters[simulation] = parameters;
}

internal IdealDiodeParameters GetModelParameters(ISimulation simulation)
{
if (simulation != null && _simulationModelParameters.TryGetValue(simulation, out var parameters))
{
return parameters;
}

return ModelParameters;
}

internal void SetModelParameterOverride(ISimulation simulation, string parameterName, double value)
{
if (simulation == null)
{
return;
}

var overrides = _simulationModelParameterOverrides.GetOrAdd(
simulation,
_ => new ConcurrentDictionary<string, double>(StringComparer.OrdinalIgnoreCase));
overrides[parameterName] = value;
}

internal IEnumerable<KeyValuePair<string, double>> GetModelParameterOverrides(ISimulation simulation)
{
if (simulation != null && _simulationModelParameterOverrides.TryGetValue(simulation, out var overrides))
{
return overrides;
}

return Array.Empty<KeyValuePair<string, double>>();
}

/// <summary>
/// Initializes a new instance of the <see cref="IdealDiode"/> class.
/// </summary>
/// <param name="name">The name of the device.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="name"/> is <c>null</c>.</exception>
public IdealDiode(string name)
: base(name, PinCount)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="IdealDiode"/> class.
/// </summary>
/// <param name="name">The name of the device.</param>
/// <param name="anode">The anode.</param>
/// <param name="cathode">The cathode.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="name"/> is <c>null</c>.</exception>
public IdealDiode(string name, string anode, string cathode)
: this(name)
{
Connect(anode, cathode);
}

/// <inheritdoc />
public override void CreateBehaviors(ISimulation simulation)
{
var behaviors = new BehaviorContainer(Name);
var context = new ComponentBindingContext(this, simulation, behaviors);

if (simulation.UsesBehaviors<IFrequencyBehavior>())
{
behaviors.Add(new Frequency(context, this, simulation));
}
else if (simulation.UsesBehaviors<IBiasingBehavior>())
{
behaviors.Add(new Biasing(context, this, simulation));
}

simulation.EntityBehaviors.Add(behaviors);
}
}
}
44 changes: 44 additions & 0 deletions src/SpiceSharpParser.CustomComponents/IdealDiodeModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using SpiceSharp.Behaviors;
using SpiceSharp.Entities;
using SpiceSharp.ParameterSets;
using SpiceSharp.Simulations;
using SpiceSharpParser.CustomComponents.IdealDiodes;

namespace SpiceSharpParser.CustomComponents
{
/// <summary>
/// Parser-side model container for LTspice-style ideal diode parameters.
/// </summary>
public class IdealDiodeModel : Entity<IdealDiodeParameters>
{
/// <summary>
/// Initializes a new instance of the <see cref="IdealDiodeModel"/> class.
/// </summary>
/// <param name="name">The model name.</param>
public IdealDiodeModel(string name)
: base(name)
{
}

/// <inheritdoc />
public override void CreateBehaviors(ISimulation simulation)
{
var behaviors = new BehaviorContainer(Name);
var context = new BindingContext(this, simulation, behaviors);
behaviors.Add(new IdealDiodeModelBehavior(context));

simulation.EntityBehaviors.Add(behaviors);
}

private sealed class IdealDiodeModelBehavior : Behavior, IParameterized<IdealDiodeParameters>
{
public IdealDiodeModelBehavior(IBindingContext context)
: base(context)
{
Parameters = context.GetParameterSet<IdealDiodeParameters>();
}

public IdealDiodeParameters Parameters { get; }
}
}
}
Loading
Loading