Skip to content

Commit aa74a4b

Browse files
Added LTspice-mode synthesis for L instance Rser, Lser, Rpar, RLshunt, and Cpar
1 parent cdb9b68 commit aa74a4b

6 files changed

Lines changed: 387 additions & 26 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ LTspice mode covers syntax such as:
133133
- model parameter aliases: resistor and capacitor models accept `tc=<tc1>[,<tc2>]`; voltage switches accept `von` / `voff`; current switches accept `ion` / `ioff`
134134
- resistor instance parasitics `Rser`, `Rpar`, and `Cpar`
135135
- capacitor instance parasitics `Rser`, `Lser`, `Rpar`, and `Cpar`
136+
- inductor instance parasitics `Rser`, `Lser`, `Rpar`, `RLshunt`, and `Cpar`
136137

137138
Topology-changing LTspice options that can be represented safely are synthesized as helper components in the parser. Behavior-changing constructs that are not represented by SpiceSharp are reported with targeted diagnostics instead of being silently ignored.
138139

‎roadmap/ltspice-compatibility-matrix.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
---
22
title: LTspice Compatibility Matrix
3-
status: P3 Baseline + .FOUR Support Refresh + Custom Passives + Ideal Diodes + Golden Evidence + Include/Lib Path Evidence + Waveform Docs Refresh + PWL Text Variants + Finite SINE + Source/R-C Parasitics
3+
status: P3 Baseline + .FOUR Support Refresh + Custom Passives + Ideal Diodes + Golden Evidence + Include/Lib Path Evidence + Waveform Docs Refresh + PWL Text Variants + Finite SINE + Source/R-C/L Parasitics
44
scope: SpiceSharpParser + SpiceSharp
5-
last_reviewed: 2026-07-06
5+
last_reviewed: 2026-07-07
66
---
77

88
# LTspice Compatibility Matrix
@@ -65,7 +65,7 @@ Compatibility classes:
6565
| LTspice metadata/rating parameters `mfg`, `manufacturer`, `pn`, `part`, `desc`, `description`, `V`, `Irms`, `Ipk` | Accepted | Warning no-op in LTspice mode | No runtime effect | Diagnostic fixture | Default: existing parameter error. LTspice: warning names parameter. | Current parser/runtime | BOM/layout metadata is not used by SpiceSharpParser. |
6666
| Resistor instance parasitics `Rser`, `Rpar`, `Cpar` | Accepted in LTspice mode | Synthesizes helper R/C entities | OP/TRAN supported | Analytic fixture | None expected for supported forms | Current parser/runtime | Parser-only topology synthesis: `Rser` adds a series resistor through an internal node; `Rpar` and `Cpar` add shunts across the resistor terminals. Core resistor model is unchanged. |
6767
| Capacitor instance parasitics `Rser`, `Lser`, `Rpar`, `Cpar` | Accepted in LTspice mode | Synthesizes helper R/L/C entities | OP/TRAN supported for R helpers and `Cpar`; `Lser` read fixture | Analytic/parser fixture | None expected for supported forms | Current parser/runtime | Parser-only topology synthesis: `Rser` and `Lser` add a series chain through internal nodes; `Rpar` and `Cpar` add shunts across the capacitor terminals. Core capacitor model is unchanged. |
68-
| Remaining inductor instance parasitics `Rser`, `Rpar`, `Cpar`, `Lser`, `RLshunt` | Accepted | Rejected in LTspice mode | Not runnable | None | Targeted LTspice instance-parameter error names parameter | Current parser/runtime | Topology-changing inductor parasitics are not synthesized yet; resistor/capacitor forms are tracked separately above. |
68+
| Inductor instance parasitics `Rser`, `Lser`, `Rpar`, `RLshunt`, `Cpar` | Accepted in LTspice mode | Synthesizes helper R/L/C entities | OP/TRAN supported for resistance helpers; `Lser` / `Cpar` read fixtures | Analytic/parser fixture | None expected for supported forms | Current parser/runtime | Parser-only topology synthesis: `Rser` and `Lser` add a series helper chain through internal nodes; `Rpar`, `RLshunt`, and `Cpar` add shunts across the inductor terminals. Core inductor model is unchanged. |
6969
| Capacitor `Q=<expr>` and inductor `Flux=<expr>` | Accepted | Core LTspice mode: targeted diagnostic. With `UseCustomComponents()`: produces `NonlinearCapacitor` / `NonlinearInductor`. | Custom components: TRAN and AC supported with operating-point incremental capacitance/inductance. | Focused parser/TRAN/AC fixtures plus optional LTspice-backed AC/TRAN golden comparisons | Core LTspice mode still emits targeted charge/flux diagnostic when custom mappings are not enabled | `SpiceSharpParser.CustomComponents` | `Q` uses `x` as terminal voltage and supports `IC`, `M`, and `N`; `Flux` uses `x` as branch current. Optional goldens compare AC small-signal voltage and transient waveform samples against LTspice when `LTSPICE_EXE` is configured. |
7070
| LTspice ideal diode parameters `Ron`, `Roff`, `Vfwd`, `Vrev`, `Rrev`, `Ilimit`, `RevIlimit`, `Epsilon`, `RevEpsilon` | Accepted | Core LTspice mode: targeted diagnostic. With `UseCustomComponents()`: produces `IdealDiodeModel` / `IdealDiode`. | Custom component: OP/DC/AC/TRAN supported as a memoryless nonlinear conductance. | Focused parser/integration/unit fixtures plus optional LTspice-backed DC sweep, AC, and rectifier-transient golden comparisons | Core LTspice mode still emits targeted ideal-diode diagnostics when custom mappings are not enabled | `SpiceSharpParser.CustomComponents` | These select LTspice's idealized diode behavior, not Berkeley diode parameters. The custom component supports model parameters, instance overrides, `M`/`N` scaling, `OFF`, and L/W model-bin selection; it does not model junction charge, capacitance, semiconductor noise, or temperature physics. |
7171
| Switch aliases `von`/`voff` and `ion`/`ioff` | Accepted | Lowered to `vt`/`vh` and `it`/`ih` | Existing switch model behavior | Read fixture | Missing pair or mixed native/alias forms are targeted errors | Current parser/runtime | Midpoint and half-span lowering only; no LTspice numeric parity claim. |

‎roadmap/ltspice-netlist-compatibility-plan.md‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: LTspice Netlist Compatibility Plan
33
status: Draft / Roadmap
44
scope: SpiceSharpParser + SpiceSharp
5-
last_reviewed: 2026-07-06
5+
last_reviewed: 2026-07-07
66
---
77

88
# LTspice Netlist Compatibility Plan
@@ -42,7 +42,7 @@ This roadmap is intentionally parser-first and evidence-first:
4242
- MOS model generation currently covers legacy levels 1, 2, and 3. LTspice `VDMOS` and advanced monolithic levels such as BSIM/EKV/HiSIM variants are runtime or intentional-unsupported candidates.
4343
- Distributed-line support currently starts from lossless `T`. LTspice lossy `O` / `LTRA` and uniform RC-line `URC` models need engine triage before runnable support is claimed.
4444
- P3 LTspice mode maps R/C model `tc=a[,b]`, switch `von`/`voff`, and current-switch `ion`/`ioff` aliases where they lower to existing parameters.
45-
- P3 LTspice mode warns on recognized metadata/rating parameters, synthesizes resistor `Rser` / `Rpar` / `Cpar` and capacitor `Rser` / `Lser` / `Rpar` / `Cpar` helper topology, and emits targeted errors for remaining topology-changing passive parasitics, ideal-diode parameters when custom mappings are not enabled, switch current-limiting/series options, `VDMOS`, high MOS levels, three-terminal power-MOS syntax, and `O` / `LTRA` / `U` / `URC` line families. The optional custom component package adds runnable `IdealDiode` support for LTspice-style diode parameters plus `NonlinearCapacitor` / `NonlinearInductor` support for LTspice-style capacitor `Q=` and inductor `Flux=` forms when `UseCustomComponents()` is enabled, with optional LTspice-backed DC/AC/transient golden comparisons when `LTSPICE_EXE` is configured.
45+
- P3 LTspice mode warns on recognized metadata/rating parameters, synthesizes resistor `Rser` / `Rpar` / `Cpar`, capacitor `Rser` / `Lser` / `Rpar` / `Cpar`, and inductor `Rser` / `Lser` / `Rpar` / `RLshunt` / `Cpar` helper topology, and emits targeted errors for ideal-diode parameters when custom mappings are not enabled, switch current-limiting/series options, `VDMOS`, high MOS levels, three-terminal power-MOS syntax, and `O` / `LTRA` / `U` / `URC` line families. The optional custom component package adds runnable `IdealDiode` support for LTspice-style diode parameters plus `NonlinearCapacitor` / `NonlinearInductor` support for LTspice-style capacitor `Q=` and inductor `Flux=` forms when `UseCustomComponents()` is enabled, with optional LTspice-backed DC/AC/transient golden comparisons when `LTSPICE_EXE` is configured.
4646

4747
## Scope And Policy
4848

@@ -241,12 +241,13 @@ Implemented P3 behavior:
241241
- Warned on recognized LTspice metadata and rating parameters only in LTspice mode.
242242
- Added LTspice-mode parser synthesis for resistor instance parasitics: `Rser` adds a series resistor through an internal node, while `Rpar` and `Cpar` add shunts across the resistor terminals.
243243
- Added LTspice-mode parser synthesis for capacitor instance parasitics: `Rser` and `Lser` add a series helper chain through internal nodes, while `Rpar` and `Cpar` add shunts across the capacitor terminals.
244-
- Added targeted diagnostics for remaining topology-changing passive parasitics, LTspice ideal-diode parameters when custom mappings are not enabled, switch `Lser` / `Vser` / `Ilimit`, high MOS levels, `VDMOS`, three-terminal power-MOS syntax, and `O` / `LTRA` / `U` / `URC` line families. LTspice ideal-diode parameters, capacitor `Q=`, and inductor `Flux=` remain targeted diagnostics in core LTspice mode but are runnable through `SpiceSharpParser.CustomComponents` as `IdealDiode`, `NonlinearCapacitor`, and `NonlinearInductor`, with optional LTspice-backed DC/AC/transient golden evidence.
244+
- Added LTspice-mode parser synthesis for inductor instance parasitics: `Rser` and `Lser` add a series helper chain through internal nodes, while `Rpar`, `RLshunt`, and `Cpar` add shunts across the inductor terminals.
245+
- Added targeted diagnostics for LTspice ideal-diode parameters when custom mappings are not enabled, switch `Lser` / `Vser` / `Ilimit`, high MOS levels, `VDMOS`, three-terminal power-MOS syntax, and `O` / `LTRA` / `U` / `URC` line families. LTspice ideal-diode parameters, capacitor `Q=`, and inductor `Flux=` remain targeted diagnostics in core LTspice mode but are runnable through `SpiceSharpParser.CustomComponents` as `IdealDiode`, `NonlinearCapacitor`, and `NonlinearInductor`, with optional LTspice-backed DC/AC/transient golden evidence.
245246

246247
Remaining follow-up:
247248

248249
- Broaden model-family alias tables only when direct SpiceSharp equivalents are confirmed by fixtures.
249-
- Add engine or parser-synthesis work before claiming runnable support for `VDMOS`, advanced MOS families, lossy transmission lines, uniform RC lines, or remaining inductor passive parasitics.
250+
- Add engine or parser-synthesis work before claiming runnable support for `VDMOS`, advanced MOS families, lossy transmission lines, or uniform RC lines.
250251
- Keep vendor-library import tests synthetic unless redistribution is clearly permitted.
251252

252253
Initial model-family priorities:

‎src/SpiceSharpParser.IntegrationTests/LTspiceCompatibility/LTspiceCompatibilityP3Tests.cs‎

Lines changed: 170 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -395,14 +395,183 @@ public void When_LtspiceCapacitorParallelResistanceIsInsideRepeatedSubcircuits_E
395395
Assert.True(EqualsWithTol(0.75, exports[1]));
396396
}
397397

398+
[Fact]
399+
public void When_LtspiceInductorSeriesResistanceIsRead_Expect_SynthesizedSeriesResistance()
400+
{
401+
var model = GetSpiceSharpModelWithCompatibility(
402+
CompatibilityOptions.LTspice,
403+
"LTspice P3 - inductor Rser",
404+
"V1 in 0 1",
405+
"L1 in out 1m Rser=10",
406+
"RLOAD out 0 90",
407+
".op",
408+
".save V(out)",
409+
".end");
410+
411+
AssertNoValidationIssues(model.ValidationResult);
412+
Assert.True(EqualsWithTol(0.9, RunOpSimulation(model, "V(out)")));
413+
Assert.IsType<Resistor>(model.Circuit["L1_rser"]);
414+
}
415+
416+
[Fact]
417+
public void When_LtspiceInductorParallelResistanceIsRead_Expect_SynthesizedTransientShunt()
418+
{
419+
var model = GetSpiceSharpModelWithCompatibility(
420+
CompatibilityOptions.LTspice,
421+
"LTspice P3 - inductor Rpar",
422+
"I1 out 0 PULSE(0 -1m 1n 1n 1n 10u 20u)",
423+
"L1 out 0 1m Rpar=1k",
424+
".tran 100n 5u",
425+
".save V(out)",
426+
".end");
427+
428+
AssertNoValidationIssues(model.ValidationResult);
429+
Assert.IsType<Resistor>(model.Circuit["L1_rpar"]);
430+
431+
var exports = RunTransientSimulation(model, "V(out)");
432+
Assert.NotEmpty(exports);
433+
434+
var oneTau = exports.OrderBy(export => Math.Abs(export.Item1 - 1e-6)).First();
435+
Assert.InRange(oneTau.Item2, 0.28, 0.45);
436+
Assert.InRange(exports.Last().Item2, -0.02, 0.02);
437+
}
438+
439+
[Fact]
440+
public void When_LtspiceInductorRlshuntIsRead_Expect_SynthesizedTransientShunt()
441+
{
442+
var model = GetSpiceSharpModelWithCompatibility(
443+
CompatibilityOptions.LTspice,
444+
"LTspice P3 - inductor RLshunt",
445+
"I1 out 0 PULSE(0 -1m 1n 1n 1n 10u 20u)",
446+
"L1 out 0 1m RLshunt=1k",
447+
".tran 100n 5u",
448+
".save V(out)",
449+
".end");
450+
451+
AssertNoValidationIssues(model.ValidationResult);
452+
Assert.IsType<Resistor>(model.Circuit["L1_rlshunt"]);
453+
454+
var exports = RunTransientSimulation(model, "V(out)");
455+
Assert.NotEmpty(exports);
456+
457+
var oneTau = exports.OrderBy(export => Math.Abs(export.Item1 - 1e-6)).First();
458+
Assert.InRange(oneTau.Item2, 0.28, 0.45);
459+
Assert.InRange(exports.Last().Item2, -0.02, 0.02);
460+
}
461+
462+
[Fact]
463+
public void When_LtspiceInductorParallelCapacitanceIsRead_Expect_SynthesizedParallelCapacitor()
464+
{
465+
var model = GetSpiceSharpModelWithCompatibility(
466+
CompatibilityOptions.LTspice,
467+
"LTspice P3 - inductor Cpar",
468+
"L1 out 0 1m Cpar=1n",
469+
".end");
470+
471+
AssertNoValidationIssues(model.ValidationResult);
472+
Assert.IsType<Capacitor>(model.Circuit["L1_cpar"]);
473+
}
474+
475+
[Fact]
476+
public void When_LtspiceInductorSeriesInductanceIsRead_Expect_SynthesizedSeriesInductor()
477+
{
478+
var model = GetSpiceSharpModelWithCompatibility(
479+
CompatibilityOptions.LTspice,
480+
"LTspice P3 - inductor Lser",
481+
"L1 out 0 1m Lser=1u",
482+
".end");
483+
484+
AssertNoValidationIssues(model.ValidationResult);
485+
Assert.IsType<Inductor>(model.Circuit["L1_lser"]);
486+
}
487+
488+
[Fact]
489+
public void When_LtspiceInductorHasCombinedParasitics_Expect_AllHelpersAreSynthesized()
490+
{
491+
var model = GetSpiceSharpModelWithCompatibility(
492+
CompatibilityOptions.LTspice,
493+
"LTspice P3 - inductor combined parasitics",
494+
"L1 out 0 1m Rser=1 Lser=1u Rpar=1k RLshunt=2k Cpar=1n",
495+
".end");
496+
497+
AssertNoValidationIssues(model.ValidationResult);
498+
Assert.IsType<Resistor>(model.Circuit["L1_rser"]);
499+
Assert.IsType<Inductor>(model.Circuit["L1_lser"]);
500+
Assert.IsType<Resistor>(model.Circuit["L1_rpar"]);
501+
Assert.IsType<Resistor>(model.Circuit["L1_rlshunt"]);
502+
Assert.IsType<Capacitor>(model.Circuit["L1_cpar"]);
503+
}
504+
505+
[Fact]
506+
public void When_LtspiceInductorParasiticValuesUseParameters_Expect_HelperExpressionsResolve()
507+
{
508+
var model = GetSpiceSharpModelWithCompatibility(
509+
CompatibilityOptions.LTspice,
510+
"LTspice P3 - inductor parameterized parasitics",
511+
".param rs=10",
512+
".param ls=1u",
513+
".param rp=1k",
514+
".param rls=2k",
515+
".param cp=1n",
516+
"V1 in 0 1",
517+
"L1 in out 1m Rser={rs} Lser={ls} Rpar={rp} RLshunt={rls} Cpar={cp}",
518+
"RLOAD out 0 90",
519+
".op",
520+
".save V(out)",
521+
".end");
522+
523+
AssertNoValidationIssues(model.ValidationResult);
524+
525+
var inToOutResistance = 1.0 / ((1.0 / 10.0) + (1.0 / 1000.0) + (1.0 / 2000.0));
526+
var expected = 90.0 / (90.0 + inToOutResistance);
527+
528+
Assert.True(EqualsWithTol(expected, RunOpSimulation(model, "V(out)")));
529+
Assert.IsType<Resistor>(model.Circuit["L1_rser"]);
530+
Assert.IsType<Inductor>(model.Circuit["L1_lser"]);
531+
Assert.IsType<Resistor>(model.Circuit["L1_rpar"]);
532+
Assert.IsType<Resistor>(model.Circuit["L1_rlshunt"]);
533+
Assert.IsType<Capacitor>(model.Circuit["L1_cpar"]);
534+
}
535+
536+
[Fact]
537+
public void When_LtspiceInductorSeriesParasiticIsInsideRepeatedSubcircuits_Expect_InternalNodesAreScoped()
538+
{
539+
var model = GetSpiceSharpModelWithCompatibility(
540+
CompatibilityOptions.LTspice,
541+
"LTspice P3 - inductor Rser subcircuit scoping",
542+
"V1 in 0 1",
543+
"XU1 in out1 lcell",
544+
"XU2 in out2 lcell",
545+
"RLOAD1 out1 0 90",
546+
"RLOAD2 out2 0 40",
547+
".subckt lcell p out",
548+
"L1 p out 1m Rser=10",
549+
".ends lcell",
550+
".op",
551+
".save V(out1)",
552+
".save V(out2)",
553+
".end");
554+
555+
AssertNoValidationIssues(model.ValidationResult);
556+
557+
var exports = RunOpSimulation(model, "V(out1)", "V(out2)");
558+
Assert.True(EqualsWithTol(0.9, exports[0]));
559+
Assert.True(EqualsWithTol(0.8, exports[1]));
560+
}
561+
398562
[Theory]
399563
[InlineData("R1 out 0 1k Rser=1", "Rser")]
400564
[InlineData("R1 out 0 1k Rpar=1Meg", "Rpar")]
401565
[InlineData("C1 out 0 1n Rser=1", "Rser")]
402566
[InlineData("C1 out 0 1n Lser=1n", "Lser")]
403567
[InlineData("C1 out 0 1n Rpar=1k", "Rpar")]
404568
[InlineData("C1 out 0 1n Cpar=1n", "Cpar")]
405-
public void When_ResistorOrCapacitorParasiticIsReadWithoutLtspiceCompatibility_Expect_DefaultError(
569+
[InlineData("L1 out 0 1u Rser=1", "Rser")]
570+
[InlineData("L1 out 0 1u Lser=1n", "Lser")]
571+
[InlineData("L1 out 0 1u Rpar=1k", "Rpar")]
572+
[InlineData("L1 out 0 1u RLshunt=1k", "RLshunt")]
573+
[InlineData("L1 out 0 1u Cpar=1p", "Cpar")]
574+
public void When_PassiveParasiticIsReadWithoutLtspiceCompatibility_Expect_DefaultError(
406575
string componentLine,
407576
string parameterName)
408577
{
@@ -417,10 +586,6 @@ public void When_ResistorOrCapacitorParasiticIsReadWithoutLtspiceCompatibility_E
417586
}
418587

419588
[Theory]
420-
[InlineData("L1 out 0 1u Rser=1", "Rser", "parasitic")]
421-
[InlineData("L1 out 0 1u Rpar=1k", "Rpar", "parasitic")]
422-
[InlineData("L1 out 0 1u Cpar=1p", "Cpar", "parasitic")]
423-
[InlineData("L1 out 0 1u RLshunt=1k", "RLshunt", "parasitic")]
424589
[InlineData("C1 out 0 Q=1n*x", "Q", "charge-defined")]
425590
[InlineData("C1 out 0 Q=1n*x Rser=1", "Q", "charge-defined")]
426591
[InlineData("L1 out 0 Flux=1m*tanh(x)", "Flux", "flux-defined")]

0 commit comments

Comments
 (0)