From 38214c882b247120c85b9f087d7a838a08f89f07 Mon Sep 17 00:00:00 2001 From: Sven Boulanger Date: Wed, 29 Dec 2021 16:27:34 +0100 Subject: [PATCH 1/2] Fix issue #68 --- .../Functions/ComplexFunctionBuilderHelper.cs | 2 +- .../Functions/RealFunctionBuilderHelper.cs | 4 +-- .../Components/BehavioralBindingContext.cs | 34 +++++++++++++------ .../BehavioralCapacitor/Biasing.cs | 7 ++-- .../BehavioralCapacitor/Frequency.cs | 2 +- .../BehavioralCapacitor/Time.cs | 4 +-- .../BehavioralCurrentSource/Biasing.cs | 8 ++--- .../BehavioralCurrentSource/Frequency.cs | 2 +- .../BehavioralResistor/Biasing.cs | 13 ++++--- .../BehavioralResistor/Frequency.cs | 4 +-- .../BehavioralVoltageSource/Biasing.cs | 8 ++--- .../FrequencyBehavior.cs | 2 +- .../Components/BuilderHelper.cs | 3 +- .../Components/BehavioralResistorTests.cs | 18 ++++++++++ .../Parsers/ParserTests.cs | 1 + 15 files changed, 72 insertions(+), 40 deletions(-) diff --git a/SpiceSharpBehavioral/Builders/Functions/ComplexFunctionBuilderHelper.cs b/SpiceSharpBehavioral/Builders/Functions/ComplexFunctionBuilderHelper.cs index 1fe573a..4dfd3a3 100644 --- a/SpiceSharpBehavioral/Builders/Functions/ComplexFunctionBuilderHelper.cs +++ b/SpiceSharpBehavioral/Builders/Functions/ComplexFunctionBuilderHelper.cs @@ -185,7 +185,7 @@ private static void If(IILState ils, IReadOnlyList arguments) arguments.Check(3); ilsc.PushReal(arguments[0]); ilsc.PushDouble(0.5); - ilsc.PushCheck(OpCodes.Bgt_S, arguments[1], arguments[2]); + ilsc.PushCheck(OpCodes.Bgt, arguments[1], arguments[2]); } private static void Limit(IILState ils, IReadOnlyList arguments) => ils.Call(HelperFunctions.Limit, arguments); diff --git a/SpiceSharpBehavioral/Builders/Functions/RealFunctionBuilderHelper.cs b/SpiceSharpBehavioral/Builders/Functions/RealFunctionBuilderHelper.cs index 2da7e39..a4e57d2 100644 --- a/SpiceSharpBehavioral/Builders/Functions/RealFunctionBuilderHelper.cs +++ b/SpiceSharpBehavioral/Builders/Functions/RealFunctionBuilderHelper.cs @@ -179,9 +179,9 @@ private static void If(IILState ils, IReadOnlyList arguments) ils.Push(0.5); var lblElse = ils.Generator.DefineLabel(); var lblEnd = ils.Generator.DefineLabel(); - ils.Generator.Emit(OpCodes.Ble_S, lblElse); + ils.Generator.Emit(OpCodes.Ble, lblElse); ils.Push(arguments[1]); - ils.Generator.Emit(OpCodes.Br_S, lblEnd); + ils.Generator.Emit(OpCodes.Br, lblEnd); ils.Generator.MarkLabel(lblElse); ils.Push(arguments[2]); ils.Generator.MarkLabel(lblEnd); diff --git a/SpiceSharpBehavioral/Components/BehavioralBindingContext.cs b/SpiceSharpBehavioral/Components/BehavioralBindingContext.cs index acf2b7a..90501e3 100644 --- a/SpiceSharpBehavioral/Components/BehavioralBindingContext.cs +++ b/SpiceSharpBehavioral/Components/BehavioralBindingContext.cs @@ -23,17 +23,6 @@ namespace SpiceSharp.Components.BehavioralComponents [BindingContextFor(typeof(BehavioralCurrentSource))] public class BehavioralBindingContext : ComponentBindingContext { - /// - /// Gets the current references. - /// - /// - /// The current references. - /// - /// - /// The reason we are tracking branches, is because they reference other components. - /// - public Dictionary Branches { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -71,6 +60,29 @@ public Dictionary CreateDerivatives(Node function) return derivatives.Derive(function) ?? new Dictionary(comparer); } + /// + /// Maps all the nodes that are referenced in the function. + /// + /// The variable value type. + /// The factory for variables. + /// The function containing the variables. + /// Optionally a branch for the current behavior branch current. + public Dictionary> MapNodes(IVariableFactory> factory, Node function, IVariable ownBranch = null) + { + var state = GetState(); + var bp = GetParameterSet(); + var comparer = new VariableNodeComparer(state.Comparer, Simulation.EntityBehaviors.Comparer, bp.VariableComparer); + var variables = new Dictionary>(comparer); + + var nf = new NodeFinder(); + foreach (var variable in nf.Build(function).Where(v => v.NodeType == NodeTypes.Voltage || v.NodeType == NodeTypes.Current)) + { + if (!variables.ContainsKey(variable)) + variables.Add(variable, MapNode(factory, variable, ownBranch)); + } + return variables; + } + /// /// Remap a variable node to an . /// diff --git a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCapacitor/Biasing.cs b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCapacitor/Biasing.cs index fb8b98a..2d58998 100644 --- a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCapacitor/Biasing.cs +++ b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCapacitor/Biasing.cs @@ -6,7 +6,6 @@ using SpiceSharpBehavioral.Parsers.Nodes; using System; using System.Collections.Generic; -using System.Linq; namespace SpiceSharp.Components.BehavioralCapacitorBehaviors { @@ -23,7 +22,7 @@ public class Biasing : Behavior /// /// Gets the variables that are associated with each variable node. /// - protected Dictionary> DerivativeVariables { get; } + protected Dictionary> VariableNodes { get; } /// /// The function that computes the value. @@ -60,9 +59,7 @@ public Biasing(BehavioralBindingContext context) }; Function = replacer.Build(bp.Function); Derivatives = context.CreateDerivatives(Function); - DerivativeVariables = new Dictionary>(Derivatives.Comparer); - foreach (var key in Derivatives.Keys) - DerivativeVariables.Add(key, context.MapNode(state, key)); + VariableNodes = context.MapNodes(state, Function); } } } diff --git a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCapacitor/Frequency.cs b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCapacitor/Frequency.cs index 050b439..9f1c1b1 100644 --- a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCapacitor/Frequency.cs +++ b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCapacitor/Frequency.cs @@ -73,7 +73,7 @@ public Frequency(BehavioralBindingContext context) var builder = new ComplexFunctionBuilder(); builder.VariableFound += (sender, args) => { - if (args.Variable == null && DerivativeVariables.TryGetValue(args.Node, out var variable)) + if (args.Variable == null && VariableNodes.TryGetValue(args.Node, out var variable)) args.Variable = new FuncVariable(variable.Name, () => variable.Value, variable.Unit); }; bp.RegisterBuilder(context, builder); diff --git a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCapacitor/Time.cs b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCapacitor/Time.cs index 4c5ae60..42ab417 100644 --- a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCapacitor/Time.cs +++ b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCapacitor/Time.cs @@ -74,7 +74,7 @@ public Time(BehavioralBindingContext context) var builder = new RealFunctionBuilder(); builder.VariableFound += (sender, args) => { - if (args.Variable == null && DerivativeVariables.TryGetValue(args.Node, out var variable)) + if (args.Variable == null && VariableNodes.TryGetValue(args.Node, out var variable)) args.Variable = variable; }; bp.RegisterBuilder(context, builder); @@ -82,7 +82,7 @@ public Time(BehavioralBindingContext context) var rhsLocs = Variables.GetRhsIndices(state.Map); foreach (var pair in Derivatives) { - var variable = DerivativeVariables[pair.Key]; + var variable = VariableNodes[pair.Key]; if (state.Map.Contains(variable)) { derivatives.Add(builder.Build(pair.Value)); diff --git a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCurrentSource/Biasing.cs b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCurrentSource/Biasing.cs index 9ca8410..f0878ff 100644 --- a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCurrentSource/Biasing.cs +++ b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCurrentSource/Biasing.cs @@ -32,7 +32,7 @@ public partial class Biasing : Behavior, /// /// Gets the variables that are associated with each variable node. /// - protected Dictionary> DerivativeVariables { get; } + protected Dictionary> VariableNodes { get; } /// /// The function that computes the value. @@ -88,13 +88,13 @@ public Biasing(BehavioralBindingContext context) // Let's build the derivative functions and get their matrix locations/rhs locations Function = bp.Function; Derivatives = context.CreateDerivatives(Function); - DerivativeVariables = Derivatives.Keys.ToDictionary(d => d, d => context.MapNode(state, d), Derivatives.Comparer); + VariableNodes = context.MapNodes(state, Function); var derivatives = new List>(Derivatives.Count); var derivativeVariables = new List>(Derivatives.Count); var builder = new RealFunctionBuilder(); builder.VariableFound += (sender, args) => { - if (args.Variable == null && DerivativeVariables.TryGetValue(args.Node, out var variable)) + if (args.Variable == null && VariableNodes.TryGetValue(args.Node, out var variable)) args.Variable = variable; }; bp.RegisterBuilder(context, builder); @@ -102,7 +102,7 @@ public Biasing(BehavioralBindingContext context) var rhsLocs = _variables.GetRhsIndices(state.Map); foreach (var pair in Derivatives) { - var variable = DerivativeVariables[pair.Key]; + var variable = VariableNodes[pair.Key]; if (state.Map.Contains(variable)) { derivatives.Add(builder.Build(pair.Value)); diff --git a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCurrentSource/Frequency.cs b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCurrentSource/Frequency.cs index a7bfa12..6e634f3 100644 --- a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCurrentSource/Frequency.cs +++ b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralCurrentSource/Frequency.cs @@ -73,7 +73,7 @@ public Frequency(BehavioralBindingContext context) var builder = new ComplexFunctionBuilder(); builder.VariableFound += (sender, args) => { - if (args.Variable == null && DerivativeVariables.TryGetValue(args.Node, out var variable)) + if (args.Variable == null && VariableNodes.TryGetValue(args.Node, out var variable)) args.Variable = new FuncVariable(variable.Name, () => variable.Value, variable.Unit); }; bp.RegisterBuilder(context, builder); diff --git a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralResistor/Biasing.cs b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralResistor/Biasing.cs index d887824..d6798a8 100644 --- a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralResistor/Biasing.cs +++ b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralResistor/Biasing.cs @@ -35,7 +35,7 @@ public partial class Biasing : Behavior, /// /// Gets the variables that are associated with each variable node. /// - protected Dictionary> DerivativeVariables { get; } + protected Dictionary> VariableNodes { get; } /// /// The function that computes the value. @@ -100,21 +100,24 @@ public Biasing(BehavioralBindingContext context) // Let's build the derivative functions and get their matrix locations/rhs locations Function = Node.Multiply(Node.Current(Name), bp.Function); Derivatives = context.CreateDerivatives(Function); - DerivativeVariables = Derivatives.Keys.ToDictionary(d => d, d => context.MapNode(state, d, _branch), Derivatives.Comparer); + VariableNodes = context.MapNodes(state, Function, _branch); var derivatives = new List>(Derivatives.Count); var derivativeVariables = new List>(Derivatives.Count); var builder = new RealFunctionBuilder(); builder.VariableFound += (sender, args) => { - if (args.Variable == null && DerivativeVariables.TryGetValue(args.Node, out var variable)) - args.Variable = variable; + if (args.Variable == null) + { + if (VariableNodes.TryGetValue(args.Node, out var variable)) + args.Variable = variable; + } }; bp.RegisterBuilder(context, builder); var matLocs = new List(Derivatives.Count); var rhsLocs = state.Map[_branch]; foreach (var pair in Derivatives) { - var variable = DerivativeVariables[pair.Key]; + var variable = VariableNodes[pair.Key]; if (state.Map.Contains(variable)) { derivatives.Add(builder.Build(pair.Value)); diff --git a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralResistor/Frequency.cs b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralResistor/Frequency.cs index 20c6a5d..354d0eb 100644 --- a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralResistor/Frequency.cs +++ b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralResistor/Frequency.cs @@ -85,13 +85,13 @@ public Frequency(BehavioralBindingContext context) var nVariables = new Dictionary>(Derivatives.Comparer); foreach (var variable in Derivatives.Keys) { - var orig = DerivativeVariables[variable]; + var orig = VariableNodes[variable]; nVariables.Add(variable, new FuncVariable(orig.Name, () => orig.Value, orig.Unit)); } var builder = new ComplexFunctionBuilder(); builder.VariableFound += (sender, args) => { - if (args.Variable == null && DerivativeVariables.TryGetValue(args.Node, out var variable)) + if (args.Variable == null && VariableNodes.TryGetValue(args.Node, out var variable)) args.Variable = new FuncVariable(variable.Name, () => variable.Value, variable.Unit); }; bp.RegisterBuilder(context, builder); diff --git a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralVoltageSource/Biasing.cs b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralVoltageSource/Biasing.cs index f769762..517352e 100644 --- a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralVoltageSource/Biasing.cs +++ b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralVoltageSource/Biasing.cs @@ -35,7 +35,7 @@ public partial class Biasing : Behavior, /// /// Gets the variables that are associated with each variable node. /// - protected Dictionary> DerivativeVariables { get; } + protected Dictionary> VariableNodes { get; } /// /// The function that computes the value. @@ -100,11 +100,11 @@ public Biasing(BehavioralBindingContext context) // Let's build the derivative functions and get their matrix locations/rhs locations Function = bp.Function; Derivatives = context.CreateDerivatives(Function); - DerivativeVariables = Derivatives.Keys.ToDictionary(d => d, d => context.MapNode(state, d, _branch), Derivatives.Comparer); + VariableNodes = context.MapNodes(state, Function, _branch); var builder = new RealFunctionBuilder(); builder.VariableFound += (sender, args) => { - if (args.Variable == null && DerivativeVariables.TryGetValue(args.Node, out var variable)) + if (args.Variable == null && VariableNodes.TryGetValue(args.Node, out var variable)) args.Variable = variable; }; bp.RegisterBuilder(context, builder); @@ -114,7 +114,7 @@ public Biasing(BehavioralBindingContext context) var rhsLocs = state.Map[_branch]; foreach (var pair in Derivatives) { - var variable = DerivativeVariables[pair.Key]; + var variable = VariableNodes[pair.Key]; if (state.Map.Contains(variable)) { derivatives.Add(builder.Build(pair.Value)); diff --git a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralVoltageSource/FrequencyBehavior.cs b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralVoltageSource/FrequencyBehavior.cs index 4b0bec5..aa9827f 100644 --- a/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralVoltageSource/FrequencyBehavior.cs +++ b/SpiceSharpBehavioral/Components/BehavioralSources/BehavioralVoltageSource/FrequencyBehavior.cs @@ -85,7 +85,7 @@ public FrequencyBehavior(BehavioralBindingContext context) var builder = new ComplexFunctionBuilder(); builder.VariableFound += (sender, args) => { - if (args.Variable == null && DerivativeVariables.TryGetValue(args.Node, out var variable)) + if (args.Variable == null && VariableNodes.TryGetValue(args.Node, out var variable)) args.Variable = new FuncVariable(variable.Name, () => variable.Value, variable.Unit); }; var rhsLocs = state.Map[_branch]; bp.RegisterBuilder(context, builder); diff --git a/SpiceSharpBehavioral/Components/BuilderHelper.cs b/SpiceSharpBehavioral/Components/BuilderHelper.cs index d5fdb01..a80cfdb 100644 --- a/SpiceSharpBehavioral/Components/BuilderHelper.cs +++ b/SpiceSharpBehavioral/Components/BuilderHelper.cs @@ -6,6 +6,7 @@ using SpiceSharpBehavioral.Builders.Functions; using SpiceSharpBehavioral; using System.Numerics; +using SpiceSharpBehavioral.Parsers.Nodes; namespace SpiceSharp.Components.BehavioralComponents { @@ -218,7 +219,7 @@ public static void RegisterDefaultBuilder(object sender, BuilderCreatedEventArgs } else { - variables.Add("smallsig", new ConstantVariable("smallsig", 1.0, _scalar)); + variables.Add("smallsig", new ConstantVariable("smallsig", 0.0, _scalar)); } // Some standard constants diff --git a/SpiceSharpBehavioralTest/Components/BehavioralResistorTests.cs b/SpiceSharpBehavioralTest/Components/BehavioralResistorTests.cs index e8377df..9a43391 100644 --- a/SpiceSharpBehavioralTest/Components/BehavioralResistorTests.cs +++ b/SpiceSharpBehavioralTest/Components/BehavioralResistorTests.cs @@ -82,5 +82,23 @@ public void When_ZeroDerivative_Expect_Reference() }; op.Run(ckt); } + + [Test] + public void When_If_Expect_Reference() + { + var ckt = new Circuit( + new VoltageSource("V1", "2", "0", 0.5), + new VoltageSource("V2", "1", "0", 10), + new BehavioralResistor("RSwitch", "1", "0", "IF(v(2, 0) >= 1, 10, (v(2, 0) <= 0 ? 1000000 : (exp(8.05904782547916 + 3 * -11.5129254649702 * (v(2, 0)-0.5)/(2*1) - 2 * -11.5129254649702 * pow(v(2, 0)-0.5, 3)/(pow(1,3))))))") + ); + var op = new OP("Voltage switch simulation"); + var refExport = new RealCurrentExport(op, "V2"); + op.ExportSimulationData += (sender, args) => + { + Assert.AreEqual(-0.00316228, refExport.Value, 1e-8); + }; + + op.Run(ckt); + } } } diff --git a/SpiceSharpBehavioralTest/Parsers/ParserTests.cs b/SpiceSharpBehavioralTest/Parsers/ParserTests.cs index 5bced5c..86a6011 100644 --- a/SpiceSharpBehavioralTest/Parsers/ParserTests.cs +++ b/SpiceSharpBehavioralTest/Parsers/ParserTests.cs @@ -52,6 +52,7 @@ public static IEnumerable Expressions yield return new TestCaseData("min(-2,6*2)", Node.Function("min", Node.Minus(2.0), Node.Multiply(6.0, 2.0))).SetName("{m}(\"min(-2,6*2)\")"); // Function with multiple arguments yield return new TestCaseData("rnd()", Node.Function("rnd")).SetName("{m}(\"rnd()\")"); // Function without arguments yield return new TestCaseData("-.14e3", Node.Minus(Node.Constant(0.14e3))).SetName("{m}(-.14e3)"); + yield return new TestCaseData("V(2,0)", Node.Voltage("2", "0")); } } } From 8f3b010f483249329ccc382adfdac1af1ae227dd Mon Sep 17 00:00:00 2001 From: Sven Boulanger Date: Wed, 29 Dec 2021 17:26:58 +0100 Subject: [PATCH 2/2] Update version --- SpiceSharpBehavioral/SpiceSharpBehavioral.csproj | 6 +++--- SpiceSharpBehavioralTest/SpiceSharpBehavioralTest.csproj | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/SpiceSharpBehavioral/SpiceSharpBehavioral.csproj b/SpiceSharpBehavioral/SpiceSharpBehavioral.csproj index 0bbb5d7..fd479af 100644 --- a/SpiceSharpBehavioral/SpiceSharpBehavioral.csproj +++ b/SpiceSharpBehavioral/SpiceSharpBehavioral.csproj @@ -2,7 +2,7 @@ netstandard2.0 - 3.1.2 + 3.1.3 Sven Boulanger Spice#.Behavioral Spice#.Behavioral is a library that allows using behavioral components in the circuit simulator Spice#. @@ -11,12 +11,12 @@ https://github.com/SpiceSharp/SpiceSharpBehavioral circuit electronics netlist parser spice simulator simulation ode solver design behavioral modeling - 3.1.2.0 + 3.1.3.0 Refer to the GitHub release for release notes. true en - 3.1.2.0 + 3.1.3.0 full true MIT diff --git a/SpiceSharpBehavioralTest/SpiceSharpBehavioralTest.csproj b/SpiceSharpBehavioralTest/SpiceSharpBehavioralTest.csproj index 4c3f6ed..2dff02b 100644 --- a/SpiceSharpBehavioralTest/SpiceSharpBehavioralTest.csproj +++ b/SpiceSharpBehavioralTest/SpiceSharpBehavioralTest.csproj @@ -86,10 +86,10 @@ 3.13.2 - 3.12.0 + 3.13.0 - 4.0.0 + 4.2.0 runtime; build; native; contentfiles; analyzers; buildtransitive all