/// <summary> /// Find the parameters /// </summary> /// <param name="definition">Subcircuit definition</param> /// <param name="parameters">Parameters</param> /// <returns></returns> private Dictionary <CircuitIdentifier, double> GenerateParameters(Netlist netlist, SubcircuitDefinition definition, Dictionary <CircuitIdentifier, Token> parameters) { // Our new parameters Dictionary <CircuitIdentifier, double> np = new Dictionary <CircuitIdentifier, double>(); // Add local parameters if (parameters != null) { foreach (var item in parameters) { np.Add(item.Key, netlist.ParseDouble(item.Value)); } } // Add default parameters if (definition.Defaults != null) { foreach (var item in definition.Defaults) { if (!np.ContainsKey(item.Key)) { np.Add(item.Key, netlist.ParseDouble(item.Value)); } } } // Other parameters if (Parameters != null) { switch (ParameterScope) { case ScopeRule.Descend: // Copy all parameters from the previous node foreach (var item in Parameters) { if (!np.ContainsKey(item.Key)) { np.Add(item.Key, item.Value); } } break; case ScopeRule.GlobalLocal: // Only copy the global parameters foreach (var item in globalparameters) { if (!np.ContainsKey(item.Key)) { np.Add(item.Key, item.Value); } } break; } } // Return results return(np); }
/// <summary> /// Read /// </summary> /// <param name="name">Name</param> /// <param name="parameters">Parameters</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override bool Read(string type, Statement st, Netlist netlist) { Transient tran = new Transient("Transient " + (netlist.Simulations.Count + 1)); switch (st.Parameters.Count) { case 0: throw new ParseException(st.Name, "Step expected", false); case 1: throw new ParseException(st.Parameters[0], "Maximum time expected", false); } // Standard st.Parameters tran.Step = netlist.ParseDouble(st.Parameters[0]); tran.FinalTime = netlist.ParseDouble(st.Parameters[1]); // Optional st.Parameters if (st.Parameters.Count > 2) { tran.InitTime = netlist.ParseDouble(st.Parameters[2]); } if (st.Parameters.Count > 3) { tran.MaxStep = netlist.ParseDouble(st.Parameters[3]); } netlist.Simulations.Add(tran); Generated = tran; return(true); }
/// <summary> /// Read /// </summary> /// <param name="type">Type</param> /// <param name="st">Statement</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override bool Read(string type, Statement st, Netlist netlist) { // Apply the change to the circuit CircuitIdentifier id; if (netlist.Path.InstancePath != null) { id = netlist.Path.InstancePath.Grow(st.Name.image); } else { id = new CircuitIdentifier(st.Name.image); } ICircuitObject result = Generate(type, id, st.Parameters, netlist); Generated = result; if (result != null) { // Add the circuit component netlist.Circuit.Objects.Add(result); return(true); } else { return(false); } }
/// <summary> /// Test a circuit object for all its parameters /// </summary> /// <param name="n">The netlist</param> /// <param name="name">The name of the object</param> /// <param name="names">The parameter names</param> /// <param name="values">The parameter values</param> /// <param name="nodes">The nodes (optional)</param> /// <returns></returns> protected T Test <T>(Netlist n, CircuitIdentifier name, string[] names = null, double[] values = null, CircuitIdentifier[] nodes = null) { var obj = n.Circuit.Objects[name]; Assert.AreEqual(typeof(T), obj.GetType()); // Test all parameters if (names != null) { TestParameters((IParameterized)obj, names, values); } // Test all nodes if (nodes != null) { TestNodes((ICircuitComponent)obj, nodes); } // Make sure there are no warnings if (CircuitWarning.Warnings.Count > 0) { throw new Exception("Warning: " + CircuitWarning.Warnings[0]); } return((T)obj); }
/// <summary> /// Read the parameter /// </summary> /// <param name="st"></param> /// <param name="netlist"></param> /// <returns></returns> public override bool Read(string type, Statement st, Netlist netlist) { // Read all assignments for (int i = 0; i < st.Parameters.Count; i++) { switch (st.Parameters[i].kind) { case ASSIGNMENT: AssignmentToken at = st.Parameters[i] as AssignmentToken; switch (at.Name.kind) { case WORD: netlist.Path.Parameters.Add(new CircuitIdentifier(at.Name.image), netlist.ParseDouble(at.Value)); break; default: throw new ParseException(at.Name, "Parameter expected"); } break; default: throw new ParseException(st.Parameters[i], "Assignment expected"); } } Generated = null; return(true); }
/// <summary> /// Perform the setup and temperature calculations /// This is often needed to calculate the default parameters /// </summary> /// <param name="n"></param> protected void Initialize(Netlist n) { n.Circuit.Setup(); foreach (var c in n.Circuit.Objects) { c.Temperature(n.Circuit); } }
/// <summary> /// Parse the value /// </summary> /// <param name="netlist">Netlist</param> /// <returns></returns> public double ParseValue(Netlist netlist) { if (Value.kind == VALUE) { return(netlist.Readers.ParseDouble(Value.image)); } throw new ParseException(Value, "Value expected"); }
/// <summary> /// Read a statement /// </summary> /// <param name="type">The reader type</param> /// <param name="name">The name</param> /// <param name="parameters">Parameters</param> /// <param name="netlist">Netlist</param> /// <returns>Returns the last generated object by a reader</returns> public object Read(Statement st, Netlist netlist) { // Check if the type exists if (!Readers.ContainsKey(st.Type)) { throw new ParseException(st.Name, "Unrecognized command type"); } return(Readers[st.Type].Read(st, netlist)); }
/// <summary> /// Constructor when reading subcircuit instances /// </summary> /// <param name="parent">Parent</param> /// <param name="subckt">Subcircuit definition</param> public SubcircuitPath(Netlist netlist, SubcircuitPath parent, Subcircuit subckt) { // Same global parameters globalparameters = parent.globalparameters; // Same globals Globals = parent.Globals; // Build parameters Parameters = GenerateParameters(netlist, subckt.Definition, subckt.Parameters); // Build instance path if (parent.InstancePath != null) { InstancePath = parent.InstancePath.Grow(subckt.Name.Name); } else { InstancePath = subckt.Name; } // Build the definition path if (parent.DefinitionPath != null) { DefinitionPath = parent.DefinitionPath.Grow(subckt.Definition.Name.Name); } else { DefinitionPath = subckt.Definition.Name; } // Node map NodeMap = GenerateNodeMap(subckt.Definition, subckt.Pins); // Add globals to the nodemap foreach (var id in Globals) { if (!NodeMap.ContainsKey(id)) { NodeMap.Add(id, id); } } // Check for recursively called paths if (parent.DefinitionPath != null) { for (int i = 0; i < parent.DefinitionPath.Path.Length; i++) { if (parent.DefinitionPath.Path[i] == subckt.Definition.Name.Name) { throw new ParseException($"Subcircuit definition {subckt.Definition} is called recursively"); } } } }
/// <summary> /// Read /// </summary> /// <param name="name">Name</param> /// <param name="parameters">Parameters</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override bool Read(string type, Statement st, Netlist netlist) { var model = GenerateModel(new CircuitIdentifier(st.Name.image), type); netlist.ReadParameters((IParameterized)model, st.Parameters); // Output netlist.Circuit.Objects.Add(model); Generated = model; return(true); }
/// <summary> /// Read /// </summary> /// <param name="st">Statement</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override object Read(Statement st, Netlist netlist) { foreach (Reader r in readers) { if (r.Read(st.Name.image.ToLower(), st, netlist)) { return(r.Generated); } } throw new ParseException(st.Name, "Unrecognized syntax"); }
/// <summary> /// Read /// </summary> /// <param name="name">Name</param> /// <param name="parameters">Parameters</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override bool Read(string type, Statement st, Netlist netlist) { // Get the nodes CircuitIdentifier node, reference = null; switch (st.Parameters.Count) { case 0: throw new ParseException(st.Name, "Node expected", false); case 2: if (!ReaderExtension.IsNode(st.Parameters[1])) { throw new ParseException(st.Parameters[1], "Node expected"); } reference = new CircuitIdentifier(st.Parameters[1].image); goto case 1; case 1: if (!ReaderExtension.IsNode(st.Parameters[0])) { throw new ParseException(st.Parameters[0], "Node expected"); } node = new CircuitIdentifier(st.Parameters[0].image); break; default: throw new ParseException(st.Name, "Too many nodes specified", false); } // Add to the exports Export ve = null; switch (type) { case "v": ve = new VoltageExport(node, reference); break; case "vr": ve = new VoltageRealExport(node, reference); break; case "vi": ve = new VoltageImaginaryExport(node, reference); break; case "vdb": ve = new VoltageDecibelExport(node, reference); break; case "vp": ve = new VoltagePhaseExport(node, reference); break; } if (ve != null) { netlist.Exports.Add(ve); } Generated = ve; return(true); }
/// <summary> /// Find a model /// </summary> /// <typeparam name="T">The model class</typeparam> /// <param name="netlist">Netlist</param> /// <param name="t">Token</param> /// <returns></returns> public static T FindModel <T>(this Netlist netlist, Token t) where T : class, ICircuitObject { switch (t.kind) { case WORD: case IDENTIFIER: return(netlist.Path.FindModel <T>(netlist.Circuit.Objects, new CircuitIdentifier(t.image))); default: throw new ParseException(t, "Invalid model name"); } }
/// <summary> /// Read /// This class will export /// </summary> /// <param name="name">Name</param> /// <param name="parameters">Parameters</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override bool Read(string type, Statement st, Netlist netlist) { for (int i = 0; i < st.Parameters.Count; i++) { if (st.Parameters[i].kind == BRACKET) { BracketToken bt = st.Parameters[i] as BracketToken; Statement s = new Statement(StatementType.Export, bt.Name, bt.Parameters); Generated = netlist.Readers.Read(s, netlist); } } return(true); }
/// <summary> /// Test using DC simulation /// The netlist should contain one DC simulation. The first exporter is tested to the reference /// </summary> /// <param name="netlist">Netlist</param> /// <param name="reference">Reference values</param> protected void TestDC(Netlist netlist, double[] reference) { int index = 0; netlist.OnExportSimulationData += (object sender, SimulationData data) => { double actual = netlist.Exports[0].Extract(data); double expected = reference[index++]; double tol = Math.Max(Math.Abs(actual), Math.Abs(expected)) * 1e-3 + 1e-12; Assert.AreEqual(expected, actual, tol); }; netlist.Simulate(); }
/// <summary> /// Test using transient simulation /// The netlist should contain a transient simulation. The first exporter is tested to the reference /// </summary> /// <param name="netlist">Netlist</param> /// <param name="reft">Reference time values</param> /// <param name="refv">Reference values</param> protected void TestTransient(Netlist netlist, double[] reft, double[] refv) { var interpolation = LinearSpline.Interpolate(reft, refv); netlist.OnExportSimulationData += (object sender, SimulationData data) => { double time = data.GetTime(); double actual = netlist.Exports[0].Extract(data); double expected = interpolation.Interpolate(time); double tol = Math.Max(Math.Abs(actual), Math.Abs(expected)) * 1e-3 + 1e-12; Assert.AreEqual(expected, actual, tol); }; netlist.Simulate(); }
/// <summary> /// Parse a token to a double. /// Both literal values and expressions {...} are accepted. /// </summary> /// <param name="netlist">The netlist</param> /// <param name="t">The token</param> /// <returns></returns> public static double ParseDouble(this Netlist netlist, Token t) { switch (t.kind) { case VALUE: return(netlist.Readers.ParseDouble(t.image)); case EXPRESSION: return(netlist.Readers.ParseDouble(t.image.Substring(1, t.image.Length - 2))); default: throw new ParseException(t, "Value or expression expected"); } }
/// <summary> /// Parse a token to a string /// Both literal and quoted "..." are accepted. /// </summary> /// <param name="netlist">The netlist</param> /// <param name="t">The token</param> /// <returns></returns> public static string ParseString(this Netlist netlist, Token t) { switch (t.kind) { case WORD: return(t.image); case STRING: return(t.image.Substring(1, t.image.Length - 2)); default: throw new ParseException(t, "String expected"); } }
/// <summary> /// Read a component statement /// </summary> /// <param name="st">Statement</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override object Read(Statement st, Netlist netlist) { char id = char.ToLower(st.Name.image[0]); if (!readers.ContainsKey(id)) { throw new ParseException(st.Name, $"Cannot recognized component \"{st.Name.image}\""); } if (readers[id].Read(id.ToString(), st, netlist)) { return(readers[id].Generated); } throw new ParseException(st.Name, $"Cannot create component \"{st.Name.image}\""); }
/// <summary> /// Read a statement /// </summary> /// <param name="st">Statement</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override object Read(Statement st, Netlist netlist) { // The name is not the name now, it is the type List <Token> parameters = new List <Token>(); string type = null; if (st.Parameters.Count < 1) { throw new ParseException(st.Name, "Invalid model definition"); } switch (st.Parameters[0].kind) { case TokenConstants.BRACKET: BracketToken bt = st.Parameters[0] as BracketToken; type = bt.Name.image.ToLower(); foreach (var p in bt.Parameters) { parameters.Add(p); } break; case SpiceSharpParserConstants.WORD: type = st.Parameters[0].image.ToLower(); for (int i = 1; i < st.Parameters.Count; i++) { parameters.Add(st.Parameters[i]); } break; default: throw new ParseException(st.Name, "Invalid model definition"); } Statement mst = new Statement(StatementType.Model, st.Name, parameters); // The name should be the identifier if (!models.ContainsKey(type)) { throw new ParseException(st.Name, $"Cannot read model \"{st.Name.image}\" of type \"{type}\""); } if (models[type].Read(type, mst, netlist)) { return(models[type].Generated); } throw new ParseException(st.Name, $"Could not create model \"{st.Name.image}\""); }
/// <summary> /// Read /// </summary> /// <param name="name">The type of the waveform</param> /// <param name="parameters">Parameters</param> /// <param name="netlist">The netlist</param> /// <returns></returns> public override bool Read(string type, Statement st, Netlist netlist) { IParameterized w = Generate(type); if (st.Parameters.Count > keys.Length) { throw new ParseException(st.Name, $"Too many arguments for waveform \"{st.Name.image}\""); } for (int i = 0; i < st.Parameters.Count; i++) { w.Set(keys[i], netlist.ParseDouble(st.Parameters[i])); } Generated = w; return(true); }
/// <summary> /// Read /// </summary> /// <param name="name">Name</param> /// <param name="parameters">Parameters</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override bool Read(string type, Statement st, Netlist netlist) { // Get the source name CircuitIdentifier source; switch (st.Parameters.Count) { case 0: throw new ParseException(st.Name, "Voltage source expected", false); case 1: if (!ReaderExtension.IsName(st.Parameters[0])) { throw new ParseException(st.Parameters[0], "Component name expected"); } source = new CircuitIdentifier(st.Parameters[0].image); break; default: throw new ParseException(st.Name, "Too many nodes specified", false); } // Add to the exports Export ce = null; switch (type) { case "i": ce = new CurrentExport(source); break; case "ir": ce = new CurrentRealExport(source); break; case "ii": ce = new CurrentImaginaryExport(source); break; case "im": ce = new CurrentMagnitudeExport(source); break; case "ip": ce = new CurrentPhaseExport(source); break; case "idb": ce = new CurrentDecibelExport(source); break; } if (ce != null) { netlist.Exports.Add(ce); } Generated = ce; return(true); }
public StatementsToken ParseNetlist(Netlist netlist) { Statement st; StatementsToken body = new StatementsToken(); while (true) { switch ((mcc_ntk == -1) ? mcc_mntk() : mcc_ntk) { case DOT: case NEWLINE: case WORD: break; default: mcc_la1[0] = mcc_gen; goto label_1; } st = ParseSpiceLine(); if (st != null) { body.Add(st); } } label_1 :; switch ((mcc_ntk == -1) ? mcc_mntk() : mcc_ntk) { case END : mcc_consume_token(END); break; case 0: mcc_consume_token(0); break; default: mcc_la1[1] = mcc_gen; mcc_consume_token(-1); throw new ParseException(); } { return(body); } throw new Exception("Missing return statement in function"); }
/// <summary> /// Test using AC analysis /// The netlist should contain one AC analysis and two exporters. The first exporter is the real part, /// the second exporter the second part. The reference is the real part followed by the imaginary part for each datapoint. /// </summary> /// <param name="netlist">Netlist</param> /// <param name="reference">Reference values</param> protected void TestAC(Netlist netlist, double[] reference) { int index = 0; netlist.OnExportSimulationData += (object sender, SimulationData data) => { // Test real part double actual = netlist.Exports[0].Extract(data); double expected = reference[index++]; double tol = Math.Max(Math.Abs(actual), Math.Abs(expected)) * 1e-6 + 1e-30; Assert.AreEqual(expected, actual, tol); // Test the imaginary part actual = netlist.Exports[1].Extract(data); expected = reference[index++]; tol = Math.Max(Math.Abs(actual), Math.Abs(expected)) * 1e-6 + 1e-30; Assert.AreEqual(expected, actual, tol); }; }
/// <summary> /// Read /// </summary> /// <param name="name">Name</param> /// <param name="parameters">Parameters</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override bool Read(string type, Statement st, Netlist netlist) { // We don't have an identifier, so we need to check here if (st.Name.kind != REFERENCE) { return(false); } if (st.Parameters.Count != 1 || (st.Parameters[0].kind != WORD && st.Parameters[0].kind != IDENTIFIER)) { return(false); } CircuitIdentifier component = new CircuitIdentifier(st.Name.image.Substring(1)); string parameter = st.Parameters[0].image.ToLower(); var pe = new ParameterExport(component, parameter); netlist.Exports.Add(pe); Generated = pe; return(true); }
/// <summary> /// Test using the noise simulation /// The netlist should contain a noise simulation. Input and output referred noise density are checked /// </summary> /// <param name="netlist">Netlist</param> /// <param name="reference">Reference values</param> protected void TestNoise(Netlist netlist, double[] reference_in, double[] reference_out) { int index = 0; netlist.OnExportSimulationData += (object sender, SimulationData data) => { double freq = data.GetFrequency(); double actual = Math.Log(data.GetInputNoiseDensity()); double expected = Math.Log(reference_in[index]); double tol = Math.Max(Math.Abs(actual), Math.Abs(expected)) * 1e-3 + 1e-12; Assert.AreEqual(expected, actual, tol); actual = Math.Log(data.GetOutputNoiseDensity()); expected = Math.Log(reference_out[index]); tol = Math.Max(Math.Abs(actual), Math.Abs(expected)) * 1e-3 + 1e-12; Assert.AreEqual(expected, actual, tol); index++; }; netlist.Simulate(); }
/// <summary> /// Read /// </summary> /// <param name="name">Name</param> /// <param name="parameters">Parameters</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override bool Read(string type, Statement st, Netlist netlist) { // Only assignments are possible for (int i = 0; i < st.Parameters.Count; i++) { switch (st.Parameters[i].kind) { case ASSIGNMENT: AssignmentToken at = st.Parameters[i] as AssignmentToken; switch (at.Name.kind) { case BRACKET: BracketToken bt = at.Name as BracketToken; if (bt.Name.image.ToLower() == "v" && bt.Parameters.Length == 1 && ReaderExtension.IsNode(bt.Parameters[0])) { netlist.Circuit.Nodes.Nodeset.Add(new CircuitIdentifier(bt.Parameters[0].image), netlist.ParseDouble(at.Value)); } else { throw new ParseException(st.Parameters[i], "Invalid format, v(<node>)=<ic> expected"); } break; default: if (ReaderExtension.IsNode(at.Name)) { netlist.Circuit.Nodes.Nodeset.Add(new CircuitIdentifier(at.Name.image), netlist.ParseDouble(at.Value)); } else { throw new ParseException(st.Parameters[i], "Invalid format, <node>=<ic> expected"); } break; } break; } } return(true); }
/// <summary> /// Read a statement /// </summary> /// <param name="st">Statement</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override object Read(Statement st, Netlist netlist) { // The name should be the identifier string type = st.Name.image.ToLower(); if (!readers.ContainsKey(type)) { foreach (Reader r in any) { if (r.Read(type, st, netlist)) { return(r.Generated); } } throw new ParseException(st.Name, $"Cannot recognize \"{st.Name.image}\""); } else if (readers[type].Read(type, st, netlist)) { return(readers[type].Generated); } throw new ParseException(st.Name, $"Could not create \"{st.Name.image}\""); }
/// <summary> /// Parse a vector of double values /// </summary> /// <param name="netlist">The netlist</param> /// <param name="t">The token</param> /// <returns></returns> public static double[] ParseDoubleVector(this Netlist netlist, Token t) { if (t.kind == TokenConstants.VECTOR) { var vt = t as VectorToken; double[] values = new double[vt.Tokens.Length]; for (int i = 0; i < values.Length; i++) { values[i] = netlist.ParseDouble(vt.Tokens[i]); } return(values); } else if (t.kind == VALUE || t.kind == EXPRESSION) { return new double[] { netlist.ParseDouble(t) } } ; else { throw new ParseException(t, "Vector expected"); } }
/// <summary> /// Read /// </summary> /// <param name="type">Type</param> /// <param name="st">Statement</param> /// <param name="netlist">Netlist</param> /// <returns></returns> public override bool Read(string type, Statement st, Netlist netlist) { Interpolated ip = new Interpolated(); if (st.Parameters.Count < 4) { throw new ParseException(st.Parameters[st.Parameters.Count - 1], "At least 2 points expected", false); } if (st.Parameters.Count % 2 != 0) { throw new ParseException(st.Parameters[st.Parameters.Count - 1], "Value expected", false); } ip.Time = new double[st.Parameters.Count / 2]; ip.Value = new double[st.Parameters.Count / 2]; for (int i = 0; i < st.Parameters.Count / 2; i++) { ip.Time[i] = netlist.ParseDouble(st.Parameters[i * 2]); ip.Value[i] = netlist.ParseDouble(st.Parameters[i * 2 + 1]); } Generated = ip; return(true); }