Skip to content

Commit 4e80b9d

Browse files
Enhance SKILL.md with additional methods and examples for circuit testing and measurement assertions
1 parent d967d3b commit 4e80b9d

1 file changed

Lines changed: 67 additions & 6 deletions

File tree

  • .claude/skills/spicesharp-circuit-design

.claude/skills/spicesharp-circuit-design/SKILL.md

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,18 +71,20 @@ tests/
7171
```csharp
7272
using System.Text;
7373
using SpiceSharp.Simulations;
74-
using SpiceSharpParser;
74+
using SpiceSharpParser; // SpiceSharpReader (simple path)
7575
using SpiceSharpParser.Common;
76-
using SpiceSharpParser.ModelReaders.Netlist.Spice;
76+
using SpiceSharpParser.ModelReaders.Netlist.Spice; // SpiceNetlistReader (advanced path)
7777
```
7878

7979
2. Create `CircuitTestHelper.cs` with shared methods:
8080
- `ParseAndRead(string netlist)` → parses, reads, validates, returns `SpiceSharpModel`
8181
- `RunOP(string netlist)` → returns `Dictionary<string, double>` of export values
8282
- `RunDC(string netlist)` → returns `Dictionary<string, List<(double SweepValue, double Value)>>`
83-
- `RunAC(string netlist)` → returns `Dictionary<string, List<(double Frequency, double Value)>>`
83+
- `RunAC(string netlist)` → returns `Dictionary<string, List<(double Frequency, double Value)>>` (no AC helper in `BaseTests.cs` — implement using `((AC)simulation).Frequency`)
8484
- `RunTran(string netlist)` → returns `Dictionary<string, List<(double Time, double Value)>>`
8585
- `GetMeasurements(string netlist)` → returns `Dictionary<string, double>` of successful .MEAS results
86+
- `AssertMeasurement(SpiceSharpModel model, string name, double expectedValue)` → checks measurement exists, succeeded, and value is within tolerance (RelTol=1e-3, AbsTol=1e-12). Mirrors `BaseTests.AssertMeasurement` from `src/SpiceSharpParser.IntegrationTests/BaseTests.cs`.
87+
- `AssertMeasurementSuccess(SpiceSharpModel model, string name)` → checks measurement exists and succeeded (for measurements where you only care it found a value)
8688
- Each method handles: parse → read → validate → attach exports → run with InvokeEvents → collect results
8789

8890
3. Verify the toolchain by writing and running a trivial RC filter test with assertions.
@@ -250,14 +252,26 @@ Title Line (required, first line)
250252

251253
**Devices**: R, C, L, K (mutual inductance), D (diode), Q (BJT), M (MOSFET), J (JFET), V (voltage source), I (current source), E (VCVS), F (CCCS), G (VCCS), H (CCVS), B (behavioral), S (voltage switch), W (current switch), T (transmission line)
252254

255+
**Behavioral Sources (B element)**
256+
B elements define voltage or current as arbitrary expressions of other circuit variables:
257+
```spice
258+
B1 out 0 V={V(in1)*V(in2)} * Voltage = product of two node voltages (ideal multiplier)
259+
B2 out 0 I={V(ctrl)/1k} * Current = voltage-controlled (ideal VCCS)
260+
B3 out 0 V={IF(V(in)>0.5, 5, 0)} * Conditional logic (ideal comparator)
261+
B4 out 0 V={V(in)*sin(6.28*1e6*TIME)} * Time-dependent (ideal mixer/modulator)
262+
```
263+
B elements are the recommended approach for modeling ideal functional blocks (op-amps, multipliers, comparators, VCOs) when full transistor-level simulation is unnecessary or impractical. See `src/SpiceSharpParser.IntegrationTests/AnalogBehavioralModeling/` tests for more examples.
264+
253265
**Value suffixes**: `T`=1e12, `G`=1e9, `MEG`=1e6, `k`=1e3, `m`=1e-3, `u`=1e-6, `n`=1e-9, `p`=1e-12, `f`=1e-15
254266

255-
**Analyses**: `.OP`, `.DC`, `.AC DEC|OCT|LIN <points> <fstart> <fstop>`, `.TRAN <tstep> <tstop> [tstart] [UIC]`, `.NOISE`
267+
**Analyses**: `.OP`, `.DC`, `.AC DEC|OCT|LIN <points> <fstart> <fstop>`, `.TRAN <tstep> <tstop> [tstart] [UIC]`, `.NOISE V(<node>) <src> <type> <points> <fstart> <fstop>` (limited — no RunNoise helper; only verified to not throw exceptions)
256268

257269
**Output**: `.SAVE V(<node>) I(<source>)`, `.MEAS <type> <name> <function>`, `.PRINT`
258270

259271
**Controls**: `.PARAM`, `.FUNC`, `.SUBCKT`/`.ENDS`, `.INCLUDE`, `.LIB`, `.STEP`, `.MC`, `.MODEL`, `.IC`, `.NODESET`, `.OPTIONS`
260272

273+
**Expressions**: Use `{expression}` syntax in component values when `.PARAM` defines the variables (e.g., `R1 in out {Rval*2}` with `.PARAM Rval=1k`). Expressions support arithmetic, built-in math functions, and references to other parameters.
274+
261275
**Waveforms**: `DC <value>`, `AC <mag> [phase]`, `SIN(offset amp freq [delay damping phase])`, `PULSE(v1 v2 td tr tf pw period)`, `PWL(t1 v1 t2 v2 ...)`, `AM(amp freq fc [delay phase])`, `SFFM(offset amp fc mod_index fsig)`
262276

263277
### Netlist Rules
@@ -461,15 +475,33 @@ public void Hypothesis_R1_Controls_CutoffFrequency()
461475
netlist.Split('\n').Select(l => l.Trim()).Where(l => l.Length > 0));
462476
```
463477

478+
**Alternative: String-array construction** (avoids trimming entirely):
479+
```csharp
480+
public static SpiceSharpModel ParseAndRead(params string[] lines)
481+
{
482+
var text = string.Join(Environment.NewLine, lines);
483+
// ... parse and read as below ...
484+
}
485+
```
486+
This is the pattern used by `BaseTests.GetSpiceSharpModel()` — each line is a standalone string, so no trimming is needed.
487+
464488
2. **Parse** with required settings (without these, parsing fails or produces wrong results):
465489
```csharp
466490
var parser = new SpiceNetlistParser();
467491
parser.Settings.Lexing.HasTitle = true;
468-
parser.Settings.Parsing.IsEndRequired = true;
492+
parser.Settings.Parsing.IsEndRequired = true; // Without this, parser silently accepts incomplete netlists missing .END
469493
var parseResult = parser.ParseNetlist(trimmed);
470494
```
471495

472-
3. **Read** using `SpiceNetlistReader` (not `SpiceSharpReader`) with required settings:
496+
3. **Read** — two options:
497+
498+
**Simple path (recommended)**`SpiceSharpReader` with sensible defaults:
499+
```csharp
500+
var reader = new SpiceSharpReader();
501+
var model = reader.Read(parseResult.FinalModel);
502+
```
503+
504+
**Advanced path**`SpiceNetlistReader` when you need custom settings (working directory, encoding, random seed):
473505
```csharp
474506
var readerSettings = new SpiceNetlistReaderSettings(
475507
new SpiceNetlistCaseSensitivitySettings(),
@@ -503,13 +535,40 @@ public void Hypothesis_R1_Controls_CutoffFrequency()
503535
codes.ToArray(); // forces enumeration
504536
```
505537

538+
**Multi-analysis netlists:** If a netlist contains multiple analysis types (e.g., `.OP` and `.AC`), iterate all simulations:
539+
```csharp
540+
foreach (var simulation in model.Simulations)
541+
{
542+
var exports = model.Exports.Where(ex => ex.Simulation == simulation).ToList();
543+
// ... attach EventExportData handlers for these exports ...
544+
var codes = simulation.Run(model.Circuit, -1);
545+
codes = simulation.InvokeEvents(codes);
546+
codes.ToArray();
547+
}
548+
```
549+
The `RunOP`/`RunDC`/`RunAC`/`RunTran` helpers assume a single simulation of the expected type.
550+
506551
7. **Extract sweep/time/frequency values** per simulation type:
507552
- DC sweep value: `((DC)simulation).GetCurrentSweepValue().Last()`
508553
- AC frequency: `((AC)simulation).Frequency` (cast to `AC`, not `FrequencySimulation`)
509554
- TRAN time: `((Transient)simulation).Time`
510555

511556
8. **Measurements**: `model.Measurements` is a `ConcurrentDictionary<string, List<MeasurementResult>>`. Each `MeasurementResult` has `.Success`, `.Value`, and `.Name`. Always check `.Success` before reading `.Value`.
512557

558+
### Tolerance Comparison Patterns
559+
560+
**For spec verification** (values from requirements.md):
561+
Use `Assert.InRange(actual, min, max)` with explicit bounds from the spec table.
562+
563+
**For reference function comparison** (comparing simulation output against an analytical formula):
564+
Use the relative+absolute tolerance pattern from `BaseTests.cs`:
565+
```csharp
566+
double tol = Math.Max(Math.Abs(actual), Math.Abs(expected)) * 1e-3 + 1e-12;
567+
Assert.True(Math.Abs(expected - actual) < tol,
568+
$"Expected {expected}, got {actual}, tolerance {tol}");
569+
```
570+
This handles both large and small values correctly — the relative term (1e-3) dominates for large values, while the absolute term (1e-12) prevents false failures near zero.
571+
513572
### AC Analysis: Voltage Export Types
514573

515574
In AC analysis, voltages are complex numbers. The export type in `.SAVE` determines what value you get:
@@ -727,6 +786,8 @@ SpiceSharp has no built-in op-amp device. You must build from discrete transisto
727786

728787
### Convergence Tips
729788
- Start with `.OPTIONS reltol=1e-3 abstol=1e-12 gmin=1e-12`
789+
- For circuits that fail to find a DC operating point, increase iteration limits: `.OPTIONS itl1=200` (default ~100)
790+
- For transient convergence issues, increase per-timepoint iterations: `.OPTIONS itl4=50` (default ~10)
730791
- Use `.IC V(node)=<value>` or `.NODESET V(node)=<value>` for known DC operating points
731792
- Add 1GΩ resistors from floating nodes to ground
732793
- For oscillators, apply a small initial perturbation: `.IC V(tank)=0.1`

0 commit comments

Comments
 (0)