@@ -41,34 +41,37 @@ public void DcSweep_WhenComparedWithLtspice_MatchesIdealDiodeParameters()
4141 }
4242
4343 [ LtspiceFact ]
44- public void Ac_WhenComparedWithLtspice_MatchesForwardBiasedSmallSignal ( )
44+ public void Ac_WhenComparedWithLtspice_MatchesSmallSignalDerivatives ( )
4545 {
4646 string ltspiceExecutable = GetLtspiceExecutable ( ) ;
4747
48- var raw = RunLtspiceRaw (
49- ltspiceExecutable ,
50- "ac_forward_biased_small_signal" ,
51- CreateLtspiceAcNetlist ( ) ) ;
52- var ltspicePoints = LtspiceAsciiRawFile . GetComplexSeries ( raw , "V(out)" ) ;
53- var spiceSharpPoints = RunSpiceSharpAcForwardBiasedSmallSignal ( ) ;
54-
55- Assert . Equal ( ltspicePoints . Count , spiceSharpPoints . Count ) ;
56- for ( int i = 0 ; i < ltspicePoints . Count ; i ++ )
48+ foreach ( var testCase in CreateAcCases ( ) )
5749 {
58- AssertClose (
59- "ac_forward_biased_small_signal" ,
60- ltspicePoints [ i ] . Frequency ,
61- ltspicePoints [ i ] . Frequency ,
62- spiceSharpPoints [ i ] . Frequency ,
63- 1e-9 ,
64- 1e-9 ) ;
65- AssertComplexClose (
66- "ac_forward_biased_small_signal" ,
67- ltspicePoints [ i ] . Frequency ,
68- ltspicePoints [ i ] . Value ,
69- spiceSharpPoints [ i ] . Value ,
70- 1e-8 ,
71- 1e-5 ) ;
50+ var raw = RunLtspiceRaw (
51+ ltspiceExecutable ,
52+ testCase . Name ,
53+ CreateLtspiceAcNetlist ( testCase ) ) ;
54+ var ltspicePoints = LtspiceAsciiRawFile . GetComplexSeries ( raw , "V(out)" ) ;
55+ var spiceSharpPoints = RunSpiceSharpAcSmallSignal ( testCase ) ;
56+
57+ Assert . Equal ( ltspicePoints . Count , spiceSharpPoints . Count ) ;
58+ for ( int i = 0 ; i < ltspicePoints . Count ; i ++ )
59+ {
60+ AssertClose (
61+ testCase . Name ,
62+ ltspicePoints [ i ] . Frequency ,
63+ ltspicePoints [ i ] . Frequency ,
64+ spiceSharpPoints [ i ] . Frequency ,
65+ 1e-9 ,
66+ 1e-9 ) ;
67+ AssertComplexClose (
68+ testCase . Name ,
69+ ltspicePoints [ i ] . Frequency ,
70+ ltspicePoints [ i ] . Value ,
71+ spiceSharpPoints [ i ] . Value ,
72+ testCase . AbsoluteTolerance ,
73+ testCase . RelativeTolerance ) ;
74+ }
7275 }
7376 }
7477
@@ -290,6 +293,64 @@ private static IReadOnlyList<LtspiceIdealDiodeCase> CreateCases()
290293 } ;
291294 }
292295
296+ private static IReadOnlyList < LtspiceIdealDiodeAcCase > CreateAcCases ( )
297+ {
298+ return new [ ]
299+ {
300+ new LtspiceIdealDiodeAcCase (
301+ "ac_forward_biased_small_signal" ,
302+ 3.0 ,
303+ ".model did D(Ron=2 Roff=1e9 Vfwd=1)" ,
304+ parameters =>
305+ {
306+ parameters . OnResistance = 2.0 ;
307+ parameters . OffResistance = 1e9 ;
308+ parameters . ForwardVoltage = 1.0 ;
309+ } ) ,
310+
311+ new LtspiceIdealDiodeAcCase (
312+ "ac_forward_current_limit_derivative" ,
313+ 5.0 ,
314+ ".model did D(Ron=1 Roff=1e12 Vfwd=0 Ilimit=2)" ,
315+ parameters =>
316+ {
317+ parameters . OnResistance = 1.0 ;
318+ parameters . OffResistance = 1e12 ;
319+ parameters . ForwardVoltage = 0.0 ;
320+ parameters . ForwardCurrentLimit = 2.0 ;
321+ } ,
322+ 1e-7 ,
323+ 1e-4 ) ,
324+
325+ new LtspiceIdealDiodeAcCase (
326+ "ac_forward_epsilon_ramp_derivative" ,
327+ 1.1 ,
328+ ".model did D(Ron=1 Roff=1e12 Vfwd=1 Epsilon=0.2)" ,
329+ parameters =>
330+ {
331+ parameters . OnResistance = 1.0 ;
332+ parameters . OffResistance = 1e12 ;
333+ parameters . ForwardVoltage = 1.0 ;
334+ parameters . ForwardEpsilon = 0.2 ;
335+ } ,
336+ 1e-7 ,
337+ 1e-4 ) ,
338+
339+ new LtspiceIdealDiodeAcCase (
340+ "ac_reverse_breakdown_rrev_derivative" ,
341+ - 5.0 ,
342+ ".model did D(Ron=1 Roff=1e12 Vfwd=1 Vrev=1.5 Rrev=3)" ,
343+ parameters =>
344+ {
345+ parameters . OnResistance = 1.0 ;
346+ parameters . OffResistance = 1e12 ;
347+ parameters . ForwardVoltage = 1.0 ;
348+ parameters . ReverseVoltage = 1.5 ;
349+ parameters . ReverseResistance = 3.0 ;
350+ } ) ,
351+ } ;
352+ }
353+
293354 private static string GetLtspiceExecutable ( )
294355 {
295356 string executable = Environment . GetEnvironmentVariable ( LtspiceExecutableVariable ) ;
@@ -375,15 +436,15 @@ private static IReadOnlyList<string> CreateLtspiceNetlist(LtspiceIdealDiodeCase
375436 } ;
376437 }
377438
378- private static IReadOnlyList < string > CreateLtspiceAcNetlist ( )
439+ private static IReadOnlyList < string > CreateLtspiceAcNetlist ( LtspiceIdealDiodeAcCase testCase )
379440 {
380441 return new [ ]
381442 {
382443 "Ideal diode LTspice AC golden comparison" ,
383- "V1 in 0 DC 3 AC 1" ,
384- "R1 in out 1" ,
444+ FormattableString . Invariant ( $ "V1 in 0 DC { testCase . SourceVoltage } AC 1") ,
445+ FormattableString . Invariant ( $ "R1 in out { testCase . SourceResistance } " ) ,
385446 "D1 out 0 did" ,
386- ".model did D(Ron=2 Roff=1e9 Vfwd=1)" ,
447+ testCase . ModelLine ,
387448 ".ac lin 1 1k 1k" ,
388449 ".save V(out)" ,
389450 ".end" ,
@@ -486,16 +547,15 @@ private static ProcessResult RunLtspice(string ltspiceExecutable, string circuit
486547 return result ;
487548 }
488549
489- private static IReadOnlyList < ( double Frequency , Complex Value ) > RunSpiceSharpAcForwardBiasedSmallSignal ( )
550+ private static IReadOnlyList < ( double Frequency , Complex Value ) > RunSpiceSharpAcSmallSignal (
551+ LtspiceIdealDiodeAcCase testCase )
490552 {
491553 var diode = new IdealDiode ( "D1" , "out" , "0" ) ;
492- diode . Parameters . OnResistance = 2.0 ;
493- diode . Parameters . OffResistance = 1e9 ;
494- diode . Parameters . ForwardVoltage = 1.0 ;
554+ testCase . Configure ( diode . Parameters ) ;
495555
496556 var circuit = new Circuit (
497- new VoltageSource ( "V1" , "in" , "0" , 3.0 ) . SetParameter ( "acmag" , 1.0 ) ,
498- new Resistor ( "R1" , "in" , "out" , 1.0 ) ,
557+ new VoltageSource ( "V1" , "in" , "0" , testCase . SourceVoltage ) . SetParameter ( "acmag" , 1.0 ) ,
558+ new Resistor ( "R1" , "in" , "out" , testCase . SourceResistance ) ,
499559 diode ) ;
500560
501561 var ac = new AC ( "ac" , new LinearSweep ( 1000.0 , 1000.0 , 1 ) ) ;
@@ -653,6 +713,41 @@ public LtspiceIdealDiodeCase(
653713 public double RelativeTolerance { get ; }
654714 }
655715
716+ private sealed class LtspiceIdealDiodeAcCase
717+ {
718+ public LtspiceIdealDiodeAcCase (
719+ string name ,
720+ double sourceVoltage ,
721+ string modelLine ,
722+ Action < IdealDiodeParameters > configure ,
723+ double absoluteTolerance = 1e-8 ,
724+ double relativeTolerance = 1e-5 ,
725+ double sourceResistance = 1.0 )
726+ {
727+ this . Name = name ;
728+ this . SourceVoltage = sourceVoltage ;
729+ this . ModelLine = modelLine ;
730+ this . Configure = configure ;
731+ this . AbsoluteTolerance = absoluteTolerance ;
732+ this . RelativeTolerance = relativeTolerance ;
733+ this . SourceResistance = sourceResistance ;
734+ }
735+
736+ public string Name { get ; }
737+
738+ public double SourceVoltage { get ; }
739+
740+ public string ModelLine { get ; }
741+
742+ public Action < IdealDiodeParameters > Configure { get ; }
743+
744+ public double AbsoluteTolerance { get ; }
745+
746+ public double RelativeTolerance { get ; }
747+
748+ public double SourceResistance { get ; }
749+ }
750+
656751 private sealed class LtspiceAsciiRawFile
657752 {
658753 private LtspiceAsciiRawFile ( IReadOnlyList < string > variables , IReadOnlyList < Complex [ ] > points )
0 commit comments